在 stm32f7 上使用 freeRTOS 的 sprint/printf 问题

Posted

技术标签:

【中文标题】在 stm32f7 上使用 freeRTOS 的 sprint/printf 问题【英文标题】:problem with sprint/printf with freeRTOS on stm32f7 【发布时间】:2021-01-14 23:57:36 【问题描述】:

两天以来,我试图让 printf\sprintf 在我的项目中工作...... 单片机:STM32F722RETx

我尝试使用 newLib、heap3、heap4 等,但没有任何效果。 HardFault_Handler 每次都会运行。 现在我正在尝试使用来自this link 的简单实现,但仍然是同样的问题。我想我的设备有一些双数问题,因为程序在 _ftoa 函数中从这一行 if (value != value) 运行 HardFault_Handler。(奇怪的是,这个 stm32 支持 FPU) 你们有什么想法吗? (现在我使用的是 heap_4.c) 我的编译器选项:

target_compile_options($PROJ_NAME PUBLIC
$<$<COMPILE_LANGUAGE:CXX>:
    -std=c++14
>
-mcpu=cortex-m7
-mthumb
-mfpu=fpv5-d16
-mfloat-abi=hard
-Wall
-ffunction-sections
-fdata-sections
-O1 -g
-DLV_CONF_INCLUDE_SIMPLE
 )

链接器选项:

target_link_options($PROJ_NAME PUBLIC
$LINKER_OPTION $LINKER_SCRIPT
-mcpu=cortex-m7
-mthumb
-mfloat-abi=hard
-mfpu=fpv5-sp-d16
-specs=nosys.specs
-specs=nano.specs
# -Wl,--wrap,malloc
# -Wl,--wrap,_malloc_r
-u_printf_float
-u_sprintf_float
 )

链接器脚本:

/* Highest address of the user mode stack */
_estack = 0x20040000;    /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200;      /* required amount of heap  */
_Min_Stack_Size = 0x400; /* required amount of stack */

/* Specify the memory areas */
MEMORY

   RAM (xrw)     : ORIGIN = 0x20000000, LENGTH = 256K
  FLASH (rx)    : ORIGIN = 0x08000000, LENGTH = 512K

更新: 我不认为这是堆栈问题,我已将 configCHECK_FOR_STACK_OVERFLOW 设置为 2,但从未调用过钩子函数。我发现奇怪的想法:这个解决方案有效:

float d = 23.5f;
char buffer[20];
sprintf(buffer, "temp %f", 23.5f);

但这个解决方案不是:

float d = 23.5f;
char buffer[20];
sprintf(buffer, "temp %f",d);

不知道为什么要通过副本传递变量,生成一个 HardFault_Handler...

【问题讨论】:

检查堆栈指针是否在导致硬故障的任何时候溢出堆栈。 我相信 STM32F722 有一个单精度 FPU,这意味着一个软件库可以用于任何双精度操作。我不知道这是否重要,但你提到了双打,所以我想我会提到它。 如果可以重现,可以尝试使用 CubeMX 生成一个简单的项目,并使用 STM32CubeIDE 中的“硬故障分析器”。如果不能,我会怀疑编译器或链接器选项错误。 【参考方案1】:

newlib C 运行时库(在许多嵌入式工具链中使用)在内部使用它自己的 malloc 系列例程。 newlib 维护一些内部缓冲区并需要对线程安全的一些支持: http://www.nadler.com/embedded/newlibAndFreeRTOS.html

硬故障可能由未对齐的内存访问引起: https://www.keil.com/support/docs/3777.htm

【讨论】:

【参考方案2】:

在为我的 SiFive HiFive Rev B 使用 FreeRTOS 时,printf 也出现错误。

为了解决这个问题,我重写了_fstat_write函数来改变printf的输出函数

/*
 * Retarget functions for printf()
 */
#include <errno.h>
#include <sys/stat.h>

int _fstat (int file, struct stat * st) 
    errno = -ENOSYS;
    return -1;


int _write (int file, char * ptr, int len) 
    extern int uart_putc(int c);
    int i;

    /* Turn character to capital letter and output to UART port */
    for (i = 0; i < len; i++) uart_putc((int)*ptr++);
    return 0;

并为SiFive HiFive Rev B硬件的UART0创建另一个uart_putc函数:

void uart_putc(int c)

#define uart0_txdata    (*(volatile uint32_t*)(0x10013000)) // uart0 txdata register
#define UART_TXFULL             (1 << 31)  // uart0 txdata flag
    while ((uart0_txdata & UART_TXFULL) != 0)  
    uart0_txdata = c;

【讨论】:

【参考方案3】:

您可以实施硬故障处理程序,该处理程序至少会为您提供问题发生的 SP 位置。这应该提供更多的洞察力。

https://www.freertos.org/Debugging-Hard-Faults-On-Cortex-M-Microcontrollers.html

它应该让您知道您的问题是由于 MCU 中的浮点错误还是由于可能由某些链接问题引起的分支错误

【讨论】:

寄存器: r0 : 536871872\ r1 : 1\ r2: 1\ r3: 1102839808\ r12: 2779096485\ lr: 134320687\ pc: 134314822,\ psr: 553648128 设置断点“pc”地址,但它设置为 sprintf 函数: 我还注意到一个 S31 寄存器有值:-nan(0x7fffff)

以上是关于在 stm32f7 上使用 freeRTOS 的 sprint/printf 问题的主要内容,如果未能解决你的问题,请参考以下文章

STM32F107VC 使用 TCP 运行 FreeRTOS

FREERTOS移植STM32F407

FREERTOS移植STM32F407

如何将带有 SPL 的 STM32F3 代码移植到 STM32F7

STM32F103移植freeRTOS(使用官方源码)

随机硬故障 - STM32F4 - FreeRTOS