Функция задержки STM32.

Функция задержки STM32.

Первое на что обратил внимание, после перехода с AVR на STM32 — это отсутствие привычных функций, для реализации задержки: delay_us() и delay_ms(), ну отсутствуют так отсутствуют, подумал тогда и если надо было реализовать задержку, то делал это так.

void delay(uint32_t time_delay)
{	
    uint32_t i;
    for(i = 0; i < time_delay; i++);
}


А переменную time_delay подбирал экспериментально. Нет, конечно же, первым делом, до того как реализовать задержку на цикле for(), искал в интернете как это делают люди. В общем, нашёл реализацию на systick, но сходу разбираться с работой таймера не было желания и всё-таки хотелось найти более простой способ.

Шло время и в одном проекте всё-таки понадобилось чуть точнее отсчитывать временные интервалы, чем это позволял цикл for(), ситуация сложилось так, что после каждого чтения микросхемы надо было выждать паузу, пока она обновит значение регистров, а данных надо было считывать много и после этого их надо было ещё выводить на TFT дисплей, в итоге дисплей перерисовывался очень редко и выглядело это уныло.
Решение было найдено случайно, в одной из прошлых статей описывал как работает DWT, вот на нём и реализовал.

#define    DWT_CYCCNT    *(volatile unsigned long *)0xE0001004
#define    DWT_CONTROL   *(volatile unsigned long *)0xE0001000
#define    SCB_DEMCR     *(volatile unsigned long *)0xE000EDFC

void delay_us(uint32_t us)
{
	int32_t us_count_tick =  us * (SystemCoreClock/1000000);
	//разрешаем использовать счётчик
	SCB_DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
        //обнуляем значение счётного регистра
	DWT_CYCCNT  = 0;
        //запускаем счётчик
	DWT_CONTROL |= DWT_CTRL_CYCCNTENA_Msk; 
	while(DWT_CYCCNT < us_count_tick);
        //останавливаем счётчик
	DWT_CONTROL &= ~DWT_CTRL_CYCCNTENA_Msk;
	
}
//////////////////////////////
void delay_ms(uint32_t ms)
{
	int32_t ms_count_tick =  ms * (SystemCoreClock/1000);
	//разрешаем использовать счётчик
	SCB_DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
         //обнуляем значение счётного регистра
	DWT_CYCCNT  = 0;
        //запускаем счётчик
	DWT_CONTROL|= DWT_CTRL_CYCCNTENA_Msk; 
	while(DWT_CYCCNT < ms_count_tick);
        //останавливаем счётчик
	DWT_CONTROL &= ~DWT_CTRL_CYCCNTENA_Msk;
	
}


Уже лучше, но данные функции сами являются источником ошибки, во-первых при вызове функции регистры пакуются в стек, во-вторых вычисляется количество тактов, обнуляется и запускается счётчик, а в итоге это всё надо просуммировать и при задержке в несколько микросекунд ошибка будет значительной. И так, что мы можем улучшить: один раз, при инициализации разрешить использовать счётчик, записать в счётный регистр ноль, запустить счётчик и больше не выключать.

#define    DWT_CYCCNT    *(volatile unsigned long *)0xE0001004
#define    DWT_CONTROL   *(volatile unsigned long *)0xE0001000
#define    SCB_DEMCR     *(volatile unsigned long *)0xE000EDFC


void DWT_Init(void)
{
        //разрешаем использовать счётчик
        SCB_DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
         //обнуляем значение счётного регистра
	DWT_CYCCNT  = 0;
         //запускаем счётчик
	DWT_CONTROL |= DWT_CTRL_CYCCNTENA_Msk; 
}

Готово, теперь осталось реализовать функцию задержки.

static __inline uint32_t delta(uint32_t t0, uint32_t t1)
{
    return (t1 - t0); 
}
void delay_us(uint32_t us)
{
      uint32_t t0 =  DWT->CYCCNT;
      uint32_t us_count_tic =  us * (SystemCoreClock/1000000);
      while (delta(t0, DWT->CYCCNT) < us_count_tic) ;
}

Данная реализация работает даже, если после присваивания t0 произошло переполнение счётчика. Давайте рассмотрим два варианта развития событий, но для простоты, вместо uint32_t будем оперировать типом uint8_t.

t0 = 1, us_count_tic = 100, а DWT->CYCCNT = 10, тогда получаем (uint8_t)(10 - 1) < 100, значение счётчика будет расти и когда оно дойдет до 101 выполнение цикла прекратится.

Если t0 = 255 получаем (uint8_t)(10 - 255) < 100, так как delta возвращает значение типа uint32_t(в данном случае заменил его на uint8_t), то (uint8_t)(10 - 255) = 11 и ситуация развивается аналогично предыдущему примеру.

На этом всё, надеюсь кому-то статья окажется полезной.
комментарии
2