cancel
Showing results for 
Search instead for 
Did you mean: 

Precise delay function on STM32F401CE

MArdm.1
Associate II

I have tried a lot of different things but I can never seem to get it, I am trying to make a semblance of a precise delay function for my controller, I am not using HAL or anything, just writing to registers directly. I tried timers, timer interrupts, I always am just slightly off and I legitimately can't find a good solution. Any advice on microsecond delay functions? Thanks in advance

1 ACCEPTED SOLUTION

Accepted Solutions

The timer will clock at whatever frequency you set.

Use the Prescaler to get down to 1 MHz (1us tick units), say 42-1 if the APB clocking at 42 MHz

Set the TIM to maximal, ie Period = 0xFFFFFFFF or 0xFFFF

It will count through all states 0x00000000 thru 0xFFFFFFFF, and back to 0

void delay_us(uint32_t delay)
{
  uint32_t start = TIM2->CNT;
  while((TIM2->CNT - start) < delay) { };
}

With a faster clock you can resolve more finely/precisely.

Consider also entry/exit time, vs the edge of the timer you're catching

//******************************************************************************
 
// Cortex M3 cycle counters in the STM32's trace unit
// From http://forums.arm.com/index.php?showtopic=13949
 
volatile unsigned int *DWT_CYCCNT   = (volatile unsigned int *)0xE0001004; //address of the register
volatile unsigned int *DWT_CONTROL  = (volatile unsigned int *)0xE0001000; //address of the register
volatile unsigned int *SCB_DEMCR    = (volatile unsigned int *)0xE000EDFC; //address of the register
 
//******************************************************************************
 
void CycleCounter_Configuration(void)
{
  *SCB_DEMCR |= 0x01000000;
  *DWT_CYCCNT = 0; // reset the counter
  *DWT_CONTROL |= 1 ; // enable the counter
}
 
//******************************************************************************
 
void SleepUSec(unsigned int Delay)
{
  unsigned int Current, Start;
 
  Delay = Delay * (SystemCoreClock / 1000000);
 
  Start = *DWT_CYCCNT;
 
  do
  {
    Current = *DWT_CYCCNT;
  }
  while((Current - Start) < Delay);
}
 
//******************************************************************************

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

View solution in original post

8 REPLIES 8

Interrupts cannot occur at excessively high rates.

You need a 32-bit timer or counter clocking at a rate that gives you a resolution you need.

For precise signal placement you need to do in hardware via a TIM, and perhaps DMA+GPIO if you want to output constructed signals from a pattern buffer.

Perhaps use the processor cycle counter, DWT CYCCNT to account for time, or TIM2 / TIM5 clocking at 1 or 10 MHz, or higher.

Code execution time and other interrupts might interfere with these types of software loop type delays.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
MArdm.1
Associate II

Alright, fair, but at this point I don't even want to use interrupts. I have a 32 bit timer. I just don't understand where to find the default frequency of the timer, how exactly to alter it, at some point I felt like I understood, I no longer think that.

MArdm.1
Associate II

An example of how to use a timer properly to make a delay function would be amazing.

gbm
Lead III

There is nothing amazing in reading a few pages of Reference Manual and writing 5 timer registers (PSC, ARR, CCRx, DIER and CR1). We do it on daily basis. Add timer enabling in RCC before it, NVIC_EnableIRQ after, then write 5 lines of timer interrupt routine and you are done.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
MArdm.1
Associate II

Ok I got that far, that's why I came here, because that timer is wildly inaccurate, so I wanted to ask what should I do to make it more accurate, something about clock frequencies maybe?

KnarfB
Principal III

So, what's your code, what do you expect and what do you observe?

"timer is wildly inaccurate" - Timer is very accurate - generaly it is the most accurate. It can generate "events" with single tick precision (and even more in case HRTIM). Your "Delay" is indefinite term. For example delay of two output signals (pulses) can be generated by timer with precision delay... Timer also can delay its output pulse ater incoming external signal with high precision... etc.

The timer will clock at whatever frequency you set.

Use the Prescaler to get down to 1 MHz (1us tick units), say 42-1 if the APB clocking at 42 MHz

Set the TIM to maximal, ie Period = 0xFFFFFFFF or 0xFFFF

It will count through all states 0x00000000 thru 0xFFFFFFFF, and back to 0

void delay_us(uint32_t delay)
{
  uint32_t start = TIM2->CNT;
  while((TIM2->CNT - start) < delay) { };
}

With a faster clock you can resolve more finely/precisely.

Consider also entry/exit time, vs the edge of the timer you're catching

//******************************************************************************
 
// Cortex M3 cycle counters in the STM32's trace unit
// From http://forums.arm.com/index.php?showtopic=13949
 
volatile unsigned int *DWT_CYCCNT   = (volatile unsigned int *)0xE0001004; //address of the register
volatile unsigned int *DWT_CONTROL  = (volatile unsigned int *)0xE0001000; //address of the register
volatile unsigned int *SCB_DEMCR    = (volatile unsigned int *)0xE000EDFC; //address of the register
 
//******************************************************************************
 
void CycleCounter_Configuration(void)
{
  *SCB_DEMCR |= 0x01000000;
  *DWT_CYCCNT = 0; // reset the counter
  *DWT_CONTROL |= 1 ; // enable the counter
}
 
//******************************************************************************
 
void SleepUSec(unsigned int Delay)
{
  unsigned int Current, Start;
 
  Delay = Delay * (SystemCoreClock / 1000000);
 
  Start = *DWT_CYCCNT;
 
  do
  {
    Current = *DWT_CYCCNT;
  }
  while((Current - Start) < Delay);
}
 
//******************************************************************************

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..