In K20 microcontroller how can we get a real time delay like delayms(100) or delayus(100) for 100 ms and 100 us delay?

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

In K20 microcontroller how can we get a real time delay like delayms(100) or delayus(100) for 100 ms and 100 us delay?

5,487 Views
Amit_Kumar1
Senior Contributor II

In K20 microcontroller can we get a real time delay like delayms(100) or delayus(100) for 100 ms and 100 us delay?

I think it may be possible through Programmable Delay Block (PDB) but I couldn't figure it out can anybody guide me for this.

16 Replies

2,518 Views
wendersonolivei
Contributor IV

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!

0 Kudos
Reply

2,518 Views
pgo
Senior Contributor V

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;

   }

}

2,518 Views
nasreenshaikh
Contributor III

Hi

I am atttaching the files for Delay routine. They are tested on K10 controller.

Should work for you i guess.

0 Kudos
Reply

2,518 Views
matthewsinger
Contributor I

Small error in the code.  This only works for 1 iteration.  R1 has to be reloaded with the loop count ;-)

0 Kudos
Reply

2,518 Views
dositeoescobars
Contributor II

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

0 Kudos
Reply

2,518 Views
Amit_Kumar1
Senior Contributor II

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

0 Kudos
Reply

2,518 Views
rogerfl
Contributor III

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);

  }

}

0 Kudos
Reply

2,518 Views
dositeoescobars
Contributor II

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


0 Kudos
Reply

2,518 Views
Amit_Kumar1
Senior Contributor II

Hi

I tried this also but it didn't worked :smileysad:

0 Kudos
Reply

2,518 Views
gibbon1
Contributor III

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

2,518 Views
Amit_Kumar1
Senior Contributor II

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

0 Kudos
Reply

2,518 Views
gibbon1
Contributor III

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;

}

0 Kudos
Reply

2,518 Views
Amit_Kumar1
Senior Contributor II

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();

        }

   

}

0 Kudos
Reply

2,518 Views
gibbon1
Contributor III

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.


0 Kudos
Reply

2,518 Views
BlackNight
NXP Employee
NXP Employee

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.

0 Kudos
Reply

2,518 Views
jeremyzhou
NXP Employee
NXP Employee

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.

0 Kudos
Reply