Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Вывод float в arm-none-eabi-gcc для stmf4
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
zemlemer
Добрый день.

Я меня возникли некоторые проблемы с выводом в терминал значений с плавающей точкой. Самый обычный sprintf прекрасно работает с целыми числами и отказывается работать с float. Например

CODE

float flttest = 123.45678;

sprintf(TestArray, "-= %lf =-", flttest);
Terminal("Test1: STR %s", TestArray);

uint16_t integer= 12345;
sprintf(TestArray, "*- %d -*", integer);
Terminal("Test2: STR %s", TestArray);


При этот вывод:
003 INFO: Test1: STR -= 403099659660755.687500 =-
004 INFO: Test2: STR *- 12345 -*

Основные ключи компилятора: arm-none-eabi-gcc -c -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -mlittle-endian -mthumb-interwork -ffunction-sections -fdata-sections -Wl,--gc-sections
Основные ключи линкера: arm-none-eabi-gcc -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Xlinker -Map="project.map" -L/opt/gcc-arm-none-eabi-5_4/arm-none-eabi/lib/armv7e-m/fpu/ --specs=rdimon.specs -T/Core/STM32F4XX_FLASH.ld

Кто-либо сталкивался с подобным?

scifi
В командную строку линкера нужно добавить "-u _printf_float". Первоисточник.
zemlemer
Цитата(scifi @ Oct 20 2016, 18:26) *
В командную строку линкера нужно добавить "-u _printf_float". Первоисточник.


На самом деле пробовал с -u _printf_float и с -u _sprintf_float с одинаковым результатом.
scifi
Я невнимательно посмотрел. Если линкуется целочисленная версия, не будет вот этих странных чисел.
Обратите внимание на выравнивание стека по границе 8 байт. Помню, это приводило к чудесам в плавучке.
Lagman
может поможет http://www.openstm32.org/tiki-view_forum_t...s_parentId=2108
dxp
Ещё вариант: https://github.com/emb-lib/io

библиотека, оптимизированная для embedded применений. Плавучку печатает без нареканий (только нужно определить макро PRINTF_FLOAT, лучше всего передать в командной строке -DPRINTF_FLOAT).
zemlemer
Цитата(scifi @ Oct 20 2016, 20:22) *
Я невнимательно посмотрел. Если линкуется целочисленная версия, не будет вот этих странных чисел.
Обратите внимание на выравнивание стека по границе 8 байт. Помню, это приводило к чудесам в плавучке.


Вроде к линковщике секция с правильным ALIGN, или я не правильно понял.
Код
  ._user_heap_stack :
  {
    . = ALIGN(4);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    PROVIDE ( __end__ = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(4);
  } >RAM

Вообще ситуация еще более печальна. Задавая вопрос, я просто упростил сложившуюся ситуацию. На самом деле я пишу небольшую библиотеку для отладочного вывода. Парсер разбора форматной строки - va_arg - корректно работает с целочисленными переменными. Т.е. intarg = va_arg(ap, int32_t); отрабатывает корректно. Как только речи идет о передаче плавучки - doublearg = va_arg(ap, double); - передается мусор. Если передать float через *((int32_t*)&floatarg и передать через va_arg(ap, int32_t); - передается правильно.
iiv
Цитата(zemlemer @ Oct 20 2016, 21:09) *
float flttest = 123.45678;

sprintf(TestArray, "-= %lf =-", flttest);

если у вас одинарная точность, sprintf хочет %f или %e или %g, а если двойная, то да, с "l" надо писать.
aaarrr
Цитата(iiv @ Oct 21 2016, 22:03) *
если у вас одинарная точность, sprintf хочет %f или %e или %g, а если двойная, то да, с "l" надо писать.

У sprintf не бывает одинарной точности, "l" игнорируется.
zemlemer
Цитата(iiv @ Oct 21 2016, 22:03) *
если у вас одинарная точность, sprintf хочет %f или %e или %g, а если двойная, то да, с "l" надо писать.

Знаю. Просто va_arg не работает с float, поэтому перед передачей я преобразовывал в double а после - обратно во float.
scifi
Цитата(zemlemer @ Oct 21 2016, 22:00) *
Вроде к линковщике секция с правильным ALIGN, или я не правильно понял.
._user_heap_stack :
{
. = ALIGN(4);

Ещё раз: выравнивать по границе 8 байт. Проверяйте на входе в sprintf(). Внутрисхемным отладчиком остановите на входе в функцию и посмотрите на SP. Если не кратно 8 - беда.
Genadi Zawidowski
Цитата
перед передачей я преобразовывал в double а после - обратно во float.

про "после" подробнее... желательно с кодом.
demiurg_spb
Цитата(aaarrr @ Oct 21 2016, 22:18) *
У sprintf не бывает одинарной точности, "l" игнорируется.
Я каждый раз задаюсь вопросом: в чём был смысл такого решения при создании сишной библиотеки?
zemlemer
Цитата(demiurg_spb @ Oct 23 2016, 00:21) *
Я каждый раз задаюсь вопросом: в чём был смысл такого решения при создании сишной библиотеки?


Смыслов несколько. У меня статически выделен массив для передачи строки в терминал, а стандартные работают с динамическим перераспределением памяти. Использовать malloc или realloc нужно когда совсем припрет. Мне не нужны все возможности printf или sprintf (кто-нить использовал \b или \v или ..... ), но все лишнее намертво прилепится к выходному бинарнику.
scifi
Цитата(demiurg_spb @ Oct 23 2016, 00:21) *
Я каждый раз задаюсь вопросом: в чём был смысл такого решения при создании сишной библиотеки?

Между прочим, если функция имеет переменное число аргументов (как sprintf), аргументы типа float приводятся к типу double перед вызовом функции. Отцы-основатели не подумали о микроконтроллерах. Да их (МК) тогда и не было, наверное laughing.gif

Цитата(zemlemer @ Oct 24 2016, 13:53) *
Мне не нужны все возможности printf или sprintf (кто-нить использовал \b или \v или ..... ), но все лишнее намертво прилепится к выходному бинарнику.

Уже проверили выравнивание стека, кратное 8 байт? Просто интересно.
demiurg_spb
Цитата(zemlemer @ Oct 24 2016, 13:53) *
Смыслов несколько.
У меня был вопрос не к вашей задаче. А вообще к libc. Вроде либа должна быть стандартная и удобная - она таковой и является, пока не задумаешься об оптимизации...
Хочешь printf'нут float, а он к double сначала приводится - обидно досадно и не понятно зачем так сделано, что %f - это double и НЕТ стандартного способа вывести float в чистом виде без приведения типа!
Цитата(scifi @ Oct 24 2016, 14:19) *
Между прочим, если функция имеет переменное число аргументов (как sprintf), аргументы типа float приводятся к типу double перед вызовом функции.
Это всем известно, но не понятно - зачем)))
Сергей Борщ
QUOTE (scifi @ Oct 24 2016, 14:15) *
если функция имеет переменное число аргументов (как sprintf), аргументы типа float приводятся к типу double перед вызовом функции.
А все, что меньше int - к int. При том зачем-то в последних стандартах в inttypes.h добавили префиксы спецификаторов форматной строки h и hh "для принудительного приведения к short и char"


QUOTE (demiurg_spb @ Oct 24 2016, 14:23) *
Это всем известно, но не понятно - зачем)))
Видимо неявное приведение позволяет написать вывод только одного типа (double) и в программах разумного размера суммарный размер всех кодов приведения типа будет меньше, чем размер дополнительной отдельной ветки кода для вывода float.
demiurg_spb
я hu и hhu использую по мере необходимости. На AVR вроде как был профит от этого.

Цитата(Сергей Борщ @ Oct 24 2016, 14:26) *
Видимо неявное приведение позволяет написать вывод только одного типа (double) и в программах разумного размера суммарный размер всех кодов приведения типа будет меньше, чем размер дополнительной отдельной ветки кода для вывода float.
Ну а если наоборот - в прошивке ни одного double нет, лишь одни float))) (типично для кортекса и около того)
scifi
Цитата(Сергей Борщ @ Oct 24 2016, 14:26) *
При том зачем-то в последних стандартах в inttypes.h добавили префиксы спецификаторов форматной строки h и hh "для принудительного приведения к short и char"

Можно предположить, что это сделано для симметрии с scanf, а там это нужная фича.
Сергей Борщ
QUOTE (demiurg_spb @ Oct 24 2016, 14:29) *
я hu и hhu использую по мере необходимости. На AVR вроде как был профит от этого.
Откуда он может взяться? Переменная приводится к (unsigned) int принудительно, на это мы повлиять не можем. Дальше работа с ней идет как с int. значение ее от приведения поменяться не могло. В чем смысл дополнительного принудительного обратного приведения внутри printf и какой выигрыш от этого можно плучить? Могу предположить, что если мы хотим вывести только младший байт или слово от int, тогда можно не накладывать маску перед передачей параметра в printf, но это настолько редкий случай, что городить ради этого поддержку дополнительных флагов... Не могу пока понять такой логики.

QUOTE (demiurg_spb @ Oct 24 2016, 14:29) *
Ну а если наоборот - в прошивке ни одного double нет, лишь одни float))) (типично для кортекса и около того)
Нет в жизни совершенства sad.gif

QUOTE (scifi @ Oct 24 2016, 14:38) *
Можно предположить, что это сделано для симметрии с scanf, а там это нужная фича.
Правдоподобно. Там значение передается по указателю, приведений не происходит.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.