Moderators: stojke369, pedja089, [eDo], trax
Samo da vidim kako stojim.
U disasembleru vidim ovo:
CODE: SELECT ALL
while(1){ /* main loop */
PORTC ^= (1<<PC5); /* Toggle my debug line */
be: 90 e2 ldi r25, 0x20 ; 32
c0: 88 b1 in r24, 0x08 ; 8
c2: 89 27 eor r24, r25
c4: 88 b9 out 0x08, r24 ; 8
c6: fc cf rjmp .-8 ; 0xc0 <main+0x22>
Bug će se javit ako interrupt okine točno u trenutku kad se izvrši EOR, a prije nego se vrijednost zapiše u PortC (out 0x08, r24).
E šta se događa.. Interupt rutina sve fino okrene PC0, al samo na koju mikrosekundu, jer čim se vratimo iz nje, stara vrijednost portaC se već nalazi u r24 i OUT mijenja PortC, ali nije uzeto u obzir novo stanje PortC iz interrupt rutine.
Ustvari kad sad bolje pogledam, osuđeni smo na propast već prije EOR, kod IN r24, 0x08 jer će ovaj fino pospremiti stanje porta i kad se vratimo iz ISR-a opet baratamo sa starim sranjem, ne novim.
E to je već ozbiljna stvar jer pošto vrtimo 5 ASM naredbi imat ćemo bug u 40% slučajeva.
Zato treba takve pizdarije micat iz ISR-a, ostaviti samo najosnovnije, jedino ako je bitno da se u baš tom i tom trenutku npr. uključi tiristor nakon zero-crossing, no opet za takve stvari postoji hardware (compare/match registri), al to je već malo dublja priča.
Eh da, rješenje.
Npr.
ATOMIC_BLOCK(ATOMIC_FORCEON) PORTC ^= (1<<PC5);
Jako fino ubaci CLI prije IN i SEI poslije OUT.
Da, treba i
#include <util/atomic.h>
PORTC |= (1<<PC5);
PORTC &=~(1<<PC5);
sbi 0x08, 5 ; Set PC5
cbi 0x08, 5 ; Clear PC5
Return to Nagradne Igre - dijelovi
Users browsing this forum: No registered users and 0 guests