In this tutorial, I will share how to use system timer (SysTick) for making delay functions. SysTick is a basic countdown timer. SysTick can be
used by an operating system to ease porting from another platform. SysTick can be polled by software or can be configured to generate an interrupt. To use SysTick we can reload a value to the reload value register. SysTick reload value register supports value between 0 - 0x00FFFFFF (24-bit).
SysTick can be configured through the 4 registers:
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks);
This function will initialize the SysTick timer and its interrupt, then start the SysTick. The counter is in free running mode to generate periodic interrupts. The input parameter of this function is the number of ticks between two interrupts.
In this tutorial, I will make 2 delay function (us delay and ms delay). First, to make 1us delay, I cofigure the SysTick interrupt to triggered every 1us. By using SysTick_Config() function you can initialize SysTick to trigger the interrupt every 1us.
There is a variable called usTicks that holds value of ticks in us. Every we call DelayUs() function, we reload this variable with the value of delay in us and then we poll this variable until reach 0. This variable will be decrement by 1 every 1us by SysTick_Handler() function.
To make DelayMs() function, we can reload the value of ms, then decrement it by 1 every 1000us using DelayUs() function.
This is the code for the delay library:
For STM32 tutorial with HAL library, you can click here.
In this tutorial, I will make 2 delay function (us delay and ms delay). First, to make 1us delay, I cofigure the SysTick interrupt to triggered every 1us. By using SysTick_Config() function you can initialize SysTick to trigger the interrupt every 1us.
There is a variable called usTicks that holds value of ticks in us. Every we call DelayUs() function, we reload this variable with the value of delay in us and then we poll this variable until reach 0. This variable will be decrement by 1 every 1us by SysTick_Handler() function.
To make DelayMs() function, we can reload the value of ms, then decrement it by 1 every 1000us using DelayUs() function.
This is the code for the delay library:
#ifndef __DELAY_H #define __DELAY_H #ifdef __cplusplus extern "C" { #endif #include "stm32f10x.h" void DelayInit(void); void DelayUs(uint32_t us); void DelayMs(uint32_t ms); #ifdef __cplusplus } #endif #endif
#include "delay.h" // For store tick counts in us static __IO uint32_t usTicks; // SysTick_Handler function will be called every 1 us void SysTick_Handler() { if (usTicks != 0) { usTicks--; } } void DelayInit() { // Update SystemCoreClock value SystemCoreClockUpdate(); // Configure the SysTick timer to overflow every 1 us SysTick_Config(SystemCoreClock / 1000000); } void DelayUs(uint32_t us) { // Reload us value usTicks = us; // Wait until usTick reach zero while (usTicks); } void DelayMs(uint32_t ms) { // Wait until ms reach zero while (ms--) { // Delay 1ms DelayUs(1000); } }To use that delay functions don't forget to call DelayInit() function first. You can see my complete code with example in here.
For STM32 tutorial with HAL library, you can click here.
I want to see your complete code. But the link is break now. Would you relink your complete code?
ReplyDeleteThe link for complete code has been fixed. Thank you.
DeleteThank you, Yohanes Erwin.
DeleteHi Yohanes,
ReplyDeleteThe idea that the processor gets interrupted 1.000.000 times per second bothered me. The clock on my STM32F103 is 72MHz so there are only 72 cycles available between interrupts. Some are used by the interrupt handler leaving even less for the rest of the program. I did some very unscientific research and concluded that 25% of processor time is spent on the systick interrupt only, when you run it every 1 uS.
So after some googling I found out about yet another timer, called DWT. This timer counts at the processor clock speed (72Mhz in my case) and is often used in a microsecond delay.
I adapted your code (only the delay.c) which I will post below this. If that becomes unreadable I will put it somewhere else. :-)
/**
******************************************************************************
* @file delay.c
* @author Yohanes Erwin Setiawan
* @date 10 January 2016
******************************************************************************
*/
#include "delay.h"
// For store tick counts in ms
static __IO uint32_t msTicks;
static uint32_t Clk_Cyc_Per_uS;
void DelayInit()
{
// Update SystemCoreClock value
SystemCoreClockUpdate();
// Configure the SysTick timer to overflow every 1 ms
SysTick_Config(SystemCoreClock / 1000);
// DWT_Init
Clk_Cyc_Per_uS = SystemCoreClock/1000000;
if (!(CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk))
{
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}
}
// SysTick_Handler function will be called every 1 ms
void SysTick_Handler()
{
if (msTicks > 0) msTicks--;
}
void DelayMs(uint32_t ms)
{
// Reload ms value
msTicks = ms;
// Wait until usTick reach zero
while (msTicks);
}
void DelayUs(uint32_t us)
{
int32_t tp = DWT->CYCCNT + us * Clk_Cyc_Per_uS;
while (((int32_t)DWT->CYCCNT - tp) < 0);
}
/********************************* END OF FILE ********************************/
/******************************************************************************/
Hi Wilko,
DeleteThat's a good idea. Thank you for sharing your work.
I added .h and .c file in user folder but facing below issue. Please suggest.
ReplyDelete*** Using Compiler 'V5.06 update 4 (build 422)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'
Build target 'Target 1'
compiling delay.c...
User\delay.h(18): warning: #1-D: last line of file ends without a newline
#endif
User\delay.c(39): warning: #1-D: last line of file ends without a newline
}
User\delay.c: 2 warnings, 0 errors
compiling main.c...
User\delay.h(18): warning: #1-D: last line of file ends without a newline
#endif
User\delay.c(39): warning: #1-D: last line of file ends without a newline
}
User\main.c: 2 warnings, 0 errors
linking...
.\Demo.axf: Error: L6200E: Symbol SysTick_Handler multiply defined (by delay.o and main.o).
.\Demo.axf: Error: L6200E: Symbol DelayInit multiply defined (by delay.o and main.o).
.\Demo.axf: Error: L6200E: Symbol DelayMs multiply defined (by delay.o and main.o).
.\Demo.axf: Error: L6200E: Symbol DelayUs multiply defined (by delay.o and main.o).
Not enough information to list image symbols.
Not enough information to list the image map.
Finished: 2 information, 0 warning and 4 error messages.
".\Demo.axf" - 4 Error(s), 4 Warning(s).
Target not created.
Build Time Elapsed: 00:00:01