Kérdés:
Miért töltik meg ilyen gyorsan az SRAM-ot? Legfeljebb 60 bájt van
SlowerPhoton
2016-02-11 00:59:08 UTC
view on stackexchange narkive permalink

Éppen átestem az összes kódomon. Maximálisan 60 bájtot használok. Mindent megtettem annak érdekében, hogy minimalizálja a használatát - még a booleant is bitként tárolom, nem bájtként! Mi történhet itt?

Csak a rendkívül nagy tömbök jutnak eszembe, például:

  const uint8_t SBoxes [8] [4] [16 ] PROGMEM;  

Ezeket azonban a program memóriájában tároljuk, amint láthatja. Hogyan ellenőrizhetem, hogy valóban vannak-e, és a memóriahasználatom? A kódom túl nagy ahhoz, hogy ide tegyem.

SZERKESZTÉS:

Az IDE elmondja nekem (bár úgy gondolom, hogy nagyon pontatlan):

Vázlat 7898 bájt (24%) program tárhelyet használ fel. Maximum 32 256 bájt. A globális változók 1023 bájtot (49%) használnak a dinamikus memóriából, 1025 bájtot hagyva a helyi változókra. A maximális érték 2048 bájt.

Az összes szó szerinti karakterláncom F () -t használ, és nem sok van belőlük.

EDIT2:

Kód a megfigyelőn. Csak egy rövid áttekintésre, valóban nagy.

EDIT3:

Saját soros nyomatok

  readysome számok (ez rendben van, megkérem, hogy nyomtasson ki egy tömböt) ENreadyainain numbursEnready ...  

Megkérem, hogy nyomtasson ready a programom legelején. Megkérem, hogy nyomtassa ki a setup funkcióm vége felé a println encr végét , de amint látja, soha nem fejezi be a nyomtatást.

Mindig viselkedik mint amikor elfogy az SRAM.

Mit mond az IDE, hogy mennyi helyet használtak fel?
Kérjük, tegye közzé az adatnyilatkozatokat. Ellenőrizze, hogy minden szó szerinti karakterlánc F () -t használ-e.
Frissítettem a kérdésemet. Kérjük, olvassa el az EDIT oldalt.
Mit mond neked az `avr-nm -Crtd --size-sort your_elf_file`? Nézze meg a „D”, „B” és „V” típusú szimbólumokat.
Milyen fájlon hívjam? Csak az .ino fájljaim vannak. És nem veszi érvként a projektfájlomat. Azt mondja nekem, hogy "nem egy közönséges fájl".
A program elkészítéséhez aktiválja a „részletes fordítás” opciót. Látni fogja, hogy az IDE létrehoz egy .elf kiterjesztésű fájlt egy ideiglenes könyvtárban. Ezt a fájlt kell megadnod az avr-nm-nek.
Használja a LiquidCrystal könyvtárat és a `Serial'-ot is (amely 64 bájtos puffert használ). Ha minden mást eltávolít, akkor körülbelül 260 bájt lesz a vége. Bár fogalmam sincs, hova kerül a többi 750 bájt.
Ó, látom, most tanítottál nekem valami újat. [Itt van a Pastebin-en] (http://pastebin.com/HexLXUwD)
A `Serial`-ról és a LiquidCrystal-ról: Igen, megfeledkeztem róla. Köszönöm, hogy felhívta a figyelmet, de félek, hogy még ez sem oldja meg a talányt.
Ha sok részletet szeretne megtudni az 1975-ös Data Encryption Standard-ről (DES), akkor a semmiből történő végrehajtása sokat fog tanítani. Ha azonban a cél az, hogy valamit ténylegesen titkosítson, talán jobb lenne (a) egy modernebb titkosítást használni, mint például a Twofish vagy az AES; vagy (b) használjon már létező könyvtárat; vagy mindkettő. Lásd: [Spaniakos] (http://spaniakos.github.io/AES/), [AESLib] (https://github.com/DavyLandman/AESLib), [AES-könyvtár] (http: //forum.arduino. cc / index.php? topic = 88890.0) stb.
Kettő válaszokat:
Edgar Bonet
2016-02-11 01:44:16 UTC
view on stackexchange narkive permalink

Ha azt kérdezi magától, hogy mi ennyi RAM-ot eszik, akkor először meg kell néznie az ELF fájlban található szimbólumtáblát. Ha makefile-t használ, valószínűleg tudja, hol található az ELF fájl. Ha az ArduinoIDE programot használja, lépjen a Fájl / Beállítások oldalra, jelölje be a „Verbose output megjelenítése a fordítás során” lehetőséget, fordítsa le és nézze meg a kimenetet: meglátja az ideiglenes könyvtárat, ahová a fordító az ELF fájlt helyezi el.

Most futtassa az avr-nm -Crtd --size-sort your_file fájl parancs és a 'D' (adatok), 'V' (vtable) és 'B' (BSS) típusú szimbólumok, akár felső, akár alacsonyabb szinten ügy. Unix stílusú operációs rendszeren át kell vezetnie a grep -i '[dbv]' fájlt. Futó ez a program lehetőséget ad:

  00000068 B tx_buffer00000068 B rx_buffer00000034 B Serial00000021 B lcd00000016 V vtable az HardwareSerial00000008 V vtable az LiquidCrystal00000004 B timer0_overflow_count00000004 B timer0_millis00000002 D __malloc_margin00000002 D __malloc_heap_start00000002 D __malloc_heap_end00000002 B __flp00000002 B __brkval00000001 b timer0_fract00000001 D encr00000001 B debug00000001 B EEPROM  

Nyilvánvaló, hogy ez nem számolhatja el a program által használt 1023 bájt statikus RAM-ot. Amit ez a parancs kihagy, az a szó szerinti tömbök és húrok. Ezek az avr-objdump -j .data -s your_elf_file paranccsal láthatók. A szó szerinti húrok teljesen nyilvánvalóak a kimenetben, a szó szerinti tömbök kevésbé. Ennek futtatása a programján hosszú listát eredményez, kezdve a következővel:

  A .data szakasz tartalma: 800100 00000005 2000010e 040d0102 0f0b0803 .... ........... 800110 0a060c05 09000700 0f07040e 020d010a ................  

Most a forráskódon láthatjuk:

  const uint8_t SBoxes [8] [4] [16] PROGMEM = {{{{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7}, {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
{4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0}, {15, 12, 8, 2, 4, 9, 1, 7 , 5, 11, 3, 14, 10, 0, 6, 13}}, ...  

Ha ezt hexadecimálisra fordítja, akkor a 0e 04 0d 01 02 0f ... , amely az előző lista első sorának végére is megjelenik. Tehát az ön hibája: az összes nagy PROGMEM tömb. A fordító nem támogatja a PROGMEM attribútumot a helyi változókon.

Az első gondolatom az volt, hogy globálissá tegyem a tömböket, és ez megoldja a problémát. Ugyanakkor, amint arra Mikael Patel egy megjegyzésében rámutatott, a PROGMEM dokumentációja kimondja, hogy „a változókat globálisan kell meghatározni, VAGY a statikus kulcsszóval definiálni, hogy működni tudjanak a PROGMEM-mel.” Ezután a tömbök static const PROGMEM készítése egy tisztító megoldás.

Nem lehet. Nincs értelme.
Teszteltem, hogy egyszerűen "statikusként" definiálom őket, ahol állnak, és az adatok mérete 311 bájtra csökken.
Megpróbáltam kihúzni őket a funkciókból, hogy globálisak legyenek. A könyvtár működésének biztosítása érdekében a tömbök fölötti bemeneti jogot hívtam meg. Amint láthatja, az IDE mást mond (a Sketch 7788 bájtot (24%) használ a program tárterületén. Legfeljebb 32 256 bájt. A globális változók 399 bájt (19%) dinamikus memóriát használnak, így 1 649 bájt marad a helyi változók számára. 2 048 bájt.) De még mindig nincs rajta az SRAM - a program ugyanúgy hurkolja a Serialt, mint korábban.
Az Arduino PROGMEM dokumentációjában van egy sor erről "Kérjük, vegye figyelembe, hogy a változókat globálisan kell meghatározni, VAGY a statikus kulcsszóval definiálni, hogy működjenek együtt a PROGMEM-mel." https://www.arduino.cc/en/Reference/PROGMEM
"De még mindig nincs rajta az SRAM - a program ugyanúgy hurkolja a sorozatát, mint korábban." - most ne folytassuk a következtetéseket. Hogy érted pontosan azt, hogy "hurkolja a sorozatát"?
Sokat nyomtat "fff" -t? Nos, ezt mondtad neki.
A soros bemenetet használom a hibakereséshez. Miután elkezdte kinyomtatni a hibákat vagy a ciklusokat (ez azt jelenti, hogy kinyomtat valamit, és a program elejétől kezdődik újra), tudom, hogy kifogytam az SRAM-ból. Nem, úgy értem, hogy a `Serial`-ban az fff az lcdDisplay-re vonatkozik - amúgy soha nem jön a parancshoz, azelőtt elkezd ciklusolni.
Kérjük, szerkessze a kérdését, és illessze be abba, amit valójában nyomtat. Most megpróbáljuk kitalálni, hogy mit keres.
Most szerkesztettem, hogy érthetőbb, jó ötlet legyen.
Nick Gammon
2016-02-11 01:56:45 UTC
view on stackexchange narkive permalink

Edgar Bonet válaszának és az alatta lévő megjegyzésem részletesebb kifejtéséhez nem lehet hasznosan elhelyezni a PROGMEM változókat helyi változóként, mert a helyi (nem statikus) változókat el kell rendelni a veremhez.

  void lookUpInSBox (méret_t mely bájt * cím, bájt * binárisKimenet, méret_t címFrom) {... const uint8_t SBoxok [8] [4] [16] PROGMEM = {/ * S1 * / {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7}, {0, 15, 7, 4, 14, 2, 13 , 1, 10, 6, 12, 11, 9, 5, 3, 8}, {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5 , 0}, {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}},  

Globálissá tehetné őket. De ha nem szeretné ezt megtenni, tegye eléjük a static -t. Ezzel a kódodon 247 bájtra csökkentettük.

  A globális változók 247 bájt (12%) dinamikus memóriát használnak, így 1801 bájt marad a helyi változók számára. . A maximum 2048 bájt.  

Valamivel többre számít, mint a megszámlált 60. A soros pufferek eltartanak egy kicsit (128 bájt).

További információkért lásd: Állandó adatok bevitele a program memóriájába (PROGMEM). Egy apró vázlaton a következő 346 bájtot találtam már használatban:

  • 34 bájt a HardwareSerial példányhoz (soros)
  • 64 bájt a soros átviteli pufferhez
  • 64 bájt a soros vételi pufferhez
  • 4 bájt a soros adó puffer fej- és farokmutatókhoz
  • 4 bájt a soros vételi puffer fej- és farokmutatókhoz
  • 9 bájt a millik / mikroszámok követéséhez
  • 4 bájt a memóriafoglaláshoz (__malloc_heap_start, __malloc_margin)
  • 128 bájt a kupac biztonsági margójához
  • 6 bájt néhány beágyazott függvényhíváshoz (main -> setup -> getFreeMemory)
  • 16 bájt a fordítóhoz nézhető a HardwareSerial számára
  • 4 bájt a __brkval és __flp változókhoz (a memdebugban használják)
  • 2 bájt a fő veremre tolva (a regiszterek mentéséhez)
  • 2 bájt a verembe tolva a beállítás során (regiszterek mentéséhez)
  • 4 bájt tolt a veremre a getFreeMemory-ban (regiszterek mentéséhez)
  • 1 bájt, mert a veremmutató 0x8FF helyett 0x900-nál kezdődik

Az oldalam vázlata dinamikus memória-allokációt használt, így valamivel többet használt, mint a tiéd (ennek nyomon követésére).


Miután elkezdte kinyomtatni a hibákat vagy a ciklusokat (ez azt jelenti, hogy kinyomtat valamit, és a program elejétől indul újra), tudom, hogy kifogytam az SRAM-ból

Kicsit értetlenkedem az összes new / delete miatt. Miért csinálja? Például:

  byte * E; E = new byte [48/8]; for (size_t i = 0; i < 48; i ++) {insertBit (E, i, bitValue (R, E_BIT [i] -1));} // XOR Kn és E (Rn-1) bájt KxorE [48 / 8]; for (size_t i = 0; i < 48; i ++) {insertBit (KxorE, i, bitValue (K, i) ^ bitValue (E, i));} törlés [] E;  

A dinamikus memóriaelosztás hatalmas mennyisége széttöredezheti a memóriát. Nem írhatod át, hogy ezt ne tedd? Tömböket átadhat referenciaként, csak furcsának tűnik (és lassúnak) az összes kiosztás.

Úgy érted, hogy `const uint8_t SBoxes [8] [4] [16] PROGMEM`? Kipróbáltam, és bár az IDE csökkentette a memóriahasználat számát, a program még mindig hurkolja a `Serial` bemenetét - még mindig nincs rajta az SRAM :( Még ha hozzáadom a további bájtjaimat is a számomhoz, 2000-hez sem jutunk.
Ezt nem értem. Ezért nem kerül ki az SRAM-ból, hacsak nem dinamikusan osztogat sokat memóriát. Lásd megjegyzésemet Edgar Bonet válasza alatt.
Lásd a dinamikus allokációval kapcsolatos módosított válaszomat.
Mind az `E`, mind a` KxorE 'tömbre szükségem van. Amit tehetek, hogy nem törölöm őket, de nem sokkal többet. Eredetileg aggódtam az SRAM miatt, ezért mindent töröltem, amit csak tudtam. Természetesen optimalizálni fogom a sebességét, de csak akkor, ha fut. De köszönöm ezt a tippet, nem tudtam, hogy a memória kiosztása ilyen lassú lesz.
Nem * lassú, de lassabb, mint ha nem csinálnánk. Ha dinamikus helyett lokális változót használ, akkor elmenti az allokációt / elosztást. Módosítania kell a függvényeket, hogy hivatkozásként vegyen egy argumentumot, vagy átadjon egy mutatót (attól függően, hogy a függvény módosítja-e az argumentumot vagy sem).
Ha újratervezi, hogy ne használjon dinamikus memóriát, legalább tudja, hogy ha elegendő memóriája van az elején, akkor nem használja tovább.
Igen, tudom. Talán észrevette, hogy még több bájt mentése érdekében az EEPROM-ot használom. Nos, nem tudok több helyet spórolni. Ez azt jelenti, hogy még annak újraprogramozása is felesleges lenne.
Mit jelent, hogy "nem tud több helyet megtakarítani"? Ha a dinamikus elosztásról statikus tömbökre vált, akkor működnie kell. Rengeteg RAM szabad (jelenleg csak 12% -ot használ).
Oké, azt hiszem, már nem értem a kupacot. Úgy gondoltam, hogy a verem és a kupac nagyjából ugyanazt a helyet foglalják el - mindkét végén egyet és a program ütközik, ha már nincs több hely közöttük. De alapvetően mindegy, hogy int [5] vagy új int [5] van. Át fogom írni statikus tömbökké.
Épp azt mondták nekem, hogy ha a tömböket a PROGMEM-be mentem, akkor a pgm_read_byte / pgm_read_word szót kell használnom azok elolvasásához. Megoldhatja ez a problémát?
@SlowerPhoton: „_nem mindegy, hogy int [5] vagy új int [5] van ._”. Az előbbivel nem áll fenn a memória töredezettségének veszélye, és nem áll fenn annak a veszélye, hogy elfelejtené törölni a tömböt. És válaszolni az utolsó megjegyzésre, a pgm \ _read \ _ \ * () függvények használata nem egyértelmű. Hogy ez a _csak_ hiba a programodban, azt nem tudom megmondani.
"Azt mondták nekem, hogy ha a tömböket a PROGMEM-be mentem, akkor a pgm_read_byte / pgm_read_word szót kell használnom az elolvasáshoz." - feltétlenül. Különböző címterek. Nem néztem ilyen részletesen a kódját, hogy észrevegyem, hogy nem az volt.


Ezt a kérdést és választ automatikusan lefordították angol nyelvről.Az eredeti tartalom elérhető a stackexchange oldalon, amelyet köszönünk az cc by-sa 3.0 licencért, amely alatt terjesztik.
Loading...