STM32程序不运行与MicroLIB讲解

成就更好的自己


目录

引言

什么是MicroLIB

不使用Microlib导致卡死的原理

卡死解决办法:

优化空间测评


引言

先说问题,这几天在使用STM32H750调试程序的过程中出现了一些问题,博主使用下载用CubeMX初始化好的程序后,程序不执行,表现为以下几个状态:

  • 简单的点灯程序不运行;
  • 程序均可通过各种方式(DAP,STLINK,JLINK,UART,USB)下载成功,也可以进行Keil的硬件在环Debug;
  • 所有GPIO引脚高阻态,对地电压1.5V左右;
  • Keil的硬件在环Debug可以进行,并不会提示找不到连接,但是Debug界面开始调试时并不是通常那样开始就是自己写的代码,而是一个.s启动文件,而且在单步执行后,调试进度卡死;
  • BOOT0与RESET引脚电平正常;
  • 通过FireDAP与STM32CubeProgram可以读取到片内Flash程序并且与文件校验一致;
  • 通过STM32CubeProgram读取到芯片并没有被锁死;
  • 例程可以运行且调试正常;

 

看到这里的朋友不知道能不能猜出问题在哪,综上所述已经能完全排除芯片问题,下载器问题,经过长时间的工程文件对比后,发现了一个极不起眼的小问题;

Use MicroLIB没有被勾选,然后勾上程序就TM运行了。

问题是解决了,但是不能这么死的不明不白,于是深入了解并学习一下MicroLIB。

 

什么是MicroLIB

来自ARM-MDK官网的解释:

MicroLib 是一个高度优化的库,适用于用 C 编写的基于 ARM 的嵌入式应用程序。与 ARM 编译器工具链中包含的标准 C 库相比,MicroLib 提供了许多嵌入式系统所需的显着代码大小优势。

MicroLib 和标准 C 库之间的主要区别是:

  • MicroLib 专为深度嵌入式应用而设计。
  • MicroLib 经过优化,可以使用比使用 ARM 标准库更少的代码和数据存储器。
  • MicroLib 设计为无需操作系统即可工作,但这并不妨碍它与任何操作系统或 RTOS(例如 Keil RTX)一起使用。
  • MicroLib 不包含文件 I/O 或宽字符支持。
  • 由于 MicroLib 已经过优化以最小化代码大小,因此某些函数的执行速度将比 ARM 编译工具中可用的标准 C 库例程更慢。
  • MicroLib 和 ARM 标准库都包含在 Keil MDK-ARM 中。
  • 有关更多详细信息,请参阅与默认 C 库的差异。

 

详细参考网址:https://www.keil.com/arm/microlib.asp

说这么多也没有什么实质作用,网上大多数资料也没有说到点子上,我结合实际开发总结一下真正跟咱们有关系:

  • 使用MicroLIB,简化嵌入式开发操作,例如你用printf()函数的时候,就会从串口1输出字符串,当然也可以重定义到其他串口;
  • 使用MicroLIB会优化代码空间,但会降低某些程序的执行效率(比如: memcpy()),效率换空间;
  • 由于MicroLIB不支持浮点运算,所以在有FPU单元的MCU上,使用MicroLIB并开启FPU会让程序死机或跑飞。
  • Microlib不支持C++,在使用C++开发MCU时,首要条件是不能使用Microlib;

 

不使用Microlib导致卡死的原理

在使用CubeMX初始化代码时,生成的工程默认是使用Microlib的,正常情况下,在STM32CubeMX通过成的.s文件里可以看到一个__main函数,这个就是microlib的入口地址,他会完成创建栈空间,创建堆空间,初始化用户可能用到的系统库等初始化动作,最后跳转到我们熟悉的main,当使用Microlib时,__main链接的是Microlib,当不使用Microlib时,__main链接的是标准库的C/C++;

至此,还并没有出现什么问题,但是,一旦在程序中调用printf等函数时,会让MCU进入半主机模式,进而程序会在__main位置卡死,这也就是为什么程序正常编译正常烧录正常调试,但是运行不起来而且Debug卡死在__main位置的原因。

使用C标准库(stdio.h)中的函数,例如printf()之类的函数,会进入半主机模式,发生软件异常,会导致程序无法运行。半主机是这么一种机制,它使得在ARM目标上跑的代码,如果主机电脑运行了调试器,那么该代码可以使用该主机电脑的输入输出设备。 这点非常重要,因为开发初期,可能开发者根本不知道该 ARM 器件上有什么输入输出设备,而半主基机制使得你不用知道ARM器件的外设,利用主机电脑的外设就可以实现输入输出调试。 所以要利用目标 ARM器件的输入输出设备,首先要关掉半主机机制。然后再将输入输出重定向到 ARM 器件上。

 

卡死解决办法:

解决办法有两种,要么使用Microlib,要么关闭标准库下的半主机模式。

个人认为,后者更加好一点,原因如下:

  • 高度精简导致不支持很多很多东西,浮点运算,RTOS,内存分配等等都可能不好使。
  • 与标准库有很多繁琐区别;如果是夸平台迁移项目代码时,对于库和底层的适配性不好。
  • 精简的程序空间十分有限,没有必要为了空间整这么复杂。

关闭半主机模式的操作方式:

将以下代码添加到文件起始处;

/* 告知连接器不从C库链接使用半主机的函数 */

#pragma import(__use_no_semihosting)

/* 定义 _sys_exit() 以避免使用半主机模式 */

void _sys_exit(int x)

{

    x = x;

}

/* 标准库需要的支持类型 */

struct __FILE

{

    int handle;

};

FILE __stdout;

之后放心大胆的重定向printf即可使用。

优化空间测评

同一个程序不使用Microlib:

同一个程序使用Microlib:

可见,并没有什么优化大小

版权声明:本文为CSDN博主「The Road of Engineer」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_36098477/article/details/117666808

成就更好的自己


目录

引言

什么是MicroLIB

不使用Microlib导致卡死的原理

卡死解决办法:

优化空间测评


引言

先说问题,这几天在使用STM32H750调试程序的过程中出现了一些问题,博主使用下载用CubeMX初始化好的程序后,程序不执行,表现为以下几个状态:

  • 简单的点灯程序不运行;
  • 程序均可通过各种方式(DAP,STLINK,JLINK,UART,USB)下载成功,也可以进行Keil的硬件在环Debug;
  • 所有GPIO引脚高阻态,对地电压1.5V左右;
  • Keil的硬件在环Debug可以进行,并不会提示找不到连接,但是Debug界面开始调试时并不是通常那样开始就是自己写的代码,而是一个.s启动文件,而且在单步执行后,调试进度卡死;
  • BOOT0与RESET引脚电平正常;
  • 通过FireDAP与STM32CubeProgram可以读取到片内Flash程序并且与文件校验一致;
  • 通过STM32CubeProgram读取到芯片并没有被锁死;
  • 例程可以运行且调试正常;

 

看到这里的朋友不知道能不能猜出问题在哪,综上所述已经能完全排除芯片问题,下载器问题,经过长时间的工程文件对比后,发现了一个极不起眼的小问题;

Use MicroLIB没有被勾选,然后勾上程序就TM运行了。

问题是解决了,但是不能这么死的不明不白,于是深入了解并学习一下MicroLIB。

 

什么是MicroLIB

来自ARM-MDK官网的解释:

MicroLib 是一个高度优化的库,适用于用 C 编写的基于 ARM 的嵌入式应用程序。与 ARM 编译器工具链中包含的标准 C 库相比,MicroLib 提供了许多嵌入式系统所需的显着代码大小优势。

MicroLib 和标准 C 库之间的主要区别是:

  • MicroLib 专为深度嵌入式应用而设计。
  • MicroLib 经过优化,可以使用比使用 ARM 标准库更少的代码和数据存储器。
  • MicroLib 设计为无需操作系统即可工作,但这并不妨碍它与任何操作系统或 RTOS(例如 Keil RTX)一起使用。
  • MicroLib 不包含文件 I/O 或宽字符支持。
  • 由于 MicroLib 已经过优化以最小化代码大小,因此某些函数的执行速度将比 ARM 编译工具中可用的标准 C 库例程更慢。
  • MicroLib 和 ARM 标准库都包含在 Keil MDK-ARM 中。
  • 有关更多详细信息,请参阅与默认 C 库的差异。

 

详细参考网址:https://www.keil.com/arm/microlib.asp

说这么多也没有什么实质作用,网上大多数资料也没有说到点子上,我结合实际开发总结一下真正跟咱们有关系:

  • 使用MicroLIB,简化嵌入式开发操作,例如你用printf()函数的时候,就会从串口1输出字符串,当然也可以重定义到其他串口;
  • 使用MicroLIB会优化代码空间,但会降低某些程序的执行效率(比如: memcpy()),效率换空间;
  • 由于MicroLIB不支持浮点运算,所以在有FPU单元的MCU上,使用MicroLIB并开启FPU会让程序死机或跑飞。
  • Microlib不支持C++,在使用C++开发MCU时,首要条件是不能使用Microlib;

 

不使用Microlib导致卡死的原理

在使用CubeMX初始化代码时,生成的工程默认是使用Microlib的,正常情况下,在STM32CubeMX通过成的.s文件里可以看到一个__main函数,这个就是microlib的入口地址,他会完成创建栈空间,创建堆空间,初始化用户可能用到的系统库等初始化动作,最后跳转到我们熟悉的main,当使用Microlib时,__main链接的是Microlib,当不使用Microlib时,__main链接的是标准库的C/C++;

至此,还并没有出现什么问题,但是,一旦在程序中调用printf等函数时,会让MCU进入半主机模式,进而程序会在__main位置卡死,这也就是为什么程序正常编译正常烧录正常调试,但是运行不起来而且Debug卡死在__main位置的原因。

使用C标准库(stdio.h)中的函数,例如printf()之类的函数,会进入半主机模式,发生软件异常,会导致程序无法运行。半主机是这么一种机制,它使得在ARM目标上跑的代码,如果主机电脑运行了调试器,那么该代码可以使用该主机电脑的输入输出设备。 这点非常重要,因为开发初期,可能开发者根本不知道该 ARM 器件上有什么输入输出设备,而半主基机制使得你不用知道ARM器件的外设,利用主机电脑的外设就可以实现输入输出调试。 所以要利用目标 ARM器件的输入输出设备,首先要关掉半主机机制。然后再将输入输出重定向到 ARM 器件上。

 

卡死解决办法:

解决办法有两种,要么使用Microlib,要么关闭标准库下的半主机模式。

个人认为,后者更加好一点,原因如下:

  • 高度精简导致不支持很多很多东西,浮点运算,RTOS,内存分配等等都可能不好使。
  • 与标准库有很多繁琐区别;如果是夸平台迁移项目代码时,对于库和底层的适配性不好。
  • 精简的程序空间十分有限,没有必要为了空间整这么复杂。

关闭半主机模式的操作方式:

将以下代码添加到文件起始处;

/* 告知连接器不从C库链接使用半主机的函数 */

#pragma import(__use_no_semihosting)

/* 定义 _sys_exit() 以避免使用半主机模式 */

void _sys_exit(int x)

{

    x = x;

}

/* 标准库需要的支持类型 */

struct __FILE

{

    int handle;

};

FILE __stdout;

之后放心大胆的重定向printf即可使用。

优化空间测评

同一个程序不使用Microlib:

同一个程序使用Microlib:

可见,并没有什么优化大小

版权声明:本文为CSDN博主「The Road of Engineer」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_36098477/article/details/117666808

生成海报
点赞 0

The Road of Engineer

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

STM32程序不运行与MicroLIB讲解

成就更好的自己 目录 引言 什么是MicroLIB 不使用Microlib导致卡死的原理 卡死解决办法: 优化空间测评 引言 先说问题,这几天在使用STM32H750调试程序的过程中出现了一些问题&#xf