0. 概述
这是cherryusb代码trace分析系列文章之七。
RT-Thread串口驱动框架与FinSH Shell运行机制深度解析:针对STM32H750 ART-PI平台,本文独辟蹊径采用创新的代码trace分析方法,破解庞大串口框架下的复杂运行逻辑。通过精确trace日志与drv_usart_v2.c、dev_serial_v2.c、kservice.c等核心驱动源码的深度结合,系统揭示了从rt_hw_usart_init串口硬件初始化、rt_console_set_device控制台设备配置、rt_kprintf调试输出机制到FinSH Shell交互的全链路执行流程。
文章特别抓取了系统启动过程中7次rt_kprintf调用的轮询发送机制细节,深入剖析UART4中断处理与FinSH Shell的完整交互过程,包括rt_ringbuffer缓冲区管理、rt_completion同步机制、NVIC中断优先级配置等关键技术点。通过trace分析,完整呈现了FinSH Shell与串口通信的底层细节,精确捕获了所有关键中断处理流程和时序关系。
本文为工程师和嵌入式爱好者提供了宝贵的技术参考,帮助他们深入理解RT-Thread底层串口通信机制,并能够针对性修改代码以适应板载串口、USB CDC_ACM等不同接口需求。文档以实际trace数据为基础,结合精确的函数调用链分析,为RT-Thread串口驱动框架的定制化开发和问题定位提供了强有力的技术支撑。
1. 运行的输入与输出
- 我们的处理方法是, 首先在如下与串口驱动和finsh有关的c源文件上, 每个函数开头和关键节点处, 用my_printf和my_printf2进行trace record. 这些文件包括:
drv_usart_v2.c
dev_serial_v2.c
kservice.c
ringbuffer.c
device.c
shell.c - STM32H750 ART-PI平台的RT-Thread配置为最精简模式, 只保留串口, 其它都不开启
- 烧录板子后, 正常输出开机rt-thread的log, 然后运行一个命令"list device\r\n". 输出结果如下:
[0m[D/drv.sdram] sdram init success, mapped at 0xC0000000, size is 33554432 bytes, data width is 16[0m\ | /
- RT - Thread Operating System/ | \ 5.2.0 build Aug 3 2025 14:32:022006 - 2024 Copyright by RT-Thread team
msh >list device
device type ref count
-------- -------------------- ----------
uart4 Character Device 2
pin Pin Device 0
msh >
msh >
- 过10秒后, trace record记录完毕, 开始打印trace到的log. 这个case的完整log文件有1723行. 我们以附录的方式提供.
2. 运行过程流程图
2.1 rt_hw_usart_init的执行
- rt_hw_usart_init是drv_common.c中rt_hw_board_init函数中实现的
/*** This function will initial STM32 board.*/
rt_weak void rt_hw_board_init(void)
{
#ifdef BSP_SCB_ENABLE_I_CACHE/* Enable I-Cache---------------------------------------------------------*/SCB_EnableICache();
#endif#ifdef BSP_SCB_ENABLE_D_CACHE/* Enable D-Cache---------------------------------------------------------*/SCB_EnableDCache();
#endif/* HAL_Init() function is called at the beginning of the program */HAL_Init();/* System clock initialization */SystemClock_Config();#if defined(RT_USING_HEAP)/* Heap initialization */rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
#endif#ifdef RT_USING_PINrt_hw_pin_init();
#endif#ifdef RT_USING_SERIALrt_hw_usart_init();
#endif#if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE)/* Set the shell console output device */rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
#endif#if defined(RT_USING_CONSOLE) && defined(RT_USING_NANO)extern void rt_hw_console_init(void);rt_hw_console_init();
#endif#ifdef RT_USING_COMPONENTS_INIT/* Board underlying hardware initialization */rt_components_board_init();
#endif
}
- 经过对trace log分析的解读, rt_hw_usart_init的函数调用链如下所示
/*来自drv_common.c中的rt_hw_board_init*/
/*
rt_hw_usart_init|-> stm32_uart_get_config|-> rt_hw_serial_register-> rt_device_register-> rt_device_find
*/
- trace到的运行log如下
drv_usart_v2.c :1380| rt_hw_usart_init
drv_usart_v2.c :1384| rt_hw_usart_init go=> stm32_uart_get_config
drv_usart_v2.c :972 | stm32_uart_get_config
drv_usart_v2.c :1392| rt_hw_usart_init go=> rt_hw_serial_register
dev_serial_v2.c :1543| rt_hw_serial_register
dev_serial_v2.c :1567| rt_hw_serial_register go=> rt_device_register
device.c :72 | rt_device_register
device.c :73 | rt_device_register uart4
device.c :74 | rt_device_register 3(0x00000003) <= flags
device.c :78 | rt_device_register go=> rt_device_find
device.c :130 | rt_device_find
device.c :131 | rt_device_find uart4
2.2 rt_console_set_device的执行(为了实现rt_kprintf)
- rt_console_set_device是drv_common.c中rt_hw_board_init函数中实现的, 上面已经列出来了. 这个函数主要是为了实现rt_kprintf, 在系统调度没有启动之前就能运行, 打印系统初始化过程日志.
- 经过对trace log分析的解读, rt_console_set_device的函数调用链如下所示
/*来自drv_common.c中的rt_hw_board_init*/
/*
rt_console_set_device|-> rt_device_find|-> rt_device_open|-> device_init->rt_serial_init->stm32_configure->HAL_UART_Init|-> device_open->rt_serial_open->rt_serial_rx_enable|-> rt_ringbuffer_init|-> stm32_control-> stm32_control-> NVIC_EnableIRQ|->rt_serial_tx_enable|-> stm32_control|-> rt_ringbuffer_init|-> rt_completion_init
*/
- trace到的运行log如下
kservice.c :192 | rt_console_set_device
kservice.c :194 | rt_console_set_device go=> rt_device_find
device.c :130 | rt_device_find
device.c :131 | rt_device_find uart4
kservice.c :207 | rt_console_set_device go=> rt_device_open
device.c :235 | rt_device_open
device.c :236 | rt_device_open uart4
/*rt_console_set_device用0x43打开uart4*/
/*oflag=0x43=> RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_STREAM*/
device.c :237 | rt_device_open 67(0x00000043) <= oflag
device.c :249 | rt_device_open go=> device_init
dev_serial_v2.c :979 | rt_serial_init
drv_usart_v2.c :120 | stm32_configure
drv_usart_v2.c :197 | stm32_configure go=> HAL_UART_Init
device.c :276 | rt_device_open go=> device_open
dev_serial_v2.c :1006| rt_serial_open
dev_serial_v2.c :1007| rt_serial_open 67(0x00000043) <= oflag
dev_serial_v2.c :1043| rt_serial_open go=> rt_serial_rx_enable
dev_serial_v2.c :800 | rt_serial_rx_enable
dev_serial_v2.c :801 | rt_serial_rx_enable 8192(0x00002000) <= rx_oflag
dev_serial_v2.c :833 | rt_serial_rx_enable go=> rt_ringbuffer_init
ringbuffer.c :43 | rt_ringbuffer_init
ringbuffer.c :44 | rt_ringbuffer_init 256(0x00000100) <= size
dev_serial_v2.c :846 | rt_serial_rx_enable go=> serial->ops->control
drv_usart_v2.c :208 | stm32_control
drv_usart_v2.c :209 | stm32_control 3(0x00000003) <= cmd/*CONFIG*/
drv_usart_v2.c :213 | stm32_control 8192(0x00002000) <= ctrl_arg/*RT_DEVICE_FLAG_RX_NON_BLOCKING*/
drv_usart_v2.c :232 | stm32_control 256(0x00000100) <= ctrl_arg/*RT_DEVICE_FLAG_INT_RX*/
drv_usart_v2.c :293 | stm32_control cmd: RT_DEVICE_CTRL_CONFIG
drv_usart_v2.c :304 | stm32_control go=> stm32_control
drv_usart_v2.c :208 | stm32_control
drv_usart_v2.c :209 | stm32_control 6(0x00000006) <= cmd/*SET_INT*/
drv_usart_v2.c :213 | stm32_control 256(0x00000100) <= ctrl_arg
drv_usart_v2.c :232 | stm32_control 256(0x00000100) <= ctrl_arg
drv_usart_v2.c :280 | stm32_control cmd: RT_DEVICE_CTRL_SET_INT
drv_usart_v2.c :281 | stm32_control go=> HAL_NVIC_SetPriority
drv_usart_v2.c :283 | stm32_control go=> NVIC_EnableIRQ
dev_serial_v2.c :1051| rt_serial_open go=> rt_serial_tx_enable
dev_serial_v2.c :672 | rt_serial_tx_enable
dev_serial_v2.c :673 | rt_serial_tx_enable 16384(0x00004000) <= tx_oflag
dev_serial_v2.c :707 | rt_serial_tx_enable go=> serial->ops->control
drv_usart_v2.c :208 | stm32_control
drv_usart_v2.c :209 | stm32_control 32(0x00000020) <= cmd/*RT_DEVICE_CHECK_OPTMODE*/
drv_usart_v2.c :213 | stm32_control 16384(0x00004000) <= ctrl_arg/*RT_DEVICE_FLAG_TX_BLOCKING*/
drv_usart_v2.c :232 | stm32_control 1024(0x00000400) <= ctrl_arg/*RT_DEVICE_FLAG_INT_TX*/
drv_usart_v2.c :310 | stm32_control cmd: RT_DEVICE_CHECK_OPTMODE
dev_serial_v2.c :718 | rt_serial_tx_enable go=> rt_ringbuffer_init
ringbuffer.c :43 | rt_ringbuffer_init
ringbuffer.c :44 | rt_ringbuffer_init 256(0x00000100) <= size
dev_serial_v2.c :755 | rt_serial_tx_enable go=> rt_completion_init
/*初始化完毕*/
2.3 rt_kprintf的执行
- 经过对trace log分析的解读, rt_kprintf的函数调用链如下所示. 可见rt_kprintf是通过_serial_poll_tx方式轮询发送的.
/*
rt_kprintf (kservice.c)|-> _kputs (kservice.c)|-> rt_console_get_device (kservice.c)|-> rt_device_write (device.c)|-> device_write (dev_serial_v2.c)|-> _serial_fifo_tx_blocking_buf (dev_serial_v2.c)|-> _serial_poll_tx (dev_serial_v2.c)|-> stm32_putc (drv_usart_v2.c) [多次调用]
*/
- 系统启动初始化过程中, trace到了7次rt_kprintf打印过程, 每次打印的数据量不同. 完整的运行log如下
/*rt_kprintf正式被调用了*/
kservice.c :372 | rt_kprintf
kservice.c :391 | rt_kprintf go=> _kputs
kservice.c :321 | _kputs
kservice.c :323 | _kputs go=> rt_console_get_device
kservice.c :337 | _kputs go=> rt_device_write
device.c :407 | rt_device_write
device.c :408 | rt_device_write uart4
device.c :409 | rt_device_write 18(0x00000012) <= size
device.c :423 | rt_device_write go=> device_write
dev_serial_v2.c :536 | _serial_fifo_tx_blocking_buf
dev_serial_v2.c :537 | _serial_fifo_tx_blocking_buf 18(0x00000012) <= size
dev_serial_v2.c :555 | _serial_fifo_tx_blocking_buf go=> _serial_poll_tx
dev_serial_v2.c :369 | _serial_poll_tx
dev_serial_v2.c :370 | _serial_poll_tx 18(0x00000012) <= size
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
dev_serial_v2.c :397 | _serial_poll_tx 18(0x00000012) <= putc_size - size/*第2次调用rt_kprintf*/
kservice.c :372 | rt_kprintf
kservice.c :391 | rt_kprintf go=> _kputs
kservice.c :321 | _kputs
kservice.c :323 | _kputs go=> rt_console_get_device
kservice.c :337 | _kputs go=> rt_device_write
device.c :407 | rt_device_write
device.c :408 | rt_device_write uart4
device.c :409 | rt_device_write 82(0x00000052) <= size
device.c :423 | rt_device_write go=> device_write
dev_serial_v2.c :536 | _serial_fifo_tx_blocking_buf
dev_serial_v2.c :537 | _serial_fifo_tx_blocking_buf 82(0x00000052) <= size
dev_serial_v2.c :555 | _serial_fifo_tx_blocking_buf go=> _serial_poll_tx
dev_serial_v2.c :369 | _serial_poll_tx
dev_serial_v2.c :370 | _serial_poll_tx 82(0x00000052) <= size
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
dev_serial_v2.c :397 | _serial_poll_tx 82(0x00000052) <= putc_size - size/*第3次调用rt_kprintf*/
kservice.c :372 | rt_kprintf
kservice.c :391 | rt_kprintf go=> _kputs
kservice.c :321 | _kputs
kservice.c :323 | _kputs go=> rt_console_get_device
kservice.c :337 | _kputs go=> rt_device_write
device.c :407 | rt_device_write
device.c :408 | rt_device_write uart4
device.c :409 | rt_device_write 5(0x00000005) <= size
device.c :423 | rt_device_write go=> device_write
dev_serial_v2.c :536 | _serial_fifo_tx_blocking_buf
dev_serial_v2.c :537 | _serial_fifo_tx_blocking_buf 5(0x00000005) <= size
dev_serial_v2.c :555 | _serial_fifo_tx_blocking_buf go=> _serial_poll_tx
dev_serial_v2.c :369 | _serial_poll_tx
dev_serial_v2.c :370 | _serial_poll_tx 5(0x00000005) <= size
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
dev_serial_v2.c :397 | _serial_poll_tx 5(0x00000005) <= putc_size - size/*第4次调用rt_kprintf*/
kservice.c :372 | rt_kprintf
kservice.c :391 | rt_kprintf go=> _kputs
kservice.c :321 | _kputs
kservice.c :323 | _kputs go=> rt_console_get_device
kservice.c :337 | _kputs go=> rt_device_write
device.c :407 | rt_device_write
device.c :408 | rt_device_write uart4
device.c :409 | rt_device_write 8(0x00000008) <= size
device.c :423 | rt_device_write go=> device_write
dev_serial_v2.c :536 | _serial_fifo_tx_blocking_buf
dev_serial_v2.c :537 | _serial_fifo_tx_blocking_buf 8(0x00000008) <= size
dev_serial_v2.c :555 | _serial_fifo_tx_blocking_buf go=> _serial_poll_tx
dev_serial_v2.c :369 | _serial_poll_tx
dev_serial_v2.c :370 | _serial_poll_tx 8(0x00000008) <= size
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
dev_serial_v2.c :397 | _serial_poll_tx 8(0x00000008) <= putc_size - size/*第5次调用rt_kprintf*/
kservice.c :372 | rt_kprintf
kservice.c :391 | rt_kprintf go=> _kputs
kservice.c :321 | _kputs
kservice.c :323 | _kputs go=> rt_console_get_device
kservice.c :337 | _kputs go=> rt_device_write
device.c :407 | rt_device_write
device.c :408 | rt_device_write uart4
device.c :409 | rt_device_write 35(0x00000023) <= size
device.c :423 | rt_device_write go=> device_write
dev_serial_v2.c :536 | _serial_fifo_tx_blocking_buf
dev_serial_v2.c :537 | _serial_fifo_tx_blocking_buf 35(0x00000023) <= size
dev_serial_v2.c :555 | _serial_fifo_tx_blocking_buf go=> _serial_poll_tx
dev_serial_v2.c :369 | _serial_poll_tx
dev_serial_v2.c :370 | _serial_poll_tx 35(0x00000023) <= size
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
dev_serial_v2.c :397 | _serial_poll_tx 35(0x00000023) <= putc_size - size/*第6次调用rt_kprintf*/
kservice.c :372 | rt_kprintf
kservice.c :391 | rt_kprintf go=> _kputs
kservice.c :321 | _kputs
kservice.c :323 | _kputs go=> rt_console_get_device
kservice.c :337 | _kputs go=> rt_device_write
device.c :407 | rt_device_write
device.c :408 | rt_device_write uart4
device.c :409 | rt_device_write 44(0x0000002c) <= size
device.c :423 | rt_device_write go=> device_write
dev_serial_v2.c :536 | _serial_fifo_tx_blocking_buf
dev_serial_v2.c :537 | _serial_fifo_tx_blocking_buf 44(0x0000002c) <= size
dev_serial_v2.c :555 | _serial_fifo_tx_blocking_buf go=> _serial_poll_tx
dev_serial_v2.c :369 | _serial_poll_tx
dev_serial_v2.c :370 | _serial_poll_tx 44(0x0000002c) <= size
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
dev_serial_v2.c :397 | _serial_poll_tx 44(0x0000002c) <= putc_size - size/*第7次调用rt_kprintf*/
kservice.c :372 | rt_kprintf
kservice.c :391 | rt_kprintf go=> _kputs
kservice.c :321 | _kputs
kservice.c :323 | _kputs go=> rt_console_get_device
kservice.c :337 | _kputs go=> rt_device_write
device.c :407 | rt_device_write
device.c :408 | rt_device_write uart4
device.c :409 | rt_device_write 41(0x00000029) <= size
device.c :423 | rt_device_write go=> device_write
dev_serial_v2.c :536 | _serial_fifo_tx_blocking_buf
dev_serial_v2.c :537 | _serial_fifo_tx_blocking_buf 41(0x00000029) <= size
dev_serial_v2.c :555 | _serial_fifo_tx_blocking_buf go=> _serial_poll_tx
dev_serial_v2.c :369 | _serial_poll_tx
dev_serial_v2.c :370 | _serial_poll_tx 41(0x00000029) <= size
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
dev_serial_v2.c :397 | _serial_poll_tx 41(0x00000029) <= putc_size - size
2.4 finsh_system_init与finsh_thread_entry的执行(创建一个finsh shell单独的线程, 处理shell的收发)
- finsh_system_init是在shell.c中实现的, 它主要是创建了一个finsh线程, 并在finsh线程中用finsh_set_device设置了device, 配置了不同的oflag属性. finsh_set_device相比rt_console_set_device, 多了一个RT_DEVICE_FLAG_INT_RX属性, 以满足中断接收的要求.
- 经过对trace log分析的解读, finsh_system_init的函数调用链如下所示
/*finsh_system_init是用INIT_APP_EXPORT初始化的*/
/*
finsh_system_init (shell.c)|-> rt_thread_create (shell.c)|-> rt_sem_init (shell.c)|-> finsh_set_prompt_mode (shell.c)|-> finsh_thread_entry (shell.c)|-> rt_console_get_device (shell.c)|-> finsh_set_device (shell.c)|-> rt_device_find (device.c) [uart4]|-> rt_device_open (device.c) [uart4, oflag=0x143]|-> rt_serial_open (dev_serial_v2.c)|-> rt_device_set_rx_indicate (device.c) [uart4]
*/
- trace到的运行log如下
shell.c :799 | finsh_system_init
shell.c :848 | finsh_system_init go=> rt_thread_create
shell.c :862 | finsh_system_init go=> rt_sem_init
shell.c :864 | finsh_system_init go=> finsh_set_prompt_mode
shell.c :157 | finsh_set_prompt_mode
shell.c :503 | finsh_thread_entry
shell.c :519 | finsh_thread_entry go=> rt_console_get_device
shell.c :523 | finsh_thread_entry go=> finsh_set_device
shell.c :233 | finsh_set_device
shell.c :237 | finsh_set_device go=> rt_device_find
device.c :130 | rt_device_find
device.c :131 | rt_device_find uart4
shell.c :248 | finsh_set_device go=> rt_device_open
device.c :235 | rt_device_open
device.c :236 | rt_device_open uart4
/*finsh_set_device用0x143打开uart4, 相比rt_console_set_device多了一个RT_DEVICE_FLAG_INT_RX*/
/*oflag=0x143=> RT_DEVICE_OFLAG_RDWR|RT_DEVICE_FLAG_INT_RX|RT_DEVICE_FLAG_STREAM*/
device.c :237 | rt_device_open 323(0x00000143) <= oflag
device.c :276 | rt_device_open go=> device_open
dev_serial_v2.c :1006| rt_serial_open
dev_serial_v2.c :1007| rt_serial_open 323(0x00000143) <= oflag
shell.c :266 | finsh_set_device go=> rt_device_set_rx_indicate
device.c :479 | rt_device_set_rx_indicate
device.c :480 | rt_device_set_rx_indicate uart4
shell.c :542 | finsh_thread_entry go=> rt_kprintf
/*执行rt_kprintf(FINSH_PROMPT), 因为#define FINSH_PROMPT finsh_get_prompt(), 所以先执行finsh_get_prompt*/
shell.c :99 | finsh_get_prompt /*第8次调用rt_kprintf, 打印rt_kprintf(FINSH_PROMPT)*/
kservice.c :372 | rt_kprintf
kservice.c :391 | rt_kprintf go=> _kputs
kservice.c :321 | _kputs
kservice.c :323 | _kputs go=> rt_console_get_device
kservice.c :337 | _kputs go=> rt_device_write
device.c :407 | rt_device_write
device.c :408 | rt_device_write uart4
device.c :409 | rt_device_write 5(0x00000005) <= size
device.c :423 | rt_device_write go=> device_write
dev_serial_v2.c :536 | _serial_fifo_tx_blocking_buf
dev_serial_v2.c :537 | _serial_fifo_tx_blocking_buf 5(0x00000005) <= size
dev_serial_v2.c :555 | _serial_fifo_tx_blocking_buf go=> _serial_poll_tx
dev_serial_v2.c :369 | _serial_poll_tx
dev_serial_v2.c :370 | _serial_poll_tx 5(0x00000005) <= size
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
dev_serial_v2.c :397 | _serial_poll_tx 5(0x00000005) <= putc_size - size
2.5 finsh_thread_entry的执行过程
- 线程循环体的执行逻辑就是finsh_getchar-> process(ch), 这里proces()过程细节就非常多了, 包括回显, push历史, 命令执行等
static void finsh_thread_entry(void *parameter)
{rt_device_t console = rt_console_get_device();finsh_set_device(console->parent.name);while (1){ch = (int)finsh_getchar();if (ch < 0){continue;}process(ch);}
}
2.6 finsh_getchar的执行(console如何获取一个char?)
- 经过对trace log分析的解读, finsh_getchar的函数调用链如下所示. 在finsh_getchar底层调用了rt_ringbuffer_get, 如果ringbuffer为空, 那么就会调用rt_sem_take等待.
/*读取第1个char*/
/*
finsh_getchar (shell.c)|-> rt_device_read (device.c)|-> device_read (dev_serial_v2.c)|-> _serial_fifo_rx (dev_serial_v2.c)|-> rt_ringbuffer_get (ringbuffer.c)|-> rt_ringbuffer_data_len (ringbuffer.c)|-> rt_sem_take (when buffer empty)|-> ......|-> rt_device_read (after wakeup)|-> device_read (dev_serial_v2.c)|-> _serial_fifo_rx (dev_serial_v2.c)|-> rt_ringbuffer_get (ringbuffer.c)|-> rt_ringbuffer_data_len (ringbuffer.c)
*/
- trace到的finsh_getchar获取一个char的完整运行log如下. 启动读后, 因为ringbuffer此时为空, 因此会调用rt_sem_take睡眠. 直到串口发生rx中断, 接收到了char, 并通过rt_ringbuffer_putchar存入ringbuff, 然后调用rt_hw_serial_isr发送信号量, finsh_getchar被唤醒继续执行, 成功读取到一个char.
/*进入finsh_thread_entry循环体执行*/
/*读取第1个char*/
shell.c :547 | finsh_thread_entry go=> finsh_getchar
shell.c :164 | finsh_getchar
shell.c :187 | finsh_getchar go=> rt_device_read
device.c :360 | rt_device_read
device.c :361 | rt_device_read uart4
device.c :362 | rt_device_read 1(0x00000001) <= size
device.c :376 | rt_device_read go=> device_read
dev_serial_v2.c :415 | _serial_fifo_rx
dev_serial_v2.c :416 | _serial_fifo_rx 1(0x00000001) <= size
dev_serial_v2.c :460 | _serial_fifo_rx go=> rt_ringbuffer_get
ringbuffer.c :189 | rt_ringbuffer_get
ringbuffer.c :394 | rt_ringbuffer_data_len
ringbuffer.c :21 | rt_ringbuffer_status
ringbuffer.c :398 | rt_ringbuffer_data_len 0(0x00000000) <= data_len
dev_serial_v2.c :465 | _serial_fifo_rx 0(0x00000000) <= recv_len
shell.c :190 | finsh_getchar go=> rt_sem_take...
/*进入睡眠状态*//*中断唤醒, 串口收到数据了*/
/*基本操作就是先用rt_ringbuffer_putchar存入ringbuff, 然后调用rt_hw_serial_isr发送信号量*/
drv_usart_v2.c :703 | UART4_IRQHandler
drv_usart_v2.c :707 | UART4_IRQHandler go=> uart_isr
drv_usart_v2.c :475 | uart_isr
drv_usart_v2.c :488 | uart_isr go=> rt_ringbuffer_putchar
drv_usart_v2.c :346 | stm32_uart_get_mask
ringbuffer.c :285 | rt_ringbuffer_putchar
ringbuffer.c :394 | rt_ringbuffer_data_len
ringbuffer.c :21 | rt_ringbuffer_status
ringbuffer.c :398 | rt_ringbuffer_data_len 0(0x00000000) <= data_len
drv_usart_v2.c :491 | uart_isr go=> rt_hw_serial_isr
/*调用rt_hw_serial_isr, 最终结果是发送rt_sem_release*/
dev_serial_v2.c :1584| rt_hw_serial_isr
dev_serial_v2.c :1585| rt_hw_serial_isr 1(0x00000001) <= event
dev_serial_v2.c :1613| rt_hw_serial_isr go=> rt_ringbuffer_data_len
ringbuffer.c :394 | rt_ringbuffer_data_len
ringbuffer.c :21 | rt_ringbuffer_status
ringbuffer.c :410 | rt_ringbuffer_data_len 1(0x00000001) <= data_len
dev_serial_v2.c :1628| rt_hw_serial_isr go=> serial->parent.rx_indicate
shell.c :214 | finsh_rx_ind
shell.c :218 | finsh_rx_ind go=> rt_sem_release/*finsh_getchar被唤醒*/
shell.c :192 | finsh_getchar wakeup from rt_sem_take...
shell.c :201 | finsh_getchar go=> rt_device_read
device.c :360 | rt_device_read
device.c :361 | rt_device_read uart4
device.c :362 | rt_device_read 1(0x00000001) <= size
device.c :376 | rt_device_read go=> device_read
dev_serial_v2.c :415 | _serial_fifo_rx
dev_serial_v2.c :416 | _serial_fifo_rx 1(0x00000001) <= size
dev_serial_v2.c :460 | _serial_fifo_rx go=> rt_ringbuffer_get
ringbuffer.c :189 | rt_ringbuffer_get
ringbuffer.c :394 | rt_ringbuffer_data_len
ringbuffer.c :21 | rt_ringbuffer_status
ringbuffer.c :410 | rt_ringbuffer_data_len 1(0x00000001) <= data_len
/*_serial_fifo_rx函数返回1, 终于读到了数据*/
dev_serial_v2.c :465 | _serial_fifo_rx 1(0x00000001) <= recv_len
2.7 UART4_IRQHandler的执行(如何获取一个char? 这个char如何存放?)
- 串口接收数据是通过中断来实现的. 我们在调用finsh_set_device的时候, 其中包含RT_DEVICE_FLAG_INT_RX属性, 以满足中断接收的要求.
- 经过对trace log分析的解读, UART4_IRQHandler的函数调用链如下所示. 基本操作就是先用rt_ringbuffer_putchar存入ringbuff, 然后调用rt_hw_serial_isr发送信号量.
/*中断唤醒, 串口收到数据了*/
/*基本操作就是先用rt_ringbuffer_putchar存入ringbuff, 然后调用rt_hw_serial_isr发送信号量*/
/*
UART4_IRQHandler (drv_usart_v2.c)|-> uart_isr (drv_usart_v2.c)|-> rt_ringbuffer_putchar (ringbuffer.c)|-> rt_ringbuffer_data_len (ringbuffer.c)|-> rt_ringbuffer_status (ringbuffer.c)|-> rt_hw_serial_isr (dev_serial_v2.c)|-> rt_ringbuffer_data_len (ringbuffer.c)|-> rt_ringbuffer_status (ringbuffer.c)|-> serial->parent.rx_indicate (shell.c)|-> rt_sem_release
*/
- trace到的运行log如下
/*中断唤醒, 串口收到数据了*/
/*基本操作就是先用rt_ringbuffer_putchar存入ringbuff, 然后调用rt_hw_serial_isr发送信号量*/
drv_usart_v2.c :703 | UART4_IRQHandler
drv_usart_v2.c :707 | UART4_IRQHandler go=> uart_isr
drv_usart_v2.c :475 | uart_isr
drv_usart_v2.c :488 | uart_isr go=> rt_ringbuffer_putchar
drv_usart_v2.c :346 | stm32_uart_get_mask
ringbuffer.c :285 | rt_ringbuffer_putchar
ringbuffer.c :394 | rt_ringbuffer_data_len
ringbuffer.c :21 | rt_ringbuffer_status
ringbuffer.c :398 | rt_ringbuffer_data_len 0(0x00000000) <= data_len
drv_usart_v2.c :491 | uart_isr go=> rt_hw_serial_isr
/*调用rt_hw_serial_isr, 最终结果是发送rt_sem_release*/
dev_serial_v2.c :1584| rt_hw_serial_isr
dev_serial_v2.c :1585| rt_hw_serial_isr 1(0x00000001) <= event
dev_serial_v2.c :1613| rt_hw_serial_isr go=> rt_ringbuffer_data_len
ringbuffer.c :394 | rt_ringbuffer_data_len
ringbuffer.c :21 | rt_ringbuffer_status
ringbuffer.c :410 | rt_ringbuffer_data_len 1(0x00000001) <= data_len
dev_serial_v2.c :1628| rt_hw_serial_isr go=> serial->parent.rx_indicate
shell.c :214 | finsh_rx_ind
shell.c :218 | finsh_rx_ind go=> rt_sem_release
2.8 finish如何识别命令并执行?
- 在finsh_thread_entry循环体中, 通过finsh_getchar成功获得char之后, 就交给process()处理.
- 在process()中有如下这样的一段, 它是以判断当前字符是’\r’或者’\n’来作为命令接收完毕的判据.
- 这意味着, 如果我们输入的命令是"list device\r\n", 当收到"list device\r"时, 就认为收到一个完整命令, 然后运行. 毫无疑问, 这会发生一次成功的命令执行.
- 接着继续接收到一个’\n’, 满足条件, 也认为是收到一个完整命令, 然后运行. 毫无疑问, 这是一次无效的命令执行, 因为命令为空.
/* handle end of line, break */if (ch == '\r' || ch == '\n'){
#ifdef FINSH_USING_HISTORYshell_push_history(shell);
#endifif (shell->echo_mode)rt_kprintf("\n");msh_exec(shell->line, shell->line_position);rt_kprintf(FINSH_PROMPT);rt_memset(shell->line, 0, sizeof(shell->line));shell->line_curpos = shell->line_position = 0;continue;}
- trace到的运行log如下
.....
...../*finsh_thread_entry循环体继续执行*/
/*读取第11个char*/
shell.c :547 | finsh_thread_entry go=> finsh_getchar
shell.c :164 | finsh_getchar
shell.c :187 | finsh_getchar go=> rt_device_read
device.c :360 | rt_device_read
device.c :361 | rt_device_read uart4
device.c :362 | rt_device_read 1(0x00000001) <= size
device.c :376 | rt_device_read go=> device_read
dev_serial_v2.c :415 | _serial_fifo_rx
dev_serial_v2.c :416 | _serial_fifo_rx 1(0x00000001) <= size
dev_serial_v2.c :460 | _serial_fifo_rx go=> rt_ringbuffer_get
ringbuffer.c :189 | rt_ringbuffer_get
ringbuffer.c :394 | rt_ringbuffer_data_len
ringbuffer.c :21 | rt_ringbuffer_status
ringbuffer.c :410 | rt_ringbuffer_data_len 3(0x00000003) <= data_len
dev_serial_v2.c :465 | _serial_fifo_rx 1(0x00000001) <= recv_len
shell.c :740 | finsh_thread_entry go=> rt_kprintf
kservice.c :372 | rt_kprintf
kservice.c :391 | rt_kprintf go=> _kputs
kservice.c :321 | _kputs
kservice.c :323 | _kputs go=> rt_console_get_device
kservice.c :337 | _kputs go=> rt_device_write
device.c :407 | rt_device_write
device.c :408 | rt_device_write uart4
device.c :409 | rt_device_write 1(0x00000001) <= size
device.c :423 | rt_device_write go=> device_write
dev_serial_v2.c :536 | _serial_fifo_tx_blocking_buf
dev_serial_v2.c :537 | _serial_fifo_tx_blocking_buf 1(0x00000001) <= size
dev_serial_v2.c :555 | _serial_fifo_tx_blocking_buf go=> _serial_poll_tx
dev_serial_v2.c :369 | _serial_poll_tx
dev_serial_v2.c :370 | _serial_poll_tx 1(0x00000001) <= size
drv_usart_v2.c :332 | stm32_putc
dev_serial_v2.c :397 | _serial_poll_tx 1(0x00000001) <= putc_size - size/*finsh_thread_entry循环体继续执行*/
/*读取第12个char*/
shell.c :547 | finsh_thread_entry go=> finsh_getchar
shell.c :164 | finsh_getchar
shell.c :187 | finsh_getchar go=> rt_device_read
device.c :360 | rt_device_read
device.c :361 | rt_device_read uart4
device.c :362 | rt_device_read 1(0x00000001) <= size
device.c :376 | rt_device_read go=> device_read
dev_serial_v2.c :415 | _serial_fifo_rx
dev_serial_v2.c :416 | _serial_fifo_rx 1(0x00000001) <= size
dev_serial_v2.c :460 | _serial_fifo_rx go=> rt_ringbuffer_get
ringbuffer.c :189 | rt_ringbuffer_get
ringbuffer.c :394 | rt_ringbuffer_data_len
ringbuffer.c :21 | rt_ringbuffer_status
ringbuffer.c :410 | rt_ringbuffer_data_len 2(0x00000002) <= data_len
dev_serial_v2.c :465 | _serial_fifo_rx 1(0x00000001) <= recv_len
/*到此, 接收到了list device\r, 一共12个char. 因为收到了 '\r'或'\n', 认为命令接收完毕*/
/*执行shell_push_history, 将命令压入历史堆栈*/
shell.c :702 | finsh_thread_entry go=> shell_push_history
shell.c :443 | shell_push_history
shell.c :706 | finsh_thread_entry go=> rt_kprintf
kservice.c :372 | rt_kprintf
kservice.c :391 | rt_kprintf go=> _kputs
kservice.c :321 | _kputs
kservice.c :323 | _kputs go=> rt_console_get_device
kservice.c :337 | _kputs go=> rt_device_write
device.c :407 | rt_device_write
device.c :408 | rt_device_write uart4
device.c :409 | rt_device_write 1(0x00000001) <= size
device.c :423 | rt_device_write go=> device_write
dev_serial_v2.c :536 | _serial_fifo_tx_blocking_buf
dev_serial_v2.c :537 | _serial_fifo_tx_blocking_buf 1(0x00000001) <= size
dev_serial_v2.c :555 | _serial_fifo_tx_blocking_buf go=> _serial_poll_tx
dev_serial_v2.c :369 | _serial_poll_tx
dev_serial_v2.c :370 | _serial_poll_tx 1(0x00000001) <= size
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
dev_serial_v2.c :397 | _serial_poll_tx 1(0x00000001) <= putc_size - size/*命令接收完毕, 开始执行命令msh_exec*/
shell.c :707 | finsh_thread_entry go=> msh_exec/*msh_exec命令执行过程, 我们的命令是list device, 因此开始产生一些输出*/
kservice.c :372 | rt_kprintf
kservice.c :391 | rt_kprintf go=> _kputs
kservice.c :321 | _kputs
kservice.c :323 | _kputs go=> rt_console_get_device
kservice.c :337 | _kputs go=> rt_device_write
device.c :407 | rt_device_write
device.c :408 | rt_device_write uart4
device.c :409 | rt_device_write 40(0x00000028) <= size
device.c :423 | rt_device_write go=> device_write
dev_serial_v2.c :536 | _serial_fifo_tx_blocking_buf
dev_serial_v2.c :537 | _serial_fifo_tx_blocking_buf 40(0x00000028) <= size
dev_serial_v2.c :555 | _serial_fifo_tx_blocking_buf go=> _serial_poll_tx
dev_serial_v2.c :369 | _serial_poll_tx
dev_serial_v2.c :370 | _serial_poll_tx 40(0x00000028) <= size
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.....
.....drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
dev_serial_v2.c :397 | _serial_poll_tx 39(0x00000027) <= putc_size - size
shell.c :710 | finsh_thread_entry go=> rt_kprintf
/*msh_exe执行完毕, 最后执行rt_kprintf(FINSH_PROMPT)*/
shell.c :99 | finsh_get_prompt
kservice.c :372 | rt_kprintf
kservice.c :391 | rt_kprintf go=> _kputs
kservice.c :321 | _kputs
kservice.c :323 | _kputs go=> rt_console_get_device
kservice.c :337 | _kputs go=> rt_device_write
device.c :407 | rt_device_write
device.c :408 | rt_device_write uart4
device.c :409 | rt_device_write 5(0x00000005) <= size
device.c :423 | rt_device_write go=> device_write
dev_serial_v2.c :536 | _serial_fifo_tx_blocking_buf
dev_serial_v2.c :537 | _serial_fifo_tx_blocking_buf 5(0x00000005) <= size
dev_serial_v2.c :555 | _serial_fifo_tx_blocking_buf go=> _serial_poll_tx
dev_serial_v2.c :369 | _serial_poll_tx
dev_serial_v2.c :370 | _serial_poll_tx 5(0x00000005) <= size
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
dev_serial_v2.c :397 | _serial_poll_tx 5(0x00000005) <= putc_size - size/*finsh_thread_entry循环体继续执行*/
/*读取第13个char, 此时读到的是'\n', 再次进入这一段逻辑(这一遍实际是无效的).*/
shell.c :547 | finsh_thread_entry go=> finsh_getchar
shell.c :164 | finsh_getchar
shell.c :187 | finsh_getchar go=> rt_device_read
device.c :360 | rt_device_read
device.c :361 | rt_device_read uart4
device.c :362 | rt_device_read 1(0x00000001) <= size
device.c :376 | rt_device_read go=> device_read
dev_serial_v2.c :415 | _serial_fifo_rx
dev_serial_v2.c :416 | _serial_fifo_rx 1(0x00000001) <= size
dev_serial_v2.c :460 | _serial_fifo_rx go=> rt_ringbuffer_get
ringbuffer.c :189 | rt_ringbuffer_get
ringbuffer.c :394 | rt_ringbuffer_data_len
ringbuffer.c :21 | rt_ringbuffer_status
ringbuffer.c :410 | rt_ringbuffer_data_len 1(0x00000001) <= data_len
dev_serial_v2.c :465 | _serial_fifo_rx 1(0x00000001) <= recv_len
/*于是再次触发shell_push_history*/
shell.c :702 | finsh_thread_entry go=> shell_push_history
shell.c :443 | shell_push_history
/*回显'\n'*/
shell.c :706 | finsh_thread_entry go=> rt_kprintf
kservice.c :372 | rt_kprintf
kservice.c :391 | rt_kprintf go=> _kputs
kservice.c :321 | _kputs
kservice.c :323 | _kputs go=> rt_console_get_device
kservice.c :337 | _kputs go=> rt_device_write
device.c :407 | rt_device_write
device.c :408 | rt_device_write uart4
device.c :409 | rt_device_write 1(0x00000001) <= size
device.c :423 | rt_device_write go=> device_write
dev_serial_v2.c :536 | _serial_fifo_tx_blocking_buf
dev_serial_v2.c :537 | _serial_fifo_tx_blocking_buf 1(0x00000001) <= size
dev_serial_v2.c :555 | _serial_fifo_tx_blocking_buf go=> _serial_poll_tx
dev_serial_v2.c :369 | _serial_poll_tx
dev_serial_v2.c :370 | _serial_poll_tx 1(0x00000001) <= size
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
dev_serial_v2.c :397 | _serial_poll_tx 1(0x00000001) <= putc_size - size
/*再次触发msh_exec, 实际上没有有效的命令*/
shell.c :707 | finsh_thread_entry go=> msh_exec
shell.c :710 | finsh_thread_entry go=> rt_kprintf
/*再次执行rt_kprintf(FINSH_PROMPT)*/
shell.c :99 | finsh_get_prompt
kservice.c :372 | rt_kprintf
kservice.c :391 | rt_kprintf go=> _kputs
kservice.c :321 | _kputs
kservice.c :323 | _kputs go=> rt_console_get_device
kservice.c :337 | _kputs go=> rt_device_write
device.c :407 | rt_device_write
device.c :408 | rt_device_write uart4
device.c :409 | rt_device_write 5(0x00000005) <= size
device.c :423 | rt_device_write go=> device_write
dev_serial_v2.c :536 | _serial_fifo_tx_blocking_buf
dev_serial_v2.c :537 | _serial_fifo_tx_blocking_buf 5(0x00000005) <= size
dev_serial_v2.c :555 | _serial_fifo_tx_blocking_buf go=> _serial_poll_tx
dev_serial_v2.c :369 | _serial_poll_tx
dev_serial_v2.c :370 | _serial_poll_tx 5(0x00000005) <= size
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
drv_usart_v2.c :332 | stm32_putc
dev_serial_v2.c :397 | _serial_poll_tx 5(0x00000005) <= putc_size - size/*finsh_thread_entry循环体继续执行*/
shell.c :547 | finsh_thread_entry go=> finsh_getchar
shell.c :164 | finsh_getchar
shell.c :187 | finsh_getchar go=> rt_device_read
device.c :360 | rt_device_read
device.c :361 | rt_device_read uart4
device.c :362 | rt_device_read 1(0x00000001) <= size
device.c :376 | rt_device_read go=> device_read
dev_serial_v2.c :415 | _serial_fifo_rx
dev_serial_v2.c :416 | _serial_fifo_rx 1(0x00000001) <= size
dev_serial_v2.c :460 | _serial_fifo_rx go=> rt_ringbuffer_get
ringbuffer.c :189 | rt_ringbuffer_get
ringbuffer.c :394 | rt_ringbuffer_data_len
ringbuffer.c :21 | rt_ringbuffer_status
ringbuffer.c :398 | rt_ringbuffer_data_len 0(0x00000000) <= data_len
dev_serial_v2.c :465 | _serial_fifo_rx 0(0x00000000) <= recv_len
shell.c :190 | finsh_getchar go=> rt_sem_take...
2.9 存在的问题: finsh假唤醒问题?
通过对trace log的仔细分析,我们发现,当finsh执行完一条命令后,后面每次finsh_getchar()运行,因为没有获得数据(rt_ringbuffer_data_len返回0),从而执行rt_sem_take,但马上就被唤醒了。通过查代码,找不到任何唤醒源。感觉是假唤醒。具体的log如下面所示:
......
....../*finsh_thread_entry循环体继续执行*/
/*读取第14个char*/
shell.c :547 | finsh_thread_entry go=> finsh_getchar
shell.c :164 | finsh_getchar
shell.c :187 | finsh_getchar go=> rt_device_read
device.c :360 | rt_device_read
device.c :361 | rt_device_read uart4
device.c :362 | rt_device_read 1(0x00000001) <= size
device.c :376 | rt_device_read go=> device_read
dev_serial_v2.c :415 | _serial_fifo_rx
dev_serial_v2.c :416 | _serial_fifo_rx 1(0x00000001) <= size
dev_serial_v2.c :460 | _serial_fifo_rx go=> rt_ringbuffer_get
ringbuffer.c :189 | rt_ringbuffer_get
ringbuffer.c :394 | rt_ringbuffer_data_len
ringbuffer.c :21 | rt_ringbuffer_status
ringbuffer.c :398 | rt_ringbuffer_data_len 0(0x00000000) <= data_len
dev_serial_v2.c :465 | _serial_fifo_rx 0(0x00000000) <= recv_len
shell.c :190 | finsh_getchar go=> rt_sem_take...
/*这里, 都没有recv到数据, 为什么会wakeup?*/
shell.c :192 | finsh_getchar wakeup from rt_sem_take...
shell.c :201 | finsh_getchar go=> rt_device_read
device.c :360 | rt_device_read
device.c :361 | rt_device_read uart4
device.c :362 | rt_device_read 1(0x00000001) <= size
device.c :376 | rt_device_read go=> device_read
dev_serial_v2.c :415 | _serial_fifo_rx
dev_serial_v2.c :416 | _serial_fifo_rx 1(0x00000001) <= size
dev_serial_v2.c :460 | _serial_fifo_rx go=> rt_ringbuffer_get
ringbuffer.c :189 | rt_ringbuffer_get
ringbuffer.c :394 | rt_ringbuffer_data_len
ringbuffer.c :21 | rt_ringbuffer_status
ringbuffer.c :398 | rt_ringbuffer_data_len 0(0x00000000) <= data_len
dev_serial_v2.c :465 | _serial_fifo_rx 0(0x00000000) <= recv_len
shell.c :190 | finsh_getchar go=> rt_sem_take...
/*这里, 都没有recv到数据, 为什么会wakeup?*/
shell.c :192 | finsh_getchar wakeup from rt_sem_take...
shell.c :201 | finsh_getchar go=> rt_device_read
device.c :360 | rt_device_read
device.c :361 | rt_device_read uart4
device.c :362 | rt_device_read 1(0x00000001) <= size
device.c :376 | rt_device_read go=> device_read
dev_serial_v2.c :415 | _serial_fifo_rx
dev_serial_v2.c :416 | _serial_fifo_rx 1(0x00000001) <= size
dev_serial_v2.c :460 | _serial_fifo_rx go=> rt_ringbuffer_get
ringbuffer.c :189 | rt_ringbuffer_get
ringbuffer.c :394 | rt_ringbuffer_data_len
ringbuffer.c :21 | rt_ringbuffer_status
ringbuffer.c :398 | rt_ringbuffer_data_len 0(0x00000000) <= data_len
dev_serial_v2.c :465 | _serial_fifo_rx 0(0x00000000) <= recv_len
shell.c :190 | finsh_getchar go=> rt_sem_take...
/*这里, 都没有recv到数据, 为什么会wakeup?*/
shell.c :192 | finsh_getchar wakeup from rt_sem_take...
shell.c :201 | finsh_getchar go=> rt_device_read
device.c :360 | rt_device_read
device.c :361 | rt_device_read uart4
device.c :362 | rt_device_read 1(0x00000001) <= size
device.c :376 | rt_device_read go=> device_read
dev_serial_v2.c :415 | _serial_fifo_rx
dev_serial_v2.c :416 | _serial_fifo_rx 1(0x00000001) <= size
dev_serial_v2.c :460 | _serial_fifo_rx go=> rt_ringbuffer_get
ringbuffer.c :189 | rt_ringbuffer_get
ringbuffer.c :394 | rt_ringbuffer_data_len
ringbuffer.c :21 | rt_ringbuffer_status
ringbuffer.c :398 | rt_ringbuffer_data_len 0(0x00000000) <= data_len
dev_serial_v2.c :465 | _serial_fifo_rx 0(0x00000000) <= recv_len
shell.c :190 | finsh_getchar go=> rt_sem_take...
/*这里, 都没有recv到数据, 为什么会wakeup?*/
shell.c :192 | finsh_getchar wakeup from rt_sem_take...
shell.c :201 | finsh_getchar go=> rt_device_read
device.c :360 | rt_device_read
device.c :361 | rt_device_read uart4
device.c :362 | rt_device_read 1(0x00000001) <= size
device.c :376 | rt_device_read go=> device_read
dev_serial_v2.c :415 | _serial_fifo_rx
......
......
3. 总结与反思
- 假设我们要让自己的某个接口(比如usb cdc_acm) 作为rt-thread的console, 如何修改代码实现呢?
- 我们的想法是尽量模仿uart串口的行为, 只要把底层的收发char的功能用我们自己的接口来替换. 来看看stm32_uart定义了那些操作函数吧.
- 首先我们观察stm32_uart_ops, 在rt_hw_usart_init中需要调用rt_hw_serial_register注册串口设备. 一共有5个操作函数.
static const struct rt_uart_ops stm32_uart_ops =
{.configure = stm32_configure,.control = stm32_control,.putc = stm32_putc,.getc = stm32_getc,.transmit = stm32_transmit
};
- 从rt_console_set_device函数调用链可以看到, stm32_configure和stm32_control被调用了, 因此必须要有. 但如果我们只需要固定一种配置即可, 那么这2个函数无用, 可以是空函数, 直接返回RET_OK即可.
- 从rt_console_set_device函数调用链可以看到, rx和tx的rt_ringbuffer_init都已经定义好了, 不用用户定义. 直接用即可.
- 从rt_kprintf函数调用链可以看到, 底层只需要实现stm32_putc即可.
- finish_getchar是如何获得char的呢? 从finish_getchar函数调用关系可见, finsh_getchar就是通过rt_ringbuffer_get从ringbuffer中读取的. 因此我们需要负责往ringbuffer中填充数据.
- 从UART4_IRQHandler接收的处理过程可以看到, 基本操作就是把读取到的ch先用rt_ringbuffer_putchar存入ringbuff, 然后调用rt_hw_serial_isr发送信号量. 因此, 我们只需要负责把接收到的数据用rt_ringbuffer_putchar存入ringbuff, 然后调用rt_hw_serial_isr发送信号即可. 比如对于usb cdc_acm, 我们可以usbd_cdc_acm_bulk_out函数中执行这2个操作. 因此stm32_getc不是必须的.
- 对于rt-thread console和finsh设备, stm32_transmit用不到. 不用定义.
- 总结以上, 假设要用usb cdc_acm作为rt-thread的console和finsh设备, 代码框架大致如下
void usbd_cdc_acm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
{struct rt_serial_rx_fifo *rx_fifo;rx_fifo = (struct rt_serial_rx_fifo *)_serial_cdc_acm.serial_rx;RT_ASSERT(rx_fifo != RT_NULL);for(int i=0; i < nbytes; i++){rt_ringbuffer_putchar(&(rx_fifo->rb), read_buffer[i]);rt_hw_serial_isr(&_serial_cdc_acm, RT_SERIAL_EVENT_RX_IND); }// 继续接收数据usbd_ep_start_read(busid, ep, &read_buffer[0], usbd_get_ep_mps(busid, ep));
}void usbd_cdc_acm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
{// USB_LOG_RAW("actual in len:%d\r\n", nbytes);if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) {/* send zlp */usbd_ep_start_write(busid, CDC_IN_EP, NULL, 0);} else {ep_tx_busy_flag = false;}
}static rt_err_t _cdc_acm_cfg(struct rt_serial_device *serial, struct serial_configure *cfg)
{return RT_EOK;
}static rt_err_t _cdc_acm_ctrl(struct rt_serial_device *serial, int cmd, void *arg)
{return RT_EOK;
}
static int _cdc_acm_putc(struct rt_serial_device *serial, char c)
{ep_tx_busy_flag = true;rt_memcpy(write_buffer, &c, 1); /*必须借助于write_buffer, 因为它是nonchache的。否则输出乱码。*/usbd_ep_start_write(0, CDC_IN_EP, write_buffer, 1);while (ep_tx_busy_flag) {}return RT_EOK;
}static int _cdc_acm_getc(struct rt_serial_device *serial)
{/*这个函数不是必须的, 因为阅读源码发现, finsh_getchar-->rt_device_read-->_serial_fifo_rx-->rt_ringbuffer_get直接从ringbuffer get的, 不需要这个函数*/char ch=-1;return ch;
}static struct rt_uart_ops _cdc_acm_ops =
{.configure= _cdc_acm_cfg,.control = _cdc_acm_ctrl,.putc = _cdc_acm_putc,.getc = _cdc_acm_getc,
#ifdef RT_USING_SERIAL_V2.transmit = NULL
#endif
};int rt_hw_cdc_acm_init(void)
{cdc_acm_init(0, HPM_USB0_BASE);struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;_serial_cdc_acm.ops = &_cdc_acm_ops;_serial_cdc_acm.config = config;m_cdc_acm_cfg.serial = &_serial_cdc_acm;rt_hw_serial_register(&_serial_cdc_acm, "cdcRtt", \RT_DEVICE_FLAG_RDWR | RT_SERIAL_EVENT_RX_IND, &m_cdc_acm_cfg);return 0;
}int rtt_hw_cdc_console_init(void)
{rt_hw_cdc_acm_init();rt_console_set_device("cdcRtt");return 0;
}
INIT_APP_EXPORT(rtt_hw_cdc_console_init);
4. 附录: 完整版的trace log
详见
《深入剖析RT-Thread串口驱动:基于STM32H750的FinSH Shell全链路Trace分析与实战解密(下)》