Skocz do zawartości

STM32F3 - crashe związane z użyciem typu double


etet100

Pomocna odpowiedź

Witam. Tworzę prostą aplikację pod Stm32CubeIDE z użycie kontrolera STM32F303 (z wbudowanym FPU). Trafiłem na dziwne problemy kiedy
próbowałem użyć sprintf z włączonym wsparciem dla %f. Za każdym razem zamiast poprawnie sformatowanej liczby dostawałem bardzo
długi ciąg cyfr. Znalazłem nawet na githubie jakąś inną implementację sprintf i to znowu często zamiast poprawnej wartości zwracało mi 0.00. W końcu
okazało się, że problem jest z va_arg:

void test(const char* format, ...)
{
  va_list va;
  va_start(va, format);

  double arg1 = va_arg(va, double);

  char buf[102];
  sprintf(buf, "a %.2f", arg1);

  va_end(va);
}

test("format", 0.1234);

Zatrzymuje kod na linii z va_arg i widzę, że to zwraca głupoty. Obszedłem to przy pomocy takiego dziwnego rozwiązania:

  uint64_t doubleBinary = va_arg(va, uint32_t) |
          ((uint64_t)va_arg(va, uint32_t) << 32);
  double arg = *(double*)&doubleBinary;

I tu dostaje poprawną wartość. Ale potem mam taki fragment (to z tego sprintf):

static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
{
  {... tu jakiś kod...}
}

//i wywołanie:
uint64_t doubleAsInt = va_arg(va, uint32_t) |
               ((uint64_t)va_arg(va, uint32_t) << 32);
double doubleAsDouble = *(double*)&doubleAsInt;

idx = _ftoa(out, buffer, idx, maxlen, doubleAsDouble, precision, width, flags);
format++;

No i na tym _ftoa znowu jest problem bo zamiast wejść do procedury to kod wpada mi do:

Default_Handler:
Infinite_Loop:
  b Infinite_Loop

Próbowałem wyłączyć FPU i skompilować wszystko na software. va_arg nadal nie działa ale nie ma tego crasha przy _ftoa. Potem uruchomiłem ten sam program
pod starym EmBitz (GCC w wersji 5) i tam wszystko wydaje się działać bezbłędnie (na tyle na ile udało mi się sprawdzić). Przy czym te projekty nie są identycznie (mój kod jest taki sam ale to co jest generowane przez środowisko już na pewno nie).

Ma ktoś pomysł jak to debugować i o co może chodzić? Nie jestem w tym specjalnie zaawansowany i skończyły mi się już pomysły. W internecie znalazłem jakieś szczątkowe informacje, że double ma 8 bajtów i z tym jest jakiś problem (niestety bez konkretów więc nic mi to nie dało).

Link do komentarza
Share on other sites

1. To że STM32F4 ma FPU nie oznacza że możesz używać typu double - FPU w tych uK ma tylko 32 bity.

2. Wątpię aby printf w twoim toolchainie drukował double.

3. Tak va_arg nie wolno sotosować - jest to UB najpierw przypisz do zmiennych następnie rób operacje arytmetyczne.

4. Kod łamie zasady strict aliasing i niekoniecznie kod musi robić to co myślisz. Użyj uniii - union punning jest bezpieczny.

 

Generalnie za dużo prób trików, które są UB.

  • Lubię! 1
Link do komentarza
Share on other sites

1 godzinę temu, stmx napisał:

1. To że STM32F4 ma FPU nie oznacza że możesz używać typu double - FPU w tych uK ma tylko 32 bity.

Ale chyba nadal istnieje tryb software? Wiem, że FPU ich nie wspiera. Wszędzie piszą, że w takiej sytuacji kompilator
po prostu zrealizuje to softwarowo.

1 godzinę temu, stmx napisał:

2. Wątpię aby printf w twoim toolchainie drukował double.

Ale floaty niby drukuje. A przetestowałem to na 1000 sposobów i nie działa. A zanim zainstalowałem te nowe STM32CubeIDE to 
nie miałem takich problemów. Czego bym nie podstawił jako parametr %f to dostaje wartość w stylu 51275175258712571248012958901285791207581251.
Tak samo czego bym nie podstawił do tego do tej metody ze zmiennymi parametrami do dostaje coś w okolicach 0. I nie ma znaczenia
czy włącze te cholerne FPU czy nie.

1 godzinę temu, stmx napisał:

3. Tak va_arg nie wolno sotosować - jest to UB najpierw przypisz do zmiennych następnie rób operacje arytmetyczne.

"TAK" czyli jak? Bo ten kod uprościłem na koniec. Wcześniej było przepisywanie do zmiennych i nie zmieniło to kompletnie nic.

1 godzinę temu, stmx napisał:

4. Kod łamie zasady strict aliasing i niekoniecznie kod musi robić to co myślisz. Użyj uniii - union punning jest bezpieczny.

Nie wiem co łamie kod ale próbowałem na dziesiątki sposobów. Właściwie to nawet podstawienie do tej funkcji stałej 
nic nie zmienia. Dopiero zmiana jednego z jej parametrów z double na przykładowo int powoduje, że kod się nie wypiepsza
na wywołaniu. 

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Zrobiłem jeszcze raz ten sam projekt w Atollic Studio (tym razem GCC 6.3.1) i działa bezbłędnie. Czyli ten STM32CubeIDE jakoś niedobrze
tworzy projekt. Ale w internecie nie ma śladu po takich przypadku. Wszystkim działa tylko mi nie.

Link do komentarza
Share on other sites

@etet100 nie wiem czy to konkretnie wina STM32CubeIDE, ale pamiętaj, że to nowe oprogramowanie (oficjalna premiera była kilka tygodni temu). Mogą tam jeszcze być pewne błędy, których nikt jeszcze nie odnalazł 😉

Link do komentarza
Share on other sites

Niby nowe ale to zdaje się jest oparte w dużej części na już istniejących rozwiązaniach. Ten CubeMX to przecież nic nowego. A wychodzi mi, że
to on coś źle generuje. Choć mogę się w 100% mylić.

Link do komentarza
Share on other sites

Już kompletnie zdesperowany postanowiłem porównać pliki linkera generowane przez atollic i cubeide. Różnic jest ogólnie sporo ale zauważyłem na początku różnicę

_estack = 0x2000A000;    /* end of "RAM" Ram type memory */

i

_estack = 0x20009FFF;    /* end of "RAM" Ram type memory */

Zmieniłem to 9FFF na A000 (jak w Atollic) i poszło! Potem zacząłem zacząłem szukać pod tym
kątem i jest takie coś:

https://community.st.com/s/question/0D50X0000Ansc6GSQQ/stm32cubeide-linker-lptim-lsi-clock

Troszkę inny kontroler, identyczne problemy, identyczne rozwiązanie. I piszą, że ST o tym wie ale się nie przejmuje.
Czy to w takim razie może traktować jak poprawne rozwiązanie?

Link do komentarza
Share on other sites

Anonim

Czy to jest pewne, że tak właśnie się dzieje za każdym razem? Sprawdzał to ktoś jeszcze czy to tylko odosobniony przypadek? Niestety nie mam jak tego sprawdzić osobiście w tej chwili ale będzie trzeba to mieć na uwadze w razie co. Może warto to zgłosić.

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.