Problémy s AVR Studiem

Tak naposled :slight_smile:
debug system na vypisy hodnot promennych. Bud na nejaky displej nebo pres uart na terminal do pc. Takhle nevis, co se v tech promennych deje.
Zmateny? me to pripada jasny. Psal jsem at vyhodis poll, ale nedosla mi ta podminka v tom while, ze vlastne to je ono, to byla moje chyba.
Ja jsem nenapsal ze nebudes schopny, to ja bych nikdy nenapsal, protoze te neznam a netusim tve moznosti a znalosti a ani o nich nehodlam pochybovat.

Ten debug systém tam nějaký mám. Momentálně dokonce na grafickém LCD. Některé proměnné si tam vypisuji, pravda, vypsat si po krocích tu PS2_Flag mě zatím nenapadlo.

jj pouzit displej je lepsi, pokud ho tam mas. Ja jsem si to pak udelal pres ten uart, protoze jsem nechtel aby se mi ty ladici vypisy michaly do standartniho vystupu toho programu. Tam se zas ale v pripade avr narazi na 1 uart, ktery muze byt pouzit k necemu jinymu. U ARMu to resit nemusim, ten ma aspon 2.
Je dobry to udelat podminenym prekladem, abys to nemusel zakomentovavat nebo mazat. Pri debugu si dat define DEBUG a vypisovat. Jinak program bezi bez vypisu.
Az na to prijdes, napis cim to bylo, to me zajima, me uz napady dosly.
V praxi se mi to zkouset nechce :slight_smile:

Tak na to koukám a nesedí mi tu pár věcí: if ((PS2_Bit==0) && (PS2_D_PIN & (1<<PS2_D))) //If this is the first received bit, { //and the DATA is LOW (startbit)
Podmínka IF je splněna, když je 1. bit high nikoli low. Chybí tam negace.

Druhá věc se týká přístupu do kódové paměti, tedy pole Scan2ASCII]. unsigned int adr; adr = (unsigned int)Scan2ASCII+PS2_Data; //otherwise decode as a normal key. PS2_ASCII = pgm_read_byte_near(adr); //naplneni vysledku
adr není pointer na pole Scan2ASCII, ale promenná int 32bitová. K čemu tak velká, když pointery v AVR8 jsou 16bitové. Součet Scan2ASCII+PS2_Data je vlastně součtem přetypovaného pointeru kódové paměti a proměnné typu char.
Jeli to zamýšleno tak, že se má získat PS2_data-tý prvek z pole Scan2ASCII, pak stačí napsat
PS2_ASCII = Scan2ASCII[PS2_data];
Funkce pgm_read_byte_near(adr) není známa, její dekarace není ve výpisu uvedena.

Pointer bys musel deklarovat takto:
char * adr = Scan2ASCII;
nebo
char * adr = &Scan2ASCII[0];
adr pak bude pointer pravděpodobně typu unsigned short pro AVR8. Záleží na procesoru. Ale je zřejmé, že k tomu bude používat pointry X,Y,Z (viz instrukce ASM).
Překladač by měl vzít i deklaraci pole takto:
const unsigned char Scan2ASCII] = {0, 0, …};
Není třeba užívat PROGMEM.

S tou chybějící negací jsi mě dokonale zmátl. Tak jak to je napsané to ale chodí. možná je jen chyba v popisku.
Ale to jsi mě docela dostal ti povím…
pcbheaven.com/wikipages/The_PS2_protocol/
(nejen) Zde je psané, že startbit by měl být LOW. Zajímavé, jaktože mi to chodí i na high. :open_mouth: :question:
Ale správná poznámka ! Díky.

Ty pointery jsme nesnášel už v pascalu. V asm je umím obratně využívat, ale takhle moc ne.

Já měl INT odjakživa jako 16bitový, a to i proto, že dkyž si přidám int proměnnou, v paměti mi to ubyde o 2 byte, ne o 4. 4byte (32bit) je long. (nebo se pletu?)

PROGMEM (a i pgm_read_byte_near()) je nutnost. Ten kompiler GCC je opravdu tak blbý, že i když se ty data využívají jen ve směru READ, tak je po startu MCU všecky zkopíruje do RAM. Takže pokud projekt využívá takovýhle tabulky ve větším množství, je hned zasviněná RAM.
Stejný problém dělají i řetězcové konstaty, byť třeba jako vstupy do funkcí. Taky si je to nakopíruje do RAM, přestože je to k ničemu, když je to jen pro čtení. (Tohle chování ale edovedu pochopit).

“Deklaraci pole takto…” to samozřejmě bere. Ale kompiler má v hlavě piliny a celé to pole zkopíruje do RAM, ačkoliv se bude z něj jen číst jako z tabulky.

EDIT: Další záhada. Ať dám podmínku pro start bit LOW nebo HIG funguje to stejně.
Ještě jsem jen tak zkusil změnit INT0 z positive edge na negative edge (jak to popisují n atamtom webu). Funguje to pořád stejně, žádná změna. Mno to je zajímavý.

Velikost typu int záleží na překladači. V GCC pro AVR8 je int = 2B.

Pointer sám o sobě je datový typ, tedy “adr” nebude “pointer typu…”, ale “pointer na typ…”. Ale to je jen slovíčkaření.

Jestli fo funguje jak na LOW tak na HIGH bit, potom je třeba tomu věnovat větší pozornost. Někde musí být zakopaný pes.

Dovol mi trochu kritiky. Způsobem, jakým píšeš programy, si do budoucna zaděláváš na problémy. Zastavím se u procedury, resp. přerušení ISR(INT0_vect).
Tato procedua vytváří SW USART, která má své vnitřní proměnné a vnější, kterými předává data ostatrním. To je důležité od sebe striktně oddělovat. Proměnné PS2_Bit a PS2_BitShift jsou vnitřní, protože jen tato procedůra má právo s nimi manipulovat. Proto by měly být deklarovány uvnitř této procedůry a né jako globální. Protože si mají uscovávat obsah i pro další volání, deklarují se jako static. Pak je zbytečné u nich používat deklaraci volatile.
Proměnné PS2_Data a PS2_Flag jsou tzv. veřejné, a musí tedy být deklarovány jako globální volatile, tedy tak, jak to máš.

Při čtení dat, resp. jednotlivých bitů z portu je někdy třeba uděla kopii stavu portu, zapsat ji do registru a pak dle tohoto registru větvit program. Toto je nutné v případě, že zmíněný port dále používáš v nějaké větvi programu. Port totiž není volatile a pochybuji, že to lze nějak říci překladači. Když zpracováváš stav portu v nějaké části programu, která je podmíněná stavem tohoto portu, muže dojít k chybnému zpracování.

Např.

IF (!(PINA & 0x80)) suma += PINA;

v tomto případě může dojít k přičtení do sumy i číslo větší než 127. Protože v době zpravování podmínky IF mohl být bit7 ještě nulový, ale při vykonávání součtu už na portu A mohou být jiná data.

Proměnné, které slouží pouze jako mezivýsledek, je dobré deklarovat pouze v té části, kde ji potřebuji. Ne na začátku pogramu. Jednak se složitě hledají dekarace a potom se rychle vyplýtvá slovník pojmů, a hlavně i paměť RAM. To se týka např. proměnné adr. Za chvíli někde nadeklaruješ další adr, a pak nebudeš vědět, jsou-li stejné nebo ne.
Pro mezivýsledek můžeš použít deklaraci register. Překladač ji dočasně uchová v registru procesoru, ale nemusí k tomu dojít, pokud nemá volný registr.
Nevím, zda ti překladač vezme toto: unsigned int adr = (unsigned int)Scan2ASCIIspc+PS2_Data;
Jinak bys to musel rozepsat na 2 řádky. Platnost deklarace končí s příslušnou uzavírací složenou závorkou, poté je její obsah přepsán jinou proměnnou.

(Ty maily s upozorněním na odpovědi odsud chodí nějak ledabyle.)

Kritika se samozřejmě přijímá. Ale pořád je to kritika věcí, které momentálně se netváří jako zásadní, a neserou mě s odpuštěním tolik, jako ta knihovna PS2. Tu jsem totiž stále ještě neopravil, protože prostě si to usmyslelo, že to fungovat nebude.¨Ať dělám cokoliv, je to pořád stejně podělané nebo občas horší. Zpět jsem zrušil používá Extended Keys, ale prozměnu jsem si všiml, že to občas stejně záhadně nerozlišuje stisk a uvolnění klávesy.

Ještě jsem dneska vylaboroval jednu věc:
Dovnitř funkce PS2_Poll jsem umístil počítadlo, kolikrát procesor vykoná ten vnitřní switch a výsledek čítače jsem si psal na displej.
Klávesnice při stisku obyčejné klávesy odešle její číslo (tedy jeden průběh switche v PS2_Poll) a při uvolnění pošle 0xF0 a z to kod uvolněné klávesy - tedy dva další přijaté byte. Na jedno ťuknutí klávesy by to tedy mělo načítat tři průběhy toho switche. Jenže, ono to někdy napočítá dva a někdy tři. To je přesně to, proč mi to nerozlišuje normální a extended keys a se.e to na key-release 0xF0. Takže se víc zaměřím na tu funkci příjmu dat z klávesnice. Počítadlo umístím tam, kolik to schválně napočítá byte.
Stejně tak mě vtá hlavou, proč to funguje ať dám podmínku startbitu LOW nebo HIGH úplně stejně. To je hodně zvláštní chování.

UPD: Data z klávesnice se přijímají správně. Obsluha přerušení je tedy správně. Co správně ale není, je to místo, kde se data ztrácí. Je ot někde mezi přerušením a PS2_Poll.

UPD2: Už jsem si na 90% jistý, čím to je.
Prostě a jednoduše volám z hlavní smyčky programu PS2_Poll moc pomalu. Takže než zpracuju předchozí data už mám přijatá jiná - přesně to sedí na tu situaci a vše tomu nasvědčuje.
Zkoušel jsem dát samostatné zpracování přijatých dat rovnou do přerušení - to se ale ukázalo jako kravina, jelikož na to už nestačilo ani oněch 18MIPSů na kterých mi ta mega644 letí. Prostě to zpracování byť jsme ho okleštil na minimum to přerušení natolik prodlužuje, že to pak nestíhá.
Řešení jsem vymyslel následující: Již dříve jsem dostal nápad to udělat, ale šetřil jsem si to až na vyšší verze téhle knihovny - takže co s tím?
Přijatá data ukládat do bufferu - prostě softwarově implementovat aspoň tak pětiúrovňové FIFO. (kolikaúrovňové je už jen o tom, kolik RAMky jsem ochotný investovat) FIFO odstraní problém nutného okamžitého zpracování. Ona ta klávesnice chrlí ta data docela rychle a mezi jednotlivými byte nenechává dostatečnou mezeru, aby mi stihla proběhnout celá hlavní smyčka programu.

Co si o tom mojem posledním poznatku myslíte?
Já se domnívám, že jsem se konečně trefil, kde to vázne a našel ten zakopaný problém. Ono mě to trklo v momentně, kdy jsme do stávajícího programu přimontoval starší verzi mojí PS2 knihovny, u které jsem si byl zatraceně jistý, že funguje a ono to taky nefungovalo a dělalo to vesměs stejné kraviny.

FIFO je dobrá myšlenka. Ta se realizuje pomoci circular bufferu. Data se tam zapisují pořád dokola. Je to úpně běžné a až budeš dělat na xmegách, tak si k nějaké periférii přiřadíš DMA kanál a v paměti se ti to bude ukládat bez intervence procesoru. Jinými slovy, je to naprosto běžné řešení.

Je potřeba ale zajistit několik podmínek, jinak je to odsouvání problému.

  1. Procedůra zpracovávající přijaté znaky musí být schopna je zpracovávat rychleji, než přichází, jinak se buffer přeplní i kdyby měl 100GB. Tzn. zpracovat více znaků najednou.
  2. Musí být ochrana bufferu proti přetečení. Není-li v něm místo, nemělo by se do něj už dále zapisovat a pro informaci by měl být nastaven nějaký flag. U USARTu takový flag exituje.

Právě 2. podmínka není v tém programu splněna. Mohlo by to vypadat např. takto:

else if((PS2_Bit==10)&&(!(PS2_Flag &(1<<PS2_RXD)))) //if this is the 10th bit (the last, STOPBIT) { //DATA line should be HIGH PS2_Bit=0; //reset the bit counter PS2_Data = PS2_BitShift; //Copy the temporary register to PS2_Data register PS2_Flag |= (1<<PS2_RXD); //set flag "data reception completed"
Snad jsem to napsal dobře. Zkrátka, jeli PS2_RXD nahozen, neměl by se PS2_Data přepisovat. Nicméně by stejně došlo ke zprátě dat.

Problémy se synchronizací hlavního programu s přerušním se těžko odhalují nějakým simulátorem. Mám na to poměrně jednoduchý recept. Najdu si nějaké piny na MCU, které mohu ovládat instrukcemi SBI a CBI. Nastavím je na výstup a připojím na ně osciloskop. Instrukce pak umístím do sledovaných míst. V tvém příadě by to bylo do ISR(INT0_vect) a PS2_Poll(void). Na osciloskopu pak uvidíš jak se obě rutiny vzájemně volají a jak dlouho trvá hlavní smyčka. Taktéž můžeš zjistit, kdy a zda MCU vykonává inkriminovanou část programu. S častým přepisováním FLASH není třeba si dělat těžkou hlavu, vydrží i více než 1000x.

Jo jo, vím co je FIFO i co je circular buffer.
Za půl hodiny mi to fungovalo. (poté, co jsem odeslal předchozí příspěvek)
Zpracování přijatých znaků je rychlé, že snad rychleji nejde. Uloží se do pole, inkrementuje ukazatel, popřípadě se skočí zpět na adr 0.
Buffer jsem nastavil na 10 Byte a chodí to s tím nádherně. (Vyřešilo to problémy s detekcí Extended keys, stejně jako občasné zdvojování stisků kláves)
Detekce přetečení - podle mě v této aplikaci zbytečné řešit, protože stejně pokud je buffer plný, někam se ten další byte musí dát a protože není kam, tak se musí zahodit. Takže ke ztrátě by došlo tak jako tak, leda že bych na displeji upozorňoval “bacha vole přetékáš” ale na tomhle místě je to k ničemu.

Nyní je celá aplikace (konečně, po půl roce) hotová a už mi nepřekáží na stole.

Takže díky všem, za poskytnutou pomoc.

Z téhle gigantické aplikace (zatím moje největší) jsem si odnesl dost nových a zajímavých poznatků. Mimo jiné i to, že 18MIPS je už rychlost značně slušná a dá se tím zvládat lecos. Jelikož tohle byla částečně komerční aplikace, chtěl bych na ní navázat projektem čistě nekomerčím a využít části předchozí aplikace k sestavení nové. Mám tu grafické LCD 240x64 bodů (řadič má, ale nikde jsem nenašel jak se to ovládá) a chtěl bych zkusit napsat na AVR nějakou hru. (inspirací bylo Space Invaders ze starých Nokií) Domnívám se, že těch ca 16MIPS je rychlost na to dostatečná. Jen si budu muset udělat trochu pořádek v práci s ukazateli v C, protože jsem se s tím docela porval a tuhle aplikaci přeložil chtě nechtě s >80 warningy (povětšinou stejného druhu).

Jen ještě jedna věc mi leží v žaludku:
To, že data z klávesnice se přijímají správně pokud se sampluje dataová linka na náběžné nebo sestupné hraně (výsledek stejný: obojí funguje) jsem překousl s tím, že hodinové impulzy chodí veprostřed platných dat.
Co jsem už ale nepřekousl, proč to funguje, když čekám na startbit v log 0 i log 1 (obojí taky funguje). To už je dost zvláštní ne?