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][C] - Dwie wersje bin w pamięci FLASH, skok pod wybrany adres

wojlej 15 Sty 2016 15:48 3747 70
  • #1 15 Sty 2016 15:48
    wojlej
    Poziom 17  

    Witam,

    Były tematy o bootloader ale mój problem jest trochę inny.

    Mam sobie soft, który standardowo jest wgrany pod adres 0x08000000. W pewnym momencie, pobieram sobie nowy plik HEX przez UART. Mój interpreter Hex dekoduje go do surowych danych. Olewam adres bazowy nowego Hexa (który również wynosi 0x0800000) i wgrywam go do 5 sektora pd adres 0x08020000, bajt po bajcie. Teraz chcę aby po wymuszonym resecie procesora:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Procesor korzystał z nowej wersji oprogramowania zapisanej pod adresem 0x08020000. Gdy znowu nowy soft pobierze plik hex, zapisze go pod 0x0800000 to znowu po resecie ma skoczyć pod 0x0800000 .

    Chodzi mi o taki ping png bez zbędnych ceregieli.

    Aktywny soft musi wiedzieć pod jakim adresem się zaczyna, żeby wiedzieć gdzie wgrywać nowy bin i gdzie później skoczyć. Wiem, że trzeba przestawić adres stosu, ale to na pewno nie wystarczy.

    Proszę o jakieś sugestie jak to najlepiej zrobić.

    0 29
  • #3 15 Sty 2016 15:56
    BlueDraco
    Specjalista - Mikrokontrolery

    Nie da się tego zrobić w prosty sposób. Konsolidator musi wiedzieć, pod jakim adresem działa oprogramowanie, czyli program działa pod z góry narzuconymi adresami. Ten sam obraz binarny nie może być uruchomiony pod dowolnym adresem.

    Istnieje coś takiego jak PIC, ale raczej nie w tym zastosowaniu, o jakim myślisz.

    Tu potrzebujesz bootloadera i aplikacji.

    Prawdopodobnie mechanizm, o jaki Ci chodzi, znajdziesz w STM32F7 (o ile dobrze pamiętam).

    0
  • #4 15 Sty 2016 20:10
    wojlej
    Poziom 17  

    Cytat:
    Nie da się tego zrobić w prosty sposób. Konsolidator musi wiedzieć, pod jakim adresem działa oprogramowanie, czyli program działa pod z góry narzuconymi adresami. Ten sam obraz binarny nie może być uruchomiony pod dowolnym adresem.


    Hmmm. Myślałem, że będę mógł zapisać np w rejestrze Backup adres bazowy aktywnego softu, po resecie go odczytać i wio. Myślałem, że dane z Hexa wrzucane są pod adres = adres bazowy + offset i wystarczy że procesor zna adres startu. Potem to leci.

    A gdybym nie olewał adresu bazowego. I mój nowy hex byłby skompilowany pod adres 0x08020000 i tam bym go sobie wrzucił, to wtedy mogę przeskoczyć mimo, że pod 0x08000000 jest stary soft?

    Dla informacji: STM32F411

    0
  • #5 15 Sty 2016 20:17
    Freddie Chopin
    Specjalista - Mikrokontrolery

    Domyślnie uruchamia się program spod adresu 0x8000000. Jeśli napiszesz go tak, żeby sprawdzał co ma zrobić i ewentualnie skoczył do innego programu to da się. W innym przypadku się nie da.

    Nie wiem jednak po co takie kombinacje zamiast po prostu zrobić normalny bootloader...

    0
  • #6 17 Sty 2016 23:34
    wojlej
    Poziom 17  

    Hmm. Jakby to określić...
    Nie wiem jak go napisać. Wiem dokładnie co powinien robić:
    1. Uruchomić się po resecie procesora. Sprawdzić czy pod adresem 0x08020000 jest jakiś soft.
    2. Jeśli nie to startuje standardowo.
    3. Jeśli jest to robi backup aktualnego softu.
    4. Kopiuje się do Ramu
    5. Kopiuje nowy soft spod 0x0802 pod 0x0800.
    6. Czyści Flash od 0x0802
    7. Reset.

    Tylko nie mam pojęcia jak to napisać. To ma być osobny "projekt" w IDE? który jest wgrane pod jaki adres?
    Czy ma to być część każdego softu?

    0
  • #7 17 Sty 2016 23:50
    Freddie Chopin
    Specjalista - Mikrokontrolery

    Generalnie robi się to zwykle nieco inaczej.
    1. jak u Ciebie
    2. jak u Ciebie, zakładając, że "startuje standardowo" oznacza uruchomienie jakiegoś kanału ładowania nowego firmware'u (np. poprzez UART)
    3. jeśli jest, to po prostu do niego skacze (firmware musi być przygotowany do działania pod adresem jaki sobie wybrałeś dla aplikacji)

    Reszta punktów to zbędna kombinacja.

    Najprościej jest całkowicie oddzielić bootloader od firmware'u - są to wtedy dwa zupełnie niezależne od siebie projekty które nic o sobie nie muszą wiedzieć - po prostu jeden z nich (aplikacja) jest ustawiony tak żeby uruchamiał się z innego adresu niż "standardowe" 0x8000000. Jeśli się tych projektów nie da od siebie łatwo oddzielić (np. dlatego, że kod bootloadera wymaga sporej ilości funkcji typu USB, ETH, system plików czy coś w ten deseń), to wtedy można kombinować inaczej.

    Na forum jest sporo tematów o bootloaderach, więc przejrzyj te informacje które już tam są i zadawaj konkretne pytania.

    0
  • #8 21 Sty 2016 18:48
    wojlej
    Poziom 17  

    Pierwsze pytanie (jeszcze nie dotyczące bootloadera ale pobliskie temu.

    Pamięć FLASH w STM32F4 jest 32 bitowa? 16? 64? Nie mogę znaleźć jasnej odpowiedzi na to pytanie w reference manualu. Jest coś takiego w rejestrze FLASH_CR jak PSIZE. Gdzie deklaruje się jakieś zapisywanie, że niby uzupełnia się wolną przestrzeń wielokrotnością tego co wpisałem. Niby, wpisuje 8 bitów a komórka ma 32 bity to w pozostałe bardziej znaczące miejsca wpisuje to co wpisałem w mniej znaczące? Czyli komórka ma 32 bity? A jak ustawie PSIZE na 11 czyli 64 bity?

    Mam coś takiego jak okno MEMORY w Keilu. Mogę sobie podejrzeć dowolny adres w pamięci. I z tego jak wół wychodzi, że pod jednym adresem jest 8 bitów. Widnieje tam FF czyli 8 bitów.

    Chodzi o to, że plik bin trzymam w tablicy po bajcie. I nie wiem czy jak zapisuje:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    to mogę sobie inkrementować tą zmienną addr o jeden.

    Proszę o wytłumaczenie bo reference manual mi to mota.

    P.S:
    Funkcja HAL_FLASH_Program to głównie coś takiego:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    a FLASH_Program_Byte
    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #9 21 Sty 2016 19:00
    BlueDraco
    Specjalista - Mikrokontrolery

    Jest napisane: ustaw PSIZE na 32 bity. To wpływa na sposób i czas zapisu i nie ma nic wspólnego z organizacją pamięci. W F4 pamięć zapisuje się w słowach 32-bitowych - zrzutuj wskaźnik na uint32_t na tę tablicę i zapisuj po 32 bity.

    0
  • #10 21 Sty 2016 19:30
    wojlej
    Poziom 17  

    OK.

    Mogę robić więc tak:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Funkcje napisałem teraz sam, bez HALowego badziewia.
    Proszę o sprawdzenie, bo jakoś się boje ją wrzucać do procesora. Mam jakieś obawy przy grzebaniu we FLASHu ;)

    0
  • #11 21 Sty 2016 19:35
    BlueDraco
    Specjalista - Mikrokontrolery

    Możesz, ale w ten sposób zapiszesz coś innego, niż byś chciał.

    Prawdopodobnie chodzi Ci o to:

    for (addr = 0; addr <= ileśtam + 3; addr += 4)
    {
    BOOT_Save_32B((BASE_ADDRESS+addr), *((uint32_t *)(&data[addr])));
    }

    0
  • #12 21 Sty 2016 19:53
    wojlej
    Poziom 17  

    Czyli, muszę zapisywać 1B co 4 bajty. Ale mimo wszystko oznacza to, że adres komórki odpowiada polu 1 bajta a nie 4 bajtów. Pole MEMORY pokazuje mi zawsze coś takiego:

    [STM32][C] - Dwie wersje bin w pamięci FLASH, skok pod wybrany adres

    Tekst: Ala ma kota a kot ma ale lubie programowanie

    Każda literka (char 8b) jest przedstawiona pod osobnym adresem, następna literka ma adres o 1 wyższy a nie o 4 wyższy - i tego nie do końca rozumiem. Dlaczego tak jest?

    A Twoja funkcja każe zapisywać w ten sposób:
    [STM32][C] - Dwie wersje bin w pamięci FLASH, skok pod wybrany adres

    0
  • Pomocny post
    #13 21 Sty 2016 20:54
    BlueDraco
    Specjalista - Mikrokontrolery

    Moja funkcja, po poprawieniu błędu (brak &) zapisuje wersję pierwszą powyżej.

    0
  • Pomocny post
    #14 21 Sty 2016 21:24
    Freddie Chopin
    Specjalista - Mikrokontrolery

    Mieszasz ze sobą dwie zupełnie oddzielne kwestie. Adresy w pamięci dotyczą komórek jednobajtowych, bo niby jak inaczej miałoby to być? Niemniej jednak fizyczny zapis dokonywany jest po 4 bajty na raz jeśli ustawiłeś zapis 32-bitowy.

    0
  • #15 21 Sty 2016 21:32
    wojlej
    Poziom 17  

    Już zgłupiałem.

    Cytat:
    Niemniej jednak fizyczny zapis dokonywany jest po 4 bajty na raz jeśli ustawiłeś zapis 32-bitowy.


    Więc: mam w buforze daną o wartości 0xAB <- 1 bajt.

    Zapisuje ją pod adres = 0, więc komórki od 0 do 3 zawierają 0x000000AB tak?

    Następna zmienna powiedzmy 0xCD zostaje zapisana pod adres 4. I komórki od 4 do 7 zawierają 0x000000CD. Więc wszystkie 8 komórek ma:
    0x000000AB000000CD

    Czyli drugi obrazek. A BlueDraco piszę, że pierwszy.
    Dane w mojej tablicy są 1 bajtowe. Więc żeby było tak jak mówi BlueDraco muszę łączyć 4 kolejne elementy tablicy w zmienną 4 bajtową tak?

    0
  • Pomocny post
    #16 21 Sty 2016 21:35
    grko
    Poziom 32  

    Moze popatrz na to tak:

    Edit: lepszy sposob liczenia sz

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Zapisuje sie naraz 4 bajty.

    0
  • #17 21 Sty 2016 21:39
    Freddie Chopin
    Specjalista - Mikrokontrolery

    Warto byłoby usystematyzować wiedzę na temat C, a szczególnie na temat wskaźników. Nikt nie napisał tutaj, że podczas Twojego zapisu podajesz do funkcji jeden bajt, a mikrokontroler zapisuje na pozostałych bajtach same zera. Zapisujesz po 4 bajty na raz, odczytujesz z tablicy źródłowej również 4 bajty na raz. Finalnie we flash będziesz mieć dokładnie to co w tablicy źródłowej.

    Niemniej jednak patrząc na Twój kod nie byłbym pewny, że to zadziała - bootloader powinien zapisywać flash w obszarze aplikacji, a Ty zapisujesz do obszaru bootloadera - bootloader nie może się sam skasować, chyba że przekopiujesz go (przynajmniej częściowo) do RAM i uruchomisz stamtąd.

    0
  • #18 21 Sty 2016 22:13
    wojlej
    Poziom 17  

    Cytat:
    Niemniej jednak patrząc na Twój kod nie byłbym pewny, że to zadziała - bootloader powinien zapisywać flash w obszarze aplikacji, a Ty zapisujesz do obszaru bootloadera - bootloader nie może się sam skasować, chyba że przekopiujesz go (przynajmniej częściowo) do RAM i uruchomisz stamtąd.


    Wiem, że kod nie może lądować tam gdzie bootloader, adres bazowy tutaj to tylko przykład.

    Nie podoba mi się to:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Ten warunek zawsze zwróci 1 i pętla for wykona się tylko raz.
    Napisałem coś takiego w DEV c++ i wyszło mi coś takiego:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    W konsoli mam:
    [STM32][C] - Dwie wersje bin w pamięci FLASH, skok pod wybrany adres

    Czyli dobrze, dane są jako little endian wpisywane pod poszczególne adresy. Czyli de facto to to samo co zapisywanie po 1 bajcie pod adres zwiększony o 1.
    Tylko, że szybciej.

    Dzięki, i daje pomógł

    0
  • #19 21 Sty 2016 22:17
    grko
    Poziom 32  

    Na wypadek niepodzielnej przez 4 wielkosci tablicy. Mozna tak:

    Edit (brakujący nawias)

    Kod: c
    Zaloguj się, aby zobaczyć kod


    albo tak:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #20 21 Sty 2016 22:24
    wojlej
    Poziom 17  

    Albo coś źle robię... na pewno coś źle robię ale spójrz:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Wynik:
    [STM32][C] - Dwie wersje bin w pamięci FLASH, skok pod wybrany adres

    Dla każdej liczby większej od zera ten warunek jest równy 1 bo:
    (i/4) + (i % 4) zawsze jest większe od 0 bo to +

    0
  • #22 21 Sty 2016 22:36
    Freddie Chopin
    Specjalista - Mikrokontrolery

    GrzegorzKostka napisał:
    Ta druga wersja jest lepsza...

    Moim zdaniem również, wygląda wtedy jak zaokrąglanie "do góry" bez cudowania (;

    0
  • #23 21 Sty 2016 22:37
    wojlej
    Poziom 17  

    Nie wiem czy o to Ci chodziło:
    [STM32][C] - Dwie wersje bin w pamięci FLASH, skok pod wybrany adres

    Warunek wskazuje ile jest 4 bajtowych danych +1 w tablicy. A nie wskazuje czy jest niepodzielna. Ale można ją wykorzystać do wpisywania danych do flasha

    Edit:

    Teraz działa:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Wynik:
    [STM32][C] - Dwie wersje bin w pamięci FLASH, skok pod wybrany adres


    Jeszcze jedno szybkie pytanie:
    Czy po zapisie 32 bitów zerować bit FLASH PG? Czy dopiero po zakończeniu zapisywania wszystkiego?

    0
  • #24 21 Sty 2016 22:42
    Freddie Chopin
    Specjalista - Mikrokontrolery

    Tak swoją drogą to te kombinacje są nieco błędne - jeśli ilość danych do zapisania nie jest podzielna przez 4, to wcale nie można sobie przeczytać "poza" koniec tablicy - undefined behavior. Nie mówiąc już o tym, że zasadniczo rzutowanie danych typu uint8_t na uint32_t bez zapewnienia w jakiś sposób wyrównania tych pierwszych jest również błędne (na ARM Cortex-M3 akurat zadziała, ale to nie ma znaczenia) - tak samo undefined behavior.

    Generalnie zapis do flash jest tak wolny, że tego typu optymalizacje pozbawione są specjalnego sensu - przynajmniej moim skromnym zdaniem.

    0
  • #25 21 Sty 2016 22:46
    grko
    Poziom 32  

    Cytat:

    Warunek wskazuje ile jest 4 bajtowych danych +1 w tablicy.


    Dla 4 bajtowej tablicy mamy 1 słowo 32 bitowe. Dla 5 bajtowej trzeba już zapisać 2 słowa itd. Chodzi po prostu o ta aby zapisać wszystkie elementy z tablicy zadeklarowanej jako uint8_t.

    Cytat:

    Moim zdaniem również, wygląda wtedy jak zaokrąglanie "do góry" bez cudowania (;


    Yep. Zapomnijmy o wersji nr 1 ;)

    0
  • #26 21 Sty 2016 22:46
    wojlej
    Poziom 17  

    Skoro zapis do FLASHa jest wolny - a jest. To dlaczego nie zapisywać po bajcie? Uniknie się wtedy undefined behavior.

    0
  • #27 21 Sty 2016 22:53
    grko
    Poziom 32  

    W zasadzie nie ma problemu aby zapisywać bajt po bajcie. Więc spokojnie możesz wrócić do tego co miałeś na początku. Z tego co pamiętam kasowanie strony w STM32F4 trwało bardzo długo w porównaniu z programowaniem. Twój bootloader i tak spędzi większość czasu na kasowaniu stron przeznaczonych na nową aplikację.

    0
  • #28 21 Sty 2016 22:55
    Freddie Chopin
    Specjalista - Mikrokontrolery

    Jak coś to po prostu zrób dwie wersje testowe i sprawdź czy jest różnica w szybkości działania (przy pomocy jakiegoś timera, np. systicka).

    0
  • #29 21 Sty 2016 22:59
    wojlej
    Poziom 17  

    ALE:

    Tak mówi RM

    Cytat:
    The bytes are coded in memory in little endian format.

    Czy jeśli w tablicy danych (plik bin) mam bajt np 0xAB to przed wpisaniem muszę go zmienić na little endian?

    0
  • #30 21 Sty 2016 23:04
    Freddie Chopin
    Specjalista - Mikrokontrolery

    Nic nie musisz zmieniać - przecież plik .bin został wygenerowany dla układu o takim właśnie uporządkowaniu danych. Generalnie musisz "wprost" skopiować blok danych do pamięci flash i tyle - bez żadnych konwersji, przeróbek i modyfikacji.

    0