SysTick Timer ARM Cortex M0 and configTICK_RATE_HZ

leroy105 wrote on Saturday, January 20, 2018:

Howdy – I’m an experienced 8 bit embedded designer, who is porting a project over to a STM32 CM0 and using FreeRTOS 9.

I’ve currently got my SysTick configured to trigger the SysTick interrupt every 1ms. (I can set it to whatever value, changing reload the value… but just for example).

I’m not clear on what configTICK_RATE_HZ is clocked too.

If I went through the code base for my FreeRTOS 9 CM0 port (my port is just right from the KEIL Pack Installer), would I find that the value I set for configTICK_RATE_HZ actually overwrites any previous reload value in the SysTick register, when I activate the kernel?

Or is configTICK_RATE_HZ some value of HZ after the SysTick interrupt (not even certain how that would work…).

Thanks,
-Tim

leroy105 wrote on Saturday, January 20, 2018:

Okay this was a bit easier to find, than I thought.

If you check the port.c, under …\RVDS\ARM_CM0:

You’ll find a line, at 345.

void prvSetupTimerInterrupt( void )
{
	/* Configure SysTick to interrupt at the requested rate. */
	*(portNVIC_SYSTICK_LOAD) = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
	*(portNVIC_SYSTICK_CTRL) = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE;
}
/*-----------------------------------------------------------*/

Just coming to Cortex M (and never having used FreeRTOS), I’m not familiar with all of the NVIC functions.

But I’m guessing NVIC_SYSTICK_LOAD changes the load value of the SysTick register.

(EDIT: Nope, NVIC_SYSTICK_LOAD is just a pointer to the SysTick register where the reload value goes…)


Is there any documentation, or could you provide any direction, on where you would look in the code to change the timer being used?

Is there anywhere else that are “hot spots” where you’d need to rewire things to change the timer from SysTick? (Sorry I literally know nothing about the underlying source code!).

Is this all handled in port.c, so you’d just have to rewire the constants in port.c?

/* Constants required to manipulate the NVIC. */
#define portNVIC_SYSTICK_CTRL		( ( volatile uint32_t *) 0xe000e010 )
#define portNVIC_SYSTICK_LOAD		( ( volatile uint32_t *) 0xe000e014 )
#define portNVIC_INT_CTRL			( ( volatile uint32_t *) 0xe000ed04 )
#define portNVIC_SYSPRI2			( ( volatile uint32_t *) 0xe000ed20 )
#define portNVIC_SYSTICK_CLK		0x00000004
#define portNVIC_SYSTICK_INT		0x00000002
#define portNVIC_SYSTICK_ENABLE		0x00000001
#define portNVIC_PENDSVSET			0x10000000
#define portMIN_INTERRUPT_PRIORITY	( 255UL )
#define portNVIC_PENDSV_PRI			( portMIN_INTERRUPT_PRIORITY << 16UL )
#define portNVIC_SYSTICK_PRI		( portMIN_INTERRUPT_PRIORITY << 24UL )

rtel wrote on Saturday, January 20, 2018:

The SysTick timer is intended for use by an RTOS. It normally runs at the same frequency as the core. Set configCPU_CLOCK_HZ to the frequency the core will be executing at, then configTICK_RATE_HZ to the rate at which you want the RTOS tick interrupt to execute at, and the RTOS will setup the SysTick timer for you when the scheduler is started.

Typing on my phone so I can’t give you the links, but the config parameters are documented on the FreeRTOS.org website, where you will also find a free to download (if a little out of date) book.

heinbali01 wrote on Sunday, January 21, 2018:

Here you can find a summary of the clocks in an STM32F.

The systick frequency is obtained by dividing the CPU clock frequency.

Is there any documentation, or could you provide any direction,
on where you would look in the code to change the timer being used?

It is possible, but why would you want to use a different timer for this?
You would have to make sure the the priorities are set correctly.

In most ports, the code for the SysTick_handler() is provided directly by the port itself (see xPortSysTickHandler() ).

But beware that the STM32F HAL drivers also wants to define a systick handler in a file called stm32f4xx_it.c:

void SysTick_Handler(void)
{
    /* USER CODE BEGIN SysTick_IRQn 0 */

    /* USER CODE END SysTick_IRQn 0 */
    if( xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED )
    {
        xPortSysTickHandler();
    }
    HAL_IncTick();
    /* USER CODE BEGIN SysTick_IRQn 1 */

    /* USER CODE END SysTick_IRQn 1 */
}

/* And defined in stm32f4xx_hal.c: */

__weak void HAL_IncTick(void)
{
    uwTick++;
}

__weak uint32_t HAL_GetTick(void)
{
    return uwTick;
}

FreeRTOSConfig.h will often have this comment:

/* IMPORTANT: This define MUST be commented when used with STM32Cube firmware,
              to prevent overwriting SysTick_Handler defined within STM32Cube HAL */
/* #define xPortSysTickHandler SysTick_Handler */

In my own projects, I tend to :

  • enable the above #define
  • remove the HAL version of SysTick_Handler()
  • provide my own version of HAL_GetTick().

Note that a working HAL_GetTick() is important for some of the HAL drivers.
Therefore some drivers can only be started up once the systick interrupt is active.

Good luck!

heinbali01 wrote on Sunday, January 21, 2018:

Is there any documentation, or could you provide any direction,
on where you would look in the code to change the timer being used?
It is possible, but why would you want to use a different timer for this?
You would have to make sure the the priorities are set correctly.

In case you also want to use the systick, there is an application hook that you can use:

#if ( configUSE_TICK_HOOK == 1 )
	void vApplicationTickHook()
	{
		/* This function will be called at a rate of "configTICK_RATE_HZ" */
	}
#endif

If you want your handler to be called at a higher frequency, I would use some Time-Counter interrupt.

Remind that your ISR code is not supposed to call normal FreeRTOS API’s. From an interrupt service routine, you should call functions that end with FromISR().

When configASSERT() is defined, the NVIC priorities will be checked for. When the priorities are not OK, the program will be kept in an infinite loop in vAssertCalled().

leroy105 wrote on Sunday, January 21, 2018:

Guys, I appreciate the guidance.

I’m racking my brain for a reason why you wouldn’t use the SysTick, I think my primary motivation is in learning the Cortex architecture for the first time and eventually looking at tickless and the whole assortment of other timers on a CM0, and mixing it up with optimal power management. [I’m not familiar enough yet, to articulate entirely what I’m thinking – but it’s not a pipe dream :wink: ].

That’s a VERY GOOD call out on the ISR, because I have ane existing project that I am porting (just to power profile a CM0 vs. our current 8 bit MCU), that samples data at rates faster than 1ms. In this case, maybe you dial the RTOS to 20ms a tick for housekeeping, and sample independetly in the ISR. This will be the learning curve to put all of that together.

I saw that earlier with the HAL. Honestly it is kind of weird a peripheral driver library would use the SysTick handler, but hey what do I know… I’m coming from a pretty bare-metal approach.

Like for me the NVIC functions where they modify several registers at a time, seem exotic!

I’m using the LL (“low level”) library from STM, which I don’t think has this dependency?

I do remember having to clean out a SysTick handler in the STM library in any case.

leroy105 wrote on Sunday, January 21, 2018:

@Richard – I also, just wanna give you a shout-out for such an outstanding project. I own a small business and get how things go. This is crazy you guys have built this good of a system and then released the whole thing as a freebie! Good karma, my man… hopefully the Amazon thing worked out well!