Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[STM32] Malloc i zwis po resecie.

15 Gru 2009 08:16 3656 13
  • Poziom 15  
    Siedzę nad problemem już kilka dni i nie mogę sobie poradzić.
    Do tej pory program ładnie chodził. Kiedy wzbogaciłem go o funkcje malloc zaczęły się schody. Jeśli załaduje to co napisałem do pamięci wszystko ładnie przechodzi. Jeśli zresetuję urządzenie to w następnym przebiegu program się wywala na malloc. Jeśli wgram jeszcze raz ten sam obraz to znów wszystko ładnie chodzi ale znów tylko raz.
    Tak jakby to co sobie malloc wcześniej przydzielił mimo resetu nadal było dla niego przydzielone. Czy ten procesor ma jakąś nieulotną pamięć RAM? Wiem, że są rejestry podtrzymywane bateryjnie ale je resetuje. Z resztą wyjęcie płytki z procesorem z urządzenia też nie pomaga. To samo się dzieje jeśli używam malloc z kompilatora i pvPortMalloc z FreeRTOS. Ktoś się kiedyś spotkał?
  • Specjalista - Mikrokontrolery
    Nikt Ci nie pomoże. A dlaczego? Bo nie podałeś praktycznie żadnych informacji. Jaki kompilator? Jaka wersja? Jaki masz skrypt linkera, startup, tablicę wektorów, Makefile? Jak wygląda Twój projekt? Czy do malloc() dodałeś implementację sbrk()? Jeśli tak, to jak wygląda kod? itd. itd. itd...

    U mnie malloc() działa, w C++ operator new również, więc nie szukaj problemu w procesorze, tylko u siebie.

    4\/3!!
  • Poziom 15  
    Przyznam się, że jeszcze nie do końca się orientuję w tablicach wektorów i skryptach linkera. Zwyczajnie nigdy nie miałem potrzeby do tego zaglądać wcześniej. Wszystko co mam praktycznie bez zmian pochodzi z dema FreeRTOS dla płytki Premier. Ktoś to demo wpakował pod Eclipse. Miało być szybciej ale jak na razie tylko problemy z nim mam.
    W jakimś innym poście tutaj też zauważyłem, że koledze linker wsadzał do ramu to co miało być we flashu. To by miało sens dlaczego po resecie nie chce poprawnie działać.
    Używam GCC 4.4.1 z code sourcery lite. Nie implementowałem sbrk(); Z resztą najlepiej jak kawałek tego projektu zwyczajnie tutaj zamieszczę.
  • Specjalista - Mikrokontrolery
    Eee... No ale bez sbrk() malloc() nie ma prawa działać... Chyba że jest to gdzieś w reszcie plików zaimplementowane.

    Pooglądaj wynikowy plik .map - tam zobaczysz co wylądowało w RAM a co we flash.

    Pliki które masz w tym przykładzie nie są zbyt dobre - szczególnie skrypt linkera... Składnia która jest tam zastosowana wg mnie w ogóle jest niejasna i dziwna - możliwe, że regiony są jednak pomieszane... Rozwiązania widzę dwa:
    1. Wywal skrypt linkera, startup i tablice wektorów, zastosuj te z moich przykładów - https://www.elektroda.pl/rtvforum/topic1339518.html (wtedy w implementacji sbrk() musiałbyś lekko zmienić nazwy, bo ja zastosowałem takie które coś mówią, a nie takie jak wszyscy)

    2. Na szybko popraw skrypt linkera:

    ...
    FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
    ...
    .text :
    {
    ...
    } >FLASH AT >FLASH

    .ARM.exidx :
    {
    *(.ARM.exidx* .gnu.linkonce.armexidx.*)
    } >FLASH AT >FLASH

    .data
    {
    _flash_data = LOADADDR(.data);
    _data = .;
    *(vtable)
    *(.data*)
    _edata = .;
    } > SRAM AT >FLASH

    .bss :
    {
    ...
    } > SRAM AT >SRAM

    4\/3!!
  • Poziom 15  
    Sposób drugi nic nie zmienił. Sposób pierwszy prawie wcieliłem w życie ale teraz muszę się uporać z listą errorów która powoduje u mnie gęsią skórkę.

    A powiedz mi taką rzecz. Jeśli coś jest faktycznie pakowane do ramu zamiast do flash to zaraz po wgraniu powinno tam być a po resecie już nie. Racja? Po drugie gdyby to było problemem to po wyłączeniu zasilania, wszystko jedno czy dopuszczę do wykonania malloc czy nie i włączeniu go spowrotem już program powinien się przyciąć. A nie przycina się. Trzecia rzecz to taka, że w gruncie rzeczy nie korzystam z malloc od gcc tylko z jego odpowiednika w heap_2.c FreeRTOS. Inne schematy jednak też nie chcą działać. Ani heap_1.c ani tym bardziej heap_3.c wykorzystujący już wbudowanego malloc().

    Program zawsze staje w tym samym miejscu:
    Code:

    void *pvPortMalloc( size_t xWantedSize )
    {
    xBlockLink *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
    static portBASE_TYPE xHeapHasBeenInitialised = pdFALSE;
    void *pvReturn = NULL;

       vTaskSuspendAll();
       {
          /* If this is the first call to malloc then the heap will require
          initialisation to setup the list of free blocks. */
          if( xHeapHasBeenInitialised == pdFALSE )
          {
             prvHeapInit();
             xHeapHasBeenInitialised = pdTRUE;
          }

          /* The wanted size is increased so it can contain a xBlockLink
          structure in addition to the requested amount of bytes. */
          if( xWantedSize > 0 )
          {
             xWantedSize += heapSTRUCT_SIZE;

             /* Ensure that blocks are always aligned to the required number of bytes. */
             if( xWantedSize & heapBYTE_ALIGNMENT_MASK )
             {
                /* Byte alignment required. */
                xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & heapBYTE_ALIGNMENT_MASK ) );
             }
          }

          if( ( xWantedSize > 0 ) && ( xWantedSize < configTOTAL_HEAP_SIZE ) )
          {
             /* Blocks are stored in byte order - traverse the list from the start
             (smallest) block until one of adequate size is found. */
             pxPreviousBlock = &xStart;
             pxBlock = xStart.pxNextFreeBlock;
             while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock ) )
             {
                pxPreviousBlock = pxBlock;
                pxBlock = pxBlock->pxNextFreeBlock;
             }

             /* If we found the end marker then a block of adequate size was not found. */
             if( pxBlock != &xEnd )
             {
                /* Return the memory space - jumping over the xBlockLink structure
                at its start. */
                pvReturn = ( void * ) ( ( ( unsigned portCHAR * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE );

                /* This block is being returned for use so must be taken our of the
                list of free blocks. */
                pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;

                /* If the block is larger than required it can be split into two. */
                if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
                {
                   /* This block is to be split into two.  Create a new block
                   following the number of bytes requested. The void cast is
                   used to prevent byte alignment warnings from the compiler. */
                   pxNewBlockLink = ( void * ) ( ( ( unsigned portCHAR * ) pxBlock ) + xWantedSize );
                   
                   /* Calculate the sizes of two blocks split from the single
                   block. */
                   pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;   
                   pxBlock->xBlockSize = xWantedSize;         
                   
                   /* Insert the new block into the list of free blocks. */
                   prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );
                }
             }
          }
       }
       xTaskResumeAll();

       return pvReturn;
    }

    Na prvInsertBlockIntoFreeList( ( pxNewBlockLink ) ); (prawie sam koniec funkcji)
    I to jest makro:
    Code:

    #define prvInsertBlockIntoFreeList( pxBlockToInsert )                        \
    {                                                               \
    xBlockLink *pxIterator;                                                \
    size_t xBlockSize;                                                   \
                                                                   \
       xBlockSize = pxBlockToInsert->xBlockSize;                              \
                                                                   \
       /* Iterate through the list until a block is found that has a larger size */   \
       /* than the block we are inserting. */                                 \
       for( pxIterator = &xStart; pxIterator->pxNextFreeBlock->xBlockSize < xBlockSize; pxIterator = pxIterator->pxNextFreeBlock )   \
       {                                                            \
          /* There is nothing to do here - just iterate to the correct position. */   \
       }                                                            \
                                                                   \
       /* Update the list to include the block being inserted in the correct */      \
       /* position. */                                                   \
       pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;               \
       pxIterator->pxNextFreeBlock = pxBlockToInsert;                           \
    }


    Jakby co jeszcze dołączam plik .map.
  • Specjalista - Mikrokontrolery
    Plik map wygląda na sensowny.

    Podejrzyj w deassemblacji (albo zdebugguj) czy aby na pewno startup czyści sekcje .bss i inicjalizuje .data (podczas wykonywania funkcji Reset_Handler). Jeśli program "nie działa" tylko jeśli poprzednio uruchomiony był malloc(), a jeśli nie był uruchomiony to działa, to wskazywałoby na problem z inicjalizacją tych sekcji.

    4\/3!!
  • Poziom 15  
    Łooo... Deassemblacja wygląda tak:
    Code:

    0x08000000 <g_pfnVectors>:    ldrdcs  r4, [r0], -r8
    0x08000004 <g_pfnVectors+4>:  stmdaeq r1, {r0, r3, r5, r8, r12, lr}
    0x08000008 <g_pfnVectors+8>:  stmdaeq r0, {r0, r2, r3, r11, r12}
    0x0800000c <g_pfnVectors+12>: stmdaeq r0, {r0, r3, r4, r11, r12}
    0x08000010 <g_pfnVectors+16>: stmdaeq r0, {r0, r2, r5, r11, r12}
    0x08000014 <g_pfnVectors+20>: stmdaeq r0, {r0, r4, r5, r11, r12}
    0x08000018 <g_pfnVectors+24>: stmdaeq r0, {r0, r2, r3, r4, r5, r11, r12}
    0x0800001c <g_pfnVectors+28>: andeq   r0, r0, r0
    0x08000020 <g_pfnVectors+32>: andeq   r0, r0, r0
    0x08000024 <g_pfnVectors+36>: andeq   r0, r0, r0
    0x08000028 <g_pfnVectors+40>: andeq   r0, r0, r0
    0x0800002c <g_pfnVectors+44>: stmdaeq r1, {r0, r7, r8, r10, r11, lr}
    0x08000030 <g_pfnVectors+48>: stmdaeq r0, {r0, r3, r6, r11, r12}
    0x08000034 <g_pfnVectors+52>: andeq   r0, r0, r0
    0x08000038 <g_pfnVectors+56>: stmdaeq r1, {r0, r2, r3, r7, r9, r10, r11, lr}
    0x0800003c <g_pfnVectors+60>: stmdaeq r1, {r0, r3, r6, r7, r9, r10, r11, lr}
    0x08000040 <g_pfnVectors+64>: stmdaeq r0, {r0, r3, r4, r5, r6, r11, r12}
    0x08000044 <g_pfnVectors+68>: stmdaeq r0, {r0, r2, r7, r11, r12}
    0x08000048 <g_pfnVectors+72>: stmdaeq r0, {r0, r4, r7, r11, r12}
    0x0800004c <g_pfnVectors+76>: stmdaeq r0, {r0, r2, r3, r4, r7, r11, r12}
    0x08000050 <g_pfnVectors+80>: stmdaeq r0, {r0, r3, r5, r7, r11, r12}
    0x08000054 <g_pfnVectors+84>: stmdaeq r0, {r0, r2, r4, r5, r7, r11, r12}
    0x08000058 <g_pfnVectors+88>: stmdaeq r0, {r0, r6, r7, r11, r12}
    0x0800005c <g_pfnVectors+92>: stmdaeq r0, {r0, r2, r3, r6, r7, r11, r12}
    0x08000060 <g_pfnVectors+96>: stmdaeq r0, {r0, r3, r4, r6, r7, r11, r12}

    To normalne?
  • Specjalista - Mikrokontrolery
    Istnieje szansa że tak - program po prostu postarał się przypisać adresom odpowiadające im rozkazy no i wyszedł taki oto mix [;

    Widać tutaj, że tablica wektorów raczej jest dobra, teraz podejrzyj Reset_Handler, a konkretnie adresy które ładuje on do "czyszczenia" .bss i inicjalizacji .data - wg pliku map Reset_Handler był pod adresem 0x08015128

    4\/3!!
  • Poziom 15  
    Kod Reset_Handler przedstawia się tak:
    Code:
    void Reset_Handler(void)
    
    {
        unsigned long *pulSrc, *pulDest;

        // Fill the stack with a known value.
        for(pulDest = pulStack; pulDest < pulStack + STACK_SIZE; )
        {
           *pulDest++ = 0xA5A5;
        }

        // Copy the data segment initializers from flash to SRAM.
        pulSrc = &_flash_data;
        for(pulDest = &_data; pulDest < &_edata; )
        {
            *(pulDest++) = *(pulSrc++);
        }

        // Zero fill the bss segment.
        for(pulDest = &_bss; pulDest < &_ebss; )
        {
            *(pulDest++) = 0;
        }

        // Call the application's entry point.
        main();
    }

    A jego deassemblacja tak:
    Code:
    {
    
    0x080150ec <Reset_Handler>:     mov     r0, sp
    0x080150ee <Reset_Handler+2>:   bic.w   r1, r0, #7
    0x080150f2 <Reset_Handler+6>:   mov     sp, r1
    0x080150f4 <Reset_Handler+8>:   push    {r0, lr}
        for(pulDest = pulStack; pulDest < pulStack + STACK_SIZE; )
    0x080150f6 <Reset_Handler+10>:  movw    r3, #19160   ; 0x4ad8
    0x080150fa <Reset_Handler+14>:  movt    r3, #8192   ; 0x2000
    0x080150fe <Reset_Handler+18>:  add.w   r2, r3, #256   ; 0x100
    0x08015102 <Reset_Handler+22>:  cmp     r2, r3
    0x08015104 <Reset_Handler+24>:  bls.n   0x8015122 <Reset_Handler+54>
    0x08015106 <Reset_Handler+26>:  mov.w   r3, #0
    0x0801511c <Reset_Handler+48>:  cmp.w   r3, #256   ; 0x100
    0x08015120 <Reset_Handler+52>:  bne.n   0x8015116 <Reset_Handler+42>
           *pulDest++ = 0xA5A5;
    0x0801510a <Reset_Handler+30>:  movw    r2, #19160   ; 0x4ad8
    0x0801510e <Reset_Handler+34>:  movt    r2, #8192   ; 0x2000
    0x08015112 <Reset_Handler+38>:  movw    r1, #42405   ; 0xa5a5
    0x08015116 <Reset_Handler+42>:  str     r1, [r2, r3]
    0x08015118 <Reset_Handler+44>:  add.w   r3, r3, #4
        for(pulDest = &_data; pulDest < &_edata; )
    0x08015122 <Reset_Handler+54>:  movw    r2, #0
    0x08015126 <Reset_Handler+58>:  movt    r2, #8192   ; 0x2000
    0x0801512a <Reset_Handler+62>:  movw    r3, #1360   ; 0x550
    0x0801512e <Reset_Handler+66>:  movt    r3, #8192   ; 0x2000
    0x08015132 <Reset_Handler+70>:  cmp     r2, r3
    0x08015134 <Reset_Handler+72>:  bcs.n   0x8015164 <Reset_Handler+120>
    0x08015136 <Reset_Handler+74>:  mov.w   r3, #0
    0x0801514a <Reset_Handler+94>:  movw    r0, #1360   ; 0x550
    0x0801514e <Reset_Handler+98>:  movt    r0, #8192   ; 0x2000
    0x0801515c <Reset_Handler+112>: add.w   r1, r3, r2
    0x08015160 <Reset_Handler+116>: cmp     r1, r0
    0x08015162 <Reset_Handler+118>: bcc.n   0x8015152 <Reset_Handler+102>
            *(pulDest++) = *(pulSrc++);
    0x0801513a <Reset_Handler+78>:  movw    r2, #0
    0x0801513e <Reset_Handler+82>:  movt    r2, #8192   ; 0x2000
    0x08015142 <Reset_Handler+86>:  movw    r12, #1192   ; 0x4a8
    0x08015146 <Reset_Handler+90>:  movt    r12, #2050   ; 0x802
    0x08015152 <Reset_Handler+102>: ldr.w   r1, [r3, r12]
    0x08015156 <Reset_Handler+106>: str     r1, [r3, r2]
    0x08015158 <Reset_Handler+108>: add.w   r3, r3, #4
        for(pulDest = &_bss; pulDest < &_ebss; )
    0x08015164 <Reset_Handler+120>: movw    r2, #1360   ; 0x550
    0x08015168 <Reset_Handler+124>: movt    r2, #8192   ; 0x2000
    0x0801516c <Reset_Handler+128>: movw    r3, #19912   ; 0x4dc8
    0x08015170 <Reset_Handler+132>: movt    r3, #8192   ; 0x2000
    0x08015174 <Reset_Handler+136>: cmp     r2, r3
    0x08015176 <Reset_Handler+138>: bcs.n   0x801518e <Reset_Handler+162>
    0x08015178 <Reset_Handler+140>: mov     r3, r2
    0x0801517e <Reset_Handler+146>: movw    r2, #19912   ; 0x4dc8
    0x08015182 <Reset_Handler+150>: movt    r2, #8192   ; 0x2000
    0x0801518a <Reset_Handler+158>: cmp     r3, r2
    0x0801518c <Reset_Handler+160>: bcc.n   0x8015186 <Reset_Handler+154>
            *(pulDest++) = 0;
    0x0801517a <Reset_Handler+142>: mov.w   r1, #0
    0x08015186 <Reset_Handler+154>: str.w   r1, [r3], #4
        main();
    0x0801518e <Reset_Handler+162>: bl      0x800010c <main>
    }
    0x08015192 <Reset_Handler+166>: ldmia.w sp!, {r0, lr}
    0x08015196 <Reset_Handler+170>: mov     sp, r0
    0x08015198 <Reset_Handler+172>: bx      lr


    Troche nie za bardzo wiem jak się zabrać do rozgryzania tego kodu.
  • Pomocny post
    Specjalista - Mikrokontrolery
    Z kodu wynika pewna ciekawa rzecz... Otóż z tego co widzę stos znajduje się... w środku sekcji .bss - nie wiem czy to normalne, ale nie sądzę...

    4\/3!!
  • Poziom 15  
    Hmm... Wygląda na to, że problem się rozwiązał. Nie wiem tylko do końca w jaki sposób. Albo dlatego, że zwiększyłem STACK_SIZE z 64 do 128, albo dlatego, że przez Ctrl+C, Ctrl+V miałem kaszanę lekką i jako argument do pewnej funkcji przekazywałem pvPortMalloc o czym kompilator nie raczył mnie poinformować. Tak czy inaczej jak na razie działa ok.
    Dzięki za chęć pomocy. Dłużny Ci jestem browara.
  • Specjalista - Mikrokontrolery
    ddokupil napisał:
    lbo dlatego, że zwiększyłem STACK_SIZE z 64 do 128

    Chodzi o rozmiar stosu dla taska, czy dla całej aplikacji? <:

    4\/3!!
  • Poziom 15  
    Dla całej aplikacji. W pliku z tablicą wektorów.
  • Specjalista - Mikrokontrolery
    64bajty dla całej aplikacji? Kurde ja mam chyba teraz ustawione na 1 albo 2kB... 64 bajty to jest odłożenie 8 rejestrów procesora... To jest nic.

    4\/3!!