ucos移植到stm32上的中断小小改进

uCosII移植到stm32上的文章和demo已经很多了,细节上建议大家可以看官方的移植文档( 当然是E文的)。网上流传的各种移植版本基本都是基于官方的移植版本做了小改进。这些改进基本都限制在更适合自己的项目或自己的使用习惯上。当然我也一样,我的改进是为了搭建一个平台,只要stm32+ucos平台都使用这个版本,无论是我使用或是一起开发者,能更快上手。 uCosII V2.86版本在cortex-m3的移植上面有bug,具体可以自己google一下。我目前使用的是V2.91版本,建立在stm32 V3.40的库基本上。我是强烈要求(或是强制要求)协同开发者使用库函数,除非在速度要求高的情况下或中断里需要直接操作寄存器,也必须使用库的地址定义,并要求在后面注明对应的库函数。因为程序不是你一个人看的……例如:

/* Clear the selected DMA interrupt pending bits */ DMA1->IFCR = DMA1_IT_TC4; //DMA_ClearITPendingBit(DMA1_IT_TC4); /* Disable the selected DMAy Channelx */ DMA1_Channel4->CCR &= (u16)(~DMA_CCR1_EN); //DMA_Cmd(DMA1_Channel4, DISABLE);


好了,进入正题。uCos在stm32上的移植官方的版本是默认不支持中断嵌套的(个人理解),因为其没有调用NVIC_PriorityGroupConfig这一函数或使用相同的功能语句。stm32在复位的状态下默认进去NVIC_PriorityGroup_0,即只要子优先级没有主优先级,即先到先处理,同时到达再按优先级处理。 官方在这上面也是留有空间,因为NVIC_PriorityGroupConfig只能调用一次,采用默认状态,开发者可以加入并完善使用中断嵌套。
官方的移植把所有的应用中断入口都指向了BSP_IntHandler这个函数,并定义了一个函数数组staticCPU_FNCT_VOIDBSP_IntVectTbl[BSP_INT_SRC_NBR]; 因此,如果要加入自己的中断函数的话,只需把自己写的中断函数的指针存入这个数组就OK了,在初始化中断前调用这函数BSP_IntVectSet。官方的中断优先级设置方式,我全删除了,使用库函数来设置将更直接,但这种中断方式保存下来,这样中断函数更自由,写中断函数时也不用考虑太多东西,只负责自己要做的东西。

/* ********************************************************************************************************* *INCLUDE FILES ********************************************************************************************************* */#defineBSP_INTERRUPT_MODULE#include #include//STM32芯片内部寄存器定议#include #include /* ********************************************************************************************************* *LOCAL DEFINES ********************************************************************************************************* */ #defineBSP_INT_SRC_NBR60/* ********************************************************************************************************* *LOCAL TABLES ********************************************************************************************************* */staticCPU_FNCT_VOIDBSP_IntVectTbl[BSP_INT_SRC_NBR]; /* ********************************************************************************************************* *LOCAL FUNCTION PROTOTYPES ********************************************************************************************************* */staticvoidBSP_IntHandler(u16int_id); staticvoidBSP_IntHandlerDummy(void); /* ********************************************************************************************************* *BSP_IntVectSet() * * Description : Assign ISR handler. * * Argument(s) : int_idInterrupt for which vector will be set. * *isrHandler to assign * * Return(s): none. * * Caller(s): Application. * * Note(s): none. ********************************************************************************************************* */voidBSP_IntVectSet (u16int_id, CPU_FNCT_VOIDisr) {#if OS_CRITICAL_METHOD == 3u/* Allocate storage for CPU status register*/ OS_CPU_SRcpu_sr = 0u; #endifif(int_id < BSP_INT_SRC_NBR){ OS_ENTER_CRITICAL(); BSP_IntVectTbl[int_id] = isr; OS_EXIT_CRITICAL(); } }/* ********************************************************************************************************* ********************************************************************************************************* *INTERNAL FUNCTIONS ********************************************************************************************************* ********************************************************************************************************* *//* ********************************************************************************************************* *BSP_IntInit() * * Description : Initialize interrupts: * * Argument(s) : none. * * Return(s): none. * * Caller(s): BSP_Init(). * * Note(s): none. ********************************************************************************************************* */voidBSP_IntInit (void) { u16int_id; OS_CPU_SRcpu_sr; OS_ENTER_CRITICAL(); /* Tell uC/OS-II that we are starting an ISR*/ OSIntNeedSW = OSIntSW_Disable; // 需退出中断时进行任务调度切换 OS_EXIT_CRITICAL(); for (int_id = 0; int_id < BSP_INT_SRC_NBR; int_id++) { BSP_IntVectSet(int_id, BSP_IntHandlerDummy); } }/* ********************************************************************************************************* *BSP_IntHandler####() * * Description : Handle an interrupt. * * Argument(s) : none. * * Return(s): none. * * Caller(s): This is an ISR. * * Note(s): none. ********************************************************************************************************* */ voidBSP_IntHandlerWWDG(void){ BSP_IntHandler(WWDG_IRQn); } voidBSP_IntHandlerPVD(void){ BSP_IntHandler(PVD_IRQn); } voidBSP_IntHandlerTAMPER(void){ BSP_IntHandler(TAMPER_IRQn); } voidBSP_IntHandlerRTC(void){ BSP_IntHandler(RTC_IRQn); } voidBSP_IntHandlerFLASH(void){ BSP_IntHandler(FLASH_IRQn); } voidBSP_IntHandlerRCC(void){ BSP_IntHandler(RCC_IRQn); } voidBSP_IntHandlerEXTI0(void){ BSP_IntHandler(EXTI0_IRQn); } voidBSP_IntHandlerEXTI1(void){ BSP_IntHandler(EXTI1_IRQn); } voidBSP_IntHandlerEXTI2(void){ BSP_IntHandler(EXTI2_IRQn); } voidBSP_IntHandlerEXTI3(void){ BSP_IntHandler(EXTI3_IRQn); } voidBSP_IntHandlerEXTI4(void){ BSP_IntHandler(EXTI4_IRQn); } voidBSP_IntHandlerDMA1_CH1(void){ BSP_IntHandler(DMA1_Channel1_IRQn); } voidBSP_IntHandlerDMA1_CH2(void){ BSP_IntHandler(DMA1_Channel2_IRQn); } voidBSP_IntHandlerDMA1_CH3(void){ BSP_IntHandler(DMA1_Channel3_IRQn); } voidBSP_IntHandlerDMA1_CH4(void){ BSP_IntHandler(DMA1_Channel4_IRQn); } voidBSP_IntHandlerDMA1_CH5(void){ BSP_IntHandler(DMA1_Channel5_IRQn); } voidBSP_IntHandlerDMA1_CH6(void){ BSP_IntHandler(DMA1_Channel6_IRQn); } voidBSP_IntHandlerDMA1_CH7(void){ BSP_IntHandler(DMA1_Channel7_IRQn); } voidBSP_IntHandlerADC1_2(void){ BSP_IntHandler(ADC1_2_IRQn); } voidBSP_IntHandlerUSB_HP_CAN_TX (void){ BSP_IntHandler(USB_HP_CAN1_TX_IRQn); } voidBSP_IntHandlerUSB_LP_CAN_RX0(void){ BSP_IntHandler(USB_LP_CAN1_RX0_IRQn); } voidBSP_IntHandlerCAN_RX1(void){ BSP_IntHandler(CAN1_RX1_IRQn); } voidBSP_IntHandlerCAN_SCE(void){ BSP_IntHandler(CAN1_SCE_IRQn); } voidBSP_IntHandlerEXTI9_5(void){ BSP_IntHandler(EXTI9_5_IRQn); } voidBSP_IntHandlerTIM1_BRK(void){ BSP_IntHandler(TIM1_BRK_IRQn); } voidBSP_IntHandlerTIM1_UP(void){ BSP_IntHandler(TIM1_UP_IRQn); } voidBSP_IntHandlerTIM1_TRG_COM(void){ BSP_IntHandler(TIM1_TRG_COM_IRQn); } voidBSP_IntHandlerTIM1_CC(void){ BSP_IntHandler(TIM1_CC_IRQn); } voidBSP_IntHandlerTIM2(void){ BSP_IntHandler(TIM2_IRQn); } voidBSP_IntHandlerTIM3(void){ BSP_IntHandler(TIM3_IRQn); } voidBSP_IntHandlerTIM4(void){ BSP_IntHandler(TIM4_IRQn); } voidBSP_IntHandlerI2C1_EV(void){ BSP_IntHandler(I2C1_EV_IRQn); } voidBSP_IntHandlerI2C1_ER(void){ BSP_IntHandler(I2C1_ER_IRQn); } voidBSP_IntHandlerI2C2_EV(void){ BSP_IntHandler(I2C2_EV_IRQn); } voidBSP_IntHandlerI2C2_ER(void){ BSP_IntHandler(I2C2_ER_IRQn); } voidBSP_IntHandlerSPI1(void){ BSP_IntHandler(SPI1_IRQn); } voidBSP_IntHandlerSPI2(void){ BSP_IntHandler(SPI2_IRQn); } voidBSP_IntHandlerUSART1(void){ BSP_IntHandler(USART1_IRQn); } voidBSP_IntHandlerUSART2(void){ BSP_IntHandler(USART2_IRQn); } voidBSP_IntHandlerUSART3(void){ BSP_IntHandler(USART3_IRQn); } voidBSP_IntHandlerEXTI15_10(void){ BSP_IntHandler(EXTI15_10_IRQn); } voidBSP_IntHandlerRTCAlarm(void){ BSP_IntHandler(RTCAlarm_IRQn); } voidBSP_IntHandlerUSBWakeUp(void){ BSP_IntHandler(USBWakeUp_IRQn); } voidBSP_IntHandlerTIM8_BRK(void){ BSP_IntHandler(TIM8_BRK_IRQn); } voidBSP_IntHandlerTIM8_UP(void){ BSP_IntHandler(TIM8_UP_IRQn); } voidBSP_IntHandlerTIM8_TRG_COM(void){ BSP_IntHandler(TIM8_TRG_COM_IRQn); } voidBSP_IntHandlerTIM8_CC(void){ BSP_IntHandler(TIM8_CC_IRQn); } voidBSP_IntHandlerADC3(void){ BSP_IntHandler(ADC3_IRQn); } voidBSP_IntHandlerFSMC(void){ BSP_IntHandler(FSMC_IRQn); } voidBSP_IntHandlerSDIO(void){ BSP_IntHandler(SDIO_IRQn); } voidBSP_IntHandlerTIM5(void){ BSP_IntHandler(TIM5_IRQn); } voidBSP_IntHandlerSPI3(void){ BSP_IntHandler(SPI3_IRQn); } voidBSP_IntHandlerUART4(void){ BSP_IntHandler(UART4_IRQn); } voidBSP_IntHandlerUART5(void){ BSP_IntHandler(UART5_IRQn); } voidBSP_IntHandlerTIM6(void){ BSP_IntHandler(TIM6_IRQn); } voidBSP_IntHandlerTIM7(void){ BSP_IntHandler(TIM7_IRQn); } voidBSP_IntHandlerDMA2_CH1(void){ BSP_IntHandler(DMA2_Channel1_IRQn); } voidBSP_IntHandlerDMA2_CH2(void){ BSP_IntHandler(DMA2_Channel2_IRQn); } voidBSP_IntHandlerDMA2_CH3(void){ BSP_IntHandler(DMA2_Channel3_IRQn); } voidBSP_IntHandlerDMA2_CH4_5(void){ BSP_IntHandler(DMA2_Channel4_5_IRQn); }/* ********************************************************************************************************* ********************************************************************************************************* *LOCAL FUNCTIONS ********************************************************************************************************* ********************************************************************************************************* *//* ********************************************************************************************************* *BSP_IntHandler() * * Description : Central interrupt handler. * * Argument(s) : int_idInterrupt that will be handled. * * Return(s): none. * * Caller(s): ISR handlers. * * Note(s): none. ********************************************************************************************************* */staticvoidBSP_IntHandler (u16int_id) {#if OS_CRITICAL_METHOD == 3u/* Allocate storage for CPU status register*/ OS_CPU_SRcpu_sr = 0u; #endifOS_ENTER_CRITICAL(); /* 不支持中断嵌套,无需关中断*/ OSIntNesting++; OS_EXIT_CRITICAL(); if (int_id < BSP_INT_SRC_NBR) { BSP_IntVectTbl[int_id](); } OSIntExit(); }/* ********************************************************************************************************* *BSP_IntHandlerDummy() * * Description : Dummy interrupt handler. * * Argument(s) : none. * * Return(s): none. * * Caller(s): BSP_IntHandler(). * * Note(s): none. ********************************************************************************************************* */staticvoidBSP_IntHandlerDummy (void) {}





从上代码可以看到,增加了一个全局变量OSIntNeedSW。这个变量的使用是判断退出中断的时候需不需要任务调度,因为你在中断里没有做改变任务优先级的事,在退出的时候就无需重新调试,如需调度,只需加一个语句 OSIntNeedSW =OSIntSW_Enable; 当然这是临界代码,需关中断。
voidBSP_IntInit (void)

这一函数必须在开中断前调用一次,初始化必要的变量。
还有两个系统函数必须改动,以实现这功能。在滴答时钟中断中,
voidOS_CPU_SysTickHandler (void)



{ OS_CPU_SRcpu_sr; OS_ENTER_CRITICAL(); /* Tell uC/OS-II that we are starting an ISR*/ OSIntNesting++; OSIntNeedSW = OSIntSW_Enable; // 需退出中断时进行任务调度切换 OS_EXIT_CRITICAL(); OSTimeTick(); /* Call uC/OS-II's OSTimeTick()*/OSIntExit(); /* Tell uC/OS-II that we are leaving the ISR*/ }

最后需改动的一个函数是OSIntExit(),



voidOSIntExit (void) { #if OS_CRITICAL_METHOD == 3u/* Allocate storage for CPU status register */ OS_CPU_SRcpu_sr = 0u; #endifif (OSRunning == OS_TRUE) { OS_ENTER_CRITICAL(); if (OSIntNesting > 0u) {/* Prevent OSIntNesting from wrapping*/ OSIntNesting--; } if (OSIntNesting == 0u) {/* Reschedule only if all ISRs complete ... */ if(OSIntNeedSW == OSIntSW_Enable){// 在这判断是否需要任务切换调试 OSIntNeedSW = OSIntSW_Disable; if (OSLockNesting == 0u) {/* ... and not locked.*/ OS_SchedNew(); OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; if (OSPrioHighRdy != OSPrioCur) {/* No Ctx Sw if current task is highest rdy */ #if OS_TASK_PROFILE_EN > 0u OSTCBHighRdy->OSTCBCtxSwCtr++; /* Inc. # of context switches to this task*/ #endif OSCtxSwCtr++; /* Keep track of the number of ctx switches */ OSIntCtxSw(); /* Perform interrupt level ctx switch*/ } } } } OS_EXIT_CRITICAL(); } }

最终目的,通过增加一个OSIntNeedSW全局变量,来判断退出中断时是否需要进行任务调试切换。这样的话,在一般的中断处理函数处理的退出过程更快,缩短无改变任务优先级中断的处理时间。 其实这功能在新的版本ucos III中已经实现了。


之前使用的版本我还按网上一些人的做法更改了ucos的移植文件,如下图,这是任务切换的时候,如果不使用OSTaskSwHook可以屏蔽下面四行汇编。,省四条语句。
; At this point, entire context of process has been saved OS_CPU_PendSVHandler_nosave ; PUSH{R14}; Save LR exc_return value ; LDRR0, =OSTaskSwHook; OSTaskSwHook(); ; BLXR0 ; POP{R14}LDRR0, =OSPrioCur; OSPrioCur = OSPrioHighRdy; LDRR1, =OSPrioHighRdy LDRBR2, [R1] STRBR2, [R0]LDRR0, =OSTCBCur; OSTCBCur= OSTCBHighRdy; LDRR1, =OSTCBHighRdy LDRR2, [R1] STRR2, [R0]LDRR0, [R2]; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr; LDMR0, {R4-R11}; Restore r4-11 from new process stack ADDSR0, R0, #0x20 MSRPSP, R0; Load PSP with new process SP ORRLR, LR, #0x04; Ensure exception return uses process stack CPSIEI BXLR; Exception return will restore



强烈推荐在调试阶段加入,并开启这宏定义

#ifdef USE_FULL_ASSERT /****************************************************************************** * * Function Name: assert_failed * Description: Reports the name of the source file and the source line number *where the assert_param error has occurred. * Input: - file: pointer to the source file name *- line: assert_param error line source number * Output: None * Return: None *******************************************************************************/ void assert_failed(uint8_t* file, uint32_t line) { /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* Infinite loop */ while (1) {} } #endif




如转载请注明出处:spark 更多交流请加QQ群: 291636736


【ucos移植到stm32上的中断小小改进】




    推荐阅读