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

STM32F103 - Zapis do FLASHa nie działa przy optymalizacji -Os. Co robić?

07 Lip 2016 23:19 2739 37
Najlepsze odpowiedzi

Dlaczego zapis do FLASH w STM32F103 działa przy -O0, a przy -Os nie, i jak poprawnie zapisać dane do pamięci FLASH?

Przy -Os zapis do FLASH psuł się dlatego, że kompilator przestawiał zapis danych przed ustawienie bitu PG w rejestrze CR; trzeba wykonać zapis przez wskaźnik `volatile` i pozostawić dostęp do rejestrów FLASH jako `volatile`, np. `*(volatile unsigned short*)Address = Data` [#15799305] [#15794093] Funkcja `FLASH_WaitForLastOperation()` nie była tu winna — zwracane `4` to `FLASH_COMPLETE`, a nie błąd programowania [#15793858] [#15793896] Po dodaniu `volatile` autor potwierdził, że zapis zaczyna działać, bo zmienia się kolejność instrukcji w asemblerze [#15796343] [#15799305]
Podsumowanie wygenerowane przez AI na podstawie treści dyskusji.
REKLAMA
  • #1 15793824
    Konto nie istnieje
    Poziom 1  
  • REKLAMA
  • Pomocny post
    #2 15793858
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    atom1477 napisał:
    3. Funkcja FLASH_WaitForLastOperation zwraca wartość 4, czyli PGERR: Programming error.

    Raczej wartość 4 czyli FLASH_COMPLETE.
  • Pomocny post
    #3 15793896
    QuadMan
    Poziom 14  
    Posty: 53
    Pomógł: 11
    Ocena: 3
    Witam,
    Freddie Chopin napisał:

    Raczej wartość 4 czyli FLASH_COMPLETE.


    No właśnie, ta funkcja jest coś nie teges, bo może zwrócić jedynie FALSH_COMPLETE, albo FLASH_TIMEOUT. Nie wnosi to co prawda nic do opisanego problemu, ale...

    Edit: W sumie to wynika z tego jedynie tyle, że ta funkcja zwraca zawsze FLASH_COMPLETE, niezależnie od poziomu optymalizacji, czyli nie tu leży problem. Wobec tego, Kolego atom1477, Twoje wnioski 3 i 4 są błędne.

    Pozdrawiam, QuadMan.
  • #4 15793909
    Konto nie istnieje
    Poziom 1  
  • Pomocny post
    #5 15794093
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    A co z tymi makrami typu CR_PER_Set i podobnymi?

    Mój kod programowania la STM32F1 jest bardzo podobny, tylko bez tych wszystkich udziwnień i działa niezawodnie przy każdym poziomie optymalizacji, niezbyt wiem co tutaj może być nie tak... Może dodaj "volatile" przy argumencie funkcji FLASH_WaitForLastOperation()? Pewnie nic to nie da, ale... Spróbowałbym też to:

    *(unsigned short*)Address = Data;

    zamienić na:

    *(volatile unsigned short*)Address = Data;
  • #6 15794143
    Konto nie istnieje
    Poziom 1  
  • REKLAMA
  • #8 15796000
    Elektro_guru
    Poziom 11  
    Posty: 73
    Ocena: 9
    Flash procesorów STM32 ma wytrzymałość 1000 cykli zapisów. Korzystasz z kilku bajtów a zapisujesz całe 4096.

    W dodatku nie wiem po co wyrównujesz do 256 te bufory, przecież one są w RAM.
  • #9 15796218
    Konto nie istnieje
    Poziom 1  
  • #10 15796282
    Elektro_guru
    Poziom 11  
    Posty: 73
    Ocena: 9
    Miałem stary (march 2007 rev 0.1) programming manual PM0042 i tam napisali że tylko 1000 cykli zapisu, w nowszym tego nie ma.
    A jeżeli chodzi o zapis częściowy flash'a to można tak, jest taka nota aplikacyjna AN2594, gdzie jest opisane jak emulować EEPROM za pomocą flash'a.
  • #11 15796343
    Konto nie istnieje
    Poziom 1  
  • #12 15796361
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    Szukasz w jakichś szczegółach typu kolejność linii assemblera, a one kompletnie nie mają znaczenia... Kod który Ci podesłałem działa "od lat" na dowolnym poziomie optymalizacji na różnych układach - z drobnymi modyfikacjami działa w zasadzie dla wszystkich rodzajów STM32 (w STM32F4 są nieco inne bity w rejestrach, ale różnice są kosmetyczne). Jeśli u Ciebie nie działa, to:
    - masz uszkodzony mikrokontroler,
    - źle go używasz.

    Po odblokowaniu flasha i skasowaniu jakiejś strony można do niej coś zapisać i to cała filozofia. Funkcje zwracają błędy, więc zawsze możesz je sprawdzić.

    atom1477 napisał:
    Rozwiązaniem może być zastąpienie funkcji w C wstawkami assemlerowymi kodu skompilowanego wcześniej dla optymalizacji -O0.

    Raczej "przypudrowaniem problemu", a nie żadnym "rozwiązaniem" (;
  • #13 15796404
    Konto nie istnieje
    Poziom 1  
  • #14 15796435
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    atom1477 napisał:
    Żeby wiedzieć że nie mają znaczenia to trzeba to sprawdzić. Dlatego sprawdziłem.
    Czy wiedziałbyś że nie mają znaczenia gdybym napisał że kody assemblerowe się różnią ale nie napisał czym się różnią (nie napisał że różnią się tylko kolejnością)?

    Wiedziałbym, że nie mają znaczenia, ponieważ jakkolwiek kompilator je poprzestawia realizują one algorytm który jest w kodzie źródłowym. Jeśli ten algorytm jest poprawny, to cokolwiek kompilator nie wyczaruje będzie działać - szybciej lub wolniej, ale poprawnie.

    atom1477 napisał:
    No to zależy od tego co jest problemem.

    Na pewno nie kod który Ci podesłałem (; Pokaż jak go używasz, najlepiej sprawdź to w projekcie w którym nie ma nic innego - nawet ustawiania zegarów, GPIO, UARTów, przerwań itd. - na domyślnych ustawieniach wszystko będzie działać. Upewnij się, że nie robisz żadnych dziwnych machinacji przy kompilacji/linkowaniu.
  • #15 15796439
    Konto nie istnieje
    Poziom 1  
  • Pomocny post
    #16 15797799
    QuadMan
    Poziom 14  
    Posty: 53
    Pomógł: 11
    Ocena: 3
    Witam,

    Kolego atom1477 z ciekawości uruchomiłem Twój projekt, z tym że zmodyfikowałem tak main-a, że najpierw wypełniam ALGO_TAB jakimiś tam danymi, a później jednorazowo kasuję sektor i te dane zapisuję do FLASH-a i u mnie działa zawsze ok, niezależnie od poziomu optymalizacji. Nie chciało mi się już robić jakiegoś porównywania danych, to co zapisuję po odczytaniu podglądam przez UARTA i też w debuggerze (Memory) i zawsze jest ok.
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Niczego więcej nie zmieniałem, nawet wywaliłem to volatile z FLASH_ProgramHalfWord(...) i i tak zawsze działa. Ja w paru swoich projektach korzystam z podobnego rozwiązania - przebudowałem trochę przykład od ST ( emulator EEPROM-a czy jakoś tak ), co prawda dla F0, ale z tego co widzę dla F1 jest identycznie. To co wyżej testowałem na STM32F103VCT6. Jeszcze co do tego volatile - jak modyfikowałem przykład od ST, to pamiętam, że najpierw też je wywaliłem, ale ostatecznie zostawiłem - bo coś mi się tam w pewnych warunkach chrzaniło, ale już dokładnie nie pamiętam co. Reasumując, masz jakiś inny problem, bo sam zapis do FLASH-a działa ok. Tą funkcję FLASH_WaitForLastOperation(...) może warto by zmodyfikować, aby zwracała też inne statusy, ale to w tej chwili nieistotne.
    Pozdrawiam, QuadMan.
  • #17 15798249
    Konto nie istnieje
    Poziom 1  
  • Pomocny post
    #18 15799305
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    Różnica nie polega na zamianie miejscami movs i strh, tylko na tym, że w jednym kodzie zapis jest wykonywany _PRZED_ ustawieniem bitu PG w rejestrze CR (to jest to "str r3, [r5, #16]"), a w drugim _PO_. Bez "volatile" kompilator może sobie przestawić ten zapis gdzie mu się podoba, natomiast w odwrotnym przypadku zostanie on wykonany w takiej kolejności w jakiej jest w kodzie źródłowym (zapisy do rejestrów sprzętowych zawsze mają "volatile").

    Swoją drogą w kodzie który Ci podesłałem tego nie ma, więc warto dodać (;
  • REKLAMA
  • #19 15799403
    Konto nie istnieje
    Poziom 1  
  • #20 15799434
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    nie żadne "volatile", tylko po prostu "const". Swoją drogą to nie wiem czy atrybuty można łączyć tak jak pokazałeś, na pewno można je łączyć po prostu po przecinku wewnątrz nawiasów.

    Twoja tablica nie jest wgrywana, bo dałeś noload - to chyba powinno być oczywiste [;

    BTW - zamiast samego "> eeprom" na końcu sekcji proponuję naprawdę " > eeprom AT > eeprom".
  • REKLAMA
  • #21 15799486
    Konto nie istnieje
    Poziom 1  
  • #23 15799520
    Konto nie istnieje
    Poziom 1  
  • #25 15799535
    Konto nie istnieje
    Poziom 1  
  • #26 15799571
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    Wrzuć tutaj minimalny przykład. Tylko niech będzie naprawdę minimalny, nie potrzebuje GPIO, UARTa, FLASHa, PLLa i tysiąca innych plików - niech to będzie najprostszy możliwy projekt z taką tablicą.
  • #27 15799619
    Konto nie istnieje
    Poziom 1  
  • #28 15799625
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    Optymalizacja kodu i wywalanie nieużywanych obiektów/funkcji to dwie odmienne sprawy. Jedno jest robione przez kompilator, drugie przez linker.
  • #29 15799663
    Konto nie istnieje
    Poziom 1  
  • #30 15799725
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    Nie ma to jak wrzucać dokładny kod błędu...

    main.c:32:32: error: Roleta_EEPROM causes a section type conflict with Roleta_EEPROM2
     volatile struct Roleta_offsets Roleta_EEPROM[7] __attribute__ ((section(".eeprom_mem"))) __attribute__ ((aligned (32))) =
                                    ^
    


    Jak chcesz to mieć we flash, to ma być "const" i koniec, ponieważ Twoja pamięć w skrypcie linkera zadeklarowana jest jako read-only. Po poprawce "volatile" na "const" działa jak należy.

Podsumowanie tematu

✨ Użytkownik zgłasza problem z zapisem do pamięci FLASH w mikrokontrolerze STM32F103, który działa poprawnie przy optymalizacji -O0, ale nie przy -Os. W trakcie dyskusji zauważono, że funkcja zwracająca status operacji FLASH zawsze wskazuje na FLASH_COMPLETE, co nie pomaga w diagnozowaniu problemu. Użytkownicy sugerują dodanie słowa kluczowego "volatile" do zmiennych oraz sprawdzenie kolejności instrukcji w kodzie, co może wpływać na działanie zapisu. Ostatecznie, problem został rozwiązany przez zmianę kolejności instrukcji oraz dodanie "volatile", co zapewniło poprawne działanie zapisu. Dodatkowo, poruszono temat deklaracji tablic w pamięci FLASH oraz ich inicjalizacji, co również wymagało uwzględnienia atrybutu "const" dla poprawnej kompilacji.
Podsumowanie wygenerowane przez AI na podstawie treści dyskusji.
REKLAMA