Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
RT-Thread一般讨论
rt-thread 系统启动及 SysTick 初始化流程优化可行性分析
发布于 2021-07-13 14:30:03 浏览:3106
订阅该版
[tocm] # 前言 论坛里有人提出了一个疑问,说 STM32 系列 bsp 在初始化系统时钟的过程中使用到了 tick ,而 tick 需要初始化并使能 SysTick 中断。但是呢,SysTick 中断中有 rtt 的 tick 以及硬定时器检测,以及可能存在的系统任务调度。初始化时钟是极其早期必须完成的工作,这个时候别说系统了,其它外围设备也没有被初始化。由此产生一个问题,极其早期使用了比较后期的资源,同时,因为需要使用 SysTick 中断而简单粗暴地使用 `__set_PRIMASK` 使能了总中断!!!这是万万不可取的。 有人发现了这一矛盾之处,在[论坛](https://club.rt-thread.org/ask/article/2857.html) 里和 gitee 的 [issue](https://gitee.com/rtthread/rt-thread/pulls/246) 里也是各执己见,热闹非凡。 下面我讲讲我的处理方案。 ### 理论前提 1. rtt 标榜的是实时操作系统,对于系统中频繁执行的代码需要严格审查,保证没有一行多余代码。(非实时操作系统也不希望自己多数时候空跑一条无用的代码) 2. 中断是个很棘手的东西,在不确定开中断会引起什么后果的时候,坚决不能开中断。 3. rtt 系统启动是有它自己的流程的。分阶段的,任何资源的初始化都有个阶段以及先后顺序。 4. 板级初始化,如非必要,如果可以延迟尽量延迟,先保证 rtt 内核调度运行起来。 基于以上几点,我的修改方案如下。 #### 预初始化 SysTick 上电后,MCU 默认使用的内部晶振,时钟也是默认值,这个时候使用默认值初始化 SysTick,但是**不开启中断**!!! 在 STM32 的 bsp 里,因为有如下调用关系 `rt_hw_board_init` -> `HAL_Init` -> `HAL_InitTick`。 `HAL_InitTick` 在 hal 里是弱实现,'drv_common.c' 重新实现并且是个空函数,这里可以借用一下。 ``` /* re-implement tick interface for STM32 HAL */ HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority) { HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / RT_TICK_PER_SECOND); /* Return function status */ return HAL_OK; } ``` #### 初始化系统时钟 第二步配置时钟频率,切换内外时钟或者倍频等等操作。中间如果有延时等待的需求,可以使用 SysTick 实现 udelay 短延时,进而通过 while 循环累积达到等待超时的效果。 首先,在 'drv_common.c' 文件里添加 `HAL_uDelay` 微秒延时实现,其实就是调用 `rt_hw_us_delay` 。 然后,在 'stm32xxx_hal_conf.h' 头文件末尾添加一个通用宏定义: ``` #define HAL_WAITFOR_CONDITION(condition, ms) do { \ uint32_t cnt = 0; \ while((condition)) { \ if (cnt > (ms) * 1000 / 10) \ { \ return HAL_TIMEOUT; \ } \ HAL_uDelay(10); \ cnt++; \ }\ } while(0) ``` 其中,condition 是等待条件,ms 是等待超时时间。 因为 udelay 了 10us ,所以整体的精度就是 10us ,时间损失可以控制在 10us 内。 涉及到的函数有 `HAL_RCC_OscConfig` `HAL_PWREx_EnableOverDrive` `HAL_RCC_ClockConfig` `HAL_RCCEx_PeriphCLKConfig` 等。 其中一处修改前后 ``` /* Get Start Tick */ tickstart = HAL_GetTick(); /* Wait till HSE is ready */ while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET) { if((HAL_GetTick() - tickstart ) > HSE_TIMEOUT_VALUE) { return HAL_TIMEOUT; } } ``` ``` /* Wait till HSE is ready */ HAL_WAITFOR_CONDITION((__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET), HSE_TIMEOUT_VALUE); ``` 其它地方如法炮制,只是把等待条件和等待时间添加到宏函数里。 #### rt_hw_board_init 调整 调整后的代码如下: 1. 去掉开启关闭全局中断操作; 2. 提前控制台串口初始化; 3. 堆栈的初始化并不需要那么着急,但是必须在 rt_components_board_init 之前; 4. gpio 初始化也在 rt_components_board_init 之前。 其中 2-4 的调整是调试需求控制台。 最终结果如下。 ``` RT_WEAK void rt_hw_board_init() { #ifdef SCB_EnableICache /* Enable I-Cache---------------------------------------------------------*/ SCB_EnableICache(); #endif #ifdef SCB_EnableDCache /* Enable D-Cache---------------------------------------------------------*/ SCB_EnableDCache(); #endif /* HAL_Init() function is called at the beginning of the program */ HAL_Init(); /* System clock initialization */ SystemClock_Config(); rt_hw_systick_init(); /* USART driver initialization is open by default */ #ifdef RT_USING_SERIAL rt_hw_usart_init(); #endif /* Set the shell console output device */ #ifdef RT_USING_CONSOLE rt_console_set_device(RT_CONSOLE_DEVICE_NAME); #endif /* Pin driver initialization is open by default */ #ifdef RT_USING_PIN rt_hw_pin_init(); #endif /* Heap initialization */ #if defined(RT_USING_HEAP) rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END); #endif /* Board underlying hardware initialization */ #ifdef RT_USING_COMPONENTS_INIT rt_components_board_init(); #endif } ``` #### 修改 `rt_hw_systick_init` 去掉 `rt_hw_systick_init` 函数中使能 SysTick 中断的操作。添加使能 SysTick 中断函数。 ``` void rt_hw_systick_irq_enable(void) { HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); } ``` #### 修改 `rtthread_startup` 添加使能 SysTick 中断处理。 ``` rt_hw_systick_irq_enable(); /* start scheduler */ rt_system_scheduler_start(); ``` #### SysTick_Handler 异常响应 目前,`SysTick_Handler` 函数就下面这么清爽,不需要考虑并行增加 hal 的tick值。 ``` void SysTick_Handler(void) { /* enter interrupt */ rt_interrupt_enter(); rt_tick_increase(); /* leave interrupt */ rt_interrupt_leave(); } ``` ### 运行测试 修改后系统启动正常,运行正常。 RCC 初始化过程如果失败,等待超时也能正常超时返回。 经过初步验证,不使用 SysTick 前提下初始化配置硬件的可行性还是有的。 ### 其它可行性 这次尝试仅限于最小范围,仅仅考虑了系统时钟配置过程,未考虑其它板级外设配置过程。考虑到 hal 是比较庞大的,每次 hal 升级都把所有的 hal 文件修改一遍工作量也是不小的。这样也不方便。如果降低修改范围,只修改 RCC 相关部分,其它外设配置仍然想正常使用 SysTick ,有一种方法就是继续提前系统调度的启动时间点。 鉴于此,系统启动流程大致如下 1. 配置系统时钟,同时配置 SysTick(同前); 2. 初始化 rtt 系统调度器; 3. 初始化 idle 线程; 4. 启动 SysTick 中断; 5. 启动 idle 线程并启动 rtt 系统调度; 6. 由 idle 线程初始化调试串口; 7. 由 idle 线程初始化内存堆; 8. 由 idle 线程调用执行 `rt_components_board_init` 初始化板级外设配置; 9. 由 idle 线程创建 main 和 soft timer 线程。 10. main 线程进行组件初始化配置,以及创建其它应用线程。 由此,可以做到以下几点: 1. 保障所有操作都在是线程中进行的。省去很多 `if (rt_thread_self() != RT_NULL)` 的操作; 2. 保障中断可以及早放心打开; 3. 明确启动流程,确定启动流程每一阶段的工作重点以及必须完成的任务。 缺点,因 idle 线程工作量变多,idle 线程栈可能会比较大。一个空闲线程占用过多的内存也是浪费。另外,多核处理器的 idle 线程数量和核心数量一样,由哪个 idle 线程完成上面的工作也需要做个抉择。 > 本优化系列所有提到的更改已经提交到 gitee ,欢迎大家测试 https://gitee.com/thewon/rt_thread_repo 相关文章: [rt-thread 系统优化系列(一) 之 关中断](https://club.rt-thread.org/ask/article/2931.html) [rt-thread 系统优化系列(二) 之 线程间同步和通信对中断的影响](https://club.rt-thread.org/ask/article/2939.html) [rt-thread 系统优化系列(三) 之 软定时器](https://club.rt-thread.org/ask/article/2967.html)
6
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
出出啊
恃人不如自恃,人之为己者不如己之自为也
文章
43
回答
1517
被采纳
342
关注TA
发私信
相关文章
1
有关动态模块加载的一篇论文
2
最近的调程序总结
3
晕掉了,这么久都不见layer2的踪影啊
4
继续K9ii的历程
5
[GUI相关] FreeType 2
6
[GUI相关]嵌入式系统中文输入法的设计
7
20081101 RT-Thread开发者聚会总结
8
嵌入式系统基础
9
linux2.4.19在at91rm9200 上的寄存器设置
10
[转]基于嵌入式Linux的通用触摸屏校准程序
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
MicroPython
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
a1012112796
15
个答案
2
次被采纳
张世争
9
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
用户名由3_15位
13
个答案
1
次被采纳
本月文章贡献
程序员阿伟
9
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
5
次点赞
RTT_逍遥
1
篇文章
2
次点赞
ThinkCode
1
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部