Vítejte na Elektro Bastlírn?
Nuke - Elektro Bastlirna
  Vytvořit účet Hlavní · Fórum · DDump · Profil · Zprávy · Hledat na fóru · Příspěvky na provoz EB

Vlákno na téma KORONAVIRUS - nutná registrace


Nuke - Elektro Bastlirna: Diskuzní fórum

 FAQFAQ   HledatHledat   Uživatelské skupinyUživatelské skupiny   ProfilProfil   Soukromé zprávySoukromé zprávy   PřihlášeníPřihlášení 

Programová záhada
Jdi na stránku Předchozí  1, 2, 3
 
Přidat nové téma   Zaslat odpověď       Obsah fóra Diskuzní fórum Elektro Bastlírny -> Miniaturní počítače (Arduino, Raspberry a další)
Zobrazit předchozí téma :: Zobrazit následující téma  
Autor Zpráva
Valdano



Založen: Jan 01, 2023
Příspěvky: 1725
Bydliště: Česká Lípa

PříspěvekZaslal: ne červen 11 2023, 10:30    Předmět: Citovat

Většina knihoven pro Arduino nepoužívá dynamickou alokaci paměti jelikož je to spíš problematické a pokud tedy používá třeba nějaký bafr tak jej má deklarován staticky viz třeba SoftwareSerial. Staticky definovaná velikost znamená, že je velikost pole bafru předem známá už při překladu. Vývojové prostředí pak celkovou velikost použité a zbylé paměti programu zobrazuje ve výpisu po provedení překladu programu.

Globální knihovna Adafruit pro OLED displeje ovšem pracuje z různými displeji a používá tak různé velikosti bafru pro vykreslování a zřejmě proto je to v ní řešeno přes dynamickou alokaci paměti voláním standardní funkce jazyka C malloc(velikost) přičemž se velikost vypočítává za běhu programu a dynamická alokace se neprojeví při překladu, ale až za běhu programu.

kód:
Adafruit_SH1106G display = Adafruit_SH1106G(128, 64, &Wire, -1);

... další globální deklarace ...

void setup() {

  Wire.begin();
  display.begin(0x3C,true);

  ... další kód v setup() ...

Volání display.begin je volání metody Adafruit_SH1106G::begin a uvnitř ní se volá metoda Adafruit_GrayOLED::_init a ta provádí dynamickou alokaci paměťového bafru voláním malloc(VELIKOST)

kód:
kde VELIKOST v bajtech = ((sirka + 7) / 8) * vyska;
1024 = ((128 + 7) / 8) * 64;


Funkce malloc interně sama kontroluje stav volné paměti a zjednodušeně řečeno pokud zjistí, že není k dispozici volný souvislý blok paměti o velikosti odpovídající hodnotě VELIKOST tak tato funkce vrací NULL a metoda Adafruit_GrayOLED::_init v takovém případě vrací false. Nicméně metoda Adafruit_SH1106G::begin na to nijak nereaguje a vrací true i když Adafruit_GrayOLED::_init vrátí false.

Předpokládám, že dynamická alokace uvnitř Adafruit_GrayOLED::_init se sice ještě podaří, ale později za běhu programu dojde k přetečení aktuálně používané části zásobníku do haldy a program pak následně zhavaruje.

Další možnost je ta, že je v programu nebo v některé z knihoven nějaká jiná záludná chyba a díky ní za určitých okolností dochází k hrábnutí někam do paměti, a to má za následek pád programu. Když se pak přeloží program pro jinou platformu nebo se změní pro tu samou platformu tak se může chyba zdánlivě ukrýt, protože hrabe do míst kde to při aktuálním rozložení v paměti prostě zrovna nevadí.

Zkuste si změřit volnou paměť za běhu programu viz níže zdroják

Pokud začne funkce freeRam() vracet záporné hodnoty tak to znamená, že halda a zásobník aktuálně používají zčásti stejný prostor paměti, a to je samozřejmě problém. Pokud to nastane tak pravděpodobně program dřív vytuhne než informaci o tom stihne odeslat na sériový port a možná i dříve než se v programu zavolá freeRam(). Pokud freeRam() proběhne a vrácená hodnota bude záporná tak se v příkladu níže rozsvítí LED signalizující problém ještě před odesíláním dat na sériový port.

V příkladu níže jsem k účelu signalizace aktuálního překrývání části haldy a zásobníku použil vestavěnou LED_BUILTIN. LED_BUILTIN může mít pro různé typy Arduina různé číslo, ale pokud máte ve vývojovém prostředí správně zvolenou desku, tak LED_BUILTIN bude odpovídat vestavěné LED, která by na příslušném Arduinu měla být standardně dostupná a pokud ji v programu nepoužíváte na nic jiného tak ji můžete pro tento účel použít a tím nemusíte používat výstup, na který by bylo potřeba připojovat externí LED s odporem.

kód:
#include <Wire.h>               
#include <Rotary.h>             
#include <si5351.h>               
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>
#include <EEPROM.h>

#if (ARDUINO >= 100)
#include <Arduino.h>
#else
#include <WProgram.h>
#endif

unsigned long tick = 0;
int mem_stav = 0;

Adafruit_SH1106G display = Adafruit_SH1106G(128, 64, &Wire, -1);

... další globální deklarace a funkce ...

#ifdef __arm__
extern "C" char* sbrk(int incr);
#else
extern unsigned int __heap_start;
extern void *__brkval;
struct __freelist
{
  size_t sz;
  struct __freelist *nx;
};
extern struct __freelist *__flp;
int freeListSize()
{
  struct __freelist* current;
  int total = 0;
  for (current = __flp; current; current = current->nx)
  {
    total += 2;
    total += (int) current->sz;
  };
  return total;
}
#endif

int freeRam()
{
  int ram = 0;
#ifdef __arm__ 
  ram = &ram - reinterpret_cast<char*>(sbrk(0));
#else
  if ((int)__brkval == 0) {
    ram = ((int)&ram) - ((int)&__heap_start);
  } else {
    ram = ((int)&ram) - ((int)__brkval);
    ram += freeListSize();
  };
#endif
  return ram;
}

void setup() {

  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  // stav volné paměti na počátku SETUP
  mem_stav = freeRam();
  if (mem_stav < 0) digitalWrite(LED_BUILTIN, HIGH);

  Serial.begin(9600);
  Serial.print(F("SETUP1 RAM = "));
  Serial.println(mem_stav, DEC);

  Wire.begin();
  display.begin(0x3C,true);

  // stav volné paměti v SETUP po volání display.begin
  mem_stav = freeRam();
  if (mem_stav < 0) digitalWrite(LED_BUILTIN, HIGH);
  Serial.print(F("SETUP2 RAM = "));
  Serial.println(mem_stav, DEC);

  ... další kód v setup() ...

  tick = millis();
}

void loop() {

  if ((millis() - tick) > 1000) {
    // stav volné paměti v LOOP cca jednou za sekundu
    mem_stav = freeRam();
    if (mem_stav < 0) digitalWrite(LED_BUILTIN, HIGH);
    Serial.print(F("LOOP RAM = "));
    Serial.println(mem_stav, DEC);
    tick = millis();
  };

  ... další kód v loop() ...

}


Naposledy upravil Valdano dne po červen 12 2023, 20:53, celkově upraveno 4 krát.
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
Celeron



Založen: Apr 02, 2011
Příspěvky: 17823
Bydliště: Nový Bydžov

PříspěvekZaslal: ne červen 11 2023, 19:24    Předmět: Citovat

Díky za přínosné info. Příležitostně to vyzkouším, nejdříve na konci týdne. ProMicro taky není žádnej zázrak. Každý druhý až čtvrtý nahrání flash se kouše a pak je po USB nedostupnej a je potřeba udělat reset bootloaderu. Naštěstí to není tak složitý, jen je potřeba se s dvojklikem na pin reset trefit do správnýho okamžiku.
S Every žádnej problém není ale je za skoro dvojnásobek ProMini nebo ProMicro. Tak by bylo docela přínosný zjistit, co se v ProMini děje při spolupráci s Oled displejema v RAMce.

_________________
Jirka

Proč mi nemůže všechno chodit hned ?!!
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
Valdano



Založen: Jan 01, 2023
Příspěvky: 1725
Bydliště: Česká Lípa

PříspěvekZaslal: po červenec 03 2023, 11:06    Předmět: Citovat

Nějak to tady usnulo. Už se za pomocí toho měření spotřeby paměti co jsem psal výše podařilo něco dalšího zjistit ohledně těch problémů s Arduino ProMini?
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
Celeron



Založen: Apr 02, 2011
Příspěvky: 17823
Bydliště: Nový Bydžov

PříspěvekZaslal: po červenec 03 2023, 13:30    Předmět: Citovat

Zatím jsem se k tomu nedostal. Tam, kde byl s OLED problém, jsem dal Every a nebo 32U4. I těch 500 byte navíc 32U4 stačí na bezproblémový chod.

A je teplo a spousta jiných "venkovních" projektů. Tak se na to dostane až bude pršet nebo až bude zima. Smile

_________________
Jirka

Proč mi nemůže všechno chodit hned ?!!
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
Zobrazit příspěvky z předchozích:   
Přidat nové téma   Zaslat odpověď       Obsah fóra Diskuzní fórum Elektro Bastlírny -> Miniaturní počítače (Arduino, Raspberry a další) Časy uváděny v GMT + 1 hodina
Jdi na stránku Předchozí  1, 2, 3
Strana 3 z 3

 
Přejdi na:  
Nemůžete odesílat nové téma do tohoto fóra.
Nemůžete odpovídat na témata v tomto fóru.
Nemůžete upravovat své příspěvky v tomto fóru.
Nemůžete mazat své příspěvky v tomto fóru.
Nemůžete hlasovat v tomto fóru.
Nemůžete připojovat soubory k příspěvkům
Můžete stahovat a prohlížet přiložené soubory

Powered by phpBB © 2001, 2005 phpBB Group
Forums ©
Nuke - Elektro Bastlirna

Informace na portálu Elektro bastlírny jsou prezentovány za účelem vzdělání čtenářů a rozšíření zájmu o elektroniku. Autoři článků na serveru neberou žádnou zodpovědnost za škody vzniklé těmito zapojeními. Rovněž neberou žádnou odpovědnost za případnou újmu na zdraví vzniklou úrazem elektrickým proudem. Autoři a správci těchto stránek nepřejímají záruku za správnost zveřejněných materiálů. Předkládané informace a zapojení jsou zveřejněny bez ohledu na případné patenty třetích osob. Nároky na odškodnění na základě změn, chyb nebo vynechání jsou zásadně vyloučeny. Všechny registrované nebo jiné obchodní známky zde použité jsou majetkem jejich vlastníků. Uvedením nejsou zpochybněna z toho vyplývající vlastnická práva. Použití konstrukcí v rozporu se zákonem je přísně zakázáno. Vzhledem k tomu, že původ předkládaných materiálů nelze žádným způsobem dohledat, nelze je použít pro komerční účely! Tento nekomerční server nemá z uvedených zapojení či konstrukcí žádný zisk. Nezodpovídáme za pravost předkládaných materiálů třetími osobami a jejich původ. V případě, že zjistíte porušení autorského práva či jiné nesrovnalosti, kontaktujte administrátory na diskuzním fóru EB.


PHP-Nuke Copyright © 2005 by Francisco Burzi. This is free software, and you may redistribute it under the GPL. PHP-Nuke comes with absolutely no warranty, for details, see the license.
Čas potřebný ke zpracování stránky 0.17 sekund