Duhovi AVR-a

Rasprava o AVR mikrokontrolerima, AVR projekti i drugo vezano za AVR...

Moderators: pedja089, stojke369, trax, InTheStillOfTheNight

Post Reply
User avatar
InTheStillOfTheNight
Odlično uznapredovao
Odlično uznapredovao
Posts: 938
Joined: 01-06-2006, 17:54
Location: Zagreb

Duhovi AVR-a

Post by InTheStillOfTheNight »

Izludio sam ova 2 dana jer sam tražio grešku po kodu kao prosjak pred malom crkvom, i zato otvorih ovaj Topic da možemo napisati većinu grešaka koje se mogu dogoditi tokom programiranja... Ovog sam duha hvatao 2 dana, pa evo zapravo je vrlo jednostavno, ali stvarno zna popiti živaca... Radi se o serijskoj komunikaciji UART baudrate 9600 1 stop bit... Najgore je što sam u source kodu mjenjao čitav protokol komunikacije, a ima podosta koda i više nisam znao di je j**** greška.

Evo source interrupt vector Uarta
//Interrupt vector for uart transmit complete
ISR(USART_TX_vect){

//If send_buffer is not empty
if (sen_in != sen_out){

//Send next byte
UDR0 = sen_buf[sen_out++];
sen_out &= 0x0F;
}
//if nothing else in send_buffer
else{
TransmitOff();
ReceiveOn();
}
}

Pojednostavio sam source tako da bude sto jasnije za skuziti. Ovo sto razvijam trenutno radi na jednosmjernoj 485 komunikaciji... Trebalo bi raditi odprilike ovako, Host šalje komandu, ovaj uređaj primi provjeri checkume i sve sto ide uz to, diže transmisiju, gasi prijem (DS485) i šalje odgovor . To je sve ok...
Eh sad ide onaj trik... Kad pošaljem zadnji byte odgovora prema HOSTU tada će se dići interrupt koji više nema u bufferu što poslati, i izvršiti će "TransmitOff(); i ReceiveOn();" I to radi dobro nekih 5 ili 7 nekad i pola minute... nekad radi samo sekudnu i dogodi se sranje.... Komanda je poslana ali interrupt nije spustio odašiljenje i upalio prijem.... Zapravo kao da se nije dogodio taj zadnji interrupt i meni atmel ostane u odašiljanju, a treba biti "SLAVE" i u prijemu...
E sad probao ja debugirati, ali ne ide jer u 7 sekundi prođe previše podataka da bi uhvatio "bug". Onda sam išao provjeravati kružeće buffere od serijske, i to je dobro, pa sam gledao overflow svih polja, a i to dobro... Pa rekoh si idem prekopati čitav kod 14 kB i opet nisam našao ništa.. Čak nisam našao ni slutnju zašto bi se ovakvo sranje moglo dogoditi... Pa sam počeo gasiti periferiju, Ugasio interrupt komparatora, ugasio PWM i ostavio samo trćeći kod... i opet ništa... Pa sam počeo komentirati program, i opet ništa, e onda sam popio "Normabel" i nastavio dalje. Sad sam ugasio i interrupt za timere realnog vremena (1ms), pa zaboga nemam više što ni ugasiti... Ugasio ja i optimizaciju koda, pa provjeravao FUSE, pa inicijalizaciju portova... Ma sve zivo sto mi je palo na pamet i opet isto sranje. Čak sam mislio tražiti i "vudu lutku" da je izbodem jer sam bio jebeno ljut... Evo i greske:

Moj source ima funkciju Service() koju dižem iz svih aplikativnih dijelova koda, i onda mi odrađuje brze usluge. Protočna je kao Švajcarski sir i odrađuje stvari na koje ne smijem zaboraviti više od 200 uS, A moja naivna greška bila je ova

#define DebugWireOn() (PORTD |= (1 << PD5))
#define TransmitOn() (PORTD |= (1 << PD3))
#define ReceiveOff() (PORTD |= (1 << PD2))

void Service(void){
DebugWireOn();
}

Ovo je naravno skroz pojednostavljen Service(); ali tu je i greška u jednoj jedinoj liniji...
Zaboga kakve veze ima moj DebugWire() na "PD5" sa mojom serijskom komunikacijom????
Direkno sa serijskom niti nema osim što su na istom portu "D" PD0 i PD1 je uart.
A i ova "transmisija" i "prijem" mi je na istom portu D.. Moze se vidjeti iz #define... Sve to na istom portu "D"..
Opet ne bi trebala biti greska, ali ako samo malo dublje razmislimo i odemo na assembler sve postaje kristalno jasno.... Što se zapravo dogodi:

Zamislimo da ovaj "DebugWireOn()" zavrtimo u ovome, to smijemo napraviti jer i moj service se vrti stalno.

while(1){
DebugWireOn();
}

i naravno zamislimo da se šalje zadnji byte odgovora prema hostu koji će dići onaj zadnji interrupt koji treba promjeniti stanje odasiljanja u prijem "ReceiveOn(); i TransmitOff()".
Trenutno stanje porta D je ovo 00111111
PD0 = 1... To je rxd ili txd
PD1 = 1... To je rxd ili txd ne znam napamet
PD2 = 1... ReceiveOff() prijem je ugasen ako je ovo 1
PD3 = 1... TransmitOn() odašiljanje je upaljeno ako je ovo 1
PD4 = 1... Uvijek mi je 1
PD5 = 1... Ovo se vrti u vhile(1) tak da je do sad sigurno log 1 :)

E sad vam ne mogu razlomiti ovo na assembler jer mi je pao AVRGCC :(
Od sada sve sto pisem je vezano na način izvršavanja assemblera a ne ovog C-a. Greška je u Assembleru prevodioca i u mojoj glavi dok sam programirao...

Kad u assembler idemo mjenjati port moramo maskirati ili raditi "logičko ili" sa čitavim byteom PORTA... U ovom slučaju da dignemo debugWire u log "1" moramo napraviti logičko "ili" porta D sa "B00100000"
Ali naš prevodilac će u assembleru smuljati sranje... Jednu assemblersku instrukciju prije nego li napravi logičko "ili" registra sa portom, u registru će imati pripremljeno ovo B00111111, a to i ne bi bila greska ako pogledamo matematiku.
PD 00111111 "LOG ILI" Ovo je stanje porta D
R16 00111111 ovo je registar 16 s kojim radimo "ili" operaciju
______________________
PD 00111111 Kvragu sve dobro...

Sječate se kada sam napisao gdje se nalazimo u programu???? Šaljemo zadnji byte prema hostu koji treba dići onaj zadnji interrupt za mjenjanje smijera komunikacije...

Ali vrag je tu... što ako nismo stigli odraditi ovo zadnje logičko "ili" sa portom??? Ako se baš trenutak prije dogodi onaj prokleti interrupt sa početka ovog teksta???? Sad stvari idu ovako: Registar R16 b00111111" ide na "stack" kao i povratna adresa te skačemo na vector interrupta, i evo nas u onom "UART Complete interruptu" ... Tamo sve super odradimo (Znači zadnji byte je poslan i trebamo ugasiti odašiljanje i upaliti prijem)... U registar recimo r17 upišemo 11110011 i napravimo logičko "i" sa "PD" (portom D) i upravo je ugašeno odašiljenj i upaljen prijem, interrupt završava i vraćamo se nazad na lokaciju odakle smo skakali na vector interrupta. Povučemo onaj r16 sa "stacka" a on glasi 00111111 i napravimo logicko ili koje nismo stigli odraditi jer se dogodio interrupt complete sa našim divnim portom "D". E jbg sad se odrati to logičko ili... I naš port D dobije to sranje iz registra 16 koje glasi 00111111... Prijem ugašen, Odašiljanje upaljeno a uređaj spreman za baciti u smeće :)

I na kraju rješenje je sljedeće:

while(1){
sei(); \\DISABLE GLOBAL INTERRUPTS !!!
DebugWireOn();
cli(); \\ENABLE GLOBAL INTERRUPTS!!!
}
InTheStillOfTheNight
User avatar
trax
Administrator sajta
Administrator sajta
Posts: 3508
Joined: 08-01-2005, 18:04
Location: 75k, BA
Contact:

Re: Duhovi AVR-a

Post by trax »

Svaka cast :D
Mene je jednom prilikom izludio PIC16F877A, njemu po defaultu je ukljucen parallel slave port (kontrolni bitovi) na PORTE. Tako da, kada se bilo sta pise na PORTB (cini mi se na njega) on sam setuje i brise izlaze na PORTE. Izludilo me je dok nisam skontao da je do toga.

Inace, komentari ti ne valjaju:

Code: Select all

while(1){
sei(); \\DISABLE GLOBAL INTERRUPTS !!!
DebugWireOn();
cli(); \\ENABLE GLOBAL INTERRUPTS!!!
}
Treba pisati:

Code: Select all

while(1){
sei(); //ENABLE GLOBAL INTERRUPTS !!!
DebugWireOn();
cli(); //DISABLE GLOBAL INTERRUPTS!!!
}
User avatar
InTheStillOfTheNight
Odlično uznapredovao
Odlično uznapredovao
Posts: 938
Joined: 01-06-2006, 17:54
Location: Zagreb

Re: Duhovi AVR-a

Post by InTheStillOfTheNight »

Ups... ovo se mal zahebao za komentare jer nisam radio copy paste nego sam pisao u postu nakon piva ili dva :) nije da mi se bunio "compiler posta" :) ... Inace u mom source codu nema toga jer sam izbrisao taj DebugWire(); kada mi i ne treba za rad...

Napravio PRTSCN tih sranja u c-u i assembleru, budem postao veceras.... Ovakvom bug-u se nikada nisam nadao i zato sam i objavio takav Topic
InTheStillOfTheNight
User avatar
Smjesko
Stariji član
Stariji član
Posts: 4012
Joined: 26-12-2005, 17:12

Re: Duhovi AVR-a

Post by Smjesko »

Pouka ili naravoučenie = "Ne pij dok voziš, ne pij dok pišeš program!" :D
User avatar
InTheStillOfTheNight
Odlično uznapredovao
Odlično uznapredovao
Posts: 938
Joined: 01-06-2006, 17:54
Location: Zagreb

Re: Duhovi AVR-a

Post by InTheStillOfTheNight »

Smjesko wrote:Pouka ili naravoučenie = "Ne pij dok voziš, ne pij dok pišeš program!" :D
hehehe imas pravo: "Rukom kojom držite alkohol nebiste trebali mijenjati brzine, prepustite mjenjač suvozaču" :azdaja:
InTheStillOfTheNight
User avatar
InTheStillOfTheNight
Odlično uznapredovao
Odlično uznapredovao
Posts: 938
Joined: 01-06-2006, 17:54
Location: Zagreb

Re: Duhovi AVR-a

Post by InTheStillOfTheNight »

trax wrote:Svaka cast :D
Treba pisati:
while(1){
sei(); //ENABLE GLOBAL INTERRUPTS !!!
DebugWireOn();
cli(); //DISABLE GLOBAL INTERRUPTS!!!
}
E trax i ti si se mal zeznuo:
treba pisati:

while(1){
sei(); //DISABLE GLOBAL INTERRUPTS !!!
DebugWireOn();
cli(); //ENABLE GLOBAL INTERRUPTS!!!
}
:lol: :lol: :lol: :lol:
InTheStillOfTheNight
User avatar
trax
Administrator sajta
Administrator sajta
Posts: 3508
Joined: 08-01-2005, 18:04
Location: 75k, BA
Contact:

Re: Duhovi AVR-a

Post by trax »

Ma nisam, cijela poenta mog odgovora je bila da kazem da:
sei() - omogucuje interrupte
cli() - onemogucuje!

Google:
Hi I got few quesionts
What does the two following functions do
Cli();
sei();
regards
DJ
A covjek odgovara:
cli() clears the global interrupt flag in SREG so prevent any form of interrupt occurring. While sei() sets the bit and switches interrupts on.
Sto mozes procitati i ovdje: http://www.nongnu.org/avr-libc/user-man ... rupts.html" onclick="window.open(this.href);return false;
User avatar
InTheStillOfTheNight
Odlično uznapredovao
Odlično uznapredovao
Posts: 938
Joined: 01-06-2006, 17:54
Location: Zagreb

Re: Duhovi AVR-a

Post by InTheStillOfTheNight »

InTheStillOfTheNight wrote:
trax wrote:Svaka cast :D
Treba pisati:
while(1){
sei(); //ENABLE GLOBAL INTERRUPTS !!!
DebugWireOn();
cli(); //DISABLE GLOBAL INTERRUPTS!!!
}
E trax i ti si se mal zeznuo:
treba pisati:

while(1){
sei(); //DISABLE GLOBAL INTERRUPTS !!!
DebugWireOn();
cli(); //ENABLE GLOBAL INTERRUPTS!!!
}
:lol: :lol: :lol: :lol:
Grijesimo i ti i ja... Prva greška je bila ona moja jer sam krivo komentirao.
Onda si me ispravio ali nisi skužio da su sei() i sli() na krivim mjestima.
Ja sam radio enable interrupts prije nego izvršim DebugWireOn(); , a treba raditi Disable globall interrupts
Onda sam ja skužio po komentaru da umijesto disable pise enable, pa sam promijenio samo komentar, a i dalje je na krivom mijesto bilo ono sei() i cli().
Evo napokon zadnji puta kako treba pisati:

while(1){
cli(); //DISABLE GLOBAL INTERRUPTS !!!
DebugWireOn();
sei(); //ENABLE GLOBAL INTERRUPTS!!!
}
InTheStillOfTheNight
User avatar
trax
Administrator sajta
Administrator sajta
Posts: 3508
Joined: 08-01-2005, 18:04
Location: 75k, BA
Contact:

Re: Duhovi AVR-a

Post by trax »

Sam sebe:
trax wrote:Ma nisam, cijela poenta mog odgovora je bila da kazem da:
sei() - omogucuje interrupte
cli() - onemogucuje!
:D
User avatar
InTheStillOfTheNight
Odlično uznapredovao
Odlično uznapredovao
Posts: 938
Joined: 01-06-2006, 17:54
Location: Zagreb

Re: Duhovi AVR-a

Post by InTheStillOfTheNight »

HeHeHe što se izvlači... Ja samo kažem da ono što si ti ispravio prvi puta ne bi opet dobro radilo u onom prvom velikom postu koji sam pisao :D :D :D :D
Što se tiče sei i cli tu si u pravu.
InTheStillOfTheNight
Post Reply