Hi Amit,
I use a timer counter as delay. So, there is the code:
void Timer100usISR(void) //Timer interrupt overflow with 100us period
{
delay_us_counter += 100;
}
void delay_us(word time)
{
delay_us_counter = 0;
while(delay_us_counter < time);
}
void delay_ms(word time)
{
time *= 1000;
while(delay_us_counter < time);
}
To use a delay function, just call this in your code:
delay_us(TIME);
or
delay_ms(TIME);
I hope it help!
Hi AMit,
The following shows yet another bare-bones busy-wait style delay using the PIT for accuracy.
Note that such busy-wait loops are not a good idea in real programs.
It assumes that clockInitialise() function set the clock to 48MHz
/*
=====================================================================================
* main.c
*
* Created on: 12/05/2013
* Author: podonoghue
*
* Simple demonstration of PIT busy-wait
*
====================================================================================
*/
#include "derivative.h"
#include "clock.h"
#define SYSTEM_CLOCK_FREQUENCY (48000000UL)
#define PIT_CLOCK_FREQUENCY SYSTEM_CLOCK_FREQUENCY
#define PIT_TICKS_PER_MICROSECOND (PIT_CLOCK_FREQUENCY/1000000)
#define PIT_TICKS_PER_MILLISECOND (PIT_CLOCK_FREQUENCY/1000)
/*! Busy wait for the given time
*
* @param interval - Time to wait in PIT ticks
* @param timerChannel - PIT Channel to use (0-3)
*
* Configures:
* - Enables PIT clock
* - Enables PIT
* - Sets PIT CH1 re-load value
*
* Waits until PIT event
*/
void busyWait(int timerChannel, uint32_t interval) {
// Enable clock to PIT
SIM_SCGC6 |= SIM_SCGC6_PIT_MASK;
// Enable PIT module
PIT_MCR = PIT_MCR_FRZ_MASK;
// Set re-load value
PIT_LDVAL(timerChannel) = interval-1;
// Enable this channel without interrupts
PIT_TCTRL(timerChannel) = PIT_TCTRL_TEN_MASK;
// Clear timer flag
PIT_TFLG(timerChannel) = PIT_TFLG_TIF_MASK;
// Wait for timer event
while ((PIT_TFLG(timerChannel)&PIT_TFLG_TIF_MASK) == 0) {
__asm__("nop");
}
// Disable channel
PIT_TCTRL(timerChannel) = 0;
}
// Mask for pin to toggle
#define LED_MASK (1<<2)
int main(void) {
initialiseClock();
// Initialise PTA12
SIM_SCGC5 |= SIM_SCGC5_PORTA_MASK;
PORTA_GPCLR = PORT_GPCLR_GPWE(LED_MASK)|PORT_PCR_MUX(1);
GPIOA_PDDR |= LED_MASK;
for(;;) {
busyWait(0, 200*PIT_TICKS_PER_MILLISECOND);
GPIOA_PTOR = LED_MASK;
}
}
Small error in the code. This only works for 1 iteration. R1 has to be reloaded with the loop count ;-)
Hi Amit,
I've recently used a code that used the systick to generate a delay. For using it you have to declare a volatile variable global variable that is called msTicks, and you have to define RVAL with the desired reload value for the sistyck, for example if you did not change the core clock (20.9Mhz) you and you want a delay of 100 us you will have to put (100u * 20.9) 2090 in RVAL. I don't recommend using a reload value for a time less than 100us because the microcontroller will only attend the SysTick_Handler.
int systick_init(void)
{
/* Set the core clk as clk source and pend the SysTick interrupt */
SYST_CSR |= SysTick_CSR_CLKSOURCE_MASK | SysTick_CSR_TICKINT_MASK;
/* set the reload value */
SYST_RVR =RVAL;
/* Enable the SysTick */
SYST_CSR |= SysTick_CSR_ENABLE_MASK;
return RV_SUCCESS;
}
void systick_delay(uint32_t ms)
{
long long bp;
bp = ms + msTicks;
while(msTicks < bp);
}
void SysTick_Handler(void)
{
msTicks++; /* increment counter necessary in Delay() */
}
Hope this is useful to you
Hi Dositeo
I have switched to Code warrior 10.4 with Processor expert. I am using your above code in this for toggling an LED but my program seems to hang. I have copied and pasted the above code in my processorexpert.c file before the main function. I have initialized the variables also. The build is showing no errors or warning. and without your functions if I am using for loop for delay LEDs are toggling. here is the main function please check if I am doing anything wrong.
int main(void)
{
/* Write your local variable definition here */
/*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/
PE_low_level_init();
/*** End of Processor Expert internal initialization. ***/
/* Write your code here*/
systick_init();
SysTick_Handler();
for(;;)
{
GPIOC_PTOR = GPIO_PTOR_PTTO_MASK;
systick_delay(100);
}
}
Regards
Amit Kumar
I only suggest this as a work-around, not a first choice design. Number of nop's determined by experimentation.
void delay_us(int n)
{
for (; n > 0; --n) {
__asm("nop");
__asm("nop");
__asm("nop");
__asm("nop");
__asm("nop");
__asm("nop");
__asm("nop");
__asm("nop");
__asm("nop");
__asm("nop");
__asm("nop"); // 11
__asm("nop");
__asm("nop");
__asm("nop");
__asm("nop");
__asm("nop");
__asm("nop");
__asm("nop");
__asm("nop");
__asm("nop");
__asm("nop"); // 21
__asm("nop");
__asm("nop");
__asm("nop");
__asm("nop");
__asm("nop");
__asm("nop");
__asm("nop");
__asm("nop");
__asm("nop");
__asm("nop"); // 31
__asm("nop");
__asm("nop");
__asm("nop");
__asm("nop");
__asm("nop"); // 36 (for 48 MHz)
#if defined(HW_FRDM_K20D50M)
__asm("nop");
__asm("nop");
__asm("nop");
__asm("nop");
__asm("nop"); // 41 (for 50 MHz)
#endif
}
return;
}
void delay_ms(uint32_t n)
{
for (; n > 0; --n) {
delay_us(1000);
}
}
the thing that I can see is that the systick_init() function returns an int, and you are not saving it anywhere. I think the best thing you can do is change the init function to:
void systick_init(void)
{
/* Set the core clk as clk source and pend the SysTick interrupt */
SYST_CSR |= SysTick_CSR_CLKSOURCE_MASK | SysTick_CSR_TICKINT_MASK;
/* set the reload value */
SYST_RVR =RVAL;
/* Enable the SysTick */
SYST_CSR |= SysTick_CSR_ENABLE_MASK;
}
also you don't have to call the handler, the interruption calls that function for you.
your program should look like this:
int main(void)
{
/* Write your local variable definition here */
/*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/
PE_low_level_init();
/*** End of Processor Expert internal initialization. ***/
/* Write your code here*/
systick_init();
for(;;)
{
GPIOC_PTOR = GPIO_PTOR_PTTO_MASK;
systick_delay(100);
}
}
this should do it, please let me know if it worked
regards
Hi
I tried this also but it didn't worked :smileysad:
I've been poking at the same thing.
If you need the uP to just spin for a little bit then consider just polling the System Timer (SysTick). The System Timer is an ARM peripheral not a Freescale one, so the documentation is on the arm website.
See... ARM Information Center
Hello
Thanks all for your suggestions. Mathew I tried with SysTick and I think I did something wrong in my code so the delay didn't worked . Is there any simplest example using this systick ? I used the following line to call the function which is included in core_cm4.h
SysTick_Config(0xffffff);
and I don't want to use the following statement for delay as it is completely random figures.
for(i=0; i<200000; i++);
Regards
Amit,
This is from a bare metal project I'm working on. (Porting a bare metal AVR project over to a Kinetis part). So not using processor expert. But the code below seems to work for me.
#include <stdint.h>
#include <stdbool.h>
// Uses kintics KL15Z4128 up
#include "MKL15Z4.h"
volatile unsigned int debug_timer;
/**
* @brief SysT Timer ISR
*/
void SysTick_Handler()
{
// counts ms
if(debug_timer>0)
debug_timer--;
}
/**
* @brief SysT Timer initilization
*
* Init the SYST timer to produce a 1khz interrupt.
* Assumes 48MHz clock
*/
void SysTimerInit(void)
{
// make sure disabled
SYST_CSR = 0;
// set to overflow over ms
SYST_CVR = 0;
SYST_RVR = 1500-1;
// enable timer and enable interupts
SYST_CSR |= SysTick_CSR_TICKINT_MASK | SysTick_CSR_ENABLE_MASK;
}
Thanks Mathew for replying. I used your code and compiled it without any errors or warning but it didn't work. I don't know if I am doing something wrong. I am posting the code below. I am using TWR-K20D50M Development kit.
#include<MK20D5.H> | // Header file |
#include <stdint.h>
#include <stdbool.h>
volatile unsigned int debug_timer;
void SysTick_Handler()
{
// counts ms
if(debug_timer>0)
debug_timer--;
}
void SysTimerInit(void)
{
// make sure disabled
SysTick->CTRL = 0;
// set to overflow over ms
SysTick->VAL=0;
SysTick->LOAD = 1500-1;
// enable timer and enable interupts
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk;
}
int main(void)
{
SIM->SCGC5 |= (1UL<<11); // Selecting Gating Clock for PORTC
PORTC->PCR[7] |= (1UL<<8); // Selecting This Pin as a GPIO Green LED
PORTC->PCR[8] = (1UL<<8); // Selecting This Pin as a GPIO Blue LED
PORTC->PCR[9] = (1UL<<8); // Selecting This Pin as a GPIO Yellow LED
PORTC->PCR[10] = (1UL<<8); // Selecting This Pin as a GPIO Orange LED
PTC->PDDR = 0xFFFFFFFF; // Setting as o/p port
PTC->PDOR = 0xFFFFFFFF; // Setting all pins to logic 1
SysTimerInit();
while(1)
{
PTC->PCOR = 0xFFFFFFFF; // Clearing values to logic 0
SysTick_Handler();
PTC->PSOR = 0xFFFFFFFF; // Setting values to logic 1
SysTick_Handler();
}
}
Amir,
SysTick_Handler() is an interrupt service routine in this example. It's called when the SysT timer interrupt fires every ms or so. You don't want to call it yourself.
Add this little function to your code. A small routine that sets debug_timer to the number of ms to wait, and then waits for debug timer to count down.
// wait miliseconds
void WaitMs(int ms)
{
// set debug timer to the number of ms to wait
EnterCriticalSection();
debug_timer = ms;
ExitCriticalSection();
// wait for debug_timer to be counted down to zero
do
{
// get the current value of debug_timer.
EnterCriticalSection();
ms = debug_timer;
ExitCriticalSection();
}
while(ms) ;
}
PS: I haven't compiled this but it aught to work.
PSS:
EnterCriticalSection(); and ExitCriticalSection(); are Processor Expert functions that disable/enable the interrupts.
They are probably not needed in this code because accessing a 32 bit integer 'int' on the ARM Cortex is atomic. And we aren't doing any read modify write operations.
One way is to use a periodic interrupt timer.
The other way is to do 'busy waiting' for the specified time. For that approach I'm using a Processor Expert components (see section "Wait Component" in Tutorial: Enlightning the Freedom KL25Z Board | MCU on Eclipse
You can get this component here: mcuoneclipse/PEupd at master · GitHub
(see Processor Expert Component *.PEupd Files on GitHub | MCU on Eclipse how to download/install additional components).
If you are not using Processor Expert, you can simply copy that code into your application.
If you just want to get a delay, I suggest you can choose LPTMR module and I think it't more easier than use PDB.
The page 984 of K20 reference manual has described the LPTMR counter work which I think will help you to create a delay function.