Saturday, March 3, 2018

Delay functions for EFM8 microcontrollers

Sometimes you need to delay the program execution, for example when waiting for another device to startup or respond and the software cannot continue. An interrupt driven delay is better in most cases but not in all cases.
Because of this I made two functions one for milliseconds and one for microseconds, that uses NOPs that holds the CPU for a certain amount of time.
The milliseconds delay is quite accurate, the microseconds one, not so much.


The constants used in calculations have been found empirically and they are dependent of variables size, number of instructions inside the function. For example multiplication, division and float numbers take much more CPU cycles than subtraction and addition. Also the while loop takes time itself and the higher the number of milliseconds, the higher the while loop takes and that must be subtracted from the number of cpu cycles calculated.

For milliseconds delay function the CPU division must be 8 or 1 for better accuracy. The microseconds function is made only for CPU divided by 1.

The code needs globals.h file included in which are defined F_CPU and CPU_DIV. The file can be downloaded from http://www.programming-electronics-diy.xyz/2018/03/globals-header-for-efm8bb1.html or make these defines inside the file.



/*_______________________________________________________________________________

delay.h v2.0

Simple delay implementation using NOPs. It is not very accurate but it works for
giving time to something to be ready.

- TESTED DEVICES:
EFM8

For complete details about the library, visit
www.programming-electronics-diy.xyz

NOTICE
--------
NO PART OF THIS WORK CAN BE COPIED, DISTRIBUTED OR PUBLISHED WITHOUT A
WRITTEN PERMISSION FROM THE AUTHOR. THE LIBRARY, NOR ANY PART
OF IT CAN BE USED IN COMMERCIAL APPLICATIONS. IT IS INTENDED TO BE USED FOR
HOBBY, LEARNING AND EDUCATIONAL PURPOSE ONLY. IF YOU WANT TO USE THEM IN
COMMERCIAL APPLICATION PLEASE WRITE TO THE AUTHOR.

Copyright (c) 2019 Istrate Liviu
__________________________________________________________________________________*/

#ifndef DELAY_H_
#define DELAY_H_

//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include "intrins.h"
#include "globals.h" // F_CPU and CPU_DIV

//-----------------------------------------------------------------------------
// Defines
//-----------------------------------------------------------------------------
#define SYSCLK_MS  ((F_CPU / CPU_DIV) / 1000.0) / 60.0 // Convert to oscillations per ms
#define SYSCLK_US  ((F_CPU / CPU_DIV) / 1000000.0) // Convert to oscillations per us
#define SUBSTRACT_MS 7500.0 / 60.0 / CPU_DIV

//-----------------------------------------------------------------------------
// Function PROTOTYPES
//-----------------------------------------------------------------------------
void _delay_ms(uint32_t ms);
void _delay_us(uint16_t us);

//-----------------------------------------------------------------------------
// Functios
//-----------------------------------------------------------------------------

/* _______________________________________________________________
 *   _delay_ms - works only with CPU_DIV 8 or less
 *
 *  Calculates the number of NOPs for a delay in milliseconds
 * Relatively accurate
 *  @param [ms] number of milliseconds to delay
 * _______________________________________________________________*/
void _delay_ms(uint32_t ms){
 // Substract n clock cycles for every ms to account for the time that the loop takes
 uint32_t clockCycles = SYSCLK_MS * ms;
 uint32_t substract = (SUBSTRACT_MS * ms) + 34;

 if(clockCycles > substract) clockCycles -= substract;

 while(clockCycles-- > 0){
  _nop_();
 }
}


/* _______________________________________________________________
 *   _delay_us - works only with CPU_DIV 1
 *
 *  Calculates the number of NOPs for a delay in microseconds
 *  Not very accurate
 *  @param [us] number of microseconds to delay
 * _______________________________________________________________*/
void _delay_us(uint16_t us){
 uint16_t clockCycles = (1 * us) + 55;

 while(clockCycles-- > 0){
  _nop_();
 }
}

#endif /* DELAY_H_ */

Download

  • Version 2.0

3 comments:

  1. can't make file- error: can't open file global.h

    ReplyDelete
  2. Did you download and include the file like it was explained above? If not you can find it here https://www.programming-electronics-diy.xyz/2018/03/globals-header-for-efm8bb1.html

    Or remove this line
    #include "globals.h"
    and replace it with
    #define F_CPU 16000000 // your CPU frequency in Hz
    #define CPU_DIV 1 // replace here with your CPU division clock

    ReplyDelete