ATMega16, GCC, problem z przerwaniami od timera

Prubuję uruchomić taki program:

<code>

#include <avr/io.h>

#include <avr/interrupt.h>

#include <avr/signal.h>

SIGNAL(SIG_OVERFLOW0) { PORTB = 0xff; PORTD = 0xff; __asm__ __volatile__ ("reti" ::); }

int main() { MCUCSR |= 0x80; MCUCSR |= 0x80; DDRA = 0xFF; DDRB = 0xFF; DDRC = 0xFF; DDRD = 0xFF; PORTB = 0x00; PORTD = 0x00; TCNT0 = 0x00; /* CTC; clk_IO/1024 (From prescaler) */ TCCR0 = 0 | (0 << WGM00) | (1 << WGM01) | (5 << CS00); /* 4194304Hz / (2 * 1024 * (1 + (OCR0)1)) = 1024Hz */ OCR0 = 1; /* Timer/Counter0 Output Compare Match Interrupt Enable */ TIMSK = 0 | (1 << OCIE0) | (0 << TOIE0); SREG |= (1 << SREG_I); while(1) { asm volatile("nop" ::); } return 0; }

</code>

Niestety stan linii portu B i D nie zmienia się (pozostaje 0 na wszystkich liniach). Porty są sprawne, bo po umieszczeniu PORTB = 0xff i PORTD = 0xff w main() wszystko działa poprawnie (porty przechodzą w stan H).

Docelowo program ma podawać odpowiednio spreparowane dane z częstotliwością ok. 1000Hz (1024Hz jest ok). Utknąłem jednak w trakcie "odpalenia" przerwań.

Z góry dziękuję za wszelkie sugestie i informacje. Być może robię jakiś trywialny błąd, ale siędzę nad tym już od dłuższego czasu i brak mi pomysłów.

Pozdrawiam!

Reply to
Daniel Jaworski
Loading thread data ...

[...]

Trochę poprawiłem, powinno ruszyć:

#include <avr/io.h>

#include <avr/interrupt.h>

#include <avr/signal.h>

SIGNAL(SIG_OVERFLOW0) { TCNT0=256-4; PORTB = 0xff; PORTD = 0xff; }

void main(void) { MCUCSR |= 0x80;

DDRA = 0xFF; DDRB = 0xFF; DDRC = 0xFF; DDRD = 0xFF;

PORTB = 0x00; PORTD = 0x00;

TCNT0 = 256-4; // przerwanie co 4*1024 cykle ~1024Hz

/* CTC; clk_IO/1024 (From prescaler) */ TCCR0 = (5 << CS00);

/* Timer/Counter0 Output Compare Match Interrupt Enable */ TIMSK = (1 << TOIE0);

sei();

while(1); }

Reply to
Zbych

Daniel Jaworski napisał(a):

jeśli używasz licznika z porównywaniem wartości OCR0 to powinieneś raczej obsługiwać SIG_OUTPUT_COMPARE0, nie przepełnienie licznika. nieobsłużone przerwanie spowoduje zatrzymanie programu.

to nie jest potrzebne. co więcej, prolog funkcji na pewno odłożył trochę danych na stosie, więc na jego szczycie na pewno nie ma adresu powrotu tylko coś w stylu zawartość rejestrów w momencie wywołania przerwania. program pójdzie w maliny.

co prawda to nie błąd, ale masz od tego makro sei().

wystarczy opuścić main(), program sam się zapętli.

w.

Reply to
Wojtek Kaniewski

Genialnie. Ruszyło :-). Dalej jednak nie wiem dlaczego licznik nie chciał liczyć w trybie CTC.

Pozdrawiam!

Reply to
Daniel Jaworski

I dokładnie o to chodziło... dziękuję wszystkim za pomoc. Źle zrozumiałem sposób działania licznika i myślałem, że zawsze zgłaszane jest SIG_OVERFLOW0, a to co je wywołuje zależy od ustawienia rejestrów. Teraz wszystko jest jasne. Jeszcze raz dziękuję.

Racja. Ale w akcie "desperacji" próbowałem wszystkiego i to się po tych próbach ostało.

OK - jest już via makro.

Pozdrawiam!

Reply to
Daniel Jaworski

Korzystając z okazji chciał bym spytać się jeszcze o jedno.

Zgodnie z notą Atmela. Częstotliwość wyjściowa licznika w trybie CTC wynosi: f_OCn = f_clkIO / (2 * N * (1 + OCRn))

Zgodnie z tym wnioskuję, że częstotliwość przerwań będzie wynosić 2 razy tyle. Na jeden okres przebiegu trzeba dwa przerwania w celu wygenerowania obu zboczy.

Zatem z w/w wzoru wywalam 2.

Podstawiam to co mam: f_clkIO = 4194304Hz N = 1024 (preskaler) OCR0 = 204

4194304 / (1024 * (1 + 204)) = 4096 / 205 = 20 Hz

Tymczasem przerwania pojawiają się 4 razy mniejszą częstotliwością (ok.

5Hz). Te 5Hz pochodzi z obserwacji organoleptycznych :-) więc może być niedokładne. O co chodzi?

Bardzo proszę o wskazówkę.

Pozdrawiam!

Reply to
Daniel Jaworski

Daniel Jaworski napisał(a):

wygląda dobrze, ale może w kodzie jest błąd? pokaż, jak ustawiasz timer.

w.

Reply to
Wojtek Kaniewski

TCNT0 = 0x00; /* CTC; clk_IO/1024 (From prescaler) */ TCCR0 = 0 | (0 << WGM00) | (1 << WGM01) | (1 << CS02) | (0 << CS01) | (1 << CS00); /* 4194304Hz / (1024 * (1 + (OCR0)1)) = 1024Hz */ OCR0 = 204; /* Timer/Counter0 Output Compare Match Interrupt Enable */ TIMSK = 0 | (1 << OCIE0) | (0 << TOIE0);

Tak ustawiam timer.

Reply to
Daniel Jaworski

EM wrote: [...]

To jest bardzo rozsądny trop. Tylko czy te bity przestawię moim programatorem...?

Pozdrawiam,

Reply to
Daniel Jaworski

ispprog ma mozliwosc modyfikacji fuse bitow.

Reply to
Filip Ozimek

Spróbuj ISP Programmerem:

formatting link

Reply to
Adam Dybkowski

Tylko 10x przed ich przestawieniem sprawdz ich ustawienie, bo kolejny post zatytulujesz - Ratunku!! Moja ATMega zdechla;) Uwaga praktyczna - czasami bit=1 to bit skasowany w ustawieniach programatora (0) i vice versa.

Reply to
T.M.F.

Atmel w swojej dokumentacji nazywa bitem skasowanym taki o wartości '1' a bitem zaprogramowanym bit o wartości '0'. Wynika to z budowy komórki pamięci Flash, której skasowanie nadaje wartość '1'. Tego się trzeba trzymać i nie będzie problemów. Jeżeli na przykład piszą, że CLKOUT=1 to taką wartość trzeba ustawić w programatorze. ISP Programmer "ptaszkami" oznacza wartość fusebitu '1', dodatkowo podaje bajt fusebitów szestnastkowo aby każdy mógł zweryfikować to przed zaprogramowaniem.

Reply to
Adam Dybkowski

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.