Search code examples
cdata-structuresstm32delay

Handling data structure for creating library of stm32


I try to create a library for stm32.How can I handle "delayus or delayms") without using "DelayHandle_t *delay1"
And how can I use "myTicks" variable to be a global variable because I can not use this one for Interrupt

void Delayus(uint8_t value,DelayHandle_t *delay1)
{
    //enable timer 4
    TIM4->CCR1 |= TIM_CR1_CNE;
    delay1->myTicks = 0;
    while(*(delay1->myTicks) < value);
    TIM4->CCR1 &= ~TIM_CR1_CNE;
}
void Deleyms(uint8_t value,DelayHandle_t *delay1)
{
    TIM4->CCR1 |= TIM_CR1_CNE;
    delay1->myTicks = 0;
    while(*(delay1->myTicks) < (value*1000));
    TIM4->CCR1 &= ~TIM_CR1_CNE;
}
void TIM4_IRQHandler()
{
    delay1->myTicks ++;
    TIM4->SR &= ~(TIM_SR_UIF);
}

Solution

  • An easier way of implementing microsecond delays on an STM32 would be to just configure a timer to have a period of 1us, and read its counter. You would use the prescaler to give you the correct period. e.g. if the clock going into the timer is 16MHz, you'd want to divide that by 16. You need to set the prescaler to one less than that, e.g.

    TIM4->PSC = 15; // Divide by 16, to get 1us period
    

    You would also set the timer to count for its full range - for a 16-bit timer, 0x0-0xffff:

    TIME4->ARR = 0xFFFFu;
    

    You would typically just start the timer running and leave it running. To delay, read the counter at the start, then loop waiting for it to increment enough microseconds for the delay.

    There are a couple of pit-falls. Some timers on an STM32 are 16-bit timers (TIM4 is on an STM32F030...) And you also don't know how close you are to the next 'tick'. Just waiting for the counter to increment by X means you are delaying between (X-1) and (X) microseconds. If you need to guarantee at least X microseconds, add one to the delay value. Putting all that together you might have something like this:

    void Delayus(uint32_t us)
    {
        uint16_t start;
        uint32_t remaining = us + 1u; // Add one to guarantee 'at least' us
    
        start = TIM4->CNT;
    
        while (remaining > 0u)
        {
            uint16_t delay = (remaining > 0xFFFFu) ? 0xFFFFu : (uint16_t)remaining;
            uint16_t end;
    
            remaining -= delay;
    
            do {
                end = TIM4->CNT;
            } while ((end - start) < delay);
    
            start = end;
        }
    }
    

    This should cope correctly with any delay up to 0xFFFFFFFEu microseconds.