两只袜子 发表于 2023-4-6 10:21

基于STM32CubeIDE的C库经验分享

一、stm32的C库
      cubeIDE针对STM32芯片开发,提供个了两大库,HLA库和C库(集成GNU Tools for STM32工具链时提供,该工具链同样是意法半导体提供),前者帮助开发这简化与硬件交互,后者帮助开发者简化底层软逻辑实现。CubeIDE已经通过插件形式将GNU Tools for STM32工具链内嵌在该开发平台的插件集中,它主要包含两大内容,一部分涉及编译相关的make、gcc及平台特性等,另一部分就是开发应用软件密切相关的newlib库(即c库)。

      因为在符合POSIX.1标准(也称为IEEE 1003.1)的系统上使用C库,C库依赖于操作系统服务的少量必要函数调用,这些必要函数中的大多数都是随操作系统提供的。若开发者基于cubeIDE开发STM32应用时,如果不加入第三方嵌入式系统时,相当于在为“裸板”系统开发软件,没有操作系统,就必须自行提供一些必须的依赖函数(子例程)。因此,当基于cubeIDE创建STM32工程时,开发平台就直接帮开发者把newlib库的调用加入输出代码中,其中syscalls.c就是已经最小化地提供不做任何操作的必要函数定义或具有最小功能的子例程。

https://shequ.stmicroelectronics.cn/data/attachment/forum/202304/04/232236lstlu8tttwusjt8f.png


      同时在程序启动文件startup_stm32*.s汇编文件中,调用了c库。

https://shequ.stmicroelectronics.cn/data/attachment/forum/202304/04/232236b356noa2oo1o5jnj.png


          CubeIDE通过集成arm-none-eabi交叉编译工具包将 C库加入STM32工程,该c库包含:
as(assembler ,汇编器)子库,用于汇编编译;
BFD(Binary File Descriptor Library)子库,用于处理目标文件,像as、ld、binutils等都依赖它间接出来文件;
libc(standard ANSI C library,基于Red Hat newlib C Library)子库;
gdb子库,用于调试。
stabs(symbol table strings)子库;
ld(GNU linker)子库,用于链接功能。
libm(C Math Library)子库,用于计算,主要是通用计算。
refcard 子库,涉及GDB相关的启停、断点监测、信号捕获、标识列表、调试脚本、调试输出、调试控制等。
ibiberty(library of free software)子库,主要是实现了一些函数的接口或者宏,用于补充、替换、优化、扩展c实现。
gprof子库,用于性能检测分析工具;
binutils( gnu Binary Utilities)子库,用于各种命令工具集;
gcc子库,用于gcc编译、部署、运行相关。
      其中,在STM32应用开发编程中涉及对c库调整的主要是libc库,该库主要包含 stdlib、stdio、ctype、string、wchar、 signal、time、locale、arglist、Protection以及前面例程组件的重写部分及其他特定例程。

二、stm32的c库重载函数调整
      CubeIDE在创建工程是输出syscalls.c源码,已经将c库在stm32MCU上运行的依赖的必要函数例程做了定义,但是都是没有具体内柔的伪实现。

      正如本专栏前面提到的将printf函数输出映射到lpuart1串口上,就是改写了syscalls.c中_write函数来实现的。在libc的printf源码中,printf接受一系列参数,从*format向每个参数应用一个格式说明符,并将格式化数据写入stdout。在不修改libc库基础上,调整_write写入到“stdout”替换成lpuart1,就可以实现printf输出内容到串口上。

      syscalls.c中的_write如下,该函数还是弱定义(_weak):

https://shequ.stmicroelectronics.cn/data/attachment/forum/202304/04/232235z1cg1eq4n27gereg.png

         例如可以调整为
[*]__attribute__((weak)) int _write(int file, char *ptr, int len)
[*]{
[*]      int DataIdx;
[*]
[*]      for (DataIdx = 0; DataIdx < len; DataIdx++)
[*]      {
[*]                //__io_putchar(*ptr++);
[*]      HAL_UART_Transmit(&lpuart1,ptr++, 1, HAL_MAX_DELAY);
[*]      }
[*]      return len;
[*]}

复制代码

      更近一步,如前面博文提到的,可以程序开始前先指定printf需要映射的实例句柄,将整个写入内容直接转发到串口实例上。

[*]UART_HandleTypeDef *gHuart;
[*]void ResetPrintInit(UART_HandleTypeDef *huart){
[*]gHuart = huart;
[*]/* Disable I/O buffering for STDOUTstream, so that
[*]   * chars are sent out as soon as they areprinted. */
[*]setvbuf(stdout, NULL, _IONBF, 0);
[*]}
[*]
[*]int _write(int fd, char* ptr, int len) {
[*]HAL_StatusTypeDef hstatus;
[*]if (fd == STDOUT_FILENO || fd ==STDERR_FILENO) {
[*]    hstatus = HAL_UART_Transmit(gHuart,(uint8_t *) ptr, len, HAL_MAX_DELAY);
[*]    if (hstatus == HAL_OK)
[*]      return len;
[*]    else
[*]      return EIO;
[*]}
[*]errno = EBADF;
[*]return -1;
[*]}

复制代码

      依据libc的移植说明,printf需要这些函数:close、fstat、isatty、lseek、read、sbrk、write支持,因此在STM32上实现printf函数,需要提供这些函数的定义(可以是伪定义、空定义或实际内容)。在实际应用中,先将映射指向串口,在调用printf函数就可以实现打印输出到指向串口,而非libc原来的stdout。

[*]ResetPrintInit(&hlpuart1);
[*]...
[*]printf("123\r\n");

复制代码

      类似printf,以下功能函数也可以根据实际项目需要调整其输出指向来实现:
fprintf与printf类似,只是输出指向流fd而不是stdout。
sprintf与printf类似,只是输出指向缓冲区str,并输出终止NUL,注意生成的输出不要超过缓冲区所能容纳的输出。
snprintf与sprintf类似,不同的是输出最多限制为字节大小,包括终止的NUL。
asprintf与sprintf类似,只是输出存储在动态分配的缓冲区pstr中,稍后应使用free释放该缓冲区。
asnprintf类似于sprintf,不同的是返回类型是原始str(如果它足够大),或者是动态分配的字符串(注意输出超过*size情况)。

      又如syscalls.c中和时间相关的_times函数,该函数是clock计时函数所需要,通过改写该函数,将其与STM32的systick关联,实现到STM32的迁移使用。

https://shequ.stmicroelectronics.cn/data/attachment/forum/202304/04/232236ptrru7i3v9vjz3x7.png

         在STM32工程中,调用clock函数时,就会进入子例程调用_times函数,通过改写_times函数,就间接地调整了clock函数,例如:

[*]int _times(struct tms *buf)
[*]{
[*]    uint32_t ct = HAL_GetTick();
[*]      return (int)ct/1000;
[*]}

复制代码

      更多关于libc库里各个功能函数依赖那些子例程函数,可以通过查找自己CubeIDE开发平台的GNU Tools for STM32工具包目录,

https://shequ.stmicroelectronics.cn/data/attachment/forum/202304/04/232236id5do6vozadouqh2.png

         进入该目录,找到pdf/libc.pdf说明文档查看,该文档会具体指出各个功能函数依赖那些子例程函数以及使用注意事项和迁移注意事项。

https://shequ.stmicroelectronics.cn/data/attachment/forum/202304/04/232236c00hp4x0nl749h69.png

updownq 发表于 2023-4-13 15:44

使用STM32 CubeIDE开发STM32系列芯片的优点是它可以提供很好的代码开发工具,同时还可以进行代码调试

zerorobert 发表于 2023-4-13 20:26

免费的多功能STM32开发工具:STM32CubeIDE。

uiint 发表于 2023-4-13 20:33

CubeIDE 嵌入式开发应用是很广泛

hudi008 发表于 2023-4-13 21:10

导入stm32cubeide工程失败怎么回事 ?

linfelix 发表于 2023-4-13 21:18

STM32CubeIDE还具有标准和高级调试功能,其中包括CPU内核寄存器、存储器和外设寄存器以及实时变量查看、串行线传输监测器接口或故障分析器的视图。

abotomson 发表于 2023-4-13 21:32

Linux下怎样搭建stm32开发环境

loutin 发表于 2023-4-13 22:10

用什么软件编程最方便呢
            

jonas222 发表于 2023-4-18 10:36

将STM32CubeMX集成在一起了吗

cemaj 发表于 2023-4-18 10:48

stm32cubeide中hex文件老是生不成是怎么回事

chenci2013 发表于 2023-4-18 10:59

stm32cubeide编译界面不见了怎么调

fengm 发表于 2023-4-18 11:32

STM32CubeIDE支持多种STM32芯片系列,包括F0、F1、F2、F3、F4、F7、G0、G4、H7等等。

minzisc 发表于 2023-4-18 13:41

嵌入式新手学寄存器还是库函数?            

youtome 发表于 2023-4-18 14:16

STM32CubeIDE是免费的吗

youtome 发表于 2023-4-18 16:17

下载STM32CubeIDE而不是STM32CubeMX?

pixhw 发表于 2023-4-18 17:54

使用芯片厂家的IDE比自己用Eclipse+GCC搭建的环境方便。

uptown 发表于 2023-4-18 18:43

STM32CubeIDE提供了丰富的库和例程,可以快速开发各种类型的STM32应用程序。

phoenixwhite 发表于 2023-4-18 19:48

STM32CubeMX和STM32CubeIDE是STM32Cube 生态系统的两个核心软件。

jtracy3 发表于 2023-4-18 20:16

stm32cube工程目录区怎么弄出来

qiufengsd 发表于 2023-4-18 20:53

STM32CubeIDE是一款由STMicroelectronics官方推出的集成开发环境(IDE),用于开发基于STM32微控制器的嵌入式应用程序。
页: [1] 2 3 4
查看完整版本: 基于STM32CubeIDE的C库经验分享