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][C/eclipse] - Inicjalizacja sekcji .text w pamięci RAM

07 Paź 2013 09:30 3396 15
  • Poziom 23  
    Witam,

    Chciałem przerobić skrypt linkera i startup.s z projektu Freddiego Chopina stm32_blink_led na kopiowanie i uruchamianie aplikacji z pamięci RAM.

    Dodałem do sekcji .text analogiczne wpisy jak w sekcji .data udostępniające zmienne __text_init_start, __text_start oraz __text_end.

    Code:

       .text :
       {
          . = ALIGN(4);
          __text_init_start = LOADADDR (.text);
                PROVIDE(__text_init_start = __text_init_start);
          __text_start = .;
          PROVIDE(__text_start = __text_start);

          . = ALIGN(4);
          KEEP(*(.vectors));
          . = ALIGN(4);
          *(.text .text.* .gnu.linkonce.t.*);
          . = ALIGN(4);
          *(.glue_7t .glue_7);
          . = ALIGN(4);
          *(.rodata .rodata.* .gnu.linkonce.r.*);

          . = ALIGN(4);
          __text_end = .;
          PROVIDE(__text_end = __text_end);
       } > rom AT > rom



    Code:

    /*
    +-----------------------------------------------------------------------------+
    | Initialize .text section
    +-----------------------------------------------------------------------------+
    */

       ldr      r1, =__text_init_start
      ldr      r2, =__text_start
      ldr      r3, =__text_end

    1:   cmp      r2, r3
       ittt   lo
       ldrlo   r0, [r1], #4
       strlo   r0, [r2], #4
       blo      1b


    Jeśli uruchomię aplikację to widzę że
    r1 = 0x08000000,
    r2 = 0x08000000,
    r3 = 0x08000xxx,

    oczywiście reszta kodu asm powoduje to hardfault bo nie można pisać po flashu.
    Zmieniam teraz linię w skrypcie linkera
    > rom AT > rom
    na
    > ram AT > rom

    r1 = 0x00000000,
    r2 = 0x08000000,
    r3 = 0x08000xxx,

    czyli nie to czego oczekuję (adres startu pamięci RAM).

    W pliku .map mam:

    Code:

    .text           0x20000000      0xcb8 load address 0x08000000
                    0x20000000                . = ALIGN (0x4)
                    0x08000000                __text_init_start = LOADADDR (.text)
                    [0x08000000]                PROVIDE (__text_init_start, __text_init_start)
                    0x20000000                __text_start = .
                    [0x20000000]                PROVIDE (__text_start, __text_start)
                    0x20000000                . = ALIGN (0x4)
     *(.vectors)
     .vectors       0x20000000      0x130 out/vectors.o
                    0x20000000                vectors
                    0x20000130                . = ALIGN (0x4)
     *(.text .text.* .gnu.linkonce.t.*)
     .text          0x20000130       0xa4 out/startup.o
                    0x20000130                Reset_Handler
     .text.FlashUnlock
                    0x200001d4       0x30 out/STM32_helper.o
                    0x200001d4                FlashUnlock

    ... ciach...


    Docelowa aplikacja to oczywiście bootloader.

    Pozdrawiam
  • Specjalista - Mikrokontrolery
    Weź tylko poprawkę na to, że część kodu MUSI być w pamięci flash - wektory przerwań i sam kod który robi kopiowanie...

    Najprościej podzielić text na dwie sekcje - jedna (z wektorami i startupem) jest tam gdzie zawsze, druga (z całą resztą) - w RAMie. Dla niewielkiego ułatwienia zabawy weź sobie skrypt linkera i startup z przykładu dla LPC4330.

    Postaram się później wrzucić Ci tutaj przykład jak coś takiego zrobić, bo akurat tak się składa, że mam to "na bieżąco" (;

    4\/3!!
  • Poziom 23  
    Konieczne jest to rozdzielenie ? Sądziłem że po skopiowaniu (włącznie z kodem kopiującym) aplikacji następuje skok już na funkcję "main" w ramie. Nie przeszkadza mi że jest kopia kodu kopiującego w ramie. Zobaczę ten kod dla LPC4330.
  • Pomocny post
    Specjalista - Mikrokontrolery
    No ale jak zrobisz takie przyporządkowanie o jakim piszesz (bez podziału) to funkcja Reset_Handler ma adres w RAM, więc w tablicy wektorów będzie adres w RAM. Oczywiście zanim ten Reset_Handler się uruchomi, to w RAM nic nie ma - tak więc to nie ma prawa działać...

    4\/3!!
  • Poziom 23  
    Racja, już wiem o co chodzi. Dzięki :)

    EDIT:

    Dodatnie "nvic_vectors" jak poniżej:

    Code:


       .nvic_vectors :
       {
          . = ALIGN(4);
          KEEP(*(.vectors));
          . = ALIGN(4);
          KEEP(*(.startup));
          
       } > rom AT > rom

       .text :
       {
          . = ALIGN(4);
          __text_init_start = LOADADDR (.text);
                PROVIDE(__text_init_start = __text_init_start);
          __text_start = .;
          PROVIDE(__text_start = __text_start);


          . = ALIGN(4);
          *(.text .text.* .gnu.linkonce.t.*);
          . = ALIGN(4);
          *(.glue_7t .glue_7);
          . = ALIGN(4);
          *(.rodata .rodata.* .gnu.linkonce.r.*);

          . = ALIGN(4);
          __text_end = .;
          PROVIDE(__text_end = __text_end);
       } > ram AT > rom



    oraz wpakowanie Reset_Handler do sekcji .startup chyba załatwiło sprawę.

    Dzięki.
  • Specjalista - Mikrokontrolery
    piti___ napisał:
    oraz wpakowanie Reset_Handler do sekcji .startup chyba załatwiło sprawę.

    To załatwiło, czy tylko "chyba załatwiło"? (; Bo nie wiem czy mam wrzucać moje rozwiązanie sprawy później... (;

    4\/3!!
  • Poziom 23  
    Wrzuć, wrzuć...

    Procesor, gdy tylko wywołam jakąś funkcję z "main", ląduje w losowych MemManage_Handler, NMI_Handler... pusta pętla w main z inkrementacją jakiegoś statica działa.
  • Pomocny post
    Specjalista - Mikrokontrolery
    Hmm... podejrzyj dezassemblację (plik .lss jeśli korzystasz z moich szablonów) i zobacz co tam ciekawego się dzieje (;

    Jeśli możesz, to wrzuć tu projekt w jakiejś przyciętej postaci.

    4\/3!!
  • Poziom 23  
    W załączniku projekt. Wystarczy u mnie wywołać system_init() które jest przed pętlą i procek ląduje w przeróżnych Handlerach...

    Aktualnie po powyższych zmianach w startup.s oraz xxx.ld nie mogę debugować kodu w startup.s (pisze brak kodu dla Reset_Handler()). Po tych zmianach również słabo działają breakpointy. Dopiero po zatrzymaniu i wznowieniu programu łapie breaka w pętli nieskończonej.

    Oryginalny projekt bez problemu się debugował i łapał breaki.

    Pozdrawiam
  • Poziom 23  
    Zauważyłem dziwną rzecz,

    W pamięci ROM znajduje się zakładamy prawidłowy kod który jest kopiowany do RAMu. Zauważyłem różnice między kodem we flashu i w ramie która najprawdopodobniej jest problemem (skąd ta różnica jeszcze nie wiem).

    W pliku *.lss pod adresem 0x20000010 jest prawidłowy skok do system_init().
    W pamięci flash pod adresem (0x08000000 + 0x1c8 + 0xc) (stąd jest inicjowana sekcja text) również znajduje się rozkaz skoku do system_init() zaś w rzeczywistości w ramie pod 0x20000010 jest jakiś śmieć, który jest interpretowany jako załadowanie czegoś do PC.

    Wyjaśnienie na zrzucie ekranu

    [STM32][C/eclipse] - Inicjalizacja sekcji .text w pamięci RAM


    EDIT:

    Udało mi się uruchomić debug krok po kroku i w pętli inicjalizującej .text w ramie... podczas zapisu tych konkretnych 4B... zmieniają się tylko 2B...
    Nie wiem o co chodzi.
  • Specjalista - Mikrokontrolery
    Hmm... nie miałem jeszcze czasu żeby rzucić okiem na Twój projekt, ale w istocie jest to dziwne...

    Problemami z debuggowaniem się raczej nie przejmuj - ja tez widziałem taki problem - generalnie GDB ma problem z ustawieniem breakpointa z RAM gdy "jeszcze" jest w ROM (i zapewne odwrotnie). Rozwiązaniem dla mnie było postawienie breakpointa na ostatniej instrukcji wykonywanej w ROM (czyli był to wtedy skok do main() wykonywany ze startupa) i naciśnięcie "step over", żeby przejść do RAM - wtedy już działało jak trzeba. Dalej sprawy nie drążyłem, bo w moim przypadku zmieniły się nieco założenia i większość kodu pozostała w ROM, natomiast w RAM jest tylko kawałeczek kodu potrzebny do aktualizacji samego bootloadera (w zasadzie skasowanie starego, skopiowanie nowego z innego miejsca pamięci flash i następnie reset), więc nie miałem potrzeby zbytniego debuggowania tego problemu...

    Jakiego używasz kompilatora (toolchaina)? Ja używałem swoich kompilacji - bleeding edge toolchain (wersji aktualnej i poprzedniej) - żadnych problemów jak te które opisujesz nie stwierdziłem.

    Anyway - spróbuj przedebuggować kod w startupie, zobacz czy aby na pewno kod jest prawidłowo kopiowany do RAM. Spróbuj też umieścić tą sekcję "text w RAM" w innym miejscu skryptu linkera - tuż przed (lub za) sekcją .data, za .exidx, za wektorami i za startupem - chodzi o to, żeby było tam takie ułożenie:
    - sekcje rom AT rom
    - sekcje ram AT rom
    - sekcje ram AT ram

    4\/3!!
  • Poziom 23  
    tak jak pisałem w poprzednim poście:

    Udało mi się uruchomić debug krok po kroku i w pętli inicjalizującej .text w ramie... podczas zapisu tych konkretnych 4B... zmieniają się tylko 2B...
    Nie wiem o co chodzi.

    Code:

    C:\Documents and Settings\User>arm-none-eabi-gcc --version
    arm-none-eabi-gcc (Sourcery G++ Lite 2010.09-51) 4.5.1
    Copyright (C) 2010 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.  There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


    C:\Documents and Settings\User>arm-none-eabi-ld --version
    GNU ld (Sourcery G++ Lite 2010.09-51) 2.20.51.20100809
    Copyright 2010 Free Software Foundation, Inc.
    This program is free software; you may redistribute it under the terms of
    the GNU General Public License version 3 or (at your option) a later version.
    This program has absolutely no warranty.


    Może ściągnę na początek coś nowszego ;)

    EDIT:

    Ściągnąłem bleeding-edge-toolchain i na starcie debugowania otrzymuję:
    Code:

    /home/freddie/bleeding-edge-toolchain/src/gdb/gdb/linespec.c:2462: internal-error: decode_line_full: Assertion `state->canonical_names[i].suffix != NULL' failed.
    A problem internal to GDB has been detected,
    further debugging may prove unreliable.

    This application has requested the Runtime to terminate it in an unusual way.
    Please contact the application's support team for more information.


    i na tym komunikacie debugger kończy pracę.


    EDIT:

    Udało się uruchomić debugger na BET, ten sam problem. Wróciłem jednak do starszej wersji toolchaina, mniej problemów z debuggerem.

    Po pętli inicjującej .text w RAMie dałem nieskończoną pętle. Ten sam problem...
    W zależności od ilości kodu w .text 3 lub 4 słowo jest błędnie kopiowane do ramu... dlaczego ?

    Po usunięciu wywołania
    ldr r0, =main
    blx r0

    Pętla kopiuje prawidłowo pierwszych 20 słów (reszty nie chciało mi się sprawdzać).



    Teraz inne pytanie, szukałem przykładów bootloadera dla stm32 i znalazłem projekt
    http://www.st.com/web/en/catalog/tools/PF257844
    całość pracuje na pamięci FLASH. Czy to oznacza że nie ma potrzeby uruchamiać bootloadera w RAM, gdy będę kasował/zapisywał na sektorach na których nie ma kodu bootloadera?
  • Pomocny post
    Poziom 20  
    piti___ napisał:
    Teraz inne pytanie, szukałem przykładów bootloadera dla stm32 i znalazłem projekt
    http://www.st.com/web/en/catalog/tools/PF257844
    całość pracuje na pamięci FLASH. Czy to oznacza że nie ma potrzeby uruchamiać bootloadera w RAM, gdy będę kasował/zapisywał na sektorach na których nie ma kodu bootloadera?

    Możesz ale należy pamiętać że w czasie kasowania/zapisywania sektora procesor "stoi".

    During a write/erase operation to the Flash memory, any attempt to read the Flash memory will caused the bus to stall.
    Read operations are processed correctly once the program operation has completed.
    This means that code or data fetches cannot be performed while a write/erase operation is ongoing.

    Pozdrawiam
  • Pomocny post
    Specjalista - Mikrokontrolery
    piti___ napisał:
    Czy to oznacza że nie ma potrzeby uruchamiać bootloadera w RAM, gdy będę kasował/zapisywał na sektorach na których nie ma kodu bootloadera?

    Uruchomienie kodu w RAM jest konieczne tylko gdy chcesz aktualizować kod samego bootloadera. Jeśli nie masz tego w planie, to nie jest Ci to potrzebne i cały bootloader może być w pamięci flash.

    4\/3!!
  • Poziom 23  
    Dzięki, bootloader od tygodnia już działa. Na razie nie zaprzątam sobie głowy z przeniesieniem sekcji .text.

    Pozdrawiam
    Piotr
  • Specjalista - Mikrokontrolery
    Trafiłem właśnie na identyczny problem jak ten opisany przez piti___ - podczas kopiowania bloku rozkazów w flash do RAM jeden 32-bitowy blok jest kopiowany tylko w połowie... /; co ciekawsze - on nawet nie tyle jest kopiowany w połowie (że druga połowa jest zerem), tylko wykonuje się jakby operacja OR z tym co akurat było wcześniej w pamięci... Normalnie W-T-F... Jakieś ciekawe pomysły, bo ja nie wiem co tu mogłoby być nie tak...

    Na 99% nie jest to kwestia użytych narzędzi - zmiana toolchaina z BET na oryginalne linaro nie zmienia w tej kwestii zupełnie nic.

    Pętla kopiująca:

    Code:
    2:   cmp      r2, r3                     // inner loop - section initialization
    
       ittt   lo
       ldrlo   r0, [r1], #4
       strlo   r0, [r2], #4
       blo      2b


    4\/3!!