• RT-thread内核之系统时钟


    一、系统时钟

    rt-thread的系统时钟模块采用全局变量rt_tick作为系统时钟节拍,该变量在系统时钟中断函数中不断加1。而系统时钟中断源和中断间隔一般由MCU硬件定时器(如stm32的嘀嗒定时器)决定,rt_tick初始值为0,每次MCU产生硬件定时中断后,在中断函数中不断加1,即rt_tick变量值与MCU硬件定时器定时中断间隔的乘积为系统真正运行时间(例如rt_tick=10,stm32嘀嗒定时器每隔1ms产生中断,则系统上电运行时间为10ms)。

    在bsp/stm32f40x/drivers/board.c中设置MCU硬件定时器定时间隔,以及执行相应定时器中断函数:

    void  SysTick_Configuration(void)
    {
        RCC_ClocksTypeDef  rcc_clocks;
        rt_uint32_t         cnts;
    
        RCC_GetClocksFreq(&rcc_clocks);//获得系统的晶振频率
    
    //RT_TICK_PER_SECOND在rtconfig.h中配置,表示每秒包含的系统时钟节拍数。默认配置为100,则嘀嗒定时器中断间隔为10ms,rt_tick每隔10ms加1,即默认情况下1s内包含100个系统时钟节拍,每个时钟节拍tick表示10ms。为了提高 精度,一般修改宏定义为1000,即1s内包含1000个系统时钟节拍(此时嘀嗒定时器中断间隔为1ms,每个时钟节拍tick则表示1ms)。
    cnts = (rt_uint32_t)rcc_clocks.HCLK_Frequency / RT_TICK_PER_SECOND;
    cnts = cnts / 8;
        SysTick_Config(cnts);                                //配置系统tick,函数在core_cm4.h中实现,使能嘀嗒定时器中断、定时器时钟源频率HCLK=168MHZ、启动嘀嗒定时器
        SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//配置定时器时钟源,函数在misc.c中实现,将定时器时源钟频率设置为HCLK/8=21MHZ
    }
    
    void SysTick_Handler(void)
    {
        /* enter interrupt */
        rt_interrupt_enter();//表示进入中断,在src/irp.c中定义,中断嵌套计数器rt_interrupt_nest加1
    
        rt_tick_increase();  //rt_tick加1,并检查当前运行线程的剩余时间片是否耗尽,若耗尽则让出处理器并重新调度线程,接着执行硬件定时器中断模式下的定时器超时检查rt_timer_check();
    
        /* leave interrupt */
        rt_interrupt_leave();//表示进入中断,在src/irp.c中定义,中断嵌套计数器rt_interrupt_nest减1
    }

    二、硬件定时器中断模式下线程调度驱动

    在src/clock.c中:

    void rt_tick_increase(void)
    {
        struct rt_thread *thread;
    
        /* increase the global tick */
        ++ rt_tick;                     //全局变量系统时钟节拍数加1  
    
        /* check time slice */
        thread = rt_thread_self();      //获取当前运行的线程  
    
        -- thread->remaining_tick;      //当前运行线程的剩余时间片减1  
        if (thread->remaining_tick == 0)//如果当前运行线程无剩余时间
        {
            /* change to initialized tick */
            thread->remaining_tick = thread->init_tick;//重新将线程的剩余时间片设置为初始化时间片
    
            /* yield */
            rt_thread_yield();//将此线程从调度器就绪队列中取出来放到同优先级线程链表末尾,然后再次调度  
        }
    
        /* check timer */
        rt_timer_check();//检查定时器链表上是否有时间到达的时钟,即包括自定义的定时器,也包括线程睡眠时启动的线程定时器
    }

    由上述代码可见,一旦系统产生时钟中断,在嘀嗒定时器中断函数中,系统首先将检查当前正在运行的线程剩余时间片是否耗尽,如果耗尽则将其从调度器就绪队列中取出放到同优先级线程链表末尾,然后再重新调度线程;接着检查是否有休眠的线程时间到达(即线程睡眠时启动的线程定时器是否超时),如果有则触发相应的线程定时器超时函数rt_thread_timeout(将当前挂起的线程加入到调度器就绪队列后重新调度),从而将线程从睡眠中唤醒。

    总而言之,在硬件定时器中断模式下,系统时钟中断(MCU硬件定时器中断或嘀嗒定时器中断)是rt-thread线程调度的驱动力。

    三、软件定时器线程模式下线程调度驱动

    若在rtconfig.h中定义了宏RT_USING_TIMER_SOFT,则使用软件定时器线程模式,此模式下系统中存在定时器线程timer_thread(在rt_system_timer_thread_init中初始化)。在此线程入口函数中通过rt_tick的增加不停地检查定时器链表中是否有定时器超时,其中也包含线程睡眠时启动的线程定时器,一旦线程对应的定时器超时,则触发相应的线程定时器超时函数rt_thread_timeout(将当前挂起的线程加入到调度器就绪队列后重新调度),从而将线程从睡眠中唤醒。

    由此可见,在软件定时器线程模式下,rt_system_timer_thread_init中初始化的定时器线程timer_thread就是rt-thread线程调度的驱动力。

  • 相关阅读:
    48、Windows驱动程序模型笔记(六),同步
    44、Windows驱动程序模型笔记(二)
    JavaP:对象创建
    JavaP:继承和多态【只有提纲】
    ASP.NET MVC:一个简单MVC示例
    JavaP: 2、类和对象
    ASP.NET MVC:解析 MVC+ADO.NET Entity(实体类)
    Oracle: 一、Oracle简介,安装,基本使用,建表增删改查,数据类型及常用命令
    JavaP:面向对象编程
    ASP.NET: PagedDataSource
  • 原文地址:https://www.cnblogs.com/King-Gentleman/p/4283453.html
Copyright © 2020-2023  润新知