avr-gcc i wstawki asemblerowe

Nov 06, 2004 5 Replies

Witam



Niedawno zaczalem zabawe z AVRami. Napisalem sobie petle opoznien w asemblerze pod AVRStudio. Teraz zabralem sie za avrgcc i chcialbym funkcje opoznien napisac jako wstawki asemblerowe. W dokumentacji wyczytalem ze mozna np. tak:



... asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); ...



Problem w tym ze w wynikowym listingu pojawia sie tylko jeden nop. Optymalizacje wylaczylem. Uzywam Avrside.



Moze jest jakis sposob zeby wywolywac funkcje napisane w calosci w asm znajdujace sie w innych plikach ?



Pozdrawiam Krzysztof Urbanski krzysztof-u@[usun_to]wp.pl


Sprobuj to zrobic w jednym bloku volatile:

asm volatile("\tnop\n" \ "\tnop\n" \ "\tnop\n");

Deklaracja volatile zabrania zmieniac kompilatorowi strukture bloku. Tylko IIRC dziala ona na _spojnych_ blokach, a Ty utworzyles trzy rozne bloki, wiec teoretycznie kompilator mogl sobie przy nich pomajstrowac.

extern "C" sygnatura_funkcji();

Jesli nazwa funkcji asemblerowej jest "dziwna", to mozna sobie jeszcze pomoc podajac pelna nazwe za pomoca __attribute__((__allias__)). Najlepiej jesli funkcje nie biora parametrow i nie zwracaja wynikow; w przeciwnym razie musisz sie zapoznac z tzw. konwencjami wywolania. Tylko pamietaj, ze wstawka to cos innego niz zewnetrzna funkcja, wiec staraj sie nie naduzywac jednego mechanizmu do symulowania drugiego -- kazdy z nich ma optymalny zakres zastosowan.

Pozdrawiam Piotr Wyderski

Piotr Wyderski napisał(a):

Dzieki. Pokombinuje. Moze cos wkoncu z tego wyjdzie.

Sat, 06 Nov 2004 19:02:18 +0100, na pl.misc.elektronika, Krzysztof Urbanski napisał(a):

Deklarujesz w pliku asemblerowym .s funkcję jako globalną, w pliku .c jako zewnętrzną (extern) i normalnie wywołujesz. Sprawa jest prosta dla funkcji void, np. przykład z opóźnieniem może wyglądać tak :

<>

.global MyDelay .section .text,"ax",@progbits .type MyDelay,@function MyDelay: nop nop nop ret .size MyDelay, .-MyDelay </>

- w deklaracjach pliku .c zapisujemy extern void MyDelay(void);

a potem sobie z miarę potrzeb wywołujemy MyDelay();

W momencie gdy trzeba przekazać argumenty do funkcji i zwrócić wartość rzeczy się oczywiście nieco komplikują. Ale i tak IMHO oddzielne pliki asm są dużo bardziej przyjazne i czytelne niż barokowa składnia wstawek ;-)) Chociaż nie zawsze się to da tak całkiem zastąpić - tutaj wstawka realizuje

3 nopy; wywołanie funkcji to 3 nopy + rcall + ret a więc dużo więcej.

może to niedokładnie to, o co Ci chodzi, ale avr-libc zawiera już większość kodu niezbędnego do opóźnień w <avr/delay.h>. dodaj zależności od zegara w #define i gotowe.

w.

Napisalem cos takiego:

Plik "delay.s" w asemblerze: ___________________________________________________________________ ;Generowanie opoznien ;Dane w jednostkach czasu podane dla rezonatora 11,0592 MHz ;Krzysztof Urbanski ;Slupsk 8.11.2004 ;Opoznienie x*1us (dokladnie 0,994646...us) czyli x*11 cykli ;x umiescic w rejestrze r24 ;orientacyjnie przy ustawieniu: 1us uzyskuje sie czas 1,625us ;i odpowiednio: ;2us - 2,62us ;3us - 3,615us ;10us - 10,57us ;100us - 100us .global waitus waitus: cpi r24,1 breq koniec_waitus dec r24 push r24 ;wytracanie czasu pop r24 ;wytracanie czasu nop nop rjmp waitus koniec_waitus: nop ret

;Opoznienie (x*1ms)+0,994646...us czyli (x*11059 cykli)+15 cykle ;x umiescic w rejestrze r24 ;uzywa rejestru r17 ;jego zawartosc jest odtwarzana przed powrotem z podprogramu .global waitms waitms: push r17 ;przechowanie r17 na stosie mov r17,r24 start_waitms: cpi r17,0 breq koniec_waitms dec r17 ldi r24,200 rcall waitus ldi r24,200 rcall waitus ldi r24,200 rcall waitus ldi r24,200 rcall waitus ldi r24,203 rcall waitus nop rjmp start_waitms koniec_waitms: pop r17 ;odtworzenie r17 ze stosu ret

;Opoznienie (x*1s)+0,994646...us czyli (x*11059200 cykli)+15 cykli ;x umiescic w rejestrze r24 ;uzywa rejestru r17 i r18 ;ich zawartosc jest odtwarzana przed powrotem z podprogramu .global waits waits: push r18 ;przechowanie r18 na stosie mov r18,r24 start_waits: cpi r18,0 breq koniec_waits dec r18 ldi r24,250 rcall waitms ldi r24,250 rcall waitms ldi r24,250 rcall waitms ldi r24,249 rcall waitms ldi r24,250 rcall waitus ldi r24,254 rcall waitus ldi r24,255 rcall waitus ldi r24,255 rcall waitus push r24 ;wytracanie czasu pop r24 ;wytracanie czasu push r24 ;wytracanie czasu pop r24 ;wytracanie czasu rjmp start_waits koniec_waits: pop r18 ;odtworzenie r18 ze stosu ret .end __________________________________________________________________

Plik "main.c" w C uzywajacy opoznien:

#include <avr\io.h>

#define led 7 //definicja bitu portu dla LED #define wy 6 //definicja bitu portu dla wyjscia

extern void waitus(unsigned char); //argument przekazywany jest przez //rejestr r24 extern void waitms(unsigned char); extern void waits(unsigned char);

int main(void) //program główny { PORTD=0xff; //jedynki na PORTD DDRD=0xff; //PORTD wyjscia while(1) { sbi(PORTD,led); sbi(PORTD,wy); waits(1); cbi(PORTD,led); cbi(PORTD,wy); waits(1); } } _________________________________________________________________

Dziala bardzo dobrze i dokladnie, moze komus sie przyda. Dzieki za odpowiedzi.

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required