Kontrola zásobníku v Atmel Studiu

Diskuze a poradna o programátorech a programování různých obvodů

Moderátor: Moderátoři

Zpráva
Autor
Uživatelský avatar
Jirka525
Příspěvky: 325
Registrován: 22 kvě 2013, 02:00
Bydliště: Psáry JN79GW

Kontrola zásobníku v Atmel Studiu

#1 Příspěvek 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
Jirka

Uživatelský avatar
FHonza
Příspěvky: 1443
Registrován: 20 lis 2012, 01:00
Bydliště: Praha

#2 Příspěvek od FHonza »

Existuje na to nástroj Stack Checker

Uživatelský avatar
Jirka525
Příspěvky: 325
Registrován: 22 kvě 2013, 02:00
Bydliště: Psáry JN79GW

#3 Příspěvek od Jirka525 »

Honzo děkuji za info. Tohle pravděpodobně nebude řešení pro současný projekt. Já tam mám MCU ATtiny1634.
Jirka

Uživatelský avatar
AB1
Příspěvky: 312
Registrován: 23 lis 2009, 01:00

#4 Příspěvek 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.

Uživatelský avatar
FHonza
Příspěvky: 1443
Registrován: 20 lis 2012, 01:00
Bydliště: Praha

#5 Příspěvek 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.

Uživatelský avatar
Jirka525
Příspěvky: 325
Registrován: 22 kvě 2013, 02:00
Bydliště: Psáry JN79GW

#6 Příspěvek 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.
Jirka

Uživatelský avatar
Habesan
Příspěvky: 6924
Registrován: 12 led 2009, 01:00
Bydliště: Plzeňsko
Kontaktovat uživatele:

#7 Příspěvek od Habesan »

ATtiny je AVR.
Sháním hasičák s CO2 "sněhový", raději funkční.
(Nemusí mít platnou revizi.)
(Celkově budu raději, když se to obejde bez papírů.)

Uživatelský avatar
Jirka525
Příspěvky: 325
Registrován: 22 kvě 2013, 02:00
Bydliště: Psáry JN79GW

#8 Příspěvek 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.
Jirka

Uživatelský avatar
AB1
Příspěvky: 312
Registrován: 23 lis 2009, 01:00

#9 Příspěvek 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.

Uživatelský avatar
mtajovsky
Příspěvky: 3694
Registrován: 19 zář 2007, 02:00
Bydliště: Praha

#10 Příspěvek 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.

Uživatelský avatar
Jirka525
Příspěvky: 325
Registrován: 22 kvě 2013, 02:00
Bydliště: Psáry JN79GW

#11 Příspěvek 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ěď.
Jirka

Uživatelský avatar
mtajovsky
Příspěvky: 3694
Registrován: 19 zář 2007, 02:00
Bydliště: Praha

#12 Příspěvek 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.

Uživatelský avatar
Jirka525
Příspěvky: 325
Registrován: 22 kvě 2013, 02:00
Bydliště: Psáry JN79GW

#13 Příspěvek 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.
Jirka

Uživatelský avatar
AB1
Příspěvky: 312
Registrován: 23 lis 2009, 01:00

#14 Příspěvek 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.
Přílohy
progmem.zip
(1.25 KiB) Staženo 62 x

Uživatelský avatar
Jirka525
Příspěvky: 325
Registrován: 22 kvě 2013, 02:00
Bydliště: Psáry JN79GW

#15 Příspěvek 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.
Jirka

Odpovědět

Zpět na „Programování PIC, ATMEL, EEPROM a dalších obvodů“