STM32F105RCT6 -- ST-Link ITM Trace printf 打印日志

news2024/10/6 18:34:49

1. STM32 可以配置UASRT,使用串口来打印日志,还有另外一种方式,使用ITM 调试功能来打印日志, 主要使用到的三个函数 core_cm3.h

1.1 发送函数 static __INLINE uint32_t ITM_SendChar(uint32_t ch),相当于串口的发送函数usart_send(), 将参数ch发送到keil 的日志打印窗口,一次只能发送一个字符,字符串需要排队发送,发送速度跟系统时钟主频相关,所以比串口要快很多很多

static __INLINE uint32_t ITM_SendChar(uint32_t ch)
{
    if ((CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk)  && // Trace enabled
        (ITM->TCR & ITM_TCR_ITMENA_Msk) && // ITM enabled
        (ITM->TER & (1ul << 0))) // ITM Port #0 enabled
    {
        while (ITM->PORT[0].u32 == 0);
        ITM->PORT[0].u8 = (uint8_t) ch;
    }
    return (ch);
}

1.2 接收函数 static __INLINE int ITM_ReceiveChar(void),第一次见在头文件中

static __INLINE int ITM_ReceiveChar(void)
{
    int ch = -1; /* no character available */

    if (ITM_RxBuffer != ITM_RXBUFFER_EMPTY)
    {
        ch = ITM_RxBuffer;
        ITM_RxBuffer = ITM_RXBUFFER_EMPTY; /* ready for next character */
    }

    return (ch);
}

1.3 检查标志位函数 static __INLINE int ITM_CheckChar(void), 相当于串口里面的传输完成中断标志位监测

static __INLINE int ITM_CheckChar(void)
{
    if (ITM_RxBuffer == ITM_RXBUFFER_EMPTY)
    {
        return (0); /* no character available */
    }
    else
    {
        return (1); /* character available */
    }
}

2. keil 配置,使用ST-Link 下载器调试, 点击Setting

在这里插入图片描述

3. 点击 Trace

在这里插入图片描述

4. Core Clock 与系统时钟主频相关,不同芯片主频会有差异,我的是STM32F105RCT6,系统时钟配置的是72Mhz

在这里插入图片描述

5. 代码配置,必须要包含系统头文件 #include <stdio.h> 不然会报错的

在这里插入图片描述

6. 我自己写了一个log.h 文件,专门用来管理日志打印的, 可以实现不同等级的日志打印,在华为搞蓝牙耳机项目的时候就是这样搞的,基本都会封装printf 函数,搞高通项目的时候也是,小公司可能就会搞这种操作了,直接就printf()

6.1 log.h

#ifndef __LOG_FILE_
#define __LOG_FILE_

#include <stdio.h>

#define USE_ITM_TRACE_DEBUG // set in keil magic wand -> Debug -> Setting -> Trace -> Trace Enable

// log level
#define ERROR_LEVEL    4
#define WARN_LEVEL    3
#define INFO_LEVEL    2
#define DEBUG_LEVEL    1

/*
 * current log level
 * error level: log only printf erro log
 * warn level: only printf warn and erro log
 * info level: only printf info, warn and error log
 * debug level: printf debug, info, warn and error
 */
#define CURRENT_LOG_LEVEL INFO_LEVEL

#if CURRENT_LOG_LEVEL <= DEBUG_LEVEL
    #define DEBUG_LOG(fmt, ...) printf("[DEBUG]" fmt, ##__VA_ARGS__)
#else
    #define DEBUG_LOG(fmt, ...)
#endif

#if CURRENT_LOG_LEVEL <= INFO_LEVEL
    #define INFO_LOG(fmt, ...) printf("[INFO]" fmt, ##__VA_ARGS__)
#else
    #define INFO_LOG(fmt, ...)
#endif

#if CURRENT_LOG_LEVEL <= WARN_LEVEL
    #define WARN_LOG(fmt, ...) printf("[WARN]" fmt, ##__VA_ARGS__)
#else
    #define WARN_LOG(fmt, ...)
#endif

#if CURRENT_LOG_LEVEL <= ERROR_LEVEL
    #define ERROR_LOG(fmt, ...) printf("[ERROR]" fmt, ##__VA_ARGS__)
#else
    #define ERROR_LOG(fmt, ...)
#endif

#endif // __LOG_FILE_

7. 我是在usart.c 里面配置软件支持ITM 调试功能的

7.1 usart.c 禁用半主机模式,这是很早以前的一种调试手段,开半主机模式的话会影响性能,所以后面ARM 就出台了ITM 功能,代替半主机模式

// when select ARMCC 5 compiler, need define __FILE and disable half host mode
#pragma import(__use_no_semihosting_swi) // 用软件中断的方式实现printf software interrupt

7.2 也可以写成

#pragma import(__use_no_semihosting) // 正点原子的例程就是这样写的

8. 定义文件IO 标准输入输出句柄

// support functions required for standard libraries
struct __FILE
{
    int handle;
    // Whatever you require here. If the only file you are using is standard output using printf() for debugging, no file handling is required
};

// FILE defined in <stdio.h>
FILE __stdout;
FILE __stdin;

9. 定义系统死循环退出

函数是一个模拟系统退出的函数。它接受一个整数类型的返回码作为参数,但实际上并没有执行任何系统退出的操作,而是通过一个无限循环来使程序陷入死循环状态。
这段代码通常被用于无嵌入式系统或者操作系统环境下的调试目的。通过将程序置于无限循环中,可以使程序停留在某个特定点,方便进行调试和观察程序行为。

void _sys_exit(int return_code)
{
label:
    goto label; // endless loop
}

10. 改写fputc 函数,printf 函数就是调用这个函数实现的打印日志的

int fgetc(FILE *f)
{
    while (ITM_CheckChar() != 1)
    {
        __NOP();
    }
    return (ITM_ReceiveChar());
}

11. 改写fgetc 函数,scanf 函数最终会调用这个函数

int fputc(int ch, FILE *f)
{
    return ITM_SendChar(ch);
}
#endif

12. 初始化接收buffer 为空

volatile int32_t ITM_RxBuffer = ITM_RXBUFFER_EMPTY;

13. 监测文件流是否发生错误,错误处理

int ferror(FILE   *f)
{
    // your implementation of ferror, handle error here

    return EOF;
}

14. 辅助函数,将字符输出到标准输出文件流中

void _ttywrch(int c)
{
    fputc(c, &__stdout);
}

15. 回退函数

int __backspace()
{
    return 0;
}

16. 将上面几行代码拷贝到文件你的.c 文件里面(main.c 或其它的.c 文件)

17. 在main函数里面写测试代码

int main(void)
{
	char c;
	printf("hello world");
	scanf("%c", &c);
	printf("hello world, %c\r\n", c);

	return 0;
}

18. 用我自己的测试代码debug, 点击小红d 进debug 模式

在这里插入图片描述

19. 进debug模式后,把keil 的日志窗口调出来 view -》 serial windows -》debug (printf) Viewer

在这里插入图片描述

20. 刚进debug 模式,停在main函数这里,按一下F5全速跑,日志就出来了

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/859774.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

锚框【目标检测】

生成多个锚框 假设输入图像高为h,宽为w,我们以图像每个像素为中心生成不同形状的锚框,缩放比 s∈(0,1],宽高比为r>0。那么锚框的宽度和高度分别为和。当中心位置给定时, 已知宽和高的锚框是确定的。缩放比为锚框高与图像高的比值,然后得到一个正方形锚框面积。 ​​…

pytest接口自动化测试框架搭建的全过程

目录 一. 背景 二. 基础环境 三. 项目结构 四、框架解析 pytest是Python的一种单元测试框架,可用来组织用例执行,用例断言,下面这篇文章主要给大家介绍了关于pytest接口自动化测试框架搭建的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下 一. 背景 Pyte…

sql高频面试题-连续完成两个指定动作的用户统计

用户行为分析 业务背景 某购物APP最近上线了一个新功能&#xff0c;用户签到后可以跳转到大转盘抽奖&#xff0c;抽奖获得的奖金可以抵消购物的费用&#xff0c;以此来培养用户使用app的习惯。 数据表介绍 现有一张用户行为表action_log&#xff0c;主要字段如下&#xff0c…

7天获英国名校邀请函|CSC青骨获批成功案例补记

Q老师要求2周内拿到邀请函且必须是世界排名前200名的高校。我们在第7天就获得了世界百强名校-英国兰卡斯特大学的邀请函&#xff0c;导师的研究方向完全契合&#xff0c;提前实现了Q老师的委托目标&#xff0c;使其顺利获批CSC青骨项目。特别提示&#xff1a;青骨项目国内派出院…

5. 服务发现

当主机较少时&#xff0c;在抓取配置中手动列出它们的IP地址和端口是常见的做法&#xff0c;但不适用于较大规模的集群。尤其不适用使用容器和基于云的实例的动态集群&#xff0c;这些实例经常会变化、创建或销毁的情况。 Prometheus通过使用服务发现解决了这个问题&#xff1…

测试人员该怎样写软件缺陷报告?

软件测试过程中&#xff0c;每个公司都制订了软件的缺陷处理流程&#xff0c;每个公司的软件缺陷处理流程不尽相同&#xff0c;但是它们遵循的最基本流程是一样的&#xff0c;都要经过提交、分配、确认、处理、复测、关闭等环节&#xff0c;如图1所示。 缺陷处理流程 关于图1所…

Linux:shell脚本:基础使用(3)

for循环语句 语句格式 for for变量 in 取值列表&#xff08;可以是变量或者自己定义&#xff09; do 循环内容 done 工作方式就是通过取值列表去判断循环的次数&#xff0c;每次循环的同时把列表一行的值赋予到for变量。取值方式如果是数字&#xff0c;那就通过数字去…

MySQL 索引 详解

一、索引概述 索引是帮助 MySQL 高效获取数据的数据结构&#xff08;有序&#xff09;。在数据之外&#xff0c;数据库系统还维护着满足特定查找算法的数据结构&#xff0c;这些数据结构以某种方式引用&#xff08;指向&#xff09;数据&#xff0c;这样就可以在这些数据结构上…

设计师常用的6款UI设计工具

在选择UI设计工具时&#xff0c;设计师需要关注UI设计工具的功能。市场上有很多设计UI的工具。既然UI设计工具这么多&#xff0c;设计师应该如何选择UI设计工具&#xff1f;本文盘点了6种流行的UI设计工具&#xff0c;快来看看。 1.即时设计 即时设计是一款免费的在线 UI 设计…

利用ChatGPT绘制思维导图——以新能源汽车竞品分析报告为例

随着人们对环境保护的日益关注和传统燃油汽车的限制&#xff0c;全球范围内对新能源汽车的需求不断增长。新能源汽车市场的激烈竞争使得了解各个竞品的特点和优劣成为关键。然而&#xff0c;针对这一领域的详尽竞品分析却常常需要大量时间和精力。 在此背景下&#xff0c;人工智…

行业追踪,2023-08-10

自动复盘 2023-08-10 凡所有相&#xff0c;皆是虚妄。若见诸相非相&#xff0c;即见如来。 k 线图是最好的老师&#xff0c;每天持续发布板块的rps排名&#xff0c;追踪板块&#xff0c;板块来开仓&#xff0c;板块去清仓&#xff0c;丢弃自以为是的想法&#xff0c;板块去留让…

maven Jar包反向install到本地仓库

maven Jar包反向install到本地仓库 需求实现 需求 项目打包时报错&#xff0c;缺少一个jar包。 但是在maven仓库都找不到此jar包&#xff0c;其他人提供了这个jar包。 需要把这个jar包install到本地仓库&#xff0c;使项目能正常打包运行。 实现 使用git bash命令执行以下脚…

qt5.15.2 使用mysql8.1

报错&#xff1a; QMYSQL driver not loaded 报错&#xff1a;无 QMYSQL 使用 QStringList drivers QSqlDatabase::drivers(); //获取现在可用的数据库驱动 foreach(QString driver, drivers) qDebug() << driver; “QSQLITE” “QMARIADB” “QMYSQL” “QMYSQL3” “…

UML-状态图

目录 状态图 状态图的图符 状态机 状态 ​转换 电话机状态图 活动图和状态图区别&#xff1a; 状态图 状态图(Statechart Diagram)是描述一个实体基于事件反应的动态行为&#xff0c;显示了该实体如何根据当前所处的状态对不同的事件做出反应。通常我们创建一个UML状态…

基于金融行业的软件测试分析

随着银行业务不断增加&#xff0c;业务模式不断复杂化&#xff0c;对我们的银行软件也要求越来越高&#xff0c;产出高质量的产品也非常重要&#xff0c;下面对银行软件测试进行分析总结。 银行软件集中度高&#xff0c;规模庞大&#xff0c;往往是以系统群的方式存在&#xff…

“去没有天花板的地方” | 小红书用户情绪数据

最近&#xff0c;话题#人就要待在没有天花板的地方#社媒讨论度居高不下&#xff0c;小红书相关话题近90天互动量超百万。 生活的无常之外&#xff0c;越来越多人渴望与大自然更深层次的链接&#xff0c;以此寻找情绪的不同出口。或许&#xff0c;剖析这些情绪的生成机理&#x…

全球飞机电磁阀总体规模分析

电磁阀是一种液压管路的电磁装置&#xff0c;通过使用电流产生磁场&#xff0c;从而驱动螺线管&#xff0c;控制阀中流体的流动。电磁阀作为流体控制自动化系统的执行器之一&#xff0c;有着结构紧凑、尺寸小、重量轻、密封良好、维修简便和可靠性高、节能降耗的特点&#xff0…

cpolar内网穿透的安装

群晖6.X安装cpolar内网穿透 文章目录 群晖6.X安装cpolar内网穿透前言1. 下载cpolar的群晖套件1.1 打开群晖套件中心1.2 选择“手动安装”1.3 选择下载cpolar套件位置 2. 打开cpolar的Web-UI界面3. 注册会员 前言 随着硬件设备和软件技术的发展&#xff0c;以及数据量的发福暴涨…

[低端局][cx32L003] 移植U8G2

文章目录 一、简介&#xff08;1&#xff09;U8g2&#xff08;2&#xff09;U8x8 二、配置要求三、移植步骤&#xff08;1&#xff09;文件准备和添加&#xff08;2&#xff09;实现回调接口(I2C的读写函数)①软件I2C②硬件I2C &#xff08;3&#xff09;功能裁剪① u8g2_d_set…

数据结构链表——单链表

数据结构链表——单链表 概念及结构单链表的实现结构体类型的定义和头文件接口函数打印链表创建新节点尾插头插尾删头删查找任意插入指定位置之前插入指定位置之后插入 指定位置删除指定位置后删除单链表空间的销毁 概念及结构 概念&#xff1a;链表是一种物理存储结构上非连续…