Stránka 1 z 2

Kontrola zásobníku v Atmel Studiu

Napsal: 29 bře 2016, 21:15
od Jirka525
Dělám jednu aplikaci v Atmel Studiu 6 a mám podeření, že jsem neuhlídal zásobník a ten mě převálcoval část datové oblasti. V projektech, které jsem dosud dělal jsem velikostí RAM neměl problémy, tak jsem to zatím nemusel řešit. Je nějaká metoda, jak omezit velikost zásobníku, nebo alespoň monitorovat maximální hodnotu zásobníku?
Díky Jirka

Napsal: 29 bře 2016, 22:04
od FHonza
Existuje na to nástroj Stack Checker

Napsal: 29 bře 2016, 23:02
od Jirka525
Honzo děkuji za info. Tohle pravděpodobně nebude řešení pro současný projekt. Já tam mám MCU ATtiny1634.

Napsal: 30 bře 2016, 03:54
od AB1
Většinou stačí když globální proměnné nezabírají víc než cca 70% RAM a nepoužívat (velká) lokální pole.

Monitorovat zásobník jde např. tak, že oblast RAM, která nás zajímá, vyplníme nějakou hodnotou, třeba 'A' a pak můžeme sledovat rozsah stacku při běhu programu, např. v simulátoru nebo výpisem RAM na terminál.

Napsal: 30 bře 2016, 10:17
od FHonza
Vyzkoušel sem nástroj s ATTiny2313 a funguje. Není to všemocné, ale pro první nástřel docela dobrý.

Tady je přímo stránka autora.

Napsal: 30 bře 2016, 17:42
od Jirka525
AB1 píše:Většinou stačí když globální proměnné nezabírají víc než cca 70% RAM a nepoužívat (velká) lokální pole.


Tak tohle bohužel není můj případ. Mě proměnné zabírají cca 85% RAM a mám tam i velké komunikační buffery. Na nějaké optimalizaci ještě zapracuji, zatím je SW v dost syrovém stavu, nicméně kontrola by nebyla od věci.

FHonza píše:Vyzkoušel sem nástroj s ATTiny2313 a funguje. Není to všemocné, ale pro první nástřel docela dobrý.

Honzo mnohokrát děkuji. Já jsem nabyl dojmu, že je to pro procesory od AVR nahoru. Tím každopádně začnu.

Napsal: 30 bře 2016, 17:47
od Habesan
ATtiny je AVR.

Napsal: 31 bře 2016, 20:53
od Jirka525
Tak děkuji všem za rady.
Nakonec se prokázalo že zásobník nepřetéká. Problém způsobuje pole konstatnt, které jsou uložené v RAM a které se z mě neznámého důvodu přepíšou. Já nyní začnu zkoumat všechna místa v programu, kde používám nepřímé adresování. Napadlo mě ale jestli to nemůže způsobovat optimalizace v překladači.
pole mám deklarované následovně:
volatile char pole1[50] = {k0,k1 .. K49};

Ten Stack Checker se mě nepovedlo rozpohybovat. Povedlo se mě vložit kód, přeložit, nahrát do MCU ale když jsem to spustil, tak hned na 1. programové instrukci mě to hlásilo 100% paměti pro zásobník 1024/1024. A ať jsem to stopnul v jakémkoli bodě, nikdy jsem neviděl jinou hodnotu.
Nicméně to vypadá jako dobrý pomocník, tak to zkusím ještě v jném projektu.

Napsal: 01 dub 2016, 08:27
od AB1
Problém způsobuje pole konstatnt, které jsou uložené v RAM

Je zvykem ukládat pole konstant do PROGMEM, ne do RAM.

Napsal: 01 dub 2016, 11:22
od mtajovsky
Dokonce to je velmi neefektivní, protože ty konstanty musí někde ve FLASH být. Takže

Kód: Vybrat vše

volatile char pole1[50] = {k0,k1 .. K49};

způsobí jednak že ty konstanty budou za běhu přítomny 2x a za druhé dodatečný kód pro překopírování konstant z FLASH do RAM.

Kromě toho postrádám smysl pole konstant v RAM.

Napsal: 01 dub 2016, 19:55
od Jirka525
Děkuji za připomínky matjovsky i AB1. Důvod je jednoduchý. Nevím, jak nadeklarovat pole konstatnt do Flash a následně, jak se na toto pole odkazovat v programu. V materiálech, které jsem přečetl jsem to buď nenašel nebo to nefungovalo.
Nicméně mám pocit, že způsob deklarace problém nevyřeší. Zdá se, že se mě část paměti dat nekontrolovaně přepisuje. Když na tomto místě nebudou konstanty ale jiná data, dojde s největší pravděpodobností rovněž k přepisu a bude zlobit jiná část programu.
Pokud je to jednoduché, napište mě sem deklaraci konstanty do Flash a referenci na ni v programu. Případně odkaz na něco, kde se to dočtu.
Teď při psaní odpovědi jsem si uvedomil, že vlastně již deklaraci jednoduchých konstant používám. Pomocí direktivy #define deklaruji jednoduché konstanty, nezkoušel jsem to zobecnit pro pole konstant.
Díky za odpověď.

Napsal: 01 dub 2016, 21:55
od mtajovsky
Při použití WinAVR.
Definice 5 konstant v programové paměti:

Kód: Vybrat vše

#include <avr/pgmspace.h>

. . .

static u08 screen_len[] PROGMEM = {4, 3, 4, 5, 4};


Modifikátor PROGMEM říká, že konstanty jsou umístěny do programové paměti.

Přístup na konstanty:

Kód: Vybrat vše

u08 table_len = pgm_read_byte(screen_len + status);


Funkce pgm_read_byte() má jako parametr adresu do programové paměti. takže screen_len je adresa prvního prvku pole, status je index do pole.

Příklad pro řetězcové konstanty pro zobrazení obsahu LCD displeje pro různé stavy programu. Vše řešeno přes pointery vypočítané při kompilaci a umístěné do programové paměti:

Kód: Vybrat vše

static char welcome_text1[] PROGMEM = "\7\0MT9851";
static char welcome_text2[] PROGMEM = "\2\1SWEEP GENERATOR";
static char welcome_text3[] PROGMEM = "\6\2""0-50 MHz";
static char welcome_text4[] PROGMEM = "\0\3Welcome to machine!!";
static char cf_heading[]    PROGMEM = "\1\0CONSTANT FREQUENCY\2";
static char am_heading[]    PROGMEM = "\1\0\3AMPLTD MODULATION\2";
static char swp_heading[]   PROGMEM = "\1\0\3SWEEP GENERATOR\2";
static char af_heading[]    PROGMEM = "\1\0\3ACOUSTIC FRQ.SWEEP";
static char fmod_value[]    PROGMEM = "\1\2Fmod: .    Hz";
static char frq_value[]     PROGMEM = "\1\1Freq:  .   .    Hz";
static char af_value[]      PROGMEM = "\1\1Freq:10-100.000 Hz";
static char mrk_value[]     PROGMEM = "\1\2Mark:  .   .    Hz";
static char v_out[]         PROGMEM = "\1\3Vout:    mV";
static char swp_value[]     PROGMEM = "\15\3\6f:  %";

// --------------- screens for individual status ----------

static prog_char* welcome_screen[] PROGMEM =
{
    welcome_text1,
    welcome_text2,
    welcome_text3,
    welcome_text4
};

static prog_char* cf_screen[] PROGMEM =
{
    cf_heading,
    frq_value,
    v_out
};

static prog_char* am_screen[] PROGMEM =
{
    am_heading,
    frq_value,
    fmod_value,
    v_out
};

static prog_char* swp_screen[] PROGMEM =
{
    swp_heading,
    frq_value,
    mrk_value,
    v_out,
    swp_value   
};

static prog_char* afsw_screen[] PROGMEM =
{
    af_heading,
    af_value,
    mrk_value,
    v_out
};


// ------------------ all screens array -------------------

static prog_char** screens[] PROGMEM =
{
    welcome_screen,
    cf_screen,
    am_screen,
    swp_screen,
    afsw_screen
};


Přístup na řetězce přes pointery pro zobrazení na LCD:

Kód: Vybrat vše

// ---------------- displayScreen -------------------------
// Function displays screen according to given state.
void displayScreen(CCP_STATUS status)
{
    LCD_clear();                                           // erase old screen content
    prog_char** screen = (prog_char**)pgm_read_word(screens + status); // load screen table addres
    u08 table_len = pgm_read_byte(screen_len + status);    // load screen table length
    for(u08 i = 0; i < table_len; ++i)                     // for all strings in table
    {
        prog_char* string = (prog_char*)pgm_read_word(screen + i); // load string from table
        LCD_putstrxy_P(string);                       // put string to LCD
    }
}


Celé je to popsáno v dokumentaci k WinAVR.

Napsal: 01 dub 2016, 22:48
od Jirka525
Mnohokrát děkuji mtajovsky. Takhe bezpracně naservírováno jsem již dlouho nic nedostal. Zítra to vyzkouším v Atmel Studiu.
Děkuji.

Napsal: 02 dub 2016, 08:41
od AB1
Příklad pana Tajovského je dobrý, ale zdá se být trochu starý.
Novější verze překladače by s ním mohly mít problém.
Viz např. http://www.tuxgraphics.org/electronics/ ... char.shtml

Psal jsem kdysi nějaké výukové texty, tak kousek přikládám.
Jsou to jenom jednoduché operace, pokud možno bez hvězdiček, s kterými mají začátečníci problémy.

Napsal: 03 dub 2016, 22:27
od Jirka525
Děkuji všem za rady. Deklarace konstant v paměti Flash funguje i v Atmel Studiu. Můj problém to ale bohužel nevyřešilo. Stále si mě neznámým způsobem přepisuji data v ram.