logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[avr-gcc][m128]zmienne lokalne nie lądują w zew. sramie?

Procekk 10 Cze 2010 23:41 1904 10
REKLAMA
  • #1 8177282
    Procekk
    Poziom 12  
    Bardzo często pisząc programy posługujemy się zmiennymi lokalnymi, które teoretycznie zwalniają pamięć jeśli nie są używane... ale dlaczego przestawiając podział pamięci na zewn. SRAM (kostka 62256), zmienne te jakby się nie inicjowały i program się wywala?
    Przykład:
    dodałem do makefile
    LDFLAGS += -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x8090ff
    a tu program:
    
    #include  (...) // tutaj początek programu
    
    /*
    	// tak dziala -- tablice jako zmienne globalne ładnie lądują
            // w sramie i rozmiar .bss zwiększa się, tak jakby procek już rezerwował
            // obszar SRAMu
    	uint16_t wartosc_reg[5376];
    	uint8_t wartosc_reg_hi[501];
    	uint8_t wartosc_reg_lo[501];
    */
    
    void init_extemem(void) __attribute__((naked,section(".init3"))) ; 
    
    void init_extemem(void)
    {
    	MCUCR |= (1<<SRE) | (1<<SRW10);
    	XMCRA = (1<<SRL2) | (0<<SRL1) | (0<<SRL0) | (1<<SRW01) | (1<<SRW00) | (1<<SRW11);
    	XMCRB = (1<<XMBK);
    } 
    
    int main(void)
    {
    /*
    	// tak nie dziala - zmienne lokalne - dlaczego :( ???????????
    	uint16_t wartosc_reg[5376];
    	uint8_t wartosc_reg_hi[501];
    	uint8_t wartosc_reg_lo[501];
    */
    /*
    	// tak się da poprawnie wykonać program - zmienne ponizej dzialaja
            // sekcja .bss nie jest zapchana dużymi tablicami
    	uint16_t *wartosc_reg;
    
    	uint8_t *wartosc_reg_hi;
    	uint8_t *wartosc_reg_lo;
    
    	unsigned char* data_pointer = (unsigned char*)0x6ff0; 
    */
    
    	// dopiero teraz moge zapisywac i odczytywac tablice
    	// ale rozmiar .bss nie rosnie, dlaczego?!
    	uint16_t *wartosc_reg;
    	wartosc_reg = (int *)malloc(5376*sizeof(uint16_t));
    	uint8_t *wartosc_reg_hi;
    	wartosc_reg_hi = (int *)malloc(501*sizeof(uint8_t));
    	uint8_t *wartosc_reg_lo;
    	wartosc_reg_lo = (int *)malloc(501*sizeof(uint8_t));
    
    	unsigned char* data_pointer = (unsigned char*)0x6ff0; 
    
    	sei();
      
    	usart_init(9600);
    	usart_write("START\n");
    
    	wartosc_reg_lo[500]=0x2d;
    
            // troche zabawy, wartosci o 1 mniejsze od adresu komórek zapisuja sie
            // do tablicy, a po przekroczeniu adresu komórki 5000 wyświetlam 
            // sobie adres i wartość tablicy po USART-cie i wszystko jest ok w przypadku
            // gdy nie używam zew. sramu (ale wtedy max. długość tablicy znacznie
            // mniejsza) lub tak jak wyżej ze sram-em działa, ale jeśli tablica jest
            // jako zmienna globalna lub poprzez wskaźniki i malloc()
            // jak to zrobić aby zmienne lokalne - duże tablice nie wywalały programu
            // i wszystko działało jak przed dodaniem kostki 62256 i dodaniu wpisu do makefile-a?
    	for (uint16_t i=0; i<5375; i++)
    	{
    		wartosc_reg[i]=i-1;	
    		if (i>=5000) usart_write("%i %i\r\n",i,wartosc_reg[i]);
    	}
    	while (1)
    	{
    		if (odebrano_znak==1)
    		{
    			*data_pointer=(unsigned char)receive_char;
    			usart_write_char(*data_pointer);
    			usart_write_char(wartosc_reg_lo[500]);
    			odebrano_znak=0;
    		}
    	}
    	return 0;
    }
    

    Reasumując: mam program, w którym jest masa modułów, masa zmiennych lokalnych i wnosząc takie dodatki jak zewnętrzny SRAM (jeśli chodzi o sprzęt) i dodatki programowe w samym makefile nie pomagają :( czy chcąc używać SRAMU muszę teraz wszystkie zmienne lokalne przerabiać na wskaźniki i posługiwać się malloc() itp? To by było bez sensu, musi być jakieś rozsądne rozwiązanie tego problemu, aby nie ingerować w kod za zbytnio.
    Problem zrodził się w rozbudowanym programie, w którym na dodatek chciałem użyć bardzo dużych tablic. Nie chcę używać pamięci flash i eepromów, nie potrzebuję nieulotności danych itp. chodzi mi konkretnie o pamięć sram. Może któryś z kolegów już coś takiego przerabiał?
    Aaa, przez nie działanie programu chciałem tutaj powiedzieć, że przez USARTa ciągu znaków "START" nie doczekamy się - wykonanie programu tutaj jakby nie dociera.
    Pozdrawiam.
  • REKLAMA
  • REKLAMA
  • #3 8177737
    tmf
    VIP Zasłużony dla elektroda
    Dokłądnie, a z kolei przeniesienie stosu na AVR w obszar ExRAM jest marnym pomysłem - dostęp do tej pamięci jest wolniejszy i cały program będzie się wolniej wykonywał ze względu na wolniejsze działanie PUSH/POP i odkładanie/zdejmowanie adresów powrotów. Dodatkowo coś mi się kołacze (trzeba to sprawdzić), że ATMega128 ma jakiś problem kiedy stos leży w ExRAM. A jeśli wystarczy ci tylko 16kB RAM to lepszym pomysłem jest wziąć procesor z wbudowaną pamięcią.
  • #4 8177842
    Procekk
    Poziom 12  
    Zastanawia mnie tylko fakt, dlaczego po dołączeniu pamięci SRAM, dopisaniu w makefile linijki
    LDFLAGS += -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x8090ff

    i na początku progranu
    MCUCR |= (1<<SRE) | (1<<SRW10);
    XMCRA = (1<<SRL2) | (0<<SRL1) | (0<<SRL0) | (1<<SRW01) | (1<<SRW00) | (1<<SRW11);
    XMCRB = (1<<XMBK);

    powoduje takie zmiany, że program, który sobie normalnie działał wcześniej, nie działa wogóle lub wykazuje tylko przejawy działania, tzn. coś się wykonało ale po drodze zdechło.
  • REKLAMA
  • #5 8177921
    tmf
    VIP Zasłużony dla elektroda
    Freddie, zauważ, że on inicjalizuje interfejs ExMem w sekcji init3, czyli ok.
    Natomiast nie wyobrażam sobie jak ten program mógł działać normalnie bez pamięci zewnętrznej, skoro inicjalizuje tablice po kilka kB, a ten procesor ma tylko 4kB SRAM.
  • REKLAMA
  • #7 8177983
    Procekk
    Poziom 12  
    Program działał bez pamięci zewnętrznej SRAM ale na mniejszych tablicach.
    Rozumiem, że choćby nie wiem co, na tym procku nie mogę posługiwać się tablicami większymi np. niż 2-3kB, tak, żeby stos miał gdzie się hodować?

    Dodatkowo pomyślałem, że może w taki sposób można by to zrobić, do makefile
    LDFLAGS += -Wl,--section-start,.xram=0x801100,--defsym=__heap_start=0x808000,--defsym=__heap_end=0x8090ff

    a w programie przy zmiennych:
    __attribute__((section(".xram"))) unsigned char zmienna[1000];

    W ten sposób avr nie powinien mieć zawalonego wewnętrznego SRAMu, a komórki tablicy tak naprawdę powinny siedzieć sobie w 62256...
    Jednak teraz kompilacja nie kończy się powodzeniem :(
  • Pomocny post
    #8 8178269
    tmf
    VIP Zasłużony dla elektroda
    Tu masz info jak posługiwać się zewnętrzną pamięcią w gcc:
    http://www.nongnu.org/avr-libc/user-manual/malloc.html#malloc_where

    Oczywiście tablice możesz mieć, tyle, że alokowane dynamicznie czyli na stercie, albo jak piszesz dodawać do nich atrybut określający sekcję. Stertę możesz umieścić w zewnętrznej pamięci. To może być o tyle sensowne, że duże tablice będziesz miał w ExRAM, a zmienne lokalne i globalne w wewnętrznym RAM, dzięki czemu dostęp do nich będzie szybszy.
  • #9 8193144
    Procekk
    Poziom 12  
    zostałem jednak przy tym - do makefile:
    LDFLAGS += -Wl,--section-start,.data=0x801100,--defsym=__heap_start=0x808000,--defsym=__heap_end=0x8090ff

    a na początku w sekcji init3 to co wcześniej i wszystko działa. Jednak rozumieć mam teraz, że zmienne będą siedziały w pamięci SRAM począwszy od adresu 0x1100 (najpierw .data, później .bss), reszta będzie wolna aż do adresu 0x8000 gdzie zacznie się sterta, która może sobie rosnąć aż do 0x90FF.
    Czyli stos będzie się robił w internal SRAM zajmując łącznie z różnymi rejestrami procesora maksymalnie 4352B (0x0000-0x10FF), zmienne będą zajmowały max. 28415B (0x7FFF-0x1100), sterta 4351B (0x90FF-0x8000)?
  • #11 8816102
    kubus_puchatek
    Poziom 18  
    tmf napisał:
    Dokłądnie, a z kolei przeniesienie stosu na AVR w obszar ExRAM jest marnym pomysłem - dostęp do tej pamięci jest wolniejszy i cały program będzie się wolniej wykonywał ze względu na wolniejsze działanie PUSH/POP i odkładanie/zdejmowanie adresów powrotów. Dodatkowo coś mi się kołacze (trzeba to sprawdzić), że ATMega128 ma jakiś problem kiedy stos leży w ExRAM. A jeśli wystarczy ci tylko 16kB RAM to lepszym pomysłem jest wziąć procesor z wbudowaną pamięcią.



    Ja tam się nie znam... Cierpię na galopujące sklerozy....
    po pierwsze: Czy przypadkiem ktoś nie myli stosu i sterty........
    po drugie: stertę można przesunąć do zewnętrznej pamięci RAM.
    po trzecie: czy ktoś już przesuwał SP poza wewnętrzny RAM? w XMEGA to jest niewykonalne. a nie chce mi się sprawdzać na mega128

    kolega przesunął stertę : LDFLAGS += -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x8090ff
    a sterta to nie stos.
    na stercie leży wszystko co przydzielono dynamicznie.
REKLAMA