pole v AVR C

Odpovědět
Uživatelský avatar
fulda
Příspěvky: 444
Registrován: 04 led 2016, 17:18

pole v AVR C

Příspěvek od fulda » 23 srp 2017, 23:20

Ahoj vespolek,

dnes se mi nedaří. Mám takovou jednoduchou úlohu. Mám 16 (0x0F) dvojic modifikátor + klíč. Jsem nepořádný, takže je v jednom poli o 32 prvcích:

Kód: Vybrat vše

PROGMEM char RandomKeys[32] = { /*List of used random keys*/
	0x00, 0x04,	//0
	0x00, 0x05,	//1
	0x00, 0x06,	//2
	0x00, 0x07,	//3
	0x00, 0x08,	//4
	0x00, 0x09,	//5
	0x00, 0x0A,	//6
	0x00, 0x0B,	//7
	0x00, 0x0C,	//8
	0x00, 0x0D,	//9
	0x00, 0x0E,	//A
	0x00, 0x0F,	//B
	0x00, 0x10,	//C
	0x00, 0x11,	//D
	0x00, 0x12,	//E
	0x00, 0x13 	//F
};
Chtěl bych náhodně vybrat jednu dvojici a tu přiřadit. Tak jsem si napsal:

Kód: Vybrat vše

	int x;
	x = rand() & 0x000F;
	x = x << 1;
	modifikator = RandomKeys[x++];
	klic = RandomKeys[x];
Bohužel dostávám úplné blbosti.
Přitom pokud zruším konstrukci s rand a dám místo něj konstantu, tak vše funguje OK. Pochopitelně pokud si vypíši hodnotu x tak je taky v pořádku.

Kód: Vybrat vše

	int x;
	x = 7;
	x = x << 1;
	modifikator = RandomKeys[x++];
	klic = RandomKeys[x];
Už vážně nevím, co dělám špatně. :(
Jen technická - attiny85

děkuji za radu
Za pravopisné chyby v této zprávě může moje učitelka češtiny.

DavidO
Příspěvky: 385
Registrován: 01 kvě 2013, 21:27

Re: pole v AVR C

Příspěvek od DavidO » 24 srp 2017, 08:30

Čím to kompiluješ?
Podíval bych se taky do listingu v assembleru, jestli se ti tam něco "nevyoptimalizovalo".
(rand by měl být úplně v pořádku, je to standardní funkce z stdlib, akorát je to celkově trochu nabobtnalý, protože se to počítá v long (32 bitů), vrací int (16 bitů) a ty z toho použiješ nakonec jen dolní nibble).

Uživatelský avatar
fulda
Příspěvky: 444
Registrován: 04 led 2016, 17:18

Re: pole v AVR C

Příspěvek od fulda » 24 srp 2017, 09:59

překládám to celkem běžným GCC v defaultním nastavení co je v AVR Studiu 4.

Ta nabobtnalost rnad je mi jasná, čím delší datový typ, tím delší vzdálenost opakování (platí pro polynomiální pseudo random). Ale do toho bych se nepouštěl.

Musím se tedy začít rejpat v tom listingu. Narazil jsem na ještě jednu věc - udělal jsem si globální proměnnou Y, kterou jen zvětšuji. A chová se to úplně stejně blbě. Když si vypíšu obsah "x" tak dostávám naprosto korektní hodnoty.

Kód: Vybrat vše

	int Y=0;	// je jedno, jestli int, nebo uchar, nebo cokoli
	...
	int x;
	x = Y++;
	if (Y>0x0F) {Y=0;}
	x = x << 1;
	modifikator = RandomKeys[x++];
	klic = RandomKeys[x];
Za pravopisné chyby v této zprávě může moje učitelka češtiny.

Uživatelský avatar
fulda
Příspěvky: 444
Registrován: 04 led 2016, 17:18

Re: pole v AVR C

Příspěvek od fulda » 25 srp 2017, 22:32

Tak už jsem došel k výsledku, ale zatím úplně netuším proč a jak.
Když jsem se díval do toho, co vzniklo při překladu, tak jsem došel k závěru, že překladač někde vytratil informaci o tom, že se má dívat do progmem a díval se sice na správnou adresu, ale do normální ram.
Pokud tedy v mém kódu smažu direktivu PROGMEM, tak funguje podle očekávání.
Ale moc netuším, proč se tak stalo.
Asi budu ještě pracovat s direktivou const nebo tak něco.
Za pravopisné chyby v této zprávě může moje učitelka češtiny.

DavidO
Příspěvky: 385
Registrován: 01 kvě 2013, 21:27

Re: pole v AVR C

Příspěvek od DavidO » 26 srp 2017, 22:39

A jo, vidíš, já na to kouk jen jedním okem a PROGMEM jsem si nevšiml. Experimentátor jsi dobrej, souvisí to s tím hodně. Ono to je pokud vím tak, že když to použiješ při deklaraci, tak to způsobí, že se daný objekt uloží do programové paměti (Flash) místo do RAM. Ale neříká to pak dál, že kdykoli na to sáhneš, že se automaticky sáhne zase do Flash. Na to je potřeba použít spešl funkce pgm_read_xxx, viz avr/pgmspace.h.

Uživatelský avatar
fulda
Příspěvky: 444
Registrován: 04 led 2016, 17:18

Re: pole v AVR C

Příspěvek od fulda » 27 srp 2017, 09:14

To právě tak není.
Za normálních okolností se PROGMEM stává read-only, ale jinak se s ním pracuje úplně normálně (ZDE). Používám to často, zejména pro definování řetězců na displaye a tak se to hodí.
Tady jsem prostě udělal něco, co přinutilo překladač si myslet, že je tabulka v oblasti "const" a nikoli "PROGMEM".

Vzhledem k malé důležitosti toho programu jsem použil závěrečné hodnocení podle mé manželky: "je to krám".
Za pravopisné chyby v této zprávě může moje učitelka češtiny.

DavidO
Příspěvky: 385
Registrován: 01 kvě 2013, 21:27

Re: pole v AVR C

Příspěvek od DavidO » 27 srp 2017, 10:22

Mě se zdá, že to, co tam píšou, mi dává za pravdu v sekci "Storing and Retrieving Data in the Program Space": nejdřív píšou, že se k deklaraci přidá PROGMEM, na tom jsme se já i ty shodli. Pak píšou
Now that your data resides in the Program Space, your code to access (read) the data will no longer work. The code that gets generated will retrieve the data that is located at the address of the mydata array, plus offsets indexed by the i and j variables. However, the final address that is calculated where to the retrieve the data points to the Data Space! Not the Program Space where the data is actually located. It is likely that you will be retrieving some garbage. The problem is that AVR GCC does not intrinsically know that the data resides in the Program Space.
což odpovídá tvému pozorování. A hned pak se píše, že
The solution is fairly simple. The "rule of thumb" for accessing data stored in the Program Space is to access the data as you normally would (as if the variable is stored in Data Space), like so:
byte = mydata[i][j];
then take the address of the data:
byte = &(mydata[i][j]);
then use the appropriate pgm_read_* macro, and the address of your data becomes the parameter to that macro:
byte = pgm_read_byte(&(mydata[i][j]));
The pgm_read_* macros take an address that points to the Program Space, and retrieves the data that is stored at that address. This is why you take the address of the offset into the array. This address becomes the parameter to the macro so it can generate the correct code to retrieve the data from the Program Space. There are different pgm_read_* macros to read different sizes of data at the address given.
Já tomu rozumím tak, že na přístup k PROGMEM datům nemůžeš použít normální Cčkový konstrukce, ale musíš použít ty jejich makra.
S těma řetězcema si dokážu představit, že by stačilo deklarovat je v PROGMEM a pak to používat jakože normálně, ale v takovém případě podle mě musí být ten zvláštní přístup schovaný v té funkci, co vezme string a zobrazí ho na displeji (kterážto by následně nemohla fungovat s řetězci uloženými v RAM).

(přiznávám nicméně, že jsem to včera psal po paměti, jen jsem vyhledal ten odkaz na pgmspace.h. Ale když jsem si to dneska přečetl pořádně, tak mám stejně pořád pocit, že jsem měl pravdu - takže by mě docela zajímal kód, kde ti to fakt funguje jen s deklarací a pak normálním přístupem)

Uživatelský avatar
fulda
Příspěvky: 444
Registrován: 04 led 2016, 17:18

Re: pole v AVR C

Příspěvek od fulda » 27 srp 2017, 13:06

a-ha, tak jsem to celý život dělal špatně a fungovalo to omylem.
Asi to budu muset číst pořádně.
Pro arduino je to stejně? nebo jsem to pomotal?

Každopádně díky
Za pravopisné chyby v této zprávě může moje učitelka češtiny.

DavidO
Příspěvky: 385
Registrován: 01 kvě 2013, 21:27

Re: pole v AVR C

Příspěvek od DavidO » 28 srp 2017, 00:42

Tak to je mi líto, že jsem ti naboural jednu ze životních jistot. Vypíchnu jen to důležité:
fungovalo to omylem
arduino
:mrgreen:

Nicméně, v Arduinu to bude stejně - kompiluje to gcc. Mrk sem: https://www.arduino.cc/en/Reference/PROGMEM

Ale fungovat ti to mohlo. Jestli jsi použil konstrukci typu Serial.print(F("Neco do Flash")); tak to díky makru F bylo ve flash, ale zároveň se to díky němu ještě prekabátilo tak, aby print nedostal obyčejný řetězec (který by bral z RAM a to nechceme), ale něco jiného, tím pádem se dá napsat print s tímhle jiným typem ("function overloading") a tam už se to správně vytáhne z Flash.

Uživatelský avatar
fulda
Příspěvky: 444
Registrován: 04 led 2016, 17:18

Re: pole v AVR C

Příspěvek od fulda » 28 srp 2017, 08:27

Tak jsem se zakoukal na případy, kdy to fungovalo a zjistil jsem že:
  1. funguje to, pokud to optimalizace dohledá jako konstantu a nahradí to konstantou (viz na začátku), pak vůbec nedělá pole
  2. funguje to v případě, kdy to překládám pomocí mplab C. Pak to ale nefunguje na AVR, ale třeba na PIC18
Prostě už nezvládám tolik překladačů.

Každopádně děkuji za konzultace.
Za pravopisné chyby v této zprávě může moje učitelka češtiny.

Odpovědět

Kdo je online

Uživatelé prohlížející si toto fórum: Žádní registrovaní uživatelé a 1 host