-
Notifications
You must be signed in to change notification settings - Fork 12
SysTick
The code snippet below are address definitions used for the SysTick examples in this guide. Visit the STCTRL, STRELOAD, and the STCURRENT section of the TM4C123G datasheet for more info.
SysTick is a timer/counter feature available on all Cortex-M microcontrollers
-
- SysTick Base Address: 0xE000.E000
-
- STCTRL offset: 0x010
- STRELOAD offset: 0x014
- STCURRENT offset: 0x018
#define NVIC_ST_CTRL_R (*((volatile unsigned long *)0xE000E010))
#define NVIC_ST_RELOAD_R (*((volatile unsigned long *)0xE000E014))
#define NVIC_ST_CURRENT_R (*((volatile unsigned long *)0xE000E018))
#define NVIC_ST_CTRL_COUNT 0x00010000 // Count flag
#define NVIC_ST_CTRL_INTEN 0x00000002 // Interrupt enable
-
- Clear the enable bit in the STCTRL register to turn off SysTick during initialization:
-
` NVIC_ST_CTRL_R = 0x00; `
-
- Set the reload (STRELOAD) register to your desired specifications (this value gets passed/copied to STCURRENT when STCURRENT's value is fully decremented to 0). Setting the STRELOAD value to its maximum value allows it to behave like a clock:
-
` NVIC_ST_RELOAD_R = 0x00FFFFFF `
-
- Write any value to the STCURRENT register to clear the counter (this value is decremented once every bus cycle):
-
` NVIC_ST_CURRENT_R = 0; `
-
- Write to your desired specification in the STCTRL register (check datasheet). In this example I will set [CLK_SRC] = 1 so the counter runs off the 16Mhz system clock, and set [ENABLE] = 1 to enable the SysTick.
-
-
` NVIC_ST_CTRL_R = 0x01 + 0x04; `
or` NVIC_ST_CTRL_R = 0x05; `
-
void SysTick_Init(void){
NVIC_ST_CTRL_R = 0x00; // disable SysTick during setup
NVIC_ST_RELOAD_R = 0x00FFFFFF; // maximum reload value
NVIC_ST_CURRENT_R = 0; // any write to current clears it
NVIC_ST_CTRL_R = 0x01 + 0x04; // enable SysTick with core clock
}
Note: When measuring elapse time with SysTick, the system can only be acurate as long as the elapse time is less than 0.209 seconds (at 80MHz), 1.05 seconds (at 16MHz), and 0.336 seconds (at 50MHz). Acuracy can be calculated by: 2^24 * 12.5ns (at 80MHz).
-
- Calculate how long it would take (in seconds) for the value of STCURRENT to decrement once every bus cycle.
-
-
- 1 tick = (1/System Clock) * 10^9 nano seconds
-
- PLL activated: (1/80MHz) * 10^9 = 12.5 nano seconds
- PLL not activated: (1/16MHz) * 10^9 = 62.5 nano seconds
- Core Clock: (1/50MHz) * 10^9 = 20 nano seconds
-
-
- Once we know how long 1 tick takes, we can calculate elapse time using simple math: (Last - Now)*1tick
-
- 5 ticks at 80MHz: (0x0000.0008 - 0x0000.0003) * 12.5ns = 62.5 nano seconds
unsigned long Now; // 24-bit time at this call (12.5ns)
unsigned long Last; // 24-bit time at previous call (12.5ns)
unsigned long Elapsed; // 24-bit time between calls (12.5ns)
void Action(void){ // function under test
Now = NVIC_ST_CURRENT_R; // what time is it now?
Elapsed = (Last-Now)&0x00FFFFFF; // 24-bit difference
Last = Now; // set up for next...
}
Using the SysTick feature as a delay requires you to create 2 functions. The first function will be used to create a SysTick delay routine we can utilise for creating a 1ms busy-wait loop. The second function will be used to iterate the first function as per the second functions argument.
-
- Instantiate a variable for elapsedTime to store the sum of startTime and STCURRENT:
-
` volatile unsigned long elapsedTime; `
-
- Instantiate a variable for startTime and set it to the curent value of the STCURRENT register:
-
`unsigned long startTime = NVIC_ST_CURRENT_R; `
-
- Set the elapse time variable to the diffrence of the start time and the current value of STCURRENT. Be sure to mask the STCURRENT with 0x00FF.FFFF since we only need the first 24 bites of the register.
-
` elapsedTime = (startTime - NVIC_ST_CURRENT_R) & 0x00FFFFFF; `
- Iterate into a loop until the elapsed time meets the 'delay' parameters:
elapsedTime = (startTime - NVIC_ST_CURRENT_R) & 0x00FFFFFF;
while(elapsedTime <= delay){
elapsedTime = (startTime - NVIC_ST_CURRENT_R) & 0x00FFFFFF;
}
void SysTick_Wait(unsigned long delay){
volatile unsigned long elapsedTime;
unsigned long startTime = NVIC_ST_CURRENT_R;
elapsedTime = (startTime - NVIC_ST_CURRENT_R) & 0x00FFFFFF;
while(elapsedTime <= delay){
elapsedTime = (startTime - NVIC_ST_CURRENT_R) & 0x00FFFFFF;
}
}
-
- Algebraically calculate the value for the argument that SysTick_Wait('arg') must take in order to delay the process for 1ms (this argument gets passed to the STRELOAD register on initilization):
-
-
- STREALOAD * [(1/System Clock)] = 1ms
-
-
- STREALOAD * [(1/80MHz)] = 1ms
-
-
- STREALOAD * 12.5ns = 1ms
-
- STREALOAD = 1ms/12.5ns
- STREALOAD = (1^-3)/(12.5^-9)
- STREALOAD = 80,000
-
-
-
6) Create a new function that will iterate the first function as per "unsigned long delay" argument:
void SysTick_Wait1ms(unsigned long delay){
unsigned long i;
for(i=0; i<delay; i++){
SysTick_Wait(50000); // wait 1ms (assumes 50 MHz clock)
}
}
Note: The guides in these wiki are quick reference guides I made for myself and should not be used for teaching as they may contain errors that could misinform students. If you are a student, make sure you confirm everything you read on this wiki using the datasheet before fully committing to the information on this wiki.
TM4C123G (datasheet)
TM4C123G is a 32bit MCU based on the ARM® Cortex®-M4F architecture. Make sure to read C++ Support on TI Compilers if you plan on using C++