完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
FreeRTOS中断配置和临界段
中断简介 STM32的中断很重要,它不同于if、switch等条件检测语句,它是由硬件产生的。在程序中,代码默认按顺序执行,当遇到中断触发时,就会打断当前执行代码并且调到中断服务函数中去执行中断任务。 这种情况在汇编语言中的表现形式一般是:
中断优先级 Cortex-M处理器有三个固定优先级和256个可编程优先级,最多有128个抢占优先级,但具体数目需要由芯片厂商自行设定。绝大多数芯片都会进行剪裁,一般优先级个数是8、16和32个。Cortex-M处理器最多有256个可编程优先级,说明控制优先级的寄存器共有8位,这个优先级是MSB(最高位)对齐的,所以一般都是前3或4位是用来表达优先级的。 例如: [tr]Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0[/tr]
PRIMASK 和 FAULTMASK 寄存器 在需要进行对时序严格要求的任务时,我们需要暂时屏蔽所有中断来保证任务的精确完成,这时可以使用 PRIMASK 寄存器,PRIMASK 用于禁止除复位 、NMI 和 HardFalut 外的所有异常和中断,可以通过汇编语言CPS指令来控制PRIMASK。 CPSIE I; //清除 PRIMASK(使能中断) CPSID I; //设置 PRIMASK(禁止中断) 以上代码等同于 MOVS R0, #0 MSR PRIMASK, R0 ;//将 0 写入 PRIMASK 以使能中断 MOVS R0, #1 MSR PRIMASK, R0 ;//将 1 写入 PRIMASK 禁止所有中断 BASEPRI 寄存器 当需要精准控制低于哪些优先级的中断需要关闭时,这时就可以使用BASEPRI寄存器,这个寄存器可以进行更加准确的屏蔽。例如屏蔽优先级0x80及以下的中断: MOV R0, #0X60 MSR BASEPRI, R0 解除屏蔽只需要将0写入BASEPRI寄存器即可 MOV R0, #0 MSR BASEPRI, R0 FreeRTOS中断配置宏 configPRIO_BITS 优先级表达位,STM32为前4位,所以此宏为4 configLIBRARY_LOWEST_INTERRUPT_PRIORITY 此宏表示最低优先级,STM32最低优先级为0~15,所以此宏为15,当处理器为其他芯片时,需要按手册修改。 configKERNEL_INTERRUPT_PRIORITY 该宏定义如下: #define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) 该宏是设置内核中断优先级,内容是将 configLIBRARY_LOWEST_INTERRUPT_PRIORITY左移四位,因为中断表达需要用高4位来表达,所以需要左移4位。除此外,也可以直接写为: #define configKERNEL_INTERRUPT_PRIORITY 0xF0 宏 configKERNEL_INTERRUPT_PRIORITY 用来设置 PendSV 和滴答定时器的中断优先级, port.c 中有如下定义: #define portNVIC_PENDSV_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL ) #define portNVIC_SYSTICK_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL ) PendSV和SysTcik的中断优先级设置是操作0xE000-0xED20地址的,这样一次写入的是个32位的数据,SysTick和PendSV的优先级寄存器分别对应这个32位数据的最高8位和次高8位,因此是一个左移16位,一个左移24位。 configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 此宏定义了FreeRTOS可管理的最大优先级,程序生成后默认设置的是5,所以优先级高于5(优先级数小于5)的都不归FreeRTOS管。 configMAX_SYSCALL_INTERRUPT_PRIORITY 此宏是由configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY左移4位而来的,原因和宏configKERNEL_INTERRUPT_PRIORITY一样。此宏设置好以后,低于此优先级的中断可以安全的调用 FreeRTOS的API函数,高于此优先级的中断FreeRTOS是不能禁止的,中断服务函数也不能调用FreeRTOS的API函数! FreeRTOS开关中断 FreeRTOS开关中断函数为portENABLE_INTERRUPTS()和portDISABLE_INTERRUPTS(),这两个函数其实是宏定义,在portmacro.h中有定义,如下: #define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI() #define portENABLE_INTERRUPTS() vPortSetBASEPRI(0) 函数vPortBASEPRI()传递了一个0,这就对应了上面说到的,开启中断是将0写入BASEPRI寄存器。 临界段代码 临界段代码也称为临界区,是指哪些必须完成运行,且不能中途打断的代码,比如某些外设的初始化过程需要遵守严格的时序,因此初始化过程不能被打断,所以我们在进行外设初始化时可以添加临界段代码。 FreeRTOS与临界段代码保护有关的函数有4个:taskENTER_CRITICAL()、 和taskEXIT_CRITICAL()、taskENTER_CRITICAL_FROM_ISR()、taskEXIT_CRITICAL_FROM_ISR(), 这四个函数其实是宏定义,在task.h文件中有定义。这四个函数的区别是前两个是任务级的临界段代码保护,后两个是中断级的临界段代码保护。 任务级临界段代码保护 taskENTER_CRITICAL()和taskEXIT_CRITICAL()是任务级的临界代码保护,一个是进入临界段,一个是退出临界段,这两个函数是成对使用的,这函数的定义如下: #define taskENTER_CRITICAL() portENTER_CRITICAL() #define taskEXIT_CRITICAL() portEXIT_CRITICAL() 而portENTER_CRITICAL()和portEXIT_CRITICAL()也是宏定义,在文件 portmacro.h中有定义。 任务级临界代码保护使用方法如下: void CriticalTask_TEST(void const * argv) { taskENTER_CRITICAL(); //进入临界区 total_num += 0.01f; printf("total_num 的值为: %.4frn",total_num); taskEXIT_CRITICAL(); //退出临界区 vTaskDelay(1000); } 当进入临界区时,中断被屏蔽,临界区代码无法被打断,只有当所有的临界段代码都退出以后才会使能中断! 注:当进入临界区时,优先级低于configMAX_SYSCALL_INTERRUPT_PRIORITY 的中断得不到及响应,所以临界区代码一定要精简。 中断级临界段代码保护 函数taskENTER_CRITICAL_FROM_ISR()和taskEXIT_CRITICAL_FROM_ISR()中断级别临界段代码保护,是用在中断服务程序中的,而且这个中断的优先级一定要低于configMAX_SYSCALL_INTERRUPT_PRIORITY。这两个函数在文件task.h中有如下定义: #define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR() #define taskEXIT_CRITICAL_FROM_ISR(x) portCLEAR_INTERRUPT_MASK_FROM_ISR(x) 中断级临界代码保护使用方法如下: void TIM3_IRQHandler(void) { if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //溢出中断 { status_value=taskENTER_CRITICAL_FROM_ISR(); //进入临界区 total_num += 1; printf("float_num 的值为: %drn",total_num); taskEXIT_CRITICAL_FROM_ISR(status_value); //退出临界区 } TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除中断标志位 } FreeRTOS中断测试实验 创建工程 打开串口1,参数默认。 配置是时钟树 配置定时器3和定时器5 配置定时器中断优先级 配置FreeRTOS并创建任务 创建工程 查看代码 打开工程可以在stm32f1xx_hal_cortex.c文件中找到定制器中断优先级配置代码。 void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle) { if(tim_baseHandle->Instance==TIM3) { /* USER CODE BEGIN TIM3_MspInit 0 */ /* USER CODE END TIM3_MspInit 0 */ /* TIM3 clock enable */ __HAL_RCC_TIM3_CLK_ENABLE(); /* TIM3 interrupt Init */ HAL_NVIC_SetPriority(TIM3_IRQn, 4, 0); HAL_NVIC_EnableIRQ(TIM3_IRQn); /* USER CODE BEGIN TIM3_MspInit 1 */ /* USER CODE END TIM3_MspInit 1 */ } else if(tim_baseHandle->Instance==TIM5) { /* USER CODE BEGIN TIM5_MspInit 0 */ /* USER CODE END TIM5_MspInit 0 */ /* TIM5 clock enable */ __HAL_RCC_TIM5_CLK_ENABLE(); /* TIM5 interrupt Init */ HAL_NVIC_SetPriority(TIM5_IRQn, 5, 0); HAL_NVIC_EnableIRQ(TIM5_IRQn); /* USER CODE BEGIN TIM5_MspInit 1 */ /* USER CODE END TIM5_MspInit 1 */ } } 可以从中看出TIM3优先级为4,大于FreeRTOS所能管理的优先级,TIM优先级为5,恰好在FreeRTOS所能管理的优先级之中。 先在main.c中将定时器回调函数代码补全: 定时器回调函数代码补全 打开main.c文件,补全HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)函数中缺少的定时器3和定时器5的代码。 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { /* USER CODE BEGIN Callback 0 */ if(htim->Instance == TIM3) { printf("TIM3 输出.......rn"); } /* USER CODE END Callback 0 */ if (htim->Instance == TIM1) { HAL_IncTick(); } /* USER CODE BEGIN Callback 1 */ if(htim->Instance == TIM5) { printf("TIM5 输出.......rn"); } /* USER CODE END Callback 1 */ } 编写测试代码 打开freertos.c文件,找到void extitask_test(void const * argument)函数,添加自己的代码: void extitask_test(void const * argument) { static uint32_t total_num = 0; /* USER CODE BEGIN extitask_test */ /* Infinite loop */ for(;;) { total_num += 1; if(total_num == 5) { printf("关闭中断.............rn"); portDISABLE_INTERRUPTS(); HAL_Delay(5000); printf("打开中断.............rn"); portENABLE_INTERRUPTS(); } } /* USER CODE END extitask_test */ } 查看运行结果 打开串口助手可以看到当中断关闭时只有定时器3在工作,而定时器5则失效,当中断重新打开时,定时器3和定时器5又重新一起计时了。 小结 当我们使用FreeRTOS时,要注意有些外设的驱动代码需要严格连续执行,不能被打断,这时我们可以使用临界段代码来保护现场。但是只需要屏蔽某些优先级的中断时,就可以使用中断屏蔽代码。 |
|||||||
|
|||||||
测试的话,可以加个IO的翻转,用示波器测时间
|
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1771 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1619 浏览 1 评论
1070 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
724 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1673 浏览 2 评论
1936浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
729浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
569浏览 3评论
594浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
552浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-22 22:02 , Processed in 0.696984 second(s), Total 47, Slave 40 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号