如果你只是对 Semihosting 偶有耳闻,那么你与楼上那位多半也是难兄难弟了。 想要深入了解 Semihosting,我们还得从它的名字说起。 【什么是Semihosting】 虽然说很多情况下谜底往往会直接贴脸写在谜面上,但 Semihosting 对非英文母语的国人来说,其实跟两眼一抹黑没有区别,更别提它还拥有一个极具嘲讽意味的中文翻译:“ 如下图所示——一个完整的Semihosting链路需要至少三个部分组成: 支持Semihosting的上位机程序 调试仿真器(Debugger Adapter) 支持Semihosting的MCU运行时库 【病理特性】嵌入式程序在调用支持Semihosting的本地运行库时,被调用的API会执行特定的指令(Cortex-M中是BKPT指令)来触发Semihosting调用。 6 依赖的一个函数 _sys_exit() 原本是用Semihosting方式默认提供的,现在你把 Semihosting 关闭了,就要负责到底。
如何关闭 Semihosting 你有没有遇到过这样神奇的情景:在调试模式下,程序可以正常运行;一旦退出调试模式,系统就死机了,重新进入调试模式后,发现系统进入了Hardfault。 恭喜你,这很可能就是(默认开启的)semihosting 在作怪。关于Semihosting的内容,篇幅过大,不在本文讨论之列。今天我们只介绍一下如何关闭它。 __use_no_semihosting"); #elif __IS_COMPILER_ARM_COMPILER_5__ #pragma import(__use_no_semihosting ) #endif 一旦关闭了 Semihosting,Arm Compiler 6 就可能会报告类似如下的错误: Error: L6915E: Library reports error: __use_no_semihosting 方式默认提供的,现在你把 Semihosting 关闭了,所以你要负责到底。
char *const argv[]) { } #endif 在arch/arm/include/asm/spl.h的BOOT DEVICE枚举中添加对semihosting 的支持 enum { … BOOT_DEVICE_SEMIHOSTING, BOOT_DEVICE_NONE }; 在common/spl/ 目录下添加文件spl_semihosting.c,并添加以下内容: #include <image.h> #include <spl.h> extern int smh_load_file(const uboot_load_addr; spl_image->os = IH_OS_U_BOOT; return 0; } SPL_LOAD_IMAGE_METHOD("SEMIHOSTING ", 0, BOOT_DEVICE_SEMIHOSTING, spl_sh_load_image);
5 extension, and is not supported by ARM Compiler 6 [-Warmcc-pragma-import] #pragma import(__use_no_semihosting ) 解决: #pragma import(__use_no_semihosting) //标准库需要的支持函数 struct __ ) for debugging, no file handling */ /* is required. */ }; 替换为: __ASM (".global __use_no_semihosting
,所以直接使用标准库会导致程序无法运行,因此必须提前告知编译器不使用半主机模式: 不使用半主机模式 /* 告知连接器不从C库链接使用半主机的函数 */ #pragma import(__use_no_semihosting 所以,重定向fputc()函数完整的代码如下: #if 1 #include <stdio.h> /* 告知连接器不从C库链接使用半主机的函数 */ #pragma import(__use_no_semihosting
com); nvic_irq_enable(USART0_IRQn, 3, 3); } 需要特别说明的是:如果需要串口支持printf,需要重新实现fputc函数并关闭半主机模式(semihosting ),代码如下: STM派: #ifdef USING_PRINTF #define PRINTF_UART USART1 #pragma import(__use_no_semihosting) return ch; } #endif 非STM派: #ifdef USING_PRINTF #define PRINTF_UART USART0 #pragma import(__use_no_semihosting
有三种实现方法: // 方法一: 1、usart3.c #if 1 #pragma import(__use_no_semihosting) //标准库需要的支持函数 struct __FILE {
USART0_IRQn, 3); } 串口打印重定向printf,没有用MicroLiB: #define PRINTF_UART USART0 __ASM (".global __use_no_semihosting
尤其是在一些安全芯片上,由于没法进行实时仿真,串口打印成了非常简便且有效定位bug的手段,直接看代码: #include "stdio.h" #if 1 #pragma import(__use_no_semihosting
} 支持printf,这个demo里面也能找到: #ifdef USING_PRINTF #define PRINTF_UART USART1 #pragma import(__use_no_semihosting
#pragma import(__use_no_semihosting) //标准库需要的支持函数 struct __FILE { int handle; }; FILE __stdout;
stm32f10x.h" // Device header #include "Usart.h" //关闭ARM的半主机模式 #pragma import(__use_no_semihosting_swi
} return len; } #else /* 告知连接器不从C库链接使用半主机的函数 */ #pragma import(__use_no_semihosting
usart.h" //使UASRT串口可用printf函数发送 //在usart.h文件里可更换使用printf函数的串口号 #if 1 #pragma import(__use_no_semihosting
verbose --board STM32F429I-Discovery --mcu STM32F429ZI -d unimp,guest_errors --image hello_rtos.elf --semihosting-config
代码段 16.3.5 可选添加内容(driver_usart.c) /* * 添加如下代码,可不在工程设置中勾选 Use MicroLIB */ #pragma import(__use_no_semihosting
或者你没有开启 microLib,则会看到一个不同的错误: 即: Error: L6915E: Library reports error: The semihosting __user_initial_stackheap
It combines the advantages of SWO and semihosting at very high performance. perf_counter 该库利用 SysTick
#if 1 #pragma import(__use_no_semihosting) //标准库需要的支持函数 struct __FILE
或者你没有开启 microLib,则会看到一个不同的错误: 即: Error: L6915E: Library reports error: The semihosting __user_initial_stackheap