FreeRTOS临界段和开关中断

2023-11-11

http://blog.sina.com.cn/s/blog_98ee3a930102wg5u.html

本章教程为大家讲解两个重要的概念,FreeRTOS的临界段和开关中断。

本章教程配套的例子含Cortex-M3内核的STM32F103Cortex-M4内核的STM32F407以及F429

15.1 临界段

15.2 任务代码临界段处理

15.3 中断服务程序临界段处理

15.4 开关中断的实现

15.5 BSP板级支持包中开关中断的特别处理

15.6. 实验例程说明

15.7       总结

 

 

15.1  临界段

代码的临界段也称为临界区,一旦这部分代码开始执行,则不允许任何中断打断。为确保临界段代码的执行不被中断,在进入临界段之前须关中断,而临界段代码执行完毕后,要立即开中断。

 

l  FreeRTOS临界段相关知识补充

FreeRTOS的源码中有多处临界段的地方,临界段虽然保护了关键代码的执行不被打断,但也会影响系统的实时性。比如此时某个任务正在调用系统API函数,而且此时中断正好关闭了,也就是进入到了临界区中,这个时候如果有一个紧急的中断事件被触发,这个中断就不能得到及时执行,必须等到中断开启才可以得到执行,如果关中断时间超过了紧急中断能够容忍的限度,危害是可想而知的。

 

FreeRTOS源码中就有多处临界段的处理,跟FreeRTOS一样,uCOS-IIuCOS-III源码中都是有临界段的,而RTX的源码中不存在临界段。另外,除了FreeRTOS操作系统源码所带的临界段以外,用户写应用的时候也有临界段的问题,比如以下两种:

u  读取或者修改变量(特别是用于任务间通信的全局变量)的代码,一般来说这是最常见的临界代码。

u  调用公共函数的代码,特别是不可重入的函数,如果多个任务都访问这个函数,结果是可想而知的。

总之,对于临界段要做到执行时间越短越好,否则会影响系统的实时性。

15.2 任务代码临界段处理

FreeRTOS任务代码中临界段的进入和退出主要是通过操作寄存器basepri实现的。进入临界段前操作寄存器basepri关闭了所有小于等于宏定义configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY所定义的中断优先级,这样临界段代码就不会被中断干扰到,而且实现任务切换功能的PendSV中断和滴答定时器中断是最低优先级中断,所以此任务在执行临界段代码期间是不会被其它高优先级任务打断的。退出临界段时重新操作basepri寄存器,即打开被关闭的中断这里我们不考虑不受FreeRTOS管理的更高优先级中断FreeRTOS进入和退出临界段的函数如下:

#define taskENTER_CRITICAL()         portENTER_CRITICAL()

#define taskEXIT_CRITICAL()          portEXIT_CRITICAL()

上面这两个函数是供用户调用的,其中函数taskENTER_CRITICAL是进入临界段,函数taskEXIT_CRITICAL是退出临界段。进一步跟踪宏定义的实现如下:

#define portENTER_CRITICAL()         vPortEnterCritical()

#define portEXIT_CRITICAL()          vPortExitCritical()

再进一步跟踪宏定义的实现如下:

void vPortEnterCritical( void )

{

     portDISABLE_INTERRUPTS();

     uxCriticalNesting++;

 

    

     if( uxCriticalNesting == 1 )

     {

         configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );

     }

}

 

 

void vPortExitCritical( void )

{

     configASSERT( uxCriticalNesting );

     uxCriticalNesting--;

     if( uxCriticalNesting == 0 )

     {

         portENABLE_INTERRUPTS();

     }

}

通过上面的两个函数vPortEnterCriticalvPortExitCritical可以看出,进入临界段和退出临界段是通过函数调用开关中断函数portENABLE_INTERRUPTSportDISABLE_INTERRUPTS实现的。细心的读者还会发现上面的这两个函数都对变量uxCriticalNesting进行了操作。这个变量比较重要,用于临界段的嵌套计数。初学的同学也许会问这里直接的开关中断不就可以了吗,为什么还要做一个嵌套计数呢?主要是因为直接的开关中断方式不支持在开关中断之间的代码里再次执行开关中断的嵌套处理,假如当前我们的代码是关闭中断的,嵌套了一个含有开关中断的临界区代码后,退出时中断就成开的了,这样就出问题了。通过嵌套计数就有效地防止了用户嵌套调用函数taskENTER_CRITICALtaskEXIT_CRITICAL时出错。

l  直接的开关中断方式不支持嵌套调用例子说明

比如下面的例子:

void FunctionA()

{

taskDISABLE_INTERRUPTS();  关闭中断

FunctionB(); 调用函数B

FunctionC(); 调用函数C

taskENABLE_INTERRUPTS();  打开中断

}

 

void FunctionB()

{

taskDISABLE_INTERRUPTS();  关闭中断

代码

taskENABLE_INTERRUPTS();  打开中断

}

工程中调用了FunctionA就会出现执行完FunctionB后中断被打开的情况,此时FunctionC

不被保护了。

 

接下来继续说明开关中断的实现,我们要打破砂锅问到底:

#define portDISABLE_INTERRUPTS()          vPortRaiseBASEPRI()

#define portENABLE_INTERRUPTS()           vPortSetBASEPRI( 0 )

函数vPortRaiseBASEPRIvPortSetBASEPRI的源码实现如下:

static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )

{

     __asm

     {

        

         msr basepri, ulBASEPRI

     }

}

 

 

static portFORCE_INLINE void vPortRaiseBASEPRI( void )

{

uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;

 

     __asm

     {

         

         msr basepri, ulNewBASEPRI

         dsb

         isb

     }

}

经过这么多次的宏定义后,终于来到了最终的原始函数。FreeRTOS的这种层层调用宏定义的方法在带来便利操作的同时,却让用户在分析源码的时候非常不方便。

通过上面的源码实现可以看出,FreeRTOS的开关全局中断是通过操作寄存器basepri实现的,关于这个寄存器,我们已经在第12章进行了详细的讲解,这里不再赘述。

使用举例:

使用的时候一定要保证成对使用

 

static void vTaskLED(void *pvParameters)

{

     TickType_t xLastWakeTime;

     const TickType_t xFrequency = 200;

 

    

    xLastWakeTime = xTaskGetTickCount();

    

    while(1)

    {

            

         taskENTER_CRITICAL();

         printf("任务vTaskLED正在运行\r\n");

            

         taskEXIT_CRITICAL();

         bsp_LedToggle(2);

         bsp_LedToggle(3);

        

       

        vTaskDelayUntil(&xLastWakeTime, xFrequency);

    }

}

嵌套使用举例:

void FunctionB()

{

     taskENTER_CRITICAL()

     临界段代码

     taskEXIT_CRITICAL();

 

}

 

void FunctionA()

{

     taskENTER_CRITICAL(); 

FunctionB();            

FunctionC();               

     taskEXIT_CRITICAL();   

}

15.3 中断服务程序临界段处理

与任务代码里临界段的处理方式类似,中断服务程序里面临界段的处理也有一对开关中断函数。

#define taskENTER_CRITICAL_FROM_ISR()     portSET_INTERRUPT_MASK_FROM_ISR()

#define taskEXIT_CRITICAL_FROM_ISR( x )   portCLEAR_INTERRUPT_MASK_FROM_ISR( x )

进一步跟踪宏定义的实现如下:

#define portSET_INTERRUPT_MASK_FROM_ISR()      ulPortRaiseBASEPRI()

#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x)   vPortSetBASEPRI(x)

再进一步跟踪宏定义的实现如下:

static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )

{

     __asm

     {

        

         msr basepri, ulBASEPRI

     }

}

 

static portFORCE_INLINE uint32_t ulPortRaiseBASEPRI( void )

{

uint32_t ulReturn, ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;

 

     __asm

     {

        

         mrs ulReturn, basepri

         msr basepri, ulNewBASEPRI

         dsb

         isb

     }

 

     return ulReturn;

}

通过上面的源码可以看出,中断服务程序里面的临界段代码的开关中断也是通过寄存器basepri实现的。

初学的同学也许会问,这里怎么没有中断嵌套计数了呢?是的,这里换了另外一种实现方法,通过保存和恢复寄存器basepri的数值就可以实现嵌套使用。如果大家研究过uCOS-II或者III的源码,跟这里的实现方式是一样的,具体看下面的使用举例。

使用举例:

使用的时候一定要保证成对使用

 

void TIM6_DAC_IRQHandler( void )

{

UBaseType_t uxSavedInterruptStatus;

 

uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();

     临界区代码

portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );

 

}

嵌套使用举例:

void FunctionB()

{

UBaseType_t uxSavedInterruptStatus;

 

uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();

     临界区代码

portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );

}

 

 

 

void TIM6_DAC_IRQHandler( void )

{

UBaseType_t uxSavedInterruptStatus;

 

uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();

FunctionB(); 

FunctionC();     

portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );

}

15.4开关中断的实现

FreeRTOS也专门提供了一组开关中断函数,实现比较简单,其实就是前面15.2小节里面临界段进入和退出函数的精简版本,主要区别是不支持中断嵌套。具体实现如下:

#define taskDISABLE_INTERRUPTS()   portDISABLE_INTERRUPTS()

#define taskENABLE_INTERRUPTS()    portENABLE_INTERRUPTS()

进一步跟踪宏定义的实现如下:

#define portDISABLE_INTERRUPTS()          vPortRaiseBASEPRI()

#define portENABLE_INTERRUPTS()           vPortSetBASEPRI( 0 )

函数vPortRaiseBASEPRIvPortSetBASEPRI的源码实现如下:

static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )

{

     __asm

     {

        

         msr basepri, ulBASEPRI

     }

}

 

 

static portFORCE_INLINE void vPortRaiseBASEPRI( void )

{

uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;

 

     __asm

     {

         

         msr basepri, ulNewBASEPRI

         dsb

         isb

     }

}

从上面的源码可以看出,FreeRTOS的全局中断开关是通过操作寄存器basepri实现的,关于这个寄存器,我们已经在第12章进行了详细的讲解,这里不再赘述。

使用举例:

使用的时候一定要保证成对使用

 

static void vTaskLED(void *pvParameters)

{

     TickType_t xLastWakeTime;

     const TickType_t xFrequency = 200;

 

    

    xLastWakeTime = xTaskGetTickCount();

    

    while(1)

    {

              

         taskDISABLE_INTERRUPTS();

         printf("任务vTaskLED正在运行\r\n");

              

          taskENABLE_INTERRUPTS();

         bsp_LedToggle(2);

         bsp_LedToggle(3);

        

       

        vTaskDelayUntil(&xLastWakeTime, xFrequency);

    }

}

15.5BSP板级支持包中开关中断的特别处理

前面为大家讲解了FreeRTOS临界段的处理方法和开关中断方法,加上了FreeRTOS操作系统后,我们实际编写的外设驱动又该怎么修改呢?因为外设驱动编写时,有些地方有用到开关中断操作,这里以此教程配套的STM32F103F407F429开发板为例进行说明,这三种开发板的外设驱动的编写架构都是统一的,用户只需将bsp.h文件里面的宏定义:

 

#define ENABLE_INT()   __set_PRIMASK(0)  

#define DISABLE_INT()  __set_PRIMASK(1)  

修改为如下的形式:

#define  USE_FreeRTOS      1

 

#if USE_FreeRTOS == 1

     #include "FreeRTOS.h"

     #include "task.h"

     #define DISABLE_INT()    taskENTER_CRITICAL()

     #define ENABLE_INT()     taskEXIT_CRITICAL()

#else

    

     #define ENABLE_INT()   __set_PRIMASK(0)  

     #define DISABLE_INT()  __set_PRIMASK(1)  

#endif

u  #define  USE_FreeRTOS      1

将中断开关设置改成了条件编译的形式,这样在使用裸机或者使用FreeRTOS时,切换自如。此宏定义配置为1表示使用FreeRTOS的开关中断API函数,配置为0表示使用裸机的方式开关中断。

u  采用taskENTER_CRITICAL()taskEXIT_CRITICAL()实现开关中断

因为BSP驱动包的源码基本没有在中断里面进行开关中断,都是在中断以外,所以开关中断是采用的任务代码里面临界段的处理函数,而且支持嵌套调用。

大家写的工程代码也可以采用类似的方案,方便裸机和FreeRTOS的切换,或者采用其它适合自己的方案。另外要注意,因为FreeRTOS存在不受其控制的更高优先级中断,用户需要根据实际情况进行特别处理,可以不采用FreeRTOS的开关中断函数,而是直接使用__set_PRIMASK实现全局中断的开关。

15.6实验例程说明

15.6.1STM32F103开发板实验

配套例子:

V4-309_FreeRTOS实验_临界段和开关中断

实验目的:

1.     学习FreeRTOS的临界段和开关中断设置

实验内容:

1.     K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。

2.     K2按键按下,挂起任务vTaskLED

3.     K3按键按下,启动单次定时器中断,50ms后在定时器中断将任务vTaskLED恢复。

4.     本实验printf函数的多任务调用通过任务代码中临界段的进入和退出函数taskENTER_CRITICAL()taskEXIT_CRITICAL()实现互斥效果。

5.     本实验中断服务程序中临界段的调用通过函数portSET_INTERRUPT_MASK_FROM_ISR()portCLEAR_INTERRUPT_MASK_FROM_ISR()实现保护。

6.     各个任务实现的功能如下:

              vTaskUserIF任务   :按键消息处理。

              vTaskLED任务     LED闪烁和串口打印。

              vTaskMsgPro任务 :消息处理,这里是用作LED闪烁和串口打印。

              vTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。

FreeRTOS的配置:

FreeRTOSConfig.h文件中的配置如下:

 

#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)

 #include

 extern volatile uint32_t ulHighFrequencyTimerTicks;

#endif

 

#define configUSE_PREEMPTION         1

#define configUSE_IDLE_HOOK          0

#define configUSE_TICK_HOOK          0

#define configCPU_CLOCK_HZ           ( ( unsigned long ) 72000000 )  

#define configTICK_RATE_HZ           ( ( TickType_t ) 1000 )

#define configMAX_PRIORITIES         ( 5 )

#define configMINIMAL_STACK_SIZE     ( ( unsigned short ) 128 )

#define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )

#define configMAX_TASK_NAME_LEN      ( 16 )

#define configUSE_TRACE_FACILITY      1

#define configUSE_16_BIT_TICKS       0

#define configIDLE_SHOULD_YIELD      1

 

 

#define configGENERATE_RUN_TIME_STATS                1

#define configUSE_STATS_FORMATTING_FUNCTIONS         1

#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()     (ulHighFrequencyTimerTicks = 0ul)

#define portGET_RUN_TIME_COUNTER_VALUE()             ulHighFrequencyTimerTicks

//#define portALT_GET_RUN_TIME_COUNTER_VALUE           1

 

 

#define configUSE_CO_ROUTINES            0

#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )

 

 

 

#define INCLUDE_vTaskPrioritySet          1

#define INCLUDE_uxTaskPriorityGet         1

#define INCLUDE_vTaskDelete               1

#define INCLUDE_vTaskCleanUpResources      0

#define INCLUDE_vTaskSuspend              1

#define INCLUDE_vTaskDelayUntil           1

#define INCLUDE_vTaskDelay                1

 

 

#ifdef __NVIC_PRIO_BITS

    

     #define configPRIO_BITS              __NVIC_PRIO_BITS

#else

     #define configPRIO_BITS              4       

#endif

 

 

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY              0x0f

 

 

#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY         0x01


FreeRTOS任务调试信息(按K1按键,串口打印):

【FreeRTOS操作系统教程】第15章 <wbr>FreeRTOS临界段和开关中断

 

上面截图中打印出来的任务状态字母B, R, D, S对应如下含义:

#define tskBLOCKED_CHAR          ( 'B' )  任务阻塞

#define tskREADY_CHAR           ( 'R' )  任务就绪

#define tskDELETED_CHAR           ( 'D' )  任务删除

#define tskSUSPENDED_CHAR   ( 'S' )  任务挂起

程序设计:

u  任务栈大小分配:

vTaskUserIF任务   2048字节

vTaskLED任务     2048字节

vTaskMsgPro任务 :2048字节

vTaskStart任务    2048字节

任务栈空间是在任务创建的时候从FreeRTOSConfig.h文件中定义的heap空间中申请的

#define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )

u  系统栈大小分配:

【FreeRTOS操作系统教程】第15章 <wbr>FreeRTOS临界段和开关中断

 

u  FreeROTS初始化:

 

int main(void)

{

    

     __set_PRIMASK(1); 

    

    

     bsp_Init();

    

    

     vSetupSysInfoTest();

    

    

     AppTaskCreate();

    

   

    vTaskStartScheduler();

 

    

     while(1);

}

u  硬件外设初始化

硬件外设的初始化是在bsp.c文件实现:

 

void bsp_Init(void)

{

    

    

          NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

 

     bsp_InitUart();   

     bsp_InitLed();    

     bsp_InitKey();    

 

     bsp_InitHardTimer();

}

u  FreeRTOS任务创建:

 

static void AppTaskCreate (void)

{

    xTaskCreate( vTaskTaskUserIF,  

                 "vTaskUserIF",    

                 512,              

                 NULL,             

                 1,                

                 &xHandleTaskUserIF );  /* 任务句柄  */

    

    

     xTaskCreate( vTaskLED,          

                 "vTaskLED",        

                 512,               

                 NULL,              

                 2,                 

                 &xHandleTaskLED );

    

     xTaskCreate( vTaskMsgPro,           

                 "vTaskMsgPro",          

                 512,                    

                 NULL,                   

                 3,                      

                 &xHandleTaskMsgPro );  /* 任务句柄  */

    

    

     xTaskCreate( vTaskStart,            

                 "vTaskStart",           

                 512,                    

                 NULL,                   

                 4,                      

                 &xHandleTaskStart );   

}

u  四个FreeRTOS任务的实现:

 

static void vTaskTaskUserIF(void *pvParameters)

{

     uint8_t ucKeyCode;

     uint8_t pcWriteBuffer[500];

 

    while(1)

    {

         ucKeyCode = bsp_GetKey();

        

         if (ucKeyCode != KEY_NONE)

         {

              switch (ucKeyCode)

              {

                  

                   case KEY_DOWN_K1: 

                       taskENTER_CRITICAL();         

                       printf("=================================================\r\n");

                       printf("任务名      任务状态 优先级   剩余栈 任务序号\r\n");

                       vTaskList((char *)&pcWriteBuffer);

                       printf("%s\r\n", pcWriteBuffer);

                  

                       printf("\r\n任务名       运行计数         使用率\r\n");

                       vTaskGetRunTimeStats((char *)&pcWriteBuffer);

                       printf("%s\r\n", pcWriteBuffer);

                       taskEXIT_CRITICAL();    

                       break;

                  

                  

                   case KEY_DOWN_K2:

                       taskENTER_CRITICAL();   

                       printf("K2键按下,挂起任务vTaskLED\r\n");

                       taskEXIT_CRITICAL();    

                       vTaskSuspend(xHandleTaskLED);

                       break;

                  

                  

                   case KEY_DOWN_K3:

                        taskENTER_CRITICAL();                       

                       printf("K3键按下,启动单次定时器中断,50ms后在定时器中断将任务vTaskLED恢复\r\n");

                       taskEXIT_CRITICAL(); 

                       bsp_StartHardTimer(1 ,50000, (void *)TIM_CallBack1);

                       break;

 

                  

                   default:                    

                       break;

              }

         }

        

         vTaskDelay(20);

     }

}

 

 

static void vTaskLED(void *pvParameters)

{

    while(1)

{

     taskENTER_CRITICAL();   

     printf("任务vTaskLED正在运行\r\n");

     taskEXIT_CRITICAL();    

     bsp_LedToggle(2);

     vTaskDelay(500);

    }

}

 

 

static void vTaskMsgPro(void *pvParameters)

{

    while(1)

{

     taskENTER_CRITICAL();  

     printf("任务vTaskMsgPro正在运行\r\n");

     taskEXIT_CRITICAL();     

     bsp_LedToggle(3);

     vTaskDelay(600);

    }

}

 

 

static void vTaskStart(void *pvParameters)

{

    while(1)

    {

        

         bsp_KeyScan();

        vTaskDelay(10);

    }

}

u  定时器中断回调函数中将任务从挂起状态恢复:

定时器中断的初始化和中断函数在bsp_timer.c 文件中实现,这个不是教程的重点,故不作介绍。 这里主要关心中断服务程序中临界段的实现方法。

 

static void TIM_CallBack1(void)

{

     BaseType_t xYieldRequired;

     UBaseType_t uxSavedInterruptStatus;

 

     uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();  

     {

        

     }

     portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );

 

   

     xYieldRequired = xTaskResumeFromISR(xHandleTaskLED);

 

      

     if( xYieldRequired == pdTRUE )

     {

         portYIELD_FROM_ISR(xYieldRequired);

     }

}

15.6.2STM32F407开发板实验

配套例子:

V5-309_FreeRTOS实验_临界段和开关中断

实验目的:

1. 学习FreeRTOS的临界段和开关中断设置

实验内容:

1.     K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。

2.     K2按键按下,挂起任务vTaskLED

3.     K3按键按下,启动单次定时器中断,50ms后在定时器中断将任务vTaskLED恢复。

4.     本实验printf函数的多任务调用通过任务代码中临界段的进入和退出函数taskENTER_CRITICAL()taskEXIT_CRITICAL()实现互斥效果。

5.     本实验中断服务程序中临界段的调用通过函数portSET_INTERRUPT_MASK_FROM_ISR()portCLEAR_INTERRUPT_MASK_FROM_ISR()实现保护。

6.     各个任务实现的功能如下:

              vTaskUserIF任务   :按键消息处理。

              vTaskLED任务     LED闪烁和串口打印。

              vTaskMsgPro任务 :消息处理,这里是用作LED闪烁和串口打印。

              vTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。

FreeRTOS的配置:

FreeRTOSConfig.h文件中的配置如下:

 

#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)

 #include

 extern volatile uint32_t ulHighFrequencyTimerTicks;

 

 

#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)

 #include

 extern volatile uint32_t ulHighFrequencyTimerTicks;

#endif

 

#define configUSE_PREEMPTION         1

#define configUSE_IDLE_HOOK          0

#define configUSE_TICK_HOOK           0

#define configCPU_CLOCK_HZ           ( ( unsigned long ) 168000000 ) 

#define configTICK_RATE_HZ           ( ( TickType_t ) 1000 )

#define configMAX_PRIORITIES         ( 5 )

#define configMINIMAL_STACK_SIZE     ( ( unsigned short ) 128 )

#define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 30 * 1024 ) )

#define configMAX_TASK_NAME_LEN      ( 16 )

#define configUSE_TRACE_FACILITY      1

#define configUSE_16_BIT_TICKS       0

#define configIDLE_SHOULD_YIELD      1

 

 

#define configGENERATE_RUN_TIME_STATS                1

#define configUSE_STATS_FORMATTING_FUNCTIONS         1

#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()     (ulHighFrequencyTimerTicks = 0ul)

#define portGET_RUN_TIME_COUNTER_VALUE()             ulHighFrequencyTimerTicks

//#define portALT_GET_RUN_TIME_COUNTER_VALUE           1

 

 

#define configUSE_CO_ROUTINES             0

#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )

 

 

 

#define INCLUDE_vTaskPrioritySet     1

#define INCLUDE_uxTaskPriorityGet         1

#define INCLUDE_vTaskDelete               1

#define INCLUDE_vTaskCleanUpResources 0

#define INCLUDE_vTaskSuspend              1

#define INCLUDE_vTaskDelayUntil           1

#define INCLUDE_vTaskDelay                1

 

 

#ifdef __NVIC_PRIO_BITS

    

     #define configPRIO_BITS              __NVIC_PRIO_BITS

#else

     #define configPRIO_BITS              4        

#endif

 

 

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY              0x0f

 

 

#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY    0x01


FreeRTOS任务调试信息(按K1按键,串口打印):

【FreeRTOS操作系统教程】第15章 <wbr>FreeRTOS临界段和开关中断

 

上面截图中打印出来的任务状态字母B, R, D, S对应如下含义:

#define tskBLOCKED_CHAR          ( 'B' )  任务阻塞

#define tskREADY_CHAR           ( 'R' )  任务就绪

#define tskDELETED_CHAR           ( 'D' )  任务删除

#define tskSUSPENDED_CHAR   ( 'S' )  任务挂起

程序设计:

u  任务栈大小分配:

vTaskUserIF任务   2048字节

vTaskLED任务     2048字节

vTaskMsgPro任务 :2048字节

vTaskStart任务    2048字节

任务栈空间是在任务创建的时候从FreeRTOSConfig.h文件中定义的heap空间中申请的

#define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 30 * 1024 ) )

u  系统栈大小分配:

【FreeRTOS操作系统教程】第15章 <wbr>FreeRTOS临界段和开关中断

 

u  FreeROTS初始化:

 

int main(void)

{

    

     __set_PRIMASK(1); 

    

    

     bsp_Init();

    

    

     vSetupSysInfoTest();

    

    

     AppTaskCreate();

    

   

    vTaskStartScheduler();

 

    

     while(1);

}

u  硬件外设初始化

硬件外设的初始化是在bsp.c文件实现:

 

void bsp_Init(void)

{

    

    

     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

 

     bsp_InitUart();   

     bsp_InitKey();    

     bsp_InitLed();    

 

     bsp_InitHardTimer();

}

u  FreeRTOS任务创建:

 

static void AppTaskCreate (void)

{

    xTaskCreate( vTaskTaskUserIF,  

                 "vTaskUserIF",    

                 512,              

                 NULL,             

                 1,                

                 &xHandleTaskUserIF );  /* 任务句柄  */

    

    

     xTaskCreate( vTaskLED,          

                 "vTaskLED",        

                 512,               

                 NULL,              

                 2,                 

                 &xHandleTaskLED );

    

     xTaskCreate( vTaskMsgPro,           

                 "vTaskMsgPro",          

                 512,                    

                 NULL,                   

                 3,                      

                 &xHandleTaskMsgPro );  /* 任务句柄  */

    

    

     xTaskCreate( vTaskStart,            

                 "vTaskStart",           

                 512,                    

                 NULL,                   

                 4,                      

                 &xHandleTaskStart );   

}


。。。。。。。。。



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FreeRTOS临界段和开关中断 的相关文章

  • 基于HAL库的FREERTOS----------二.任务API函数

    任务API函数览概 CUBEMX对 做了API的封装 很多 的函数没有封装到位 可以用原函数调用 任务API函数分别介绍 1 uxTaskPriorityGet 此函数用来获取指定任务的优先级 要使用此函数的话宏 INCLUDE uxTas
  • 【FreeRtos学习笔记】STM32 CubeMx——Timers(定时器)

    目录 1 软件定时器 2 示例程序 2 1 例程功能 2 2 步骤 2 3 实验结果 2 4 函数讲解 1 软件定时器 定时器是MCU常用的外设 我们在学习各种单片机时必然会学习它的硬件定时器 但是 MCU自带的硬件定时器资源是有限的 而且
  • FreeRTOS内核配置说明---FreeRTOS Kernel V10.2.1

    FreeRTOS内核是高度可定制的 使用配置文件FreeRTOSConfig h进行定制 每个FreeRTOS应用都必须包含这个头文件 用户根据实际应用来裁剪定制FreeRTOS内核 这个配置文件是针对用户程序的 而非内核 因此配置文件一般
  • FreeRTOS学习笔记(3、信号量、互斥量的使用)

    FreeRTOS学习笔记 3 信号量 互斥量的使用 前言 往期学习笔记链接 学习工程 信号量 semaphore 两种信号量的对比 信号量的使用 1 创建信号量 2 give 3 take 4 删除信号量 使用计数型信号量实现同步功能 使用
  • Freertos中vTaskDelay()是怎么用的

    1 常见的使用场景 void vLED Task void pvParameters while 1 Heartbeat LED vTaskDelay 1000 portTICK RATE MS 说明 上面这段代码的意思是 led翻转后经过
  • freeRTOS手册 第六章 . 中断管理

    如果我对本翻译内容享有所有权 允许任何人复制使用本文章 不会收取任何费用 如有平台向你收取费用与本人无任何关系 第六章 中断管理 章节介绍和范围 事件 嵌入式实时系统必需对环境中的事件做出响应 比如 外部网络设备收到一个发送给TCP IP栈
  • FreeRTOS_中断

    传送门 博客汇总帖 传送门 Cortex M3 中断 异常 传送门 Cortex M3笔记 基础 笔记内容参考 正点原子的FreeRTOS开发手册 cortex m3权威指南 Cortex M3和Cortex M4权威指南等 文中stm32
  • FreeRTOS:中断配置

    目录 一 Cortex M 中断 1 1中断简介 1 2中断管理简介 1 3优先级分组定义 1 4优先级设置 1 5用于中断屏蔽的特殊寄存器 1 5 1PRIMASK 和 FAULTMASK 寄存器 1 5 2BASEPRI 寄存器 二 F
  • 基于HAL库的FREERTOS-----------三.队列

    一 队列简介 在实际的应用中 常常会遇到一个任务或者中断服务需要和另外一个任务进行 沟通交流 这个 沟通交流 的过程其实就是消息传递的过程 在没有操作系统的时候两个应用程序进行消息传递一般使用全局变量的方式 但是如果在使用操作系统的应用中用
  • STM32F103移植FreeRTOS必须搞明白的系列知识---2(FreeRTOS任务优先级)

    STM32F103移植FreeRTOS必须搞明白的系列知识 1 Cortex CM3中断优先级 STM32F103移植FreeRTOS必须搞明白的系列知识 2 FreeRTOS任务优先级 STM32F103移植FreeRTOS必须搞明白的系
  • FreeRTOS学习(三)开关中断

    声明及感谢 跟随正点原子资料学习 在此作为学习的记录和总结 环境 keil stm32f103 背景知识 Cotex M3的NVIC最多支持240个IRQ 中断请求 1个不可屏蔽 NMI 1个Systick 滴答定时器 Cortex M处理
  • 基于STM32的FreeRTOS学习之中断测试实验(五)

    记录一下 方便以后翻阅 本章内容是接着上一章节进行的实际演练 1 实验目的 FreeRTOS可以屏蔽优先级低于configMAX SYSCALL INTERRUPT PRIORITY的中断 不会屏蔽高于其的中断 本次实验就是验证这个说法 本
  • RT-Thread记录(五、RT-Thread 临界区保护与FreeRTOS的比较)

    本文聊聊临界区 以及RT Thread对临界区的处理 通过源码分析一下 RT Thread 对临界区保护的实现以及与 FreeRTOS 处理的不同 目录 前言 一 临界区 1 1 什么是临界区 1 2 RTOS中的临界区 二 RT Thre
  • 【FreeRTOS 事件】任务通知事件

    普通任务通知事件创建创建及运行 参阅安富莱电子demo define BIT 0 1 lt lt 0 define BIT 1 1 lt lt 1 static TaskHandle t xHandleTaskUserIF NULL sta
  • FreeRTOS笔记(二)

    FreeRTOS笔记 二 静态任务 文章目录 FreeRTOS笔记 二 静态任务 一 任务定义 二 任务创建 2 1 定义任务栈 2 2 定义任务函数 2 3 定义任务控制块 2 4 实现任务创建函数 三 实现就绪列表 3 1 定义就绪列表
  • FreeRTOS临界段

    1 临界段 在访问共享资源时不希望被其他任务或者中断打断的代码 这段要执行的代码称为临界段代码 2 设置临界段的目的 保护共享资源 例如 全局变量 公共函数 不可重入函数 函数里面使用 了一些静态全局变量 malloc 等 保护外设的实时性
  • 再论FreeRTOS中的configTOTAL_HEAP_SIZE

    关于任务栈和系统栈的基础知识 可以参考之前的随笔 FreeRTOS 任务栈大小确定及其溢出检测 这里再次说明 define configTOTAL HEAP SIZE size t 17 1024 这个宏 官方文档解释 configTOTA
  • 使用 GCC 编译器的 ARM 内核的堆栈回溯(当存在 MSP 到 PSP 切换时)

    核心 ARM Cortex M4 编译器 GCC 5 3 0 ARM EABI 操作系统 免费 RTOS 我正在使用 gcc 库函数 Unwind Reason Code Unwind Backtrace Unwind Trace Fn v
  • 如何将 void* 转换为函数指针?

    我在 FreeRTOS 中使用 xTaskCreate 其第四个参数 void const 是传递给新线程调用的函数的参数 void connect to foo void const task params void on connect
  • 小型 ARM 微控制器的 RTOS 内核之间的可量化差异 [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 有许多不同的 RTOS 可用于微控制器 我专门寻找支持 ARM Cortex M 处理器的 RTOS 另外 我对闭源解决方案不感兴趣 试图从网站

随机推荐

  • 解决JDK版本导致JMeter无法启动问题

    最近在做一个秒杀系统练习时 需要使用JMeter进行压力测试 但是安装JMeter后 出现了以下错误 很明显是JDK的版本问题导致的 但是我又不想改变系统的JDK版本 所以可以下载高版本的JDK 无需改变系统的JDK版本 直接在bin jm
  • nginx-代理多个服务

    目录 1 主机多Ip 1 1单网卡多ip主机配置 1 2修改default conf 1 3server1 conf 1 3server2 conf 1 4测试文件 1 4重启测试 2 主机多端口 2 1server1 conf 2 2se
  • 三个不等_高中数学竞赛常用的不等式归纳(续一)

    当 时 代入 23 为减少篇幅就不在此写出完整的 23式 下同 式得 即 25 25 式正是 22 九 加权不等式 9 1若 且 则 26 26 式就是加权的均值不等式 简称加权不等式 26 式形式直接理解为 几何均值不大于算术均值 十 赫
  • 2020第八届“泰迪杯”特等奖(基于 BERT 深度语言模型的“智慧政务”文本挖掘应用)

    目录 1绪论 1 1 智慧政务 文本挖掘的意义 1 2 智慧政务 文本挖掘的目标 1 3语言智能的里程碑技术 BERT 深度语言模型介绍 1 4本文的总体框架 1 5本文主要的创新之处 2基于 BERT 模型的留言自动分类 2 1任务介绍与
  • 数据库连接池C3P0学习

    数据库连接池C3P0框架是个非常优异的开源jar 高性能的管理着数据源 这里只讨论程序本身负责数据源 不讨论容器管理 一 实现方式 C3P0有三种方式实现 1 自己动手写代码 实现数据源 例如 在类路径下配置一个属性文件 config pr
  • 1-2 继承和接口

    1 继承 关键字extends 父类中私有成员可以被继承 只是外界无法访问 父类中公共属性 方法可以被子类继承 支持单继承 多重继承 单链式继承 不支持多继承 一个类继承多个父类 子类中的方法重写必须是父类中已有的方法 重写后再次调用父类的
  • shell 自动备份 MySQL 数据库脚本

    前提 在当前的机器中 已经安装了 MySQL 并且将 MySQL 已经加入到环境当中 安装 MySQL 和配置 MySQL 环境可参考文章 CentOS 8 通过二进制安装 MySQL 需求 编写 shell 脚本 自动备份 MySQL 数
  • 插入排序和选择排序(普通排序)

    我自己的代码 更容易理解 void XuanZePaiXu int a int n int i j k for int i 0 i lt n i k i for int j i 1 j lt n j if a k gt a j k j if
  • Vue2 _ 实现拖拽功能

    老项目重构 其中有一些拖拽功能 不过用的是两个开源 JS 拖拽文件实现的效果 版本太老了 所以需要换代了 然后就查阅了能够用 Vue 来简单快速实现拖拽的功能实现方法 目录 一 HTML 拖放 二 Vue Draggable 强烈推荐 三
  • NFT.net批量生成NFT头像(汉化版+使用文档)

    本程序NFT net可用于批量快速生成NFT头像 相同风格但不尽相同 原程序由老外开发 本人将其汉化 并制作使用文档 工具参考 NFT net 一个可以批量生成NFT头像的工具 素材参考 B站up主 卡司红茶 汉化版 使用文档 本人首发 如
  • maven如何快速查找某个包哪里引入的

    描述 最近项目中遇到一个问题 有个jar包跟项目的中的代码冲突导致一些奇怪的异常 项目是maven项目 问题查找 由maven官网可知道maven的Dependency plugin就有这个问题的解决方案filtering the depe
  • Sybase的客户端工具

    虽然已经离开用Sybase的项目很久了 但今天突然有同事问我Sybase的客户端工具都用什么 我却不记得当时天天用的什么工具了 上网找了半天才找到软件的名字 在此做个小小的总结 以免以后更想不起来 以下几个工具都是当时常用的 他们各有优缺点
  • panda3d虚幻引擎--(1)

    目录 前言 阿巴阿巴 安装 调整窗口 导入环境 前言 阿巴阿巴 前几天无意间看到了一个叫做panda3d的东西 觉得挺好玩 就翻教程 发现现在中文教程似乎没有那么全面成体系 大部分都是复制粘贴过来官网的实例然后就发布出去了 看得云里雾里的
  • 网络安全与密码学

    1 网络安全威胁 破坏网络安全的一些理论方式 窃听 窃听信息 在网路通信双方直接进行窃听 插入 主动在网络连接中插入信息 可以在message中插入恶意信息 假冒 伪造 spoof 分组中的源地址 假冒客户端或服务器 劫持 通过移除 取代发
  • idea的bug导致的项目编译问题。

    项目代码报红 方法一 删掉依赖的子项目target 然后重新install子项目 本项目重新maven reimport 重新install 方法二 删掉 idea 文件夹 重新引入项目 方法三 invalidate Caches 清除缓存
  • 运算放大器的异常总结——震荡和发热

    上图中 运算放大器输出端F1是保险丝 此处的保险丝有2个作用 1 防止输出端短路 保护运放 2 保险丝本身存在电阻 防止运放震荡 对于第一条不需要过多解释 但是第二条 如果此处保险丝去除改为直通 则因为容性负载的存在 运放可能引起震荡 此外
  • 《画解数据结构》(2 - 5)- 堆 与 优先队列

    画解数据结构 2 5 堆
  • tcp业务层粘包和半包理解及处理

    tcp粘包处理 tcp是流式传输的 是安全的 可靠的 顺序的 udp是数据报协议 是不可靠的 面试中经常被问到tcp粘包是如何处理的 通过百度和自己的理解 这里做笔记记录 如果有不对 请指正 参考 https bbs csdn net to
  • Auto.js实现返回到应用首页(判断是否在应用首页)

    文章目录 前言 一 实现思路 二 实现步骤 使用与总结 前言 Auto js使用实现模拟点击过程中 有时软件并不在脚本运行页面 使得脚本运行无效 例如脚本需要在软件首页才能找到相关元素实现模拟操作 就需要判断页面状态 不是首页返回到首页 是
  • FreeRTOS临界段和开关中断

    http blog sina com cn s blog 98ee3a930102wg5u html 本章教程为大家讲解两个重要的概念 FreeRTOS的临界段和开关中断 本章教程配套的例子含Cortex M3内核的STM32F103和Co