Fórum témák

» Több friss téma
Fórum » AVR - Miértek hogyanok
 
Témaindító: pakibec, idő: Márc 11, 2006
Témakörök:
WinAVR / GCC alapszabályok:
1. Ha ISR-ben használsz globális változót, az legyen "volatile"
2. Soha ne érjen véget a main() függvény
3. UART/USART hibák 99,9% a rossz órajel miatt van
4. Kerüld el a -O0 optimalizációs beállítást minden áron
5. Ha nem jó a _delay időzítése, akkor túllépted a 65ms-et, vagy rossz az optimalizációs beállítás
6. Ha a PORTC-n nem működik valami, kapcsold ki a JTAG-et
Bővebben: AVR-libc FAQ
Lapozás: OK   617 / 840
(#) csabeszq válasza killbill hozzászólására (») Szept 5, 2014 /
 
A Commodore 64-nek 1 regisztere volt (A) és két index regisztere (X,Y), amit indexelésen kívül nem sokra tudtál használni.

Ha kiszámoltad az új értéket és az A regiszterben már benne volt, akkor
- vagy az XOR-os csodát játszod el
- vagy letárolod memóriában és visszatöltöd

XOR-ral:
  1. LDA #$CB; az érték, amit valahogy kiszámoltunk, a felső 3 bitet akarjuk beírni
  2.   ;
  3.   EOR $FC;
  4.   AND #$E0; csak a felső három bitet állítod
  5.   EOR $FC;
  6.   STA $FC; eltárolni az FC cellában


XOR nélkül memóriával:
  1. LDA #$CB; az érték, amit valahogy kiszámoltunk, a felső 3 bitet akarjuk beírni
  2.   ;
  3.   AND #$E0; csak a felső 3 bit érdekel
  4.   STA $FE; ideiglenes memóriában eltárolod
  5.   LDA $FC; a módosítandó cella betöltése
  6.   AND #$1F; az alsó bitek megtartása
  7.   ORA $FE; OR művelet
  8.   STA $FC; eltárolni az FC cellában


Commodore 64-en az XOR egyértelműen olcsóbb volt, AVR alatt minthogy több regiszter van és teljesen más az architektúrája, ugyanannyiba kerül.

AVR OR:
  1. ldi r24, $CB // a számítás végeredménye
  2.   //
  3.   in r25, PORTD;
  4.   and r25, 0x1F;
  5.   and r24, 0xE0;
  6.   or r25, r24;
  7.   out PORTD, r25;


AVR XOR:
  1. ldi r24, $CB // a számítás végeredménye
  2.   //
  3.   in r25, PORTD;
  4.   xor r25, r24;
  5.   and r25, 0xE0;
  6.   xor r25, r24;
  7.   out PORTD, r25;


Annyiban jobb a XOR, hogy r24 értéke megmarad a végén.
(#) rolandgw válasza csabeszq hozzászólására (») Szept 5, 2014 / 1
 
A megadott C-ből és rajzból kiindulva: behívom a portd-t,ami bármi lehet,és így néz ki : xxxx xxxx ,a kiemelt bitek nem változhatnak visszaírás után.A példa alapján a 3-as számot szeretné kiíratni,ami kódolva a portd-re eső rész 0x89.
  1. ldi r24,0x89
  2. in r25,portd
  3. and r25,0x66  //törlöm a szegmens értékeket,a többi változatlan
  4. or r25,r24   // beállítom az új szegmens értékeket,a többi változatlan marad a kódolás miatt,1-es nem lehet a kiemelt bitek helyén,amit átbillentene az or
  5. out portd,r25

Tehát,szerintem a második and nem kell.
(#) Droot válasza rolandgw hozzászólására (») Szept 6, 2014 /
 
Srácok!!! Végül szándékosan csak a kódrészletet raktam fel, mert gondoltam hogy elő fog fordulni hogy nem csak arra kapok segítséget amire szeretnék, holott most egy hibára koncentrálok. Eléggé elkanyarodtatok a témától, nem tudom hogy jött a commodore (lehet hogy kellene nyitni egy commodore miértek hogyanok témát? ). Csak azt szerettem volna megtudni hogy ha csak egy digitet kapcsolok be tökéletesen megy de ha többet akkor or kapcsolattal jelennek meg a szegmensek. A probléma napok óta és még most is megven, de köszönöm hogy igyekeztetek segíteni, most itt a hétvége, majd elmerülök benne jobban és rájövök, ha maga jön rá az ember jobban megtanulja.
(#) killbill válasza csabeszq hozzászólására (») Szept 6, 2014 /
 
Ertem. Tenyleg rafkos. Csak a pelda kicsit felrevezeto, mert mind azzal kezd, hogy egy konstansot egy masik konstanssal maszkol. De tenyleg jo, ha Akkumulatoros architekturan dolgozol.
(#) Toto25V hozzászólása Szept 7, 2014 /
 
Sziasztok!

Távirányítós infra jelet akarok kiolvasni 8 Mhz-es ATMEGA168-al, TSOPxx38 vevővel, melynek kimenete INT1 lábra van kötve. Interrupt INT1-re beállítva, engedélyezve, bármilyen jelváltozásnál működésbe lép.
SIGNAL függvénybe pedig nem tudom, hogy mit írjak. 8 bites trimer to count is engedélyezve van, (TCNT0) CLK/64 beállítással.

Girder PC programmal előtte kiolvastam az infra távirányító 16 bites jeleit. Azt akarom elérni, hogy
ugyan azt a 16 bitet olvassa be a mikrokontroller is, és beolvasása után írja azt ircode_tw regiszterbe. Arra lennék kíváncsi, mit írjak a SIGNAL függvénybe?

Segítséget előre is köszönöm.
(#) kapu48 válasza Toto25V hozzászólására (») Szept 7, 2014 /
 
Én valahogy így csinálnám!
Némi útmutató:
AVR-GCC-Tutorial/Assembler und Inline-Assembler
  1. #include <avr/io.h>
  2.  
  3. volatile uint8_t byte1, byte2, flag =0
  4. volatile uint16_t ircode_tw
  5.  
  6. int16_t main (void)
  7. {
  8. if(flag){
  9.     // Itt meg feldolgozod (Vagy teheted ezt is az INT1-be?)
  10.         flag =0
  11. }
  12. }
  13.  
  14. //INT1 a PIND.3-ason érkezik.
  15. //Megszakításban beolvasol minden változást.
  16. .global INT1_vect
  17. INT1_vect:
  18. if (num<8){
  19. num++
  20.  
  21. in      R16,PIND ; Read port D
  22. //PD.3-at be Rotálod Carry-ba
  23. ROR R16 ; Rotate Right Through Carry 0
  24. ROR R16 ; Rotate Right Through Carry 1
  25. ROR R16 ; Rotate Right Through Carry 2
  26. ROR R16 ; Rotate Right Through Carry 3
  27. //Kérdés, hogy az adó milyen irányban shifttel?
  28. //Carry-t be shiftteled R24-be balra:
  29. ROL R17;  Rotate Left Through Carry Rd(0)←C,Rd(n+1)← Rd(n),C←Rd(7)
  30. //Vagy jobbra:
  31. ROR R17 Rotate Right Through Carry Rd(7)←C,Rd(n)← Rd(n+1),C←Rd(0)
  32. //Ezt meg csinálod, 8 szór.
  33. }alse{
  34. //Aztán elteszed valahova az SRAM-ba
  35. STS byte1, R17
  36. //Jelzed, hogy OK
  37. flag=1
  38. }
  39. reti
  40.  
  41. .end
A hozzászólás módosítva: Szept 7, 2014
(#) kapu48 válasza kapu48 hozzászólására (») Szept 7, 2014 /
 
Hopssz!

Mi van, ha több egyforma Bit jön egymás után?
Ehhez már ismerni kellene az adó frekvenciáját, hogy be állítsuk a timert.
...
És kel egy start Bit figyelés, hogy tudjuk, mikor indítsuk a vételt!

(#) Toto25V hozzászólása Szept 7, 2014 /
 
Őszintén szólva nagyon kezdő vagyok a témában, eddig mindent megtudtam oldani, csak az Infrát nem. C nyelvet ismerem valamennyire. Példaprogramnak köszönhetően már beállítottam mindent, csak a Signal-ban kéne úgy módosítani, hogy felismerje a 16 bites Irda jelet, úgy, ahogy a Girder PC.

Íme a mostani kód:
  1. SIGNAL(SIG_INTERRUPT1) {
  2.         static unsigned char value;
  3.         static unsigned char sigcount = 0;
  4.  
  5.         if (PIND & 0x8) { // rising edge
  6.                 unsigned short count;
  7.                 count = TCNT0;
  8.                 //LED_OFF(1);
  9.  
  10.                 if (count < 14) { // 0
  11.                         sigcount++;
  12.                         value = value & ~(1 << (sigcount-1)); }
  13.                
  14.                 else if (count < 31) { // 1
  15.                         sigcount++;
  16.                         value = value | (1 << (sigcount-1)); }
  17.                
  18.                 else { // this starts a new one
  19.                         sigcount = 0;
  20.                         value = 0;
  21.                 }
  22.  
  23.                 if (sigcount == 16) {
  24.                   ircode_tw = value;   
  25.                 }
  26.                
  27.         } else { // falling edge
  28.                 TCNT0 = 0; // reset
  29.                 //LED_ON(1);
  30.                 }
  31. }
(#) gabi20 válasza Toto25V hozzászólására (») Szept 7, 2014 /
 
Szia ha a távirányító RC5 protokollt használ akkor használhatod ezt a programot is. Én INT0 megszakítást használtam, ami lefutó élre van beállítva, vagyis pontosan a start jel érkezésekor kér megszakítást. Az RC5 - nél 14 bitet kell beolvasni. Az időt pedig timer2 - vel mérem, ami 128 - as frekvenciaosztóval működik (a processzor 16MHz). üdv Gábor
  1. ISR(INT0_vect){
  2.  
  3.                 rc5_command = 0;
  4.  
  5.                 TCNT2 = 0;
  6.                 while(TCNT2 < 56);                      // wait 444,5 us
  7.  
  8.                 for(unsigned char i = 0; i < 14; i++){
  9.                                
  10.                                 rc5_command = rc5_command << 1;
  11.                                 if(!(PIND & 0x04)) rc5_command++;
  12.  
  13.                                 TCNT2 = 0;
  14.                                 while(TCNT2 < 222);     // wait 1778 us
  15.                 }
  16.                
  17.                 rc5_command = rc5_command & 0x3F;  // also 6 bit kimaszkolasa
  18.                 GIFR |= 0x40;                           // Clear interrupt flag bit
  19. }
(#) Toto25V hozzászólása Szept 7, 2014 /
 
Köszönöm szépen mindenkinek a segítséget, megoldódott!
(#) horka001 hozzászólása Szept 9, 2014 /
 
Sziasztok. Lenne egy kérdésem. Nincs itt valakinek megtervezett AVR NYÁK adaptere? ISP kellene. Egyszerűen megfogalmazva van egy nyák ISP csatlakozóval, amibe berakom a különböző AVR microcontrollert és mehet is a programozás. Ebben kérek segítséget.
(#) lac12345 hozzászólása Szept 9, 2014 /
 
Sziasztok

Elore bocsatanam nagyon nagyon kezdo vagyok avr programozas teren es elkovettem egy nagyon nagy hibat...rossz fuse bit... Most nem tudom se programozni se torolni se semmit csinalni vele..
Adva van egy atmega162 ami nem egy kvarc rol kapja az orajelet hanem egy masik procirol xtal1 labra...ezeket a beallitasokat kelett volna megtegyem EESAVE BODLEVEL SUT1 CKSEL3 CKSEL2 CKSEL1 CKSEL0 tobbi bealotast nem kell kivallaszszam...Epitettem egy STK200 as programozot lpt portra ugy gondolom tokeletessen mukodott is a dolog...burn o mat al be is programoztam flash tartalmat es most jot volna fuse bit beallitas..Csakhogy ezeken a manualis bealitasokon kivul volt megy egy info hogy hex fuse beallitasokkal is be lehet allitania fuse bit eket ekkor gondoltam jobb lesz ugy beallitani mert nehogy kihagyjak valamit...H l E 0xD0, 0xF7, 0xFB ezeket allitottam en be programozonal .. csakhogy ez igy rossz mert leirasban H es L meg van cserelve igy en most ezel a hex fuse bit beallitasokkal ezt alitottam be...(utolag egy fuse bit calculatorral neztem meg) tehat ezek vannak beallitva most CKSEL3 SPIEN BOOTSZ1 BOOTSTR BOOTSZ0 EESAVE BOODLEVEL1..Ugy gondolom de nagoyn nem vagyok biztos benne egesz éjjel a googlit bujtam hogy a orajel beallitasok nem jok es ezert nem tudok most programozni se kiolvasni.. Ha az eredeti fuse beallitasokat irom be akkor sztem meg nagyobb lenne a baj mert ott nincs SPIEN es ha az nincs akkor en stk200 al nem tudnam programozni ha jol ertema dolgot..Cikkek kozott van egy HVPP programozo csak sajnos az nem tamogatja az atmega162 est van meg neten egy masik atmega fuse doctor nevre halgato reseter kapcsolas ..Csak most lehet nem kiserleteznek tovabbi epitgetessel mert lehet lesz megegy halott avr em..De lehet megiscsak megkiserlem ha nincs mas megoldas..olvasgattam meg hogy letezhet egy oylan megoldas hogy kulso orajelet kell rakotni avr xtal1 labara es akkor lehetne programozni..Ez ep kapora is jonne nekem mert ezena labon van nalam most egy 8 MHZ es orajal emit a masik mcu kuld ide...De most se tudom progizni se kiolvasni burn o mat al..se ponyproggal se bascom programozojaval Lehet tul nagy az a 8Mhz mert mindenfele 1 Mhz koruli kulso orajelet kuldenek ra..Es talaltam egy olyan infot is hogy ilyenkor le kellene csokkenteni a programozasi orajelet 1/4 reszere a kulso orajelnek...Na ezt nem tudom hol kellene megtenni.Tudtok segiteni ebben nem szeretnem mindejart a kukaba dobni a teljessen uj atmega162 est...

koszonom a segitseget..
(#) csabeszq válasza horka001 hozzászólására (») Szept 10, 2014 /
 
Kísérletező panel:
- veszel egy breadboard-ot (link)
- veszel kábeleket hozzá (link)

Hogyan csinálsz ISP csatlakozóhoz breadboard adaptert (2x3)?
- veszel egy univerzális nyákot (link)
- veszel ISP szalagkábel csatlakozót (link)
- veszel tördelhető tüskesort (link)

A varázslás ezután történik. Az univerzális nyákkal és tüskesorral kiszélesíted az ISP szalagkábel csatlakozót 2 raszterről 4 raszter szélesre. A 4 rasztert már simán be tudod dugni breadboardba, úgy hogy mind a 6 lábához köthetsz vezetéket.

Tehát:
- elkészíted az ISP adaptert breadboardhoz
- bedugod az IC-t a breadboardba
- összekötöd a vezetékeket az AVR chip leírása alapján az ISP adapterrel
- az adapterbe meg bedugod a programozót
A hozzászólás módosítva: Szept 10, 2014
(#) csabeszq válasza csabeszq hozzászólására (») Szept 10, 2014 /
 
Itt van egy hasonló leírás: link

Itt a 2x3-as ISP headerből 1x6-os sort csinál.

Szerintem túlbonyolítja, mert én meghagytam a 2x3-as elrendezést, csak melléforrasztottam egy lefelé álló tüskesort.

A következő kép már az én megoldásomra hasonlít, de még univerzális nyákot sem használ.
(itt)

Csomó vackot bedugok hasonló csalafintaságokkal a breadboardba. Van egy komplett zacskóm amiben forgatható potméterektől kezdve kismillió csatlakozón át az ethernet aljzatig az égvilágon mindent képes vagyok bedugni.
A hozzászólás módosítva: Szept 10, 2014
(#) steelgoofy hozzászólása Szept 11, 2014 /
 
Üdv!
Arduino 2560 boardomon tönkrement az USB chip, ezért vettem egy STK500 programozót, hogy a továbbiakban ezen keresztül programozhassak. Az utolsó programom arduinon, ami jelenleg is fut rajta, digitális kimenetként használja az 52,51,50 es pineket (SCK,MOSI,MISO) amikbe pont a programozót kellene kötni.
Szabad ennek ellenére bekötni a programozót, vagy baj lesz belőle ?
(#) holex válasza steelgoofy hozzászólására (») Szept 11, 2014 /
 
Szabad, amikor elkezded programozni, akkor a programozó reseteli az AVR-t, tehát nem elsz gond. Pont hogy bemenetként nem szabad őket használni (illetve azt is lehet, de csak bizonyos megkötésekkel).
(#) Sick-Bastard hozzászólása Szept 11, 2014 /
 
Üdv!

A következő problémával szembesültem:
Egy checksum számításra írtam egy rutint:

  1. void CheckSum(unsigned char array[], unsigned int type)
  2. {
  3.         unsigned long int checksum = 0;
  4.         unsigned int y = 0;
  5.         if(type == ICMPv4)
  6.         {
  7.                 i = 34;
  8.                 y = 74;
  9.         }
  10.         if(type == IPv4)
  11.         {
  12.                 i = 14;
  13.                 y = 34;
  14.         }
  15.        
  16.         USART0_TX_String("Checksum:     ");
  17.         itoa(checksum, StringA, 16);
  18.         USART0_TX_String(StringA);
  19.         USART0_TXD(13);
  20.         USART0_TXD(10);
  21.        
  22.         for(i=i;i<y;i+=2)                       //      loop for IPv4 header length
  23.         {
  24.                 checksum += (array[i]<<8);
  25.                 checksum += array[i+1];
  26.                
  27.                 USART0_TX_String("byte: ");
  28.                 itoa(i, StringA, 10);
  29.                 USART0_TX_String(StringA);
  30.                 USART0_TXD(9);
  31.                
  32.                 if(array[i] < 0x10)
  33.                 {
  34.                         USART0_TX_String("0");
  35.                 }
  36.                 itoa(array[i], StringA, 16);
  37.                 USART0_TX_String(StringA);
  38.                 if(array[i+1] < 0x10)
  39.                 {
  40.                         USART0_TX_String("0");
  41.                 }
  42.                 itoa(array[i+1], StringA, 16);
  43.                 USART0_TX_String(StringA);
  44.                 USART0_TXD(9);
  45.                 itoa(checksum, StringA, 16);
  46.                 USART0_TX_String(StringA);
  47.                 USART0_TXD(13);
  48.                 USART0_TXD(10);
  49.  
  50.         }
  51.        
  52.         USART0_TX_String("Checksum_L:   ");
  53.         itoa((checksum), StringA, 16);
  54.         USART0_TX_String(StringA);
  55.         USART0_TXD(13);
  56.         USART0_TXD(10);
  57.         USART0_TX_String("Checksum_H:   ");
  58.         itoa((checksum>>16), StringA, 16);
  59.         USART0_TX_String(StringA);
  60.         USART0_TXD(13);
  61.         USART0_TXD(10);
  62.        
  63.         checksum = ((checksum & 0x0000FFFF) + ((checksum>>16) & 0x0000FFFF));
  64.         checksum = ~checksum;
  65.        
  66.         USART0_TX_String("Checksum:     ");
  67.         itoa(checksum, StringA, 16);
  68.         USART0_TX_String(StringA);
  69.         USART0_TXD(13);
  70.         USART0_TXD(10);
  71.        
  72.         if(type == IPv4)
  73.         {
  74.                 checksum -=2;
  75.                 array[24] = (checksum>>8);
  76.                 array[25] = checksum;
  77.         }
  78.        
  79.         if(type == ICMPv4)
  80.         {
  81.                 array[36] = (checksum>>8);
  82.                 array[37] = checksum;
  83.         }
  84. }


A gondom az, hogy ha ICMPv4-re használom, akkor jól működik, ha IPv4-re akkor a számítás során valahol elveszíti a 0xFFFF-nél nagyobb biteket/értékeket.
Pl.: 0x0006ab6b helyett csak 0x0000ab6b-t kapok.

Általában mi okozhatja ezt?

checksum.txt
    
(#) csabeszq válasza Sick-Bastard hozzászólására (») Szept 11, 2014 /
 
Elég nehéz megérteni a kódot, de

itoa - integer to ascii
ltoa - long integer to ascii

Az itoa AVR alatt 2 byte-os. Azt javaslom, hogy az itoa-t nézd végig, ha kell cseréld le ltoa-ra.
A hozzászólás módosítva: Szept 11, 2014
(#) csabeszq válasza Sick-Bastard hozzászólására (») Szept 11, 2014 /
 
  1. unsigned char array[];
  2. unsigned long int checksum;
  3.  
  4. checksum += (array[i]<<8);


Ilyet én nem szoktam használni, mert halvány gőzöm sincs arról, hogy mi a végeredmény. Ezt a leginkább a C guruk tudják, de még arra a szintre nem jutottam el.

- A 8-as shiftelést vajon az unsigned char típusú array[i]-n végzi el, vagy előtte mindent konvertál unsigned long-ra?

Már öregszem, ezért inkább kiírok mindent, mielőtt aknára lépnék:
  1. checksum += ((unsigned long)array[i]<<8);


Be kell valljam, nem ismerem a C standardot, ezért a leghalványabb fogalmam sincs, hogy a fenti rész miképpen fog lefordulni.
(#) Sick-Bastard válasza csabeszq hozzászólására (») Szept 11, 2014 /
 
Köszi a választ!

Az itoa-t csak az UART-on való küldésre használom, hogy HyperTerminal-ban szövegként jelenhessen meg, hibakeresés céljából.

Az ltoa-t még nem ismertem, ki is próbáltam és segített tisztábban látni.

A problémám beigazolódott.
Az egyik esetben(ICMP) a rutin így ad össze: c59e + 6566 = 12b04 (ez ok).
A másikban(IPv4) meg így: 9bad + c0a8 = 5c55 (15C55 helyett) (ez már nem jó).
(#) Sick-Bastard válasza csabeszq hozzászólására (») Szept 11, 2014 /
 
Hogy tisztább legyen a helyzet:

  1. unsigned char array[] ---> ez a küldendő csomag
  2. unsigned int type ---> a csomag típusa (ICMP vagy IP)
  3. unsigned long int checksum = 0; --> átmeneti long int a számításokhoz
  4. unsigned int y = 0;           ---> egy helyi változó
  5. if(type == ICMPv4)
  6.         {
  7.                 i = 34;          ---> i egy globális változó, itt a csomag egy bizonyos részének az első bájt meghatározására kell
  8.                 y = 74;         ---> y helyi változó, a csomag bizonyos részének az utolsó bájt meghatározására kel
  9.         }
  10.         if(type == IPv4)
  11.         {
  12.                 i = 14;
  13.                 y = 34;
  14.         }
  15. // a checksum változó printelése
  16. USART0_TX_String("Checksum:     ");
  17.         itoa(checksum, StringA, 16);
  18.         USART0_TX_String(StringA);
  19.         USART0_TXD(13);
  20.         USART0_TXD(10);
  21. // a checksum változó printelése
  22. for(i=i;i<y;i+=2)               ---> szükséges byte-ok szummolása
  23.         {
  24.                 checksum += (array[i]<<8);       ---> checksum-hoz hozzáadok 2 byte-ot, a felő bíte az array[i]
  25.                 checksum += array[i+1];            ---> checksum-hoz hozzáadok 1 byte-ot, ami az array[i+1]
  26.                
  27. // ez itt csak printelés, a hibakereséhez
  28.                 USART0_TX_String("byte: ");
  29.                 itoa(i, StringA, 10);
  30.                 USART0_TX_String(StringA);
  31.                 USART0_TXD(9);
  32.                
  33.                 if(array[i] < 0x10)
  34.                 {
  35.                         USART0_TX_String("0");
  36.                 }
  37.                 itoa(array[i], StringA, 16);
  38.                 USART0_TX_String(StringA);
  39.                 if(array[i+1] < 0x10)
  40.                 {
  41.                         USART0_TX_String("0");
  42.                 }
  43.                 itoa(array[i+1], StringA, 16);
  44.                 USART0_TX_String(StringA);
  45.                 USART0_TXD(9);
  46.                 ltoa(checksum, StringA, 16);
  47.                 USART0_TX_String(StringA);
  48.                 USART0_TXD(13);
  49.                 USART0_TXD(10);
  50. // ez itt csak printelés, a hibakereséhez
  51.         }
  52. // szintén printelés, a hibakereséhez
  53. USART0_TX_String("Checksum_L:   ");
  54.         itoa((checksum), StringA, 16);
  55.         USART0_TX_String(StringA);
  56.         USART0_TXD(13);
  57.         USART0_TXD(10);
  58.         USART0_TX_String("Checksum_H:   ");
  59.         itoa((checksum>>16), StringA, 16);
  60.         USART0_TX_String(StringA);
  61.         USART0_TXD(13);
  62.         USART0_TXD(10);
  63. // szintén printelés, a hibakereséhez
  64.  
  65. checksum = ((checksum & 0x0000FFFF) + ((checksum>>16) & 0x0000FFFF));    ---> a kapott 32bites értéket 16-ossá alakítom
  66. checksum = ~checksum;           ---> majd invertálom
  67.  
  68. // ismét egy print
  69. USART0_TX_String("Checksum:     ");
  70.         itoa(checksum, StringA, 16);
  71.         USART0_TX_String(StringA);
  72.         USART0_TXD(13);
  73.         USART0_TXD(10);
  74. // ismét egy print
  75.  
  76. // a kapott érték a helyére illesztése
  77. if(type == IPv4)
  78.         {
  79.                 checksum -=2;
  80.                 array[24] = (checksum>>8);
  81.                 array[25] = checksum;
  82.         }
  83.        
  84.         if(type == ICMPv4)
  85.         {
  86.                 array[36] = (checksum>>8);
  87.                 array[37] = checksum;
  88.         }
  89. // a kapott érték a helyére illesztése


Itt a wikipediás magyarázat is:
Checksum számítása
(#) killbill válasza Sick-Bastard hozzászólására (») Szept 12, 2014 /
 
A checksum += (array[i] << 8); azt csinalja, hogy az array[i]-t eloszor int-re konvertalja, balra shifteli 8 bittel, majd a checksum += miatt unsigned long int-re konvertalja es hozzaadja checksum-hoz. Ennek jol kellene osszeadnia.

A C az egy muveletben szereplo ket operandusbol a kisebb bitszamu operandust konvertalja a nagyobb bitszamura. Ha unsigned es signed keveredik, akkor a signedbol lesz unsigned. Ha egesz es lebegopontos keveredik, akkor az egeszet konvertalja lebegopontossa. Ezen felul a char, unsigned char, short tipusokat mindig int-re konvertalja. A float-ot mindig double-re konvertalja.

A konverzioknal az elojelnek szerepe van: pl, ha van egy signed char valtozo, aminek az erteke 0x81, az int-re konvertalva 0xff81 lesz. unsigned char eseteben 0x0081 lesz belole.

Tehat a checksum = checksum + valami eseteben a valamit atkonvertalja 32 bitesre, mert a checksum is az.

Viszont nem ertek valamit. Ha neked 1db 16 bites szamot kell hozzaadni a checksum-hoz, akkor miert 2db 8 bitest adsz hozza:

checksum += (array[i] <<8) | array[i+1];

lenne a korrekt sor. Ha egy ciklusban meg lehet sporolni egy 16 bites osszeadast (kulonosen egy 8 bites processzoron), akkor azt meg is kell sporolni.

Es par aprosag: a for( ; ; ) barmelyik reszet elhagyhatod, felesleges az i = i; Ha a kozepsot hagyod el, akkor vegtelen ciklust kapsz. Ha jot akarsz magadnak, akkor nem hasznalsz i, j, stb nevu globalis valtozokat, mert ezek tipikusan lokalis valtozok nevei, es rutul meg tudja viccelni az embert, amikor egy for(i = 0; i < ...) ciklusbol hivsz egy olyan fuggvenyt, ami elrontja a globalis 'i'-t. Es mondjuk elfelejtetted deklaralni a lokalis 'i'-t, amiert a fordito nem szol, mert van egy globalis 'i'. Egyebkent sem szerencses ugyanolyan nevu lokalis es globalis valtozot deklaralni. Abbol csak a baj van. De a problemadra nem latom a valaszt, mert annak 32 bitesen kellene osszeadnia. Akarhonnan is szedi a byte-okat.
(#) csabeszq válasza killbill hozzászólására (») Szept 12, 2014 /
 
Idézet:
„A checksum += (array[i] << 8); azt csinalja, hogy az array[i]-t eloszor int-re konvertalja”


Az elmélet és a gyakorlat AVR alatt nem mindig találkozik.

  1. void set_bit(uint8_t bit)
  2. {
  3.   PORTD |= (1 << bit);
  4. }


A gcc régi verziói valóban int-re konvertáltak. Lehetett látni a lefordított kódban, hogy a fenti shift-elés 16 biten történt. Az új gcc-kben már nem. Nézd meg ezt a bug reportot.

Amikor 2k-s chipekre írnak programot, akkor a nép elvárja, hogy a 16 bit csak indokolt esetben legyen.
A hozzászólás módosítva: Szept 12, 2014
(#) killbill válasza csabeszq hozzászólására (») Szept 12, 2014 /
 
Az termeszetes, hogy csak akkor konvertal 16 bitere, ha ez muszaj. Azaz, ha az eredmeny szempontjabol jelentosege van. Ez is resze az optimalizacionak. A te peldadban nem kell 16 biten shifteljen, mert az eredmeny felso 8 bitjet eldobja. Viszont az array-os sorban 16 bitre kell konvertalja, mert aztan az eredmenyt meg fel is kell bovitenie 32 bitre, nem dobhat el semmit. Persze, vannak gcc bug-ok, szivtam vele en is eleget. Kulonosen long-okkal. De altalaban csak optimalizacio mellett teved. De ettol fuggetlenul erdekes, hogy a problemas kod egyszer jol szamol, egyszer meg nem (ICMP/IPv4). Kicsit magikus a dolog.
(#) killbill válasza csabeszq hozzászólására (») Szept 12, 2014 /
 
Ez a bug report is csak arrol szol, hogy nem optimalizal rendesen, tehat akkor is 16 biten szamol, amikor eleg lenne a 8. Raadasul 2008-as a felvetes...
(#) csabeszq válasza killbill hozzászólására (») Szept 12, 2014 /
 
Fentebb írtam, hogy már jól működik a gcc. Most, 2014-ben nem tudok olyan esetről, hogy az avr-gcc szószátyárkodna, pedig mindig megnézem, hogy mit ügyködött.

Gyakorlatilag ha én magam írnám meg assembly-ben, több helyet foglalna a kód, mert az avr-gcc jobban tud nálam optimalizálni.
A hozzászólás módosítva: Szept 12, 2014
(#) Sick-Bastard válasza killbill hozzászólására (») Szept 12, 2014 /
 
Üdv!

A checksum-ot azért, írtam így, mert így sikerült
Még nem vagyok valami összeszedett a kódok írásában, így néha összetettebb sorokat írok, néha darabokban, lépésekben írom le.
A for(;-nál is azért hagytam meg az i=i-t, mert könnyebben megértem, hogy mit is csináltam vagy akartam csinálni.

Mellékelem a kód letisztított változatát, amiben megvan minden rész ahol a void CheckSum() rutin megjelenik.
Amiket kihagytam:
SPI, UART, ENC28J60... stb. saját készítésű könyvtárak(header files), az említett hiba szempontjából nem relevánsak nemde?

Ill. a txt-ben a void CheckSum() rutin eredményeit nyomtattam ki.
(#) killbill válasza Sick-Bastard hozzászólására (») Szept 12, 2014 /
 
Idézet:
„Amiket kihagytam:
SPI, UART, ENC28J60... stb. saját készítésű könyvtárak(header files),”

Csak az egyertelmuseg kedveert: a header files az nem konyvtarak. A header file, az C forras kod. A konyvtar pedig mar leforditott kod (akarmilyen nyelven is irodott) es a linker dolgozik vele. Az igaz, hogy a bennuk levu fuggvenyek deklaracioi altalaban ilyen .h header file-okban vannak. Pl. a memcpy() meg a memcmp(), amik hasznalataval helybol a felere csokkenne a programod merete.

Idézet:
„az említett hiba szempontjából nem relevánsak nemde?”

Azt nem lehet tudni. A globalis valtozok hasznalata komoly odafigyelest igenyel. Fokepp, ha a valtozo neve 'i'. Ha esetleg egy masik file-ban is hasznalsz 'i' nevu globalis valtozot, es tortenetesen egy interrupt rutin is hasznalja, akkor abbol barmi is lehet. Ugyanis a kulonbozo file-okban deklaralt azonos nevu valtozok csak egyszer keletkeznek, es ugyanazok lesznek.
Szoval semmi nem garantalt ilyen esetekben. Ha olyan globalis valtozot akarsz, amit csak az adott forras file-ban hasznalsz, akkor deklarald static-nak. Es ez igaz a file-on beluli fuggvenyekre is. Ha egy fuggvenyt nem akarsz mas forrasbol meghivni, akkor jobb, ha static. De a problemadra a megoldast meg mindig nem tudom. Nem nagyaon latom okat annak, hogy ugyanaz a fuggveny ket meghivasbol maskepp mukodik. Es ugy mukodik maskepp, hogy hibasan szamol egy teljesen egyszeru ciklusban.
(#) csabeszq válasza Sick-Bastard hozzászólására (») Szept 12, 2014 /
 
Bevallom, nekem nem jött be az ENC28J60.

Az internet szabvány szerint nem kellene problémát jelentenie annak, ha egy eszköz fordított polaritással küld, azaz az TPIN+ és TPIN- felcserélődik.

A chip dokumentációja le is írja, hogy az ENC28J60 képes fordított polaritással fogadni az adatokat, csak az maradt ki, hogy 60-70%-os packet loss mellett.

Szóval nem árt kétféle ethernet kábelt tartani otthon, az egyik legyen egyenes polaritású, a másik pedig fordított. Ha éppen egyenes polaritású routerrel beszélsz, akkor az egyik kábelt használod, ha a másik félével, akkor fordítottat.
(#) Sick-Bastard válasza csabeszq hozzászólására (») Szept 12, 2014 /
 
Itt van nálad a megoldás.
Ezt kicseréltem:
  1. checksum += ((array[i]<<8) | array[i+1]);

Erre:
  1. checksum += ((unsigned int)(array[i]<<8) | (unsigned int)array[i+1]);


Így már működik.
Azért még most is zavar, hogy az első verzió mért ment és miért nem ment...
Következő: »»   617 / 840
Bejelentkezés

Belépés

Hirdetés
XDT.hu
Az oldalon sütiket használunk a helyes működéshez. Bővebb információt az adatvédelmi szabályzatban olvashatsz. Megértettem