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

Funkcje UARTU zaśmiecają SRAM? [c][winavr][atmega32]

AVRowiec 26 Paź 2009 13:16 1411 13
REKLAMA
  • #1 7176768
    AVRowiec
    Poziom 18  
    Witam,

    Otóż mam dziwny problem. Pewna procedura wysyła coś na UART. robi to prawidłowo ale to co jest wysyłane trafia także na pewien obszar pamięci (na tablice przechowującą string). Czy ktoś ma pojęcie dlaczego tak się dzieje skoro prockowi nie brakuje zasobów (użyte do tej pory 25% pamięci programu i 70% pamięci danych).
    Tak wygląda procedura obsługująca uart. Samo USART_Transmit() jest z datasheeta i nie było modyfikowane. Moja wersja przesyła kilka znaków. Mam wrażenie że char*slowo coś psuje. Gdzieś ginie wskaźnik albo nie wiem co..

    void USART_Transmit_Word( char *slowo)
    {
       char n=0;
       while (slowo[n]) 
       { 
         USART_Transmit(slowo[n]);
    	 n++;
       }
    }


    Prosze o pomoc bo walcze z tym od dwóch dni już :(
  • REKLAMA
  • #2 7176778
    chudybyk
    Poziom 31  
    Daj więcej kodu. Pewnie przeoczyłeś coś przy deklaracji lub namieszałeś we wskaźnikach.
    Pozdrawiam!
  • REKLAMA
  • #3 7176798
    zdebel
    Poziom 15  
    A problem ze sprintfem rozwiązany?
  • #4 7176830
    mieczotronix
    Poziom 16  
    Takie zjawisko masz, jak stos ci wchodzi na zmienne. Rejestry odkładają się na stosie, jak wywołujesz zagnieżdżone funkcje. Stos przyrasta z przeciwnej strony RAMu, niż zmienne. Jak masz 70% pamięci danych zajęte, to jest to na 99.99% tego skutek.
    Rozwiązanie jest takie, żeby zmniejszyć liczbę zagnieżdżeń, ew. rozwinąć USART_Transmit wewnątrz USART_Transmit_Word. Możesz np. zadeklarować prostsze funkcje, jako inline albo niektóre zmienne, jako globalne.
  • #5 7176846
    AVRowiec
    Poziom 18  
    Witam,

    Zmieniona wersja USART_Transmit_Word:

    void USART_Transmit_Word( char *slowo)
    {
       char n=0;
       while (slowo[n]) 
       { 
     
         while ( !( UCSRA & (1<<UDRE)) );
    
         UDR = slowo[n];
    	 
    	 n++;
       }
    }


    Tak to jest użyte:

    USART_Transmit_Word(LOSCA); 
      USART_Transmit_Word(TOSCA); 
      USART_Transmit_Word(SCA);
      USART_Transmit_Word(FO);
      USART_Transmit_Word(MR);
      USART_Transmit_Word(LODA); 
      USART_Transmit_Word(TODA);
      USART_Transmit_Word(numer_odbiorcy);	
      USART_Transmit_Word(PID);
      USART_Transmit_Word(DCS);
      USART_Transmit_Word("ten tekst wjedzie na zmienna numery_autoryzowane"); 
    
    

    Czyli o jedno zagnieżdżenie mniej.
    Pamięć danych zmniejszona do 60%, kodu do 22%.
    Dałem inline (rozumiem że przed USART_Transmit_Word) i nie pomogło.
    Brak efektu.

    Może rozwiązaniem jest dać bufor na tą wysyłaną treść? Ale szkoda pamięci a pozatym trzeba by jakiegoś sprintf'a użyć żeby to poskładać a on zabiera kolejną pamięć. Wiem że zamiast sprintf zostaje funkcja strcat() ale nie sprawdzałem jak dużo pamięci pochłonie.
    A pozatym i tak zastanawia mnie co ma UART do SRAM...

    W dalszym ciągu proszę o pomoc :)

    Dodano po 3 [minuty]:

    PS. problem printf'a nie rozwiązany. Narazie wyrzuciłem go z kodu i potem do tego wróce. Ale coś czuje że zamiast printów użyje funkcji operujących na stringach, typu strcat etc.
  • REKLAMA
  • #6 7176888
    mieczotronix
    Poziom 16  
    W avr stałe tekstowe siedzą w ramie, a nie we flashu jeśli się ich specjalnie nie zadeklaruje. Więc "ten tekst wjedzie na zmienna numery_autoryzowane" siedzi już w buforze, czyli w RAMie. Więc go dodatkowo do bufora żadnego nie wsadzaj.
    Z jakiegoś powodu zamazuje ci on zmienne.

    W ogóle do obsługi takich długich stałych tekstowych powinieneś napisać oddzielną funkcję wykorzystującą pgm_read_byte i deklarować stałe tekstowe z atrybutem PROGMEM.
    Ja to tak robię (przykład dla LCD ale jasny):
    
    #include <avr/pgmspace.h>
    
    void lcd_txtF(const char *ptr)
    {
    	unsigned char c;
    	
    	do
    	{
    		c = pgm_read_byte(ptr);
    		ptr ++;
    		if( !c )
    			break;
      		lcd_txtc(c);
    	}while(1);
    }
    

    a potem deklaruję stałe i używam je tak:
    
    #include <avr/pgmspace.h>
    const char PROGMEM TXT_text1 [] = "habla babla espanol";
    
    lcd_txtF( TXT_text1 );
    

    Jak tak zrobisz to napewno tego tekstu nie będzie w ramie.
  • #7 7176923
    AVRowiec
    Poziom 18  
    Wiem o PROGMEM i całej reszcie. Tutaj dałem taką długą zmienną tekstową tylko po to żeby uprościć przykład. Bo w rzeczywistości niżej jest pętla która wysyła jeszcze kilka znaków w PDU i to one wjeżdżają na moją zmienną. A że to co do tej pętli trafia jest za każdym razem inne nie da się użyć pgmspace. Wszystko co jest wysyłane przez USART_Transmit_Word jest zdefiniowane w #define, np:

    #define LOSCA "07"  // Długość numeru SCA+1
    #define TOSCA "91"  // Typ numeracji SCA
    #define SCA "8405210077F7"   // ORANGE: +48501200777


    Pozmniejszałem bufory jeszcze bardziej (tak że prawie ich nie ma) i mam 50% wolnej pamięci danych I nadal nic...
  • REKLAMA
  • #8 7176945
    mieczotronix
    Poziom 16  
    Przecież to wszystko co masz w #define to są stałe, które mogą siedzieć w PROGMEMie.
    Przecież nie ma znaczenia, czy napiszesz:
    
    #define TEXT "ten tekst wjedzie na zmienna numery_autoryzowane"
    USART_Transmit_Word(TEXT); 
    

    czy
    
    USART_Transmit_Word("ten tekst wjedzie na zmienna numery_autoryzowane"); 
    

    więc to wszystko może siedzieć we flashu.

    No i pokaż tą pętlę, skoro to ona maże
  • #9 7177014
    AVRowiec
    Poziom 18  
    Owszem mogło by to siedzieć we fleshu ale musi zostać tak jak jest bo potem będzie przerobione na zmienne.
    I to nie pętla maże ale któreś z wywołań USART_Transmit_word. Jak się to wywoła kilka razy to to ostatnie wlezie na inne zmienne. Przykładowo jakbym usuną kilka linijek z USART_Transmit_Word to to co wjedzie na moją zmienną będzie inne. Będą to przesunięte znaki ze USART_Transmit_Word("ten tekst wjedzie na zmienna numery_autoryzowane"); troche w lewo.
    Krótko mówiąc:
    To co robi USART_Transmit_Word zbiera się gdzieś w pamięci doklejając się do poprzedniej treści aż w końcu włazi na inne zmienne.

    Pozatym tak czy siak procek ma dużo wolnej pamięci i nie powinno do takich jaj dochodzić.
  • #10 7177055
    chudybyk
    Poziom 31  
    Argumentem funkcji USART_Transmit_Word() powinien być wskaźnik na tekst, a ty przekazujesz też jakieś stałe w postaci liczb (np. TOSCA). Transmitowana będzie kaszana.
    Wrzuć konstrukcję pętli głównej, bo ten błąd wygląda na problem ze stosem.
  • #11 7177143
    mieczotronix
    Poziom 16  
    Weź włącz symulator i rozpocznij debugowanie i wybierz podgląd całego RAMu - przyciśnij F4 i wybierz Data i zobacz czy masz rzeczywiście masę FF pomiędzy początkiem RAMu, a końcem gdzie jest stos.
  • #12 7177159
    Freddie Chopin
    Specjalista - Mikrokontrolery
    chudybyk napisał:
    Argumentem funkcji USART_Transmit_Word() powinien być wskaźnik na tekst, a ty przekazujesz też jakieś stałe w postaci liczb (np. TOSCA). Transmitowana będzie kaszana.

    To jest liczba -> 55
    To jest napis - "55"

    4\/3!!
  • #13 7177354
    szelus
    Poziom 34  
    1. Jak obliczasz to 70% zużycie RAMu? Uwzględniasz .data i .bss?

    2. Jeżeli używasz napisów w sposób, w jaki używasz (przez #define), to każde odwołanie do danego napisu w kodzie tworzy jego nową kopię w RAMie. Chociaż, jeżeli uwzględniłes i .data, i .bss, to nie powinno to (na razie) stanowić problemu.
  • #14 7177698
    AVRowiec
    Poziom 18  
    Rozwiązałem problem. Jak to zwykle bywa błąd był w zupełnie innym miejscu...
    Przepełniał się pewien bufor odbiorczy UARTu i mazał po pamięci.

    Dziękuje wszystkim za pomoc i poświęcony czas.
    Przynajmniej dowiedziałem się czegoś o stosie i pamięci oraz o tym jak to jest zapisywane.

    Pozdrawiam.
REKLAMA