使用STM32编写一个简单的RTOS:4.时钟管理(一)SysTick

文章目录

参考资料:RTT官网文档、《cortex-M3权威指南》
关键字:分析RT-Thread源码、stm32、RTOS、时钟管理。

简介

完成了调度器,对象管理,线程管理后,我们就可以多任务并行执行了,但是还是有很多问题,例如我们同优先级的线程,在不挂起的情况下,只能通过手动yield放弃CPU,另一个线程才有机会运行。低优先级的线程也得不到获取CPU资源的机会,这样我们的多任务功能就大打折扣。同时我们的线程也无法做一些延时操作,不能做一些定时任务。所以,为了确保没有任务能霸占系统,以及为系统提供各种定时功能,我们需要一个时钟管理。

首先,时钟管理需要哪些功能:
1,要有一个定期性的中断或者异常来作为系统的时基 --时钟节拍
2,通过时钟节拍来推动我们的任务管理(调度) --管理时间片
3,通过时钟节拍来实现延时功能 --延时功能
4,通过时钟节拍来实现定时功能 --定时功能

可以看出,时钟节拍是我们实现这些功能的核心。

时钟节拍
任何操作系统都需要提供一个时钟节拍,以供系统处理所有和时间有关的事件,如线程的延时、线程的时间片轮转调度以及定时器超时等。时钟节拍是特定的周期性中断,这个中断可以看做是系统心跳,中断之间的时间间隔取决于不同的应用,一般是 1ms–100ms,时钟节拍率越快,系统的额外开销就越大,从系统启动开始计数的时钟节拍数称为系统时间。

RT-Thread 中,时钟节拍的长度可以根据 RT_TICK_PER_SECOND 的定义来调整,等于 1/RT_TICK_PER_SECOND 秒。RT_TICK_PER_SECOND默认是100,即一个时钟节拍为10ms。

SysTick定时器
在以前,大多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。现在,cortex-M3处理器内部就包含了一个专门用来处理系统滴答的定时器–SysTick。
CM3为它专门开出一个异常类型,SYSTICK异常(异常号:15)。在上下文切换的时候,CM3也专门提供了一个PendSV异常,是不是很贴心。下面介绍一下SysTick这个定时器。
SysTick 是一个24 位的倒计数定时器,当计到0 时,将从RELOAD 寄存器中自动重装载定时初值。只要不把它在SysTick 控制及状态寄存器中的使能位清除,就永不停息。

Alt

详细请看一下CM3权威指南第8章。

源码分析

下面我们来看SysTick在RTT中的具体操作。

在 rt_hw_board_init 初始化了SysTick。

void rt_hw_board_init(void)
{
   ...
    /* Configure the SysTick */
    SysTick_Config( SystemCoreClock / RT_TICK_PER_SECOND );
   ...
}

SystemCoreClock = 72000 000,因为我的是103的,频率是72M。RT_TICK_PER_SECOND默认是100,所以这里将触发异常改为了10ms触发。

异常处理函数:

void SysTick_Handler(void)
{
    rt_tick_increase();
}

void rt_tick_increase(void)
{
    struct rt_thread *thread;

    /* increase the global tick */
    ++ rt_tick;

    /* check time slice */
    thread = rt_thread_self();

    -- thread->remaining_tick;
    if (thread->remaining_tick == 0)
    {
        /* change to initialized tick */
        thread->remaining_tick = thread->init_tick;

        /* yield */
        rt_thread_yield();
    }

    /* check timer */
    rt_timer_check();
}

在时钟节拍SysTick的的异常处理函数中调用了rt_tick_increase,rt_tick_increase里维护了一个系统节拍数的变量rt_tick,然后检查当前线程是否已经达到规定的时间片,如果是则调用rt_thread_yield让出cpu控制权。接着是定时器检测,这个我们后面再详细讲,暂时先不管。

测试

接下来我们就将系统时间节拍和时间片加入我们的RTT-Mini中。

void clock_systick_handler(void)
{
    ++systick;
    
    --current_thread->remaining_tick;
    
    if (current_thread->remaining_tick == 0) {
        current_thread->remaining_tick = current_thread->tick;
        thread_yield();
    }
    
}
                             
void thread_1_entry(void *param)
{
    uint32_t i = 0;
    
    while (1) {
        printf("hello. i : %ld\r\n", i++);
//        thread_yield();
    }
}


void thread_2_entry(void *param)
{
    uint32_t i = 0;
    
    while (1) {
        printf("world. i : %ld\r\n", i++);
//        thread_yield();
    }
}

在这里插入图片描述
现在我们线程中去掉yield,两个任务也能轮流运行了。

测试源码:https://download.csdn.net/download/u012220052/11236203

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值