0.引言

说起来,本来只是想尝个鲜,看看cubeIDE是怎么用的,结果随手做个实验freeRTOS+串口的实验就跌进了坑,花了我一个星期往外爬,在此做个记录。
cubeIDE使用起来。感觉很多初始化代码出比较快,一些资源使用也很直观,但是内部的SDK使用起来还是有些坑,并不是那么的完善。
看看这些吐槽,哈哈哈。



哈哈哈欢乐,SDK团队也不容易啊,一直受到全球人民的鞭策。
以前都是很信任官方SDK的,自从我转来做SDK之后,才发现bug也不少,毕竟也是人写的。只不过版本控制和代码review、merge要严格很多。
多一些宽容多一些理解多一些等待,SDK和客户一起成长 ~

1. 实验

1.1 原理

想用cubeIDE在freeRTOS下printf浮点数,你需要按照下面这么几个步骤来做:

  1. 驱动串口(图形化引脚配置,cubeIDE的驱动代码生成)
  2. 使用printf(串口重定向)
  3. 使用printf输出浮点数 (菜单勾选)
  4. 在freeRTOS中使用printf (修改task默认堆栈大小,默认128 word小了,会进hardfault)
  5. 怎么使用printf在freeRTOS中输出浮点数 (本文内容,增加第三方提供的补丁)

其中,1、2、3、4都是很常规的操作,在网上能搜到不少教程和帖子。
实在不行可以看我的上一篇
一般来说,到这里就应该结束了,没想到让我爬了一个星期。
(至少截止目前,2020.7.16,cubeIDE v1.3.0版本)依然存在在freeRTOS下,线程中使用printf、USB库等接口的异常。
因为这些接口使用了malloc等接口,而不是freeRTOS提供的有线程保护的pvPortMalloc等接口,ST官方自己实现的_sbrk函数有些问题(sysmem.c里),导致线程中一些调用了系统自身malloc的函数接口出问题。

这个情况有几种解决方法,这位大神都列了:

  1. 使用第三方的printf实现,这样规避了ST自带的printf会malloc的问题,但是你需要自己确认其他的代码(printf之外的)是否还有这个问题
  2. 所有的包括ST生成的系统代码的malloc等接口全部改成freeRTOS提供的pvPortMalloc等接口。但是这里freeRTOS没有提供realloc的实现,printf却需要使用、
  3. 使用第三方补丁,使用一些hook的API。

1.2 步骤

这里我们使用第三种方法。

具体步骤如下:

  1. 添加heap_useNewlib.c(可以在文末复制)

  1. 把sysmem.c 和 FreeRTOS里的heapX.c从编译内容中排除。点击文件,右键Resource configuration - exclude from build

  1. ioc文件中的freeRTOS USE_NEWLIB_REENTRANT 选择enable.

1.3 结果

串口printf可以正常打印。

2. 深入探究

ST的bug是怎么形成的?
heap_useNewlib.c做了些什么?

参考链接

  • 重要的第三方补丁说明 - 大神讲解详细
  • 解决方案
  • 讨论帖
  • 第三方工程,解决malloc问题

附录

另外附上heap_useNewlib.c全文,出自参考链接一。

/*** \file heap_useNewlib.c* \brief Wrappers required to use newlib malloc-family within FreeRTOS.** \par Overview* Route FreeRTOS memory management functions to newlib's malloc family.* Thus newlib and FreeRTOS share memory-management routines and memory pool,* and all newlib's internal memory-management requirements are supported.** \author Dave Nadler* \date 7-August-2019* \version 23-Sep-2019 comments, check no malloc call inside ISR** \see http://www.nadler.com/embedded/newlibAndFreeRTOS.html* \see https://sourceware.org/newlib/libc.html#Reentrancy* \see https://sourceware.org/newlib/libc.html#malloc* \see https://sourceware.org/newlib/libc.html#index-_005f_005fenv_005flock* \see https://sourceware.org/newlib/libc.html#index-_005f_005fmalloc_005flock* \see https://sourceforge.net/p/freertos/feature-requests/72/* \see http://www.billgatliff.com/newlib.html* \see http://wiki.osdev.org/Porting_Newlib* \see http://www.embecosm.com/appnotes/ean9/ean9-howto-newlib-1.0.html*** \copyright* (c) Dave Nadler 2017-2019, All Rights Reserved.* Web:         http://www.nadler.com* email:       drn@nadler.com** Redistribution and use in source and binary forms, with or without modification,* are permitted provided that the following conditions are met:** - Use or redistributions of source code must retain the above copyright notice,*   this list of conditions, ALL ORIGINAL COMMENTS, and the following disclaimer.** - Redistributions in binary form must reproduce the above copyright notice, this*   list of conditions and the following disclaimer in the documentation and/or*   other materials provided with the distribution.** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/// ================================================================================================
// =======================================  Configuration  ========================================
// These configuration symbols could be provided by from build...
#define STM_VERSION// use STM standard exported LD symbols
//#define SUPPORT_MALLOCS_INSIDE_ISRs // #define iff you have this crap code (ie unrepaired STM USB CDC)
#define SUPPORT_ISR_STACK_MONITOR// #define to enable ISR (MSP) stack diagnostics
#define ISR_STACK_LENGTH_BYTES  512// #define bytes to reserve for ISR (MSP) stack
// =======================================  Configuration  ========================================
// ================================================================================================#include <stdlib.h>// maps to newlib...
#include <malloc.h>// mallinfo...
#include <errno.h>// ENOMEM
#include <stdbool.h>
#include <stddef.h>#include "newlib.h"
#if (__NEWLIB__ != 3) || (__NEWLIB_MINOR__ != 0)#warning "This wrapper was verified for newlib version 3.0.0; please ensure newlib's external requirements for malloc-family are unchanged!"
#endif#include "freeRTOS.h"// defines public interface we're implementing here
#if !defined(configUSE_NEWLIB_REENTRANT) ||  (configUSE_NEWLIB_REENTRANT!=1)#warning "#define configUSE_NEWLIB_REENTRANT 1// Required for thread-safety of newlib sprintf, strtok, etc..."// If you're *REALLY* sure you don't need FreeRTOS's newlib reentrancy support, remove this warning...
#endif
#include "task.h"// ================================================================================================
// External routines required by newlib's malloc (sbrk/_sbrk, __malloc_lock/unlock)
// ================================================================================================// Simplistic sbrk implementations assume stack grows downwards from top of memory,
// and heap grows upwards starting just after BSS.
// FreeRTOS normally allocates task stacks from a pool placed within BSS or DATA.
// Thus within a FreeRTOS task, stack pointer is always below end of BSS.
// When using this module, stacks are allocated from malloc pool, still always prior
// current unused heap area...
#if 0// STM CubeMX 2018-2019 Incorrect Implementation (fails for FreeRTOS)caddr_t _sbrk(int incr){extern char end asm("end"); // lowest unused RAM address, just beyond end of BSS.static char *heap_end;char *prev_heap_end;if (heap_end == 0) heap_end = &end;prev_heap_end = heap_end;if (heap_end + incr > stack_ptr) // of course, always true for FreeRTOS task stacks{errno = ENOMEM; // ...so first call inside a FreeRTOS task lands herereturn (caddr_t) -1;}heap_end += incr;return (caddr_t) prev_heap_end;}
#endifregister char * stack_ptr asm("sp");#ifdef STM_VERSION// Use STM CubeMX LD symbols for heap+stack area// To avoid modifying STM LD file (and then having CubeMX trash it), use available STM symbols// Unfortunately STM does not provide standardized markers for RAM suitable for heap!// STM CubeMX-generated LD files provide the following symbols:// end       /* aligned first word beyond BSS */// _estack   /* one word beyond end of "RAM" Ram type memory, for STM32F429 0x20030000 */// Kludge below uses CubeMX-generated symbols instead of sane LD definitions#define __HeapBase  end#define __HeapLimit _estack// except in K64F this was already adjusted in LD for stack...static int heapBytesRemaining;// no DRN HEAP_SIZE symbol from LD... // that's (&__HeapLimit)-(&__HeapBase)uint32_t TotalHeapSize; // publish for diagnostic routines; filled in first _sbrk call.
#else// Note: DRN's K64F LD provided: __StackTop (byte beyond end of memory), __StackLimit, HEAP_SIZE, STACK_SIZE// __HeapLimit was already adjusted to be below reserved stack area.extern char HEAP_SIZE;  // make sure to define this symbol in linker LD command filestatic int heapBytesRemaining = (int)&HEAP_SIZE; // that's (&__HeapLimit)-(&__HeapBase)
#endif#ifdef MALLOCS_INSIDE_ISRs// STM code to avoid malloc within ISR (USB CDC stack)// We can't use vTaskSuspendAll() within an ISR.// STM's stunningly bad coding malpractice calls malloc within ISRs (for example, on USB connect function USBD_CDC_Init)// So, we must just suspend/resume interrupts, lengthening max interrupt response time, aarrggg...#define DRN_ENTER_CRITICAL_SECTION(_usis) { _usis = taskENTER_CRITICAL_FROM_ISR(); }// Disables interrupts (after saving prior state)#define DRN_EXIT_CRITICAL_SECTION(_usis)  { taskEXIT_CRITICAL_FROM_ISR(_usis);     }// Re-enables interrupts (unless already disabled prior taskENTER_CRITICAL)
#else#define DRN_ENTER_CRITICAL_SECTION(_usis) vTaskSuspendAll();// Note: safe to use before FreeRTOS scheduler started, but not in ISR#define DRN_EXIT_CRITICAL_SECTION(_usis)  xTaskResumeAll();// Note: safe to use before FreeRTOS scheduler started, but not in ISR
#endif#ifndef NDEBUGstatic int totalBytesProvidedBySBRK = 0;
#endif
extern char __HeapBase, __HeapLimit;  // make sure to define these symbols in linker LD command file//! _sbrk_r version supporting reentrant newlib (depends upon above symbols defined by linker control file).
void * _sbrk_r(struct _reent *pReent, int incr) {#ifdef MALLOCS_INSIDE_ISRs// block interrupts during free-storage useUBaseType_t usis; // saved interrupt status#endifstatic char *currentHeapEnd = &__HeapBase;#ifdef STM_VERSION// Use STM CubeMX LD symbols for heapif(TotalHeapSize==0) {TotalHeapSize = heapBytesRemaining = (int)((&__HeapLimit)-(&__HeapBase))-ISR_STACK_LENGTH_BYTES;};#endifchar* limit = (xTaskGetSchedulerState()==taskSCHEDULER_NOT_STARTED) ?stack_ptr   :  // Before scheduler is started, limit is stack pointer (risky!)&__HeapLimit-ISR_STACK_LENGTH_BYTES;  // Once running, OK to reuse all remaining RAM except ISR stack (MSP) stackDRN_ENTER_CRITICAL_SECTION(usis);char *previousHeapEnd = currentHeapEnd;if (currentHeapEnd + incr > limit) {// Ooops, no more memory available...#if( configUSE_MALLOC_FAILED_HOOK == 1 ){extern void vApplicationMallocFailedHook( void );DRN_EXIT_CRITICAL_SECTION(usis);vApplicationMallocFailedHook();}#elif defined(configHARD_STOP_ON_MALLOC_FAILURE)// If you want to alert debugger or halt...// WARNING: brkpt instruction may prevent watchdog operation...while(1) { __asm("bkpt #0"); }; // Stop in GUI as if at a breakpoint (if debugging, otherwise loop forever)#else// Default, if you prefer to believe your application will gracefully trap out-of-memory...pReent->_errno = ENOMEM; // newlib's thread-specific errnoDRN_EXIT_CRITICAL_SECTION(usis);#endifreturn (char *)-1; // the malloc-family routine that called sbrk will return 0}// 'incr' of memory is available: update accounting and return it.currentHeapEnd += incr;heapBytesRemaining -= incr;#ifndef NDEBUGtotalBytesProvidedBySBRK += incr;#endifDRN_EXIT_CRITICAL_SECTION(usis);return (char *) previousHeapEnd;
}
//! non-reentrant sbrk uses is actually reentrant by using current context
// ... because the current _reent structure is pointed to by global _impure_ptr
char * sbrk(int incr) { return _sbrk_r(_impure_ptr, incr); }
//! _sbrk is a synonym for sbrk.
char * _sbrk(int incr) { return sbrk(incr); };#ifdef MALLOCS_INSIDE_ISRs// block interrupts during free-storage usestatic UBaseType_t malLock_uxSavedInterruptStatus;
#endif
void __malloc_lock(struct _reent *r)     {#if defined(MALLOCS_INSIDE_ISRs)DRN_ENTER_CRITICAL_SECTION(malLock_uxSavedInterruptStatus);#elsebool insideAnISR = xPortIsInsideInterrupt();configASSERT( !insideAnISR ); // Make damn sure no more mallocs inside ISRs!!vTaskSuspendAll();#endif
};
void __malloc_unlock(struct _reent *r)   {#if defined(MALLOCS_INSIDE_ISRs)DRN_EXIT_CRITICAL_SECTION(malLock_uxSavedInterruptStatus);#else(void)xTaskResumeAll();#endif
};// newlib also requires implementing locks for the application's environment memory space,
// accessed by newlib's setenv() and getenv() functions.
// As these are trivial functions, momentarily suspend task switching (rather than semaphore).
// ToDo: Move __env_lock/unlock to a separate newlib helper file.
void __env_lock()    {       vTaskSuspendAll(); };
void __env_unlock()  { (void)xTaskResumeAll();  };#if 1// Provide malloc debug and accounting wrappers/// /brief  Wrap malloc/malloc_r to help debug who requests memory and why./// To use these, add linker options: -Xlinker --wrap=malloc -Xlinker --wrap=_malloc_r// Note: These functions are normally unused and stripped by linker.int TotalMallocdBytes;int MallocCallCnt;static bool inside_malloc;void *__wrap_malloc(size_t nbytes) {extern void * __real_malloc(size_t nbytes);MallocCallCnt++;TotalMallocdBytes += nbytes;inside_malloc = true;void *p = __real_malloc(nbytes); // will call malloc_r...inside_malloc = false;return p;};void *__wrap__malloc_r(void *reent, size_t nbytes) {extern void * __real__malloc_r(size_t nbytes);if(!inside_malloc) {MallocCallCnt++;TotalMallocdBytes += nbytes;};void *p = __real__malloc_r(nbytes);return p;};
#endif// ================================================================================================
// Implement FreeRTOS's memory API using newlib-provided malloc family.
// ================================================================================================void *pvPortMalloc( size_t xSize ) PRIVILEGED_FUNCTION {void *p = malloc(xSize);return p;
}
void vPortFree( void *pv ) PRIVILEGED_FUNCTION {free(pv);
};size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION {struct mallinfo mi = mallinfo(); // available space now managed by newlibreturn mi.fordblks + heapBytesRemaining; // plus space not yet handed to newlib by sbrk
}// GetMinimumEverFree is not available in newlib's malloc implementation.
// So, no implementation is provided: size_t xPortGetMinimumEverFreeHeapSize( void ) PRIVILEGED_FUNCTION;//! No implementation needed, but stub provided in case application already calls vPortInitialiseBlocks
void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION {};

【stm32】stm32cubeIDE在freeRTOS无法printf float 浮点数相关推荐

  1. float浮点数的四舍五入

    瑞生网http://www.rationmcu.com版权所有 前几天,有个小伙伴在做实验过程中,发现了一个奇怪的现象,这个现象就是- 他在用printf输出浮点数的时候,想把数据保留到小数点后的两位 ...

  2. 基于在STM32下完成FreeRTOS的多任务程序开发,多任务串口以及AHT20封装库,原理图,PCB图以及AHT20(实际用到的是LMT70)及采集一次温度数据的模块实战

    基于在STM32下完成FreeRTOS的多任务程序开发,多任务串口以及AHT20封装库,原理图,PCB图以及AHT20(实际用到的是LMT70)及采集一次温度数据的模块实战 序 言 1)FreeRTO ...

  3. int输出%f浮点值是0,double/float 浮点数%d输出0的原因

    #include <cstdio> using namespace std; int main() {int a = 3;printf("int a print float : ...

  4. STM32CUBEIDE(6)----printf打印配置

    STM32CUBEIDE.6----printf打印配置 概述 样品申请 视频教学 csdn付费课程 生成例程 STM32CUBEIDE配置 串口重定向 打印测试 结果 最后 概述 本章STM32CU ...

  5. Float浮点数的使用和条件

    在这里简单的说一下,我对浮点数的理解,可能说的比较浅,老师也没有说,只是略微的提了一下,完全是我自己个人的理解. 我觉得float浮点数的用法和int的用法有些雷同,浮点数用于计算小数点单位,我们先可 ...

  6. php比较float大小,PHP中两个float(浮点数)比较实例分析

    本文实例讲述了PHP中两个float(浮点数)比较方法.分享给大家供大家参考.具体如下: 最近在开发一个合同管理系统的时候,涉及到两个浮点数比较,算是把我郁闷惨了. 在N久以前,就不晓得从哪里听来的一 ...

  7. STM32串口通信中使用printf发送数据配置方法 开发环境 Keil

    STM32串口通信中使用printf发送数据配置方法(开发环境 Keil RVMDK) 已有 12456 次阅读2011-6-29 23:29 | 在STM32串口通信程序中使用printf发送数据, ...

  8. python float精度问题_Python之☞float浮点数精度问题

    (下面是精度漏洞的问题-转自其它) 从下面这段脚本体现出来: >>> x = 0.0 >>> for i in range(10): x += 0.1 print( ...

  9. STM32 F107VC移植freeRTOS

    一.写在前面 网络上有很多freeRTOS移植到STM32平台上的文章.尤其是对于新手来说,如果没有一个完整的示例,讲的再多,也是一头雾水.我参考了技术大牛strongerHuang的canopen系 ...

最新文章

  1. HABBY CEO王嗣恩:这个下载量近20亿的爆款,曾被我推翻重做两次
  2. 亿佰特WiFi无线通信模块在物联网智慧农场应用案例
  3. SQL server 2008下载+安装详细
  4. [css] 使用css实现对话气泡的效果
  5. python入门系列:函数
  6. 均方根误差有没有单位_mse均方误差是否有单位
  7. 【黑苹果】联想Lenovo ThinkPad E550+i55200U+macos10.13.x efi文件下载
  8. 【稀饭】react native 实战系列教程之热更新原理分析与实现
  9. android投屏功能开发,Android PC投屏功能实现的示例代码
  10. 显卡更新后重启计算机就没了,在windows10系统更新显卡后黑屏的解决方法
  11. uni-app运行到微信开发工具无法预览
  12. ubuntu看不了bilibili视频
  13. 橙狮Scratch编程
  14. caffe配置 一生不可自决
  15. 数据中心网络机房动力环境监控解决方案
  16. Spring Cloud (Eureka,Feign,Hystrix整合)
  17. matlab数学建模-神经网络经典应用:逼近非线性函数
  18. Windows11 WSL2 ubuntu中vscode调试代码
  19. 关于模拟信号,数字信号,电磁波,基带传输的一点点感悟
  20. 图像处理-特征融合:相加、拼接、Attention

热门文章

  1. Ubuntu下系统重启dns就被清空的解决方案
  2. TCP收到RST的几种情况
  3. 分位数回归的r语言代码
  4. 手把手教你写一个生成yapi接口代码Chrome 扩展插件
  5. VM15.5.0+Ubuntu16.04.6+ns2.35仿真平台
  6. Electron入门教程1 —— 编写第一个桌面应用程序
  7. 2019/01/21 一位前端实习生 艰辛过程 励志 实习周记(四)——第四 五周
  8. 宝塔面板子目录伪静态设置
  9. 驻极体麦克前置放大器
  10. Kuberntes部署MetalLB负载均衡器