Hi,
I am trying to migrate my application from RTOS to RTOS2 on a LPC4337. I did not have any issue yet to migrate M4 application which uses the SysTick timer for the kernel tick.
But I am not able to configure the M0 OS tick using an alternate timer (M0 do not have acces to the SysTick Timer).
With the RTOS I use the RITIMER (freq. = 1000Hz) as an alternate timer In the file "RTX_Conf_CM.c" my functions are :
int os_tick_init (void) { (...) //RITIMER configuration return(M0_RITIMER_OR_WWDT_IRQn); } uint32_t os_tick_val (void) { return (0); } uint32_t os_tick_ovf (void) { return (0); } void os_tick_irqack (void) { RIT_GetIntStatus(LPC_RITIMER); }
And I call the "OS_Tick_Handler" function in the assembly file instead of the RIT handler (I have no issue with RTOS, everything works fine).
With the RTOS2 I was stuck using the RITIMER (the interrupt and acknowledge did not work correctly) so I switched with the TIMER3 (freq. = 1MHz) Here are my functions :
int32_t osRtxSysTimerSetup (void){ (...) //TIMER3 Init code NVIC_SetPriority(M0_TIMER3_IRQn,(1UL << __NVIC_PRIO_BITS) - 1UL); //? NVIC_EnableIRQ(M0_TIMER3_IRQn); return(M0_TIMER3_IRQn); } /// Enable System Timer. void osRtxSysTimerEnable (void){ TIM_Cmd(LPC_TIMER3,ENABLE); } void osRtxSysTimerDisable (void){ TIM_Cmd(LPC_TIMER3,DISABLE); } void osRtxSysTimerAckIRQ (void){ TIM_ClearIntPending(LPC_TIMER3,TIM_MR0_INT); NVIC_ClearPendingIRQ(M0_TIMER3_IRQn); } uint32_t osRtxSysTimerGetCount (void){ return (_tick); //? } uint32_t osRtxSysTimerGetFreq (void){ return 1000000; } void M0_TIMER3_IRQHandler (void){ _tick++; //? osRtxTick_Handler(); }
I have no idea of what I need to implement in these functions for an alternate timer (Keil doc. and examples are very light on this topic). My TIMER3 interrupt works and is called at the desired frequency (1MHz), all other functions are called by the system but I am not sure about the return values. I tried a lot of differents frequencies, differents return values, etc.
I have only one thread running at the moment with a simple loop that sends a message after a short delay (I tried with "osDelayUntil" and "osDelay"). Depending on the delay, the loop can work twice or three times then the system "gets stuck" and loops forever in the "osRtxIdleThread" function.
int32_t main(void) { SystemInit(); //init system osKernelInitialize(); osThreadNew(Init_Thread, NULL, NULL); // start init task osKernelStart(); for (;;); } void Init_Thread(void *argument){ while(1){ (...)//send message through UART //osDelay(10); osDelayUntil(osKernelGetTickCount() + 10); } }
Could someone help me implementing an alternate timer or would have more documentations on this topic to guide me ?
Thank you.
The "osRtxSysTimerGetCount" function needs to return the 32-bit value of the free running timer. See below how this function is implemented when using the SysTick.
uint32_t osRtxSysTimerGetCount (void) { uint32_t tick; uint32_t val; tick = (uint32_t)osRtxInfo.kernel.tick; val = SysTick_GetVal(); if (SysTick_GetOvf()) { val = SysTick_GetVal(); tick++; } val += tick * SysTick_GetPeriod(); return val; }
It is also important that the timer has the correct interrupt priority which must be the lowest priority.
The latest RTX5 5.1.1 (github.com/.../) configures the interrupt for the timer automatically (see code below):
// Setup and Enable System Timer osRtxInfo.tick_irqn = osRtxSysTimerSetup(); if (osRtxInfo.tick_irqn >= 0) { ExtTick_SetupIRQ (osRtxInfo.tick_irqn); ExtTick_EnableIRQ(osRtxInfo.tick_irqn); } osRtxSysTimerEnable();
Therefore the user does not need (and should not) configure the interrupt priority.
In older versions of RTX5 the user needs to configure the correct interrupt priority. This can be easy achieved by using the following "ExtTick_SetupIRQ" function:
/// Setup External Tick Timer Interrupt /// \param[in] irqn Interrupt number __STATIC_INLINE void ExtTick_SetupIRQ (int32_t irqn) { #if ((__ARM_ARCH_7M__ == 1U) || \ (__ARM_ARCH_7EM__ == 1U)) NVIC->IP[irqn] = 0xFFU; #elif (__ARM_ARCH_6M__ == 1U) NVIC->IP[irqn >> 2] = (NVIC->IP[irqn >> 2] & ~(0xFFU << ((irqn & 3) << 3))) | (0xFFU << ((irqn & 3) << 3)); #endif }
Implementation of "osRtxSysTimerSetup" should look like:
int32_t osRtxSysTimerSetup (void){ (...) //TIMER3 Init code ExtTick_SetupIRQ(M0_TIMER3_IRQn); return(M0_TIMER3_IRQn); }
Hi Robert,
Thank you for your answers. Here is a working code from ARM support based on your comments (hope this may help other users with the same issue)
#include "rtx_os.h" // ARM::CMSIS:RTOS2:Keil RTX5 #include "LPC43xx.h" // Device header /* ** forward the M0_SVC_Handler to the RTX SVC_Handler */ __asm __declspec( noreturn ) void M0_SVC_Handler( void ) { EXTERN SVC_Handler LDR R0, =SVC_Handler BX R0 } /* ** forward the M0_PendSV_Handler to the RTX PendSV_Handler */ __asm __declspec( noreturn ) void M0_PendSV_Handler( void ) { EXTERN PendSV_Handler LDR R0, =PendSV_Handler BX R0 } /* ** forward the M0_RIT_OR_WWDT_IRQHandler to the RTX SysTick_Handler */ __asm __declspec( noreturn ) void M0_RITIMER_OR_WWDT_IRQHandler( void ) { EXTERN SysTick_Handler LDR R0, =SysTick_Handler BX R0 } int32_t osRtxSysTimerSetup( void ) { LPC_CCU1->CLK_M4_RITIMER_CFG = CCU1_CLK_M4_RITIMER_CFG_RUN_Msk ; LPC_RITIMER->COUNTER = 0x00000000 ; LPC_RITIMER->MASK = 0x00000000 ; LPC_RITIMER->COMPVAL = osRtxInfo.kernel.sys_freq / osRtxConfig.tick_freq - 1 ; return( M0_RITIMER_OR_WWDT_IRQn ) ; /* Return IRQ number of SysTick timer */ } void osRtxSysTimerEnable( void ) { LPC_RITIMER->CTRL = RITIMER_CTRL_RITENBR_Msk | RITIMER_CTRL_RITENCLR_Msk | RITIMER_CTRL_RITEN_Msk ; } void osRtxSysTimerDisable( void ) { LPC_RITIMER->CTRL = 0 ; } void osRtxSysTimerAckIRQ( void ) { /* Acknowledge timer interrupt. */ LPC_RITIMER->CTRL |= ( RITIMER_CTRL_RITINT_Msk ) ; } uint32_t osRtxSysTimerGetCount( void ) { uint32_t tick; uint32_t val; tick = ( uint32_t )osRtxInfo.kernel.tick ; val = LPC_RITIMER->COUNTER ; if( LPC_RITIMER->CTRL & ( RITIMER_CTRL_RITINT_Msk ) ) { val = LPC_RITIMER->COUNTER ; tick++ ; } val += tick * ( LPC_RITIMER->COMPVAL + 1 ) ; return( val ) ; } uint32_t osRtxSysTimerGetFreq( void ) { return( osRtxInfo.kernel.sys_freq ) ; }
I re-open this topic because I encounter a new issue. Everything worked fine for the last weeks using the solution described above and using CMSIS 5.01.
Last week I updated the CMSIS Package from 5.01 to 5.20 available in keil (I have the same issue using CMSIS 5.10).
With this new CMSIS version the code does not compile anymore. The variable "osRtxInfo.kernel.sys_freq" does not exist in these versions (I assume that I simply need to replace it by SystemCoreClock variable).
With this modification my project compiles but as soon as I call "osDelay" or "osDelayUntil" functions, my code gets stuck. I am not able to use Delay functions anymore (nothing else was changed in my code and if I re-use CMSIS 5.01 everything works fine).
What should I add/modify to be able to update the CMSIS software pack from 5.01 to 5.2 and keep using the RIT Timer as alternate systick timer for my LPC4337 M0 core (I have no issue with the LPC4337 M4 core, which uses the systick timer) when updating the CMSIS software pack)?
I tried to contact Keil Support but they assumed that it should be caused by internal API changes so maybe someone here could help me !
Regards.