问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

STM32之HAL例程-FreeRTOS底层开关中断以及临界区汇总

创作时间:
作者:
@小白创作中心

STM32之HAL例程-FreeRTOS底层开关中断以及临界区汇总

引用
CSDN
1.
https://m.blog.csdn.net/youk110/article/details/123351030

在嵌入式系统开发中,中断管理是实时操作系统(RTOS)的核心功能之一。本文将深入探讨STM32微控制器中FreeRTOS的中断管理机制,包括数据类型定义、优先级设置、中断开关函数以及临界区管理等关键内容,并通过实验验证来加深理解。

1. 数据类型重定义和宏定义预览

FreeRTOS在移植到不同平台时,需要对一些基础数据类型进行重定义,以确保代码的可移植性和效率。以下是FreeRTOS中一些常用数据类型的定义:

/* Type definitions. */
#define portCHAR		char
#define portFLOAT		float
#define portDOUBLE		double
#define portLONG		long
#define portSHORT		short
#define portSTACK_TYPE	uint32_t
#define portBASE_TYPE	long
typedef portSTACK_TYPE StackType_t;
typedef long BaseType_t;
typedef unsigned long UBaseType_t;
typedef void * TaskHandle_t;
typedef uint32_t TickType_t;
typedef void (*TaskFunction_t)( void * ); // 一种函数类型的申明,返回类型为void,形式参数为    
                                              void类型的指针
// 用于含MPU单元的宏定义
#define PRIVILEGED_FUNCTION
#define PRIVILEGED_DATA
#define portUSING_MPU_WRAPPERS 0

2. 优先级设置

STM32使用高4位作为其优先级设置位,FreeRTOS通过以下宏定义来配置中断优先级:

#define configPRIO_BITS                        4        /* 15 priority levels for stm32 */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY  5
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY     0xf
#define configMAX_SYSCALL_INTERRUPT_PRIORITY  ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configKERNEL_INTERRUPT_PRIORITY     ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

为什么要左移呢?这是因为STM32使用高4位作为其优先级设置位。默认采用中断分组采用第4种类型,即抢占优先级占用4位,子优先级0位,故用户优先级编号为0~15。设置受RTOS管理最高的优先级编号为5,即优先级编号小于5的不收RTOS管理。

3. 任务的开关中断

FreeRTOS使用basepri寄存器来管理中断,向该寄存器写入某值后,优先级标号高于此值的中断将被屏蔽,向该寄存器写0时,打开所有的中断。

(1)关中断

#define taskDISABLE_INTERRUPTS()	    portDISABLE_INTERRUPTS()
#define portDISABLE_INTERRUPTS()				vPortRaiseBASEPRI()
// 高于configMAX_SYSCALL_INTERRUPT_PRIORITY数值的中断被屏蔽,本列编号为5
static portFORCE_INLINE void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
    __asm
    {
        /* Set BASEPRI to the max syscall priority to effect a critical
        section. */
        msr basepri, ulNewBASEPRI
        dsb
        isb
    }
}

(2)开中断

#define taskENABLE_INTERRUPTS()		    portENABLE_INTERRUPTS()
#define portENABLE_INTERRUPTS()			vPortSetBASEPRI( 0 )
// 清零开中断
static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )
{
    __asm
    {
        /* Barrier instructions are not used as this function is only used to
        lower the BASEPRI value. */
        msr basepri, ulBASEPRI
    }
}

(3)进入临界区

#define taskENTER_CRITICAL()		    portENTER_CRITICAL()
#define portENTER_CRITICAL()					vPortEnterCritical()
void vPortEnterCritical( void )
{
    portDISABLE_INTERRUPTS();
    uxCriticalNesting++;
    /* This is not the interrupt safe version of the enter critical function so
    assert() if it is being called from an interrupt context.  Only API
    functions that end in "FromISR" can be used in an interrupt.  Only assert if
    the critical nesting count is 1 to protect against recursive calls if the
    assert function also uses a critical section. */
    if( uxCriticalNesting == 1 )
    {
        configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
    }
}

(4)退出临界区

#define taskEXIT_CRITICAL()			    portEXIT_CRITICAL()
#define portEXIT_CRITICAL()						vPortExitCritical()
void vPortExitCritical( void )
{
    configASSERT( uxCriticalNesting );
    uxCriticalNesting--;
    if( uxCriticalNesting == 0 )
    {
        portENABLE_INTERRUPTS();
    }
}

(5)中断内临界区的进入和退出

#define taskENTER_CRITICAL_FROM_ISR()   portSET_INTERRUPT_MASK_FROM_ISR()
#define portSET_INTERRUPT_MASK_FROM_ISR()		ulPortRaiseBASEPRI()
#define taskEXIT_CRITICAL_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( x )
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x)	vPortSetBASEPRI(x)

4. 实验体验

HAL_Delay(uint32_t Delay)函数是HAL库用于进行延时的基础函数,未使用RTOS时主要使用SYSTICK的定时中断产生。在使用RTOS时,我们可配置HAL_Delay的时钟基准来自定时器,RTOS的时间基准来自于SYSTICK。

在FREERTOS下,默认情况下SYSTICK和HAL_Delay的定时器中断优先级均为15。为了验证vPortRaiseBASEPRI功能,我们可设置TIMER优先级为4,并在任务中使用taskDISABLE_INTERRUPTS()关闭中断,看TIMER的回调函数是否还能进入。

实测结果是关闭FREERTOS的中断,timer中断还是会进入的。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号