FreeRTOS在Cortex-M系列内核中遇到的关于系统滴答中断的问题

这篇具有很好参考价值的文章主要介绍了FreeRTOS在Cortex-M系列内核中遇到的关于系统滴答中断的问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

众所周知,在Cortex-M内核中,系统节拍由Systick时钟提供,当配置好系统滴答时钟后,每次时钟中断就会触发中断处理函数 xPortSysTickHandler(),

void xPortSysTickHandler( void )
{
    /* The SysTick runs at the lowest interrupt priority, so when this interrupt
     * executes all interrupts must be unmasked.  There is therefore no need to
     * save and then restore the interrupt mask value as its value is already
     * known - therefore the slightly faster vPortRaiseBASEPRI() function is used
     * in place of portSET_INTERRUPT_MASK_FROM_ISR(). */
    vPortRaiseBASEPRI();//屏蔽归属FreeRTOS的中断优先级
    {
        /* Increment the RTOS tick. */
        if( xTaskIncrementTick() != pdFALSE )//时钟计数处理
        {
            /* A context switch is required.  Context switching is performed in
             * the PendSV interrupt.  Pend the PendSV interrupt. */
            portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;//如果需要切换上下文操作,PendSV标记置位
        }
    }

    vPortClearBASEPRIFromISR();
}

 文章来源地址https://www.toymoban.com/news/detail-710424.html

  这部分主要是依靠 xTaskIncrementTick(),来判断任务切换是否在此次系统时钟中断时被需要。如果是,则PendSV标记置位,等待触发PendSV中断。

  来看看 xTaskIncrementTick()

BaseType_t xTaskIncrementTick( void )
{
    TCB_t * pxTCB;
    TickType_t xItemValue;
    BaseType_t xSwitchRequired = pdFALSE;

    /* Called by the portable layer each time a tick interrupt occurs.
     * Increments the tick then checks to see if the new tick value will cause any
     * tasks to be unblocked. */
    traceTASK_INCREMENT_TICK( xTickCount );

    if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) //调度是否被挂起,默认为否
    {
        /* Minor optimisation.  The tick count cannot change in this
         * block. */
        const TickType_t xConstTickCount = xTickCount + ( TickType_t ) 1;

        /* Increment the RTOS tick, switching the delayed and overflowed
         * delayed lists if it wraps to 0. */
        xTickCount = xConstTickCount;

        if( xConstTickCount == ( TickType_t ) 0U ) /*lint !e774 'if' does not always evaluate to false as it is looking for an overflow. 如果xConstTickCount为0,说明溢出了*/
        {
            taskSWITCH_DELAYED_LISTS();/*切换延迟列表*/
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

        /* See if this tick has made a timeout expire.  Tasks are stored in
         * the  queue in the order of their wake time - meaning once one task
         * has been found whose block time has not expired there is no need to
         * look any further down the list. */
        if( xConstTickCount >= xNextTaskUnblockTime )
        {
            for( ; ; )
            {
                if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
                {
                    /* The delayed list is empty.  Set xNextTaskUnblockTime
                     * to the maximum possible value so it is extremely
                     * unlikely that the
                     * if( xTickCount >= xNextTaskUnblockTime ) test will pass
                     * next time through. */
                    xNextTaskUnblockTime = portMAX_DELAY; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
                    break;
                }
                else
                {
                    /* The delayed list is not empty, get the value of the
                     * item at the head of the delayed list.  This is the time
                     * at which the task at the head of the delayed list must
                     * be removed from the Blocked state. */
                    pxTCB = listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too.  Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
                    xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) );
......
   

  关键问题是,这个函数使用到了 pxDelayedTaskList, 这定义在本文件

PRIVILEGED_DATA static List_t * volatile pxDelayedTaskList; 

  该变量初始化为0,该变量正常初始化位置在创建 Task 对象等的函数中, 也就是说,如果在Tick中断到来时,如果还没有任务被创建,就会导致不可预期的结果,中断服务函数会使用这个野指针,执行任务切换。

  这会导致触发栈溢出钩子函数,或者是直接 Hardfault。

  

  有些硬件初始化需要借助delay功能,不得不在初始化之前配置SysTick。而又不希望在硬件初始化阶段触发这个Bug。

  所以在配置SysTick之前,先创建一个初始化任务,初始化 pxDelayedTaskList 这个指针,在初始化任务里配置SysTick,和其他初始化,这样能够避免此类问题。

  或者是在配置SysTick的时候屏蔽中断,一切准备就绪后,开启中断。

  执行 vTaskStartScheduler(),默认创建一个空闲任务。

 

到了这里,关于FreeRTOS在Cortex-M系列内核中遇到的关于系统滴答中断的问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【ARM Cortex-M 系列 2 -- CPU 之 Cortex-M7 介绍】

    请阅读 【ARM Coresight | AMBA BUS| Armv8/v9 | GCC 专栏导读】 上篇文章:ARM Cortex-M 系列 1 番外篇-- Cortex-M0, M3, M4, M7, M33 , M35P 差异 下篇文章:ARM Cortex-M 系列 2.1 – RT-Thread Cortex-M7 异常处理及 hardfault 处理分析 Cortex-M7是基于ARMv7架构,ARMv7 架构主要分为以下三类: 其中 Cortex-M 系列应用

    2024年02月17日
    浏览(27)
  • 【ARM Cortex-M 系列 1.1 -- Cortex-M33 与 M4 差异 详细介绍】

    请阅读 【嵌入式开发学习必备专栏 之 Cortex-Mx 专栏】 在移植 RT-Thread 到 瑞萨RA4M2(Cortex-M33)上时,遇到了hardfault 问题,最后使用了Cortex-M4中的调度相关的函数后,OS 可以正常调度了。所以这里做下 M33与 M4的关系梳理。 ARM Cortex-M33 和 Cortex-M4 都是 ARM 公司设计的32位RISC微处理

    2024年01月21日
    浏览(32)
  • Cortex-M3/M4内核中断及HAL库函数详解(1):中断相关寄存器

    Keil uVision5 Cortex M3权威指南(中文) Cortex M3与M4权威指南 stm32f407的HAL库工程 STM32F4xx中文参考手册 在Cortex-M3/M4内核上搭载了一个异常响应系统,支持为数众多的系统异常和外部中断。其中,Cortex-M3/M4内核包括15个系统异常,大部分系统异常的中断优先级都可以设置。外部中断由

    2024年01月21日
    浏览(40)
  • 【ARM Cortex-M 系列 1 -- Cortex-M0, M3, M4, M7, M33 差异】

    请阅读 【ARM Coresight | AMBA BUS| Armv8/v9 | GCC 专栏导读】 下篇文章:ARM Cortex-M 系列 2 – CPU 之 Cortex-M7 介绍 Cortex-M0/M0+ 介绍 Cortex-M0 是 ARM 公司推出的一款微控制器(MCU)核心。这个核心是基于 ARMv6-M 架构设计的, 只支持 56 条指 令的小指令集,大部分指令是 16 位指令, 是 ARM Cor

    2024年02月17日
    浏览(32)
  • Cortex-M3/M4内核NVIC及HAL库函数详解(2):HAL库中断底层函数实现

    Keil uVision5 Cortex M3权威指南(中文) Cortex M3与M4权威指南 stm32f407的HAL库工程 STM32F4xx中文参考手册 打开stm32f407的HAL库工程,可以在CMSIS-Include-core_cm4.h内找到有关NVIC寄存器设置的相关函数: 该函数操作步骤如下: (1)读取SCB-AIRCR旧值,保存到reg_value (2)将reg_value的bit31-16(访

    2024年01月20日
    浏览(41)
  • Cortex-M3/M4内核NVIC及HAL库函数详解(4):使用HAL库配置外部中断

    Keil uVision5 Cortex M3权威指南(中文) Cortex M3与M4权威指南 stm32f407的HAL库工程 STM32F4xx中文参考手册 前面我们已经熟悉了有关内核部分的寄存器配置,接下来我们结合stm32f407的GPIO外设,从实战角度进一步加深对这些寄存器的认识。 我们这里使用PA0作为输入引脚,可以看到SW1未按

    2024年01月24日
    浏览(37)
  • 【ARM Cortex-M 系列 1 -- Cortex-M0, M3, M4, M7, M33, M35P 差异】

    请阅读 【ARM Coresight | AMBA BUS| Armv8/v9 | GCC 专栏导读】 下篇文章:ARM Cortex-M 系列 2 – CPU 之 Cortex-M7 介绍 Cortex-M0/M0+ 介绍 Cortex-M0 是 ARM 公司推出的一款微控制器(MCU)核心。这个核心是基于 ARMv6-M 架构设计的, 只支持 56 条指 令的小指令集,大部分指令是 16 位指令, 是 ARM Cor

    2024年02月05日
    浏览(34)
  • 关于stm32 Flash Download failed -“Cortex-M3”的问题

    当使用仿真器或者其他方式烧录程序进入单片机时,有时候会遇到Flash Download failed -“Cortex-M3”的提示弹窗 1.首先我们可以检查一下型号是否选对,点击魔术棒选中Device选择与自己单片机相匹配的型号 (例如我的是野火的指南者所以我选择STM32F103VE)    再点击Debug选择自己所

    2024年02月13日
    浏览(42)
  • SUB-1G SOC芯片DP4306F 32 位 ARM Cortex-M0+内核替代CMT2380F32

    DP4306F是一款高性能低功耗的单片集成收发机,集成MO核MCU,工作频率可覆盖200MHiz^ 1000MHz。 支持230/408/433/470/868/915频段。该芯片集成了射频接收器、射频发射器、频率综合器、GFSK调制器、GFSK解调器等功能模块。通过SPI接口可以对输出功率、频道选择以及数据包格式进行灵活配

    2024年02月07日
    浏览(31)
  • 【ARMv8M Cortex-M33 系列 1 -- SAU 介绍】

    请阅读 【嵌入式开发学习必备专栏 之Cortex-M33 专栏】 在 ARMv8-M 架构中,SAU(Security Attribution Unit)是安全属性单元,用于配置和管理内存区域的安全属性。SAU 是 ARM TrustZone 技术的一部分,该技术提供了在单个处理器中创建安全(Secure)和非安全(Non-secure)状态的能力,允许

    2024年02月04日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包