avr i C - kto nie rozumie: kompilator, procesor czy ja?

Witajcie,

Ostatnie moje problemy (tu na grupie poruszane) z obsługą uarta na atmelkach stały się moim gwoździem do trumny bascoma i w końcu się zawziąłem na C, choć zabierałem się do tego już od roku jak pies do jeża. No to na początek, standardowo pomrugamy diodą. Ot taki programik:

#define F_CPU 16000000UL #include <avr/io.h>

#include <util/delay.h>

int main(void) { DDRD = 0xFF; PORTD = 0x00; while(1) { PORTD ^= _BV(0); _delay_ms(500); } }

I zonk, na porcie ciągle stan wysoki. Podejrzałem plik .lss i niby wszystko ok, jak patrzę na instrukcję asemblera to powinno działać:

00000038 <main>: 38: 8f ef ldi r24, 0xFF 3a: 81 bb out 0x11, r24 3c: 12 ba out 0x12, r1 3e: 91 e0 ldi r25, 0x01 40: 82 b3 in r24, 0x12 42: 89 27 eor r24, r25 44: 82 bb out 0x12, r24 46: ef ef ldi r30, 0xFF 48: ff e3 ldi r31, 0x3F 4a: 31 97 sbiw r30, 0x01 4c: f1 f7 brne .-4 4e: 00 c0 rjmp .+0 50: f7 cf rjmp .-18

Ale niestety nie działa, stan na porcie zmienia się bez opóźnienia. A teraz ciekawostka, zamiast wykorzystywać funkcję _delay_ms wstawiłem swoją:

void delay(void) { uint16_t i; for (i=0;i<15000;i++); }

Patrzę na plik .lss, a tu:

00000038 <delay>: 38: 88 e9 ldi r24, 0x98 3a: 9a e3 ldi r25, 0x3A 3c: 01 97 sbiw r24, 0x01 3e: f1 f7 brne .-4 40: 08 95 ret 00000042 <main>: 42: 8f ef ldi r24, 0xFF 44: 81 bb out 0x11, r24 46: 12 ba out 0x12, r1 48: 91 e0 ldi r25, 0x01 4a: 82 b3 in r24, 0x12 4c: 89 27 eor r24, r25 4e: 82 bb out 0x12, r24 50: fc cf rjmp .-8

Wychodzi na to, że po przełączeniu bitu PD0 w ogóle nie wywołuje funkcji delay() - no i port tak właśnie się zachowuje, w kółko się przełącza.

Obstawiam opcję, że ja czegoś nie rozumie, ale może ktoś mnie oświeci.

Reply to
Jakub Rakus
Loading thread data ...

Nie użyłeś volatile przy deklaracji zmiennej "i" w funkcji delay(), "i" nie jest nigdzie wykorzystane dalej w kodzie funkcji więc optymalizator wywalił cały for, jak nie potrzebny for to i cała funkcja delay()...

Reply to
Marek

Jakub Rakus snipped-for-privacy@op.pl napisał(a):

A problem był po stronie Bascoma czy niedopracowanego algorytmu?

Ustawiłeś optymalizacje zgodnie z dokumentacją? Którego kompilatora używasz?

Reply to
Grzegorz Niemirowski

W dniu 06.01.2013 15:26, Marek pisze:

Ooo, no to jest racja, nie pomyślałem. Faktycznie, dodaję volatile, wtedy śmiga. Podziękował! Ale nadal pozostaje problem nie działającej funkcji _delay_ms().

Reply to
Jakub Rakus

W dniu 06.01.2013 15:29, Grzegorz Niemirowski pisze:

Problem polegał na tym, że pomimo wielu prób nie doszedłem do tego jak stworzyć poprawnie działający algorytm pisząc go tylko w bascomie, nie angażując w to asemblera, a nie miałem na to ochoty ;) - poza tym po skompilowaniu miałem i tak już ogromny program (3kB!), a w planie jeszcze kilka funkcjonalności, więc i tak bym doszedł do granicy możliwości darmowego bascoma.

Korzystam z code::blocks i avr-gcc w wersji 4.5.3. Ustawiam optymalizację na -O. Co ciekawe, gdy wyłączę optymalizację w ogóle, oczywiście mam ostrzeżenie, że funkcje z delay.h będą działać niepoprawnie, kompiluje się, program wynikowy jest ogromny, ale... działa.

Reply to
Jakub Rakus

Zgaduje teraz (nie znam się na avr), czy czasem nie potrzeba wcześniej wywolac jakaś funkcję konfigurujaca bibliotekę wszystkich funkcji delay? Skąd delay wie jaka jest aktualna częstotliwość zegara?

Reply to
Marek

Zgodnie z tym co napisano na początku delay.h wystarczająca jest linijka, którą mam na początku kodu:

#define F_CPU 16000000UL

A nawet gdyby jej nie było to przyjmie sobie domyślną wartość F_CPU

1000000UL.
Reply to
Jakub Rakus

Jakub Rakus snipped-for-privacy@op.pl napisał(a):

Nie wiem, co u Ciebie dokładnie oznacza -O, u mnie jest to -O1. Twój program działa bez żadnego problemu u mnie na ATmega32 (może kompilujesz na zły procesor). Używam Atmel Studio 6 ( AVR/GNU C Compiler : (AVR_8_bit_GNU_Toolchain_3.4.0_663) 4.6.2) Poza tym w pierwszym poście piszesz: "I zonk, na porcie ciągle stan wysoki." z czego wynika, że u Ciebie w ogóle nie wykonuje się pętla while. Mój lss:

00000092 <main>: #define F_CPU 16000000UL #include <avr/io.h>

#include <util/delay.h>

int main(void) { DDRD = 0xFF;

92: 8f ef ldi r24, 0xFF ; 255 94: 81 bb out 0x11, r24 ; 17 PORTD = 0x00; 96: 12 ba out 0x12, r1 ; 18 while(1) { PORTD ^= _BV(0); 98: 91 e0 ldi r25, 0x01 ; 1 9a: 82 b3 in r24, 0x12 ; 18 9c: 89 27 eor r24, r25 9e: 82 bb out 0x12, r24 ; 18 #else //round up by default __ticks_dc = (uint32_t)(ceil(fabs(__tmp))); #endif __builtin_avr_delay_cycles(__ticks_dc); a0: 2f ef ldi r18, 0xFF ; 255 a2: 39 e6 ldi r19, 0x69 ; 105 a4: 48 e1 ldi r20, 0x18 ; 24 a6: 21 50 subi r18, 0x01 ; 1 a8: 30 40 sbci r19, 0x00 ; 0 aa: 40 40 sbci r20, 0x00 ; 0 ac: e1 f7 brne .-8 ; 0xa6 <main+0x14>

ae: 00 c0 rjmp .+0 ; 0xb0 <main+0x1e>

b0: 00 00 nop b2: f3 cf rjmp .-26 ; 0x9a <main+0x8>

000000b4 <_exit>: b4: f8 94 cli 000000b6 <__stop_program>: b6: ff cf rjmp .-2 ; 0xb6 <__stop_program>
Reply to
Grzegorz Niemirowski

W dniu 06.01.2013 16:58, Grzegorz Niemirowski pisze:

Zjadła się jedynka, też mam -O1.

Zasugerowałem się tym, że leda mi ciągle świeci, ale faktycznie pętla się wykonuje - tylko, że cholernie szybko...

O widzisz tu właśnie jest rozbieżność - u Ciebie jak widzę działa to dokładnie tak jak opisane jest to na początku delay.h. U mnie _HAS_DELAY_CYCLES ma wartość 1, więc teoretycznie także powinna zostać wywołana funkcja _builtin_avr_delay_cycles, a z jakiegoś powodu tak się nie dzieje.

Reply to
Jakub Rakus

Jakub Rakus snipped-for-privacy@op.pl napisał(a):

A czy ten Twój toolchain ma w ogóle tę funkcję? I dlaczego użwasz akurat tego toolchaina a nie np. Atmel Studio 6 albo WinAVR?

Reply to
Grzegorz Niemirowski

W dniu 06.01.2013 17:46, Grzegorz Niemirowski pisze:

Ale ja to wszystko robię pod linuxem. Więc podejrzewam właśnie brak owej funkcji.

Reply to
Jakub Rakus

Jakub Rakus snipped-for-privacy@op.pl napisał(a):

Też mi się wydaje, że jej tam nie ma. Ma moim Ubuntu jest tak samo jak u Ciebie. Dlatego najprościej będzie zainstalować sobie Atmel Studio na Windowsie. Chyba, że jest jakiś prosty patch na avt-libc, ale nie znalazłem.

Reply to
Grzegorz Niemirowski

W dniu 06.01.2013 18:56, Grzegorz Niemirowski pisze:

Windows jest feee, nie chce go :P Ale znalazłem przyczynę i rozwiązanie problemu, otóż problemem jest położenie plików nagłówkowych. Domyślnie kompilator gcc-avr w ich poszukiwaniu przeszukuje katalog /usr/include a tam niestety wszystkiego nie ma, wystarczy w ustawieniach kompilatora zmienić mu ścieżkę na /usr/lib/avr/include i nagle wszystko zaczyna działać jak należy.

Reply to
Jakub Rakus

W dniu 2013-01-06 16:09, Jakub Rakus pisze:

Chyba, że ustawimy inną w makefile.

Reply to
Atlantis

Za dużo.

formatting link
The maximal possible delay is 262.14 ms / F_CPU in MHz.

Daj:

for (int i(0); i < 50; ++i) _delay_ms(10);

Reply to
Adam Wysocki

Jakub Rakus snipped-for-privacy@op.pl napisał(a):

Fajnie, dzięki za info, przyda się

Reply to
Grzegorz Niemirowski

Czytaj dalej: "When the user request delay which exceed the maximum possible one, _delay_ms() provides a decreased resolution functionality. In this mode _delay_ms() will work with a resolution of 1/10 ms, providing delays up to 6.5535 seconds (independent from CPU frequency). The user will not be informed about decreased resolution."

Michał

Reply to
Michał Lankosz

Punkt dla Ciebie :)

Reply to
Adam Wysocki

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.