[应用方案] Cortex-M内核知识点总结

[复制链接]
5817|105
 楼主| 米多0036 发表于 2023-9-15 15:46 | 显示全部楼层
取向量
在入栈的同时 , 指令总线会获取程序状态字中的异常号 ,在中断向量表中查询对应的 中断服务地址入口。
 楼主| 米多0036 发表于 2023-9-15 15:47 | 显示全部楼层
寄存器更新
更新栈指针SP , 选择栈指针 MSP, 更新连接寄存器LR , 程序计数器PC,在入栈完成后,栈指针会更新(PSP或者MSP因为压栈操作而生长), 在执行服务程序时,将由MSP 负责对堆栈的访问。更新LR 比较特殊,前面我们说过LR 寄存器在函数调用过程中的作用 : 它记录了被调函数的下一条指令地址,这样函数返回后就可以继续执行。但在中断服务中LR 会有特殊的用法 ,在进入中断服务程序后 , LR 会被计算赋值为 EXC_RETURN (异常返回)
 楼主| 米多0036 发表于 2023-9-15 15:47 | 显示全部楼层

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
 楼主| 米多0036 发表于 2023-9-15 15:47 | 显示全部楼层

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
 楼主| 米多0036 发表于 2023-9-15 15:48 | 显示全部楼层

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
 楼主| 米多0036 发表于 2023-9-15 15:48 | 显示全部楼层
LR的取值只有以上3种(以上为CM3的异常返回,其余需要找对应的ARM核) , 他能修改中断服务返回后的模式和使用哪个堆栈指针 , 还记得CONTROL 寄存器吗 它在特权模式下,也能修改模式和选择栈指针。只不过,CONTROL 寄存器是主动修改 , 这里的LR 值是系统自己判断的 , 判断依据如下:
 楼主| 米多0036 发表于 2023-9-15 15:49 | 显示全部楼层
主程序在线程模式下 , 并且使用MSP 被中断 , 则 EXC_RETURN 的 值为 0xFFFFFFF9 (裸机系统为这个)

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
 楼主| 米多0036 发表于 2023-9-15 15:49 | 显示全部楼层
主程序在线程模式下 , 并且使用PSP 被中断 , 则 EXC_RETURN 的 值为 0xFFFFFFFD (RTOS系统为这个)
 楼主| 米多0036 发表于 2023-9-15 15:49 | 显示全部楼层

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
 楼主| 米多0036 发表于 2023-9-15 15:50 | 显示全部楼层
异常返回时,只需要令PC 等于 LR 即可, 系统会自动切换模式 和 选择栈指针 , 并且从栈中恢复先前寄存器的值(包括PC重新回到打断的地方)。可以看到,中断始终使用的是主堆栈 , 因此中断的嵌套深度,局部变量,函数调用都会消耗主堆栈,在RTOS设计时,不仅需要考虑每个线程的栈空间大小,还需要考虑主堆栈的空间大小。
 楼主| 米多0036 发表于 2023-9-15 15:50 | 显示全部楼层
调度器
为什么需要调度器
实时性
在顺序执行结构中,常见的任务处理模式如下:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
 楼主| 米多0036 发表于 2023-9-15 15:50 | 显示全部楼层
int main(void)
{
    while(1)
    {
        do_something1();
        do_something2();
        do_something3();
    }
}
void ISR(void)
{
    do_something4();
}
 楼主| 米多0036 发表于 2023-9-15 15:51 | 显示全部楼层
可以发现,每一个任务的执行都受其余任务执行时间的影响,虽然有任务放在中断中执行 , 但其余非中断任务实时性得不到保证。为了提高实时性,基于一个事实,一般任务都有一个执行周期,比如按键检测任务,可以5ms扫描一次,显示任务可以50ms 刷新一次 ,传感器采集任务可以500ms采集一次。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
 楼主| 米多0036 发表于 2023-9-15 15:51 | 显示全部楼层
int main(void)
{
    while(1)
    {
        if(Timer5ms_flag){
                do_something1();
        }if(Timer10ms_flag){
            do_something2();
        }if(Timer8ms_flag){
            do_something3();
        }
    }
}
void ISR(void)
{
    do_something4();
}
 楼主| 米多0036 发表于 2023-9-15 15:51 | 显示全部楼层
按照上述方式 , 由于将各个任务指定执行周期 , 在同一时刻让任务就绪错开 , 这样单个任务的实时性得到了提高。

按上述方法,实时性有一定的提高,多数情况下不会出现多个任务就绪的情况,但是极端情况下也会出现,如某个任务执行时间过长或执行时间不确定,破环了上图的任务错开时间运行的平衡 , 或者周期互为公约数,且启动时时间未使用质数错开 ,最终会出现类似 “共振”的现象,隔一段时间多个任务同时就绪。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
 楼主| 米多0036 发表于 2023-9-15 15:51 | 显示全部楼层
多个任务同时就绪 , 我们更期望的时并行处理,而不是串行,如上图所示。但是MCU为单核,无法并行处理,为了实现类并行处理,时间片轮转调度由此而生。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
 楼主| 米多0036 发表于 2023-9-15 15:52 | 显示全部楼层
时间片即任务允许执行的最长时间,时间到了就需要切换到下一个任务执行,时间片轮转需要考虑的是任务执行时间到了,如何切换到下一个任务,如何保存当前任务执行环境,如何恢复下一任务的执行环境等,当前主流的RTOS都支持时间片调度。虽然任务切换会消耗一定的时间,但是任务本身在时间片足够小时,几乎可以任务是并行执行。
 楼主| 米多0036 发表于 2023-9-15 15:52 | 显示全部楼层
解耦合
调度器能提供统一的接口,管理任务执行时序,避免了各种就绪标志位胡乱分布耦合。后文中将介绍几种常见的调度器实现,可以发现基于调度器框架开发的优势
 楼主| 米多0036 发表于 2023-9-15 15:52 | 显示全部楼层
裸机下的调度器
使用软件定时器实现调度
  1. /***************************************************************************//**
  2. * [url=home.php?mod=space&uid=247401]@brief[/url]         设置ctimer定时器
  3. * [url=home.php?mod=space&uid=1543424]@Details[/url]      
  4. *
  5. * @param[in]     period    运行周期
  6. * @param[in]     counter   运行次数
  7. * @param[in]     p_func    函数指针
  8. * @param[in]     p_arg     函数
  9. * [url=home.php?mod=space&uid=266161]@return[/url]        分配的定时器指针,如果没有定时器分配,返回NULL
  10. *
  11. * [url=home.php?mod=space&uid=536309]@NOTE[/url]         
  12. * [url=home.php?mod=space&uid=8537]@see[/url]           
  13. * [url=home.php?mod=space&uid=157211]@warning[/url]      
  14. ******************************************************************************/
  15. struct ctimer* ctimer_set(UINT32 ulPeriod, UINT32 ulCount, void (*pfFunc)(void* p), void* pArg);
  16. void ctimer_mainloop(void);
  17. void task1_process(void* pArg)
  18. {
  19.    
  20. }
  21. void task2_process(void* pArg)
  22. {
  23.    
  24. }
  25. int main(void)
  26. {
  27.     ctimer_set( 5,  0  , task1_process, NULL);
  28.     ctimer_set( 20,  0 , task1_process, NULL);
  29.     while(1)
  30.     {
  31.         ctimer_mainloop();
  32.     }
  33. }
 楼主| 米多0036 发表于 2023-9-15 15:53 | 显示全部楼层
使用事件驱动的调度器
QP状态机框架: https://www.state-machine.com/
  1. /********************************************************************
  2. upgrade fsm:

  3.        <--------------------------------------------------
  4.       /                                            \      \
  5.     idle -----> info ----->transfer ------------> finsh    \
  6.                   \            \                            \
  7.                    \            \                            \
  8.                     --------------------------------------->error
  9.                     
  10. *********************************************************************/
  11. R_state_t ecu_upgrade_state_idle(fsm_t* me, uint32_t evt)
  12. {
  13.     switch(evt)
  14.     {
  15.         case SYS_ENTER_EVT:
  16.         {
  17.             log_d("enter idle state");
  18.             memset(&upgrade_info , 0 , sizeof(struct ecu_upgrade_info));
  19.             return S_HANDLE();
  20.         }
  21.         case ECU_UPGRADE_REQUEST_EVT:
  22.         {
  23.             return S_TRAN(ecu_upgrade_state_transfer);
  24.             //return S_TRAN(ecu_upgrade_state_info);
  25.         }
  26.         default:
  27.         {
  28.              return S_IGNORE();
  29.         }
  30.     }
  31. }
  32. R_state_t ecu_upgrade_state_info(fsm_t* me, uint32_t evt)
  33. {
  34.     switch(evt)
  35.     {
  36.         case SYS_ENTER_EVT:
  37.         {
  38.             /*step1:   session control*/
  39.             /*step2:   security_access*/
  40.             /*step3:   file_download request*/
  41.             /*period:  tester present*/
  42.             fsm_set_timeout_evt(me , 3000 , SYS_TIMEOUT_EVT);
  43.             return S_HANDLE();
  44.         }
  45.         case SYS_TIMEOUT_EVT:
  46.         {
  47.             /*period:  tester present*/
  48.             fsm_set_timeout_evt(me , 3000 , SYS_TIMEOUT_EVT);
  49.             return S_HANDLE();
  50.         }   
  51.         default:
  52.         {
  53.             return S_IGNORE();
  54.         }
  55.     }
  56. }
  57. ...
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部