Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Za wolny timer w ATmega8. Program wysyłający znak co 1 s poprzez UART.

tkaz 05 Maj 2006 23:40 1689 11
  • #1 05 Maj 2006 23:40
    tkaz
    Poziom 10  

    Witam,

    mam w ukladzie ATmega8 + MAX232 do komunikacji z komputerem.
    ATmega jest taktowana z zewnetrznego kwarcu 16MHz. Wydaje sie, ze fuse bity sa dobrze ustawione, bo do obliczenia parametru predkosci USART (wpisywanego w UBRR) musze wykorzystywac wlasnie 16000000.

    Mam jednak problem z timerami. Zarowno _delay_ms(), jak i _delay_loop_2() dzialaja tak, jakby ATmega byla taktowana 1MHz.

    Czy cos przegapilem w konfiguracji? Moze ktos podeslalby mi prosty program wysylajacy przez USART co 1 sekunde jakis znak?

    Z gory dziekuje,
    T.Kaz.

    0 11
  • #2 06 Maj 2006 00:17
    adamusx
    Poziom 27  

    Skonfigurowales odpowiednio Fusebity Atmegi? Musisz je ustawic tak by uC pracowal z zewnetrznym kwarcem 16Mhz, bo prawdopodobnie narazie uC chodzi Ci na wewnetrznym zegarze 1Mhz. Jesli nie wiesz o co biega z fuse bitami poszukaj na elektrodzie, bylo walkowane z milion razy :)

    0
  • #3 06 Maj 2006 01:24
    zerpo
    Poziom 22  

    Pamiętaj także, że jako argument funkcji _delay_ms(xxx) mozesz podac liczbę milisekund max 255/freq., gdzie freq to częstot. kwarca. W Twoim przypadku jednym wywołaniem tej funkcji możesz opóźnić o max ok. 16ms...

    0
  • #4 06 Maj 2006 17:21
    tkaz
    Poziom 10  

    Mam wrazenie, ze fuse bity mam ustawione dobrze:

    # uisp -dprog=dapa -dlpt=0x378 --rd_fuses
    Atmel AVR ATmega8 is found.

    Fuse Low Byte = 0x9f
    Fuse High Byte = 0xc9
    Fuse Extended Byte = 0xff
    Calibration Byte = 0xb9 -- Read Only
    Lock Bits = 0xff
    BLB12 -> 1
    BLB11 -> 1
    BLB02 -> 1
    BLB01 -> 1
    LB2 -> 1
    LB1 -> 1

    Przemawia za tym dodatkowo fakt, ze do obliczania predkosci USART musze wziac wlasnie 15MHz, zeby dzialalo.

    Ograniczenia argumentu _delay_ms() znam - mam petle
    for(i=0; i<100; i++) _delay_ms(10);
    ktora wykonuje sie przez 15 sekund. Poza tym sprawdzalem jeszcze _delay_loop_2(65500) - ta wykonuje sie przez ok. 200 ms, czyli jak z zegarem 1MHz.

    Dziwne to wszystko.

    Pozdrawiam,
    T.Kaz.

    0
  • #5 06 Maj 2006 18:08
    icdark
    Poziom 13  

    Mam nadzieje ze nie zapomniales o

    Code:
    #define XTAL 16000000


    nie wiem czy czasem domyslne XTAL nie jest ustawione na 1MHz :]

    pzdr

    0
  • #6 06 Maj 2006 18:26
    LordBlick
    VIP Zasłużony dla elektroda

    W AVRgcc używa się F_CPU, a nie XTAL, i to najlepiej tak:

    Code:
    #define F_CPU 16000000UL
    Daje to mozliwość uzyskania obliczeń wielu stałych w trakcie kompilacji.

    0
  • #7 06 Maj 2006 18:31
    tkaz
    Poziom 10  

    Tak czy siak - nie zapomniałem o F_CPU. Dodałem też definicję XTAL, ale nie ma wpływu.

    Jak wstawić do kodu w C fragment asemblera? Wymyśliłem, żeby wstawić pętlę, powiedzmy 255 razy po 255 razy NOP i zmierzyć, jak długo się wykonuje. Powiedziałoby mi to jednoznacznie z jaką prędkością działa układ.

    Może ktoś ma jakieś doświadczenie z takimi wstawkami i podzieliłby się gotowym kodem?

    Pozdrawiam,
    T.Kaz.

    0
  • #8 06 Maj 2006 18:59
    icdark
    Poziom 13  

    nie doczytalem ze chodzi o gcc, tam faktycznie jest F_CPU. Co do wstawek to

    Code:
    asm volatile ("nop"::);

    volatile jest po to aby kompilator nie wywalil Ci tej wstawki (zwiazane jest to z optymalizacja)

    0
  • #9 06 Maj 2006 19:15
    tkaz
    Poziom 10  

    A jak będzie wyglądać wstawka w stylu:

    mov ecx, 0xff
    petla:
    nop
    dec ecx
    cmp ecx, 0
    jz petla

    ?

    Dzięki,
    T.Kaz.

    0
  • #10 06 Maj 2006 19:26
    icdark
    Poziom 13  

    Cytat:
    mov ecx, 0xff
    petla:
    nop
    dec ecx
    cmp ecx, 0
    jz petla

    nie ten uP chyba ;]... rozumiem ze poprzez okreslenie "cos w tym stylu" masz na mysli wersje asm dla avr.

    Code:
    ldi r16,255
    
    petla:
    nop
    dec r16
    brne petla


    wstaw to do asm volatile zgodnie z opisem w dokumentacji avrgcc i bedzie smigalo. Sa tam tez inne opcje pozwalajace na dostep do zmiennych zadeklarowanych w C (po to wlasnie sa tamte ":" i znaczniki w stylu "%0" itd). Po szczegoly odsylam do dokumentacji.

    0
  • #11 07 Maj 2006 14:28
    tkaz
    Poziom 10  

    Zbadałem systematycznie swój problem i okazało się, że przyczyną było włączenie przerwań ("sei").

    Jeśli przerwań nie ma, to wszystko działa jak powinno, natomiast po ich włączeniu obserwuję kilkunastokrotne spowolnienie procesora. To jest prawdziwe spowolnienie, a nie tylko timera - pętla assemblerowa o znanej długości wykonuje się o wiele za wolno.

    Czy włączenie przerwań musi być tak kosztowne?

    Pozdrawiam,
    T.Kaz.

    0
  • #12 07 Maj 2006 17:26
    icdark
    Poziom 13  

    Idea przerwan nie zmienia wszybkosci dzialania glownego programu. Oczywiscie trzeba liczyc sie z tym, ze gdy przerwania wystepuja program jest przerywany i zostaje dane przerwanie obslugiwane. Sytuacja taka jaka opisujesz moze wystapic przy wielokrotnym wywolaniu przerwan np. zew przerwanie INT0 w przypadku wystepowania zaklocen moze wielokrotnie sie wzbudzac i przerywac wykonywanie glownego programu kosztem tego przerwania (np. przycisk podpiety pod INT0, wykrywa zwarcie do masy i w celu eliminacji drgan zestykow programowo odczekuje np 20ms, po tym czasie ponownie sprawdza stan i jezeli byly to zaklocenia to wychodzi gladko z funkcji. Zakladajac, ze podobna zasada u Ciebie wystepuje opoznia dzialania glownego programu, pomimo iz dane przerwania de facto niczego do programu nie wnosi). Sprawdz ktore przerwanie jest wielokrotnie wyzwalane. Opoznia ono program o czas potrzebny do wykonania wlasnej funkcji. Co dokladnie ten program powinien robic? Jakie przerwania stosujesz i jak wyglada hardware?

    pozdrawiam
    icdark

    0