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

[STM32][eclipse/GCC] Bootloader CAN

aborygen84 15 Lis 2009 16:27 3902 8
  • #1 15 Lis 2009 16:27
    aborygen84
    Poziom 9  

    Witam.

    Jestem w trakcie pisania bootloadera po magistrali CAN dla STM32F103VE. Opieram się głównie na publikacji AN2557 zamieszczonej na stronie ST. Potrafię przesłać aplikację użytkownika po magistrali CAN do uC i zaprogramować pamięć Flash od wybranego adresu w górę. Na wstępnie odblokowuje pamięć Flash (FLASH_Unlock(); ) następnie podgrywam aplikację użytkownika od adresu 0x08002000 w góre, do tego momentu wszystko jest ok, po podejrzeniu pamięci właściwe dane są na właściwym miejscu. Problem pojawia się w momencie przejścia (skoku) do aplikacji użytkownika. Użyty do tego celu kod wygląda tak:

    Code:
       
    
    typedef  void (*pFunction)(void);
    pFunction Jump_To_Application;

        if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)
           { /* pobranie z wektora przerwan adresu obslugi resetu (base + 4) */
             JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
             Jump_To_Application = (pFunction) JumpAddress;
             /* CAN FIFO0 message pending interrupt disable */
             CAN_ITConfig(CAN1, CAN_IT_FMP0, DISABLE);
             /*deinicjalizacja magistrali CAN*/
             CAN_DeInit(CAN1);
             /* Wylaczenie wszystkich przerwan */
             __asm volatile (" CPSID F       \n");
             /* Initialize user application's Stack Pointer */
             __set_MSP(*(__IO uint32_t*) ApplicationAddress);
             /* Flash lock */
             FLASH_Lock();

             /* Skok do aplikacji uzytkownika */
             Jump_To_Application();
           }


    Chcę wykonać skok do funkcji obsługującej przerwanie Resetu, pobieram jej adres z tablicy wektorów przerwań. Następnie wyłączam przerwania aktywowane w bootloaderze (czyli przerwania z CANA). Inicjuje wskaźnik stosu i dokonuje skoku do aplikacji. Dodatkowo używam instrukcji __asm volatile (" CPSID F \n"); w celu wyłączenia przerwań globalnie, bez tej instrukcji skok nie był wykonywany lecz procesor sygnalizował Hard Fault po wykonaniu instrukcji blx R3, pomimo obecności poprawnego adresu obsługi Resetu + 1 (brak przełączenia w tryb instrukcji ARM) w rejestrze R3. W momencie gdy instrukcja __asm volatile (" CPSID F \n"); jest użyta skok jest wykonywany poprawnie i aplikacja użytkownika się uruchamia, lecz nie działają przerwania. Modyfikacje aplikacji użytkownika w celu wgrania jej do pamięci Flash z offsetem 0x2000 wykonuje następujące:




    -zmiana origin w skrypcie linkera
    Code:
    MEMORY
    
    {
      RAM      (RWX) : ORIGIN = 0x20000000+0, LENGTH = 64K-0
      EXTSRAM  (RWX) : ORIGIN = 0x68000000, LENGTH = 0
      FLASH    (RX)  : ORIGIN = 0x08000000+0x2000, LENGTH = 504K - 2K
      EEMUL    (RWX) : ORIGIN = 0x08000000+0x2000+504k-2K, LENGTH = 2k
      FLASHB1  (RX)  : ORIGIN = 0x00000000, LENGTH = 0
      EXTMEMB0 (RX)  : ORIGIN = 0x00000000, LENGTH = 0
      EXTMEMB1 (RX)  : ORIGIN = 0x00000000, LENGTH = 0
      EXTMEMB2 (RX)  : ORIGIN = 0x00000000, LENGTH = 0
      EXTMEMB3 (RX)  : ORIGIN = 0x00000000, LENGTH = 0
    }

    - podegranie tablicy wektora przerwań z offsetem
    NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x2000);

    Po tych operacjach aplikacja powinna działać poprawnie, lecz w tym przypadku przerwania nie działają. Aplikacja użytkownika bez dwóch powyższych modyfikacji i wgrana do pamięci bez offsetu działa jak należy. Wszystkie przerwania są inicjowane poprawnie.
    Tablica wektora przerwań jest w pamięci Flash i zaczyna się od adresu 0x08002000, w środku znajdują się poprawne adresy podprogramów obsługi przerwań (porównanie pliku Map z zawartością pamięci), więc wszystko jest tak jak powinno. Oraz na początku aplikacji włączam przerwania globalnie __asm volatile (" CPSIE F \n");.


    Dlaczego w momencie skoku do aplikacji procesor przeskakuje do Hard Fault Handler??
    Co najważniejsze, o czym zapomniałem w związku z niedziałającymi przerwaniami??

    Proszę o pomoc.

    0 8
  • Pomocny post
    #2 15 Lis 2009 19:00
    Tantalos
    Poziom 18  

    Witam,

    Wg manual'a do procesora Cortex M3 jeśli się zmienia kod programu lub/i tablicę wektorów przerwań, to przed następną instrukcją powinno się użyć instrukcji ISB, DSB i DMB aby bufory załadowały nowe wartości.

    0
  • #3 16 Lis 2009 21:52
    aborygen84
    Poziom 9  

    Dzięki za szybką odpowiedź.

    Niestety to nie rozwiązało problemu. Dziś napisałem krótką aplikację która podgrywana jest zamiast bootloadera i składa się tylko ze skoku do aplikacji użytkownika, żadne przerwania nie są w niej inicjowane. Okazało się, że w takiej sytuacji przerwania i cała aplikacja użytkownika działają dobrze. Więc problem leży w tym że przerwania inicjowane w bootloaderze uniemożliwiają mi działanie ich w aplikacji użytkownika. Wychodzi na to że muszę doprowadzić do stanu jak gdyby przerwania nie były nigdy inicjowane. We wcześniejszej wersji StdPeriphLibrary była funkcja NVIC_DeInit(), w wersji 3.1.2 nie ma już takiej funkcji. Ale dlaczego procesor przechodzi do Hard fault handler w momencie skoku nie wiem nadal.

    0
  • #4 16 Lis 2009 22:23
    Tantalos
    Poziom 18  

    Czy skok do aplikacji jest wykonywany z podprogramu obsługi przerwania CAN albo masz aktywne w tym czasie jakieś inne przerwania?

    0
  • Pomocny post
    #5 16 Lis 2009 22:26
    Freddie Chopin
    Specjalista - Mikrokontrolery

    Nie używaj tej głupawej biblioteki to będziesz wiedział dokładnie Co zrobiłeś i jak to cofnąć.

    Zmiana wskaźnika stosu PRZED wywołaniem jakiejś funkcji (FLASH_Lock() ) też nie wydaje mi się szczególnie dobrym pomysłem.

    W ogóle proste zadanie, ale tak je zakręciłeś jakimiś dziwnymi konstrukcjami, że nie wiadomo o co chodzi...

    A tak przy okazji, to skoro tablicę wektorów masz pod adresem 0x8002000, to czemu nie podasz takiej wartości do NVIC_SetVectorTable() ?

    4\/3!!

    0
  • #6 16 Lis 2009 22:33
    aborygen84
    Poziom 9  

    Tak skok jest wykonywany z podprogramu obsługi przerwania CAN. Nie mam aktywnych w tym czasie żadnych innych przerwań. Jedynym przerwaniem jakiego używam w bootloaderze jest przerwanie od odebrania danych po CAN-ie.

    Dodano po 3 [minuty]:

    Z tego co pamiętam, parametrem funkcji NVIC_SetVectorTable() jest offset a nie konkretny adres, więc podaje dobrą wartość. Problem tkwi w konfiguracji przerwań a nie w tablicy, która jest we właściwym miejscu i ma właściwe adresy w środku.

    0
  • Pomocny post
    #7 16 Lis 2009 22:38
    Freddie Chopin
    Specjalista - Mikrokontrolery

    No ale jak skaczesz z przerwania, to cały Twój program wykonuje się jakby "wewnątrz" przerwania... Tak absolutnie nie można robić - musisz skok wykonać z trybu Thread, a nie Handler!

    4\/3!!

    0
  • Pomocny post
    #8 16 Lis 2009 22:46
    Tantalos
    Poziom 18  

    Jeżeli skok jest z przerwania to HardFault jest spowodowany tym, że zmieniasz wskaźnik stosu w obsłudze przerwania.

    0
  • #9 17 Lis 2009 09:05
    aborygen84
    Poziom 9  

    Wyrzucenie skoku z przerwania pomogło. Dziękuje obu Panom:)

    0