Перейти к содержанию
    

Как сделать программную задержку на STM32

Пожалуйста подскажите.

Пишу в FreeRTOS.

Нужно написать библиотеку работы с LCD.

Там нужна задержка около 1мкс.

Как ее сделать?

Может функцию на ассемблере кто подскажет?

Потому что Keil оптимизирует в ничто вот такой код:

i = 100;

while (i --)

;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

используй специально для этого предназначенное ключевое слово "volatile", оно говорит компилятору чтоб не оптимизировал значение и работу с этой переменной или кодом.

 

volatile int i;

 

...

 

i = 100;

while (i --)

;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Может функцию на ассемблере кто подскажет?
XTAL_CLK    equ    24000 ; частота тактирования в килогерцах
....

Delay_us    PROC
        push {lr,r4}
del_us     mov    r4,#((XTAL_CLK/1000)/3)
del1u    subs r4,r4,#1
        bne    del1u
        subs r0,r0,#1
        bne    del_us        
        pop {lr,r4}
        bx    lr
    ENDP

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

C volatile все равно оптимизит.

Вот я тут сам нашаманил.

Вопрос - на сколько тактов процессора эта функция делает задержку? Сам цикл.

Вносит ли переход сброс конвейера и глотает ли он доп.циклы?

Или 10*2 циклов получается ровно?

 

 

__asm void delay_us(void)

{

mov r0,#10

loop

subs r0,#1

bne loop

}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

C volatile все равно оптимизит.
Не верю.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вопрос - на сколько тактов процессора эта функция делает задержку? Сам цикл.

Железобетонный способ - измерить с секундомером. Для этого делается задержка не на 10 циклов, а на 10^9 циклов или около того. Не слишком маленькая, чтобы погрешность отсчёта времени была мала, и не слишком большая, чтобы не уснуть с секундомером в руке.

Кстати, задержки для LCD, как правило, не должны быть точными. Обычно достаточно, чтобы было "гарантированно не меньше N циклов".

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вопрос - на сколько тактов процессора эта функция делает задержку? Сам цикл.

Вносит ли переход сброс конвейера и глотает ли он доп.циклы?

Или 10*2 циклов получается ровно?

ПМСМ, переход (кроме последнего раза) будет заново заполнять конвеер.

(не заполняет тогда, когда не выполняется условие - нет перехода)

 

Лучше 1 раз посчитать, используя системный таймер, с предделением 1.

(Вызов функции тоже переход с заполнением конвеера.)

 

Более того, время выполнения, возможно, будеть зависеть от модели контроллера (разрядность памяти)

и настроек регистра доступа к памяти.

 

Мне тоже интересна эта тема. Если посчитаете системным таймером - поделистесь, пожалуйста.

 

По крайней мере на IAR вариант с volatile у меня работает.

void delay_y()
{
volatile u32_t i, ty;
for(i=0; i<10000; i++) ty=GPIOA_ODR;
}

 

И ещё замечание.. практически гарантировано не будет заоптимизировано обращение к портам.

Но ваш вариант лучше - точнее.

Изменено пользователем Юрий_СВ

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

    inline void _delay_loops(U32 loops) {
        asm volatile (
            "1: SUBS %[loops], %[loops], #1 \n"
            "   BNE 1b \n"
            : [loops] "+r"(loops)
        );
    }
    #define delay_us( US ) _delay_loops( (U32)((double)US * F_CPU / 3000000.0) )
    #define delay_ms( MS ) _delay_loops( (U32)((double)MS * F_CPU / 3000.0) )
    #define delay_s( S )   _delay_loops( (U32)((double)S  * F_CPU / 3.0) )

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Пожалуйста подскажите.

Пишу в FreeRTOS.

Нужно написать библиотеку работы с LCD.

Там нужна задержка около 1мкс.

Как ее сделать?

Посмотрите DWT счетчик (DWT_CYCCN, описано тут и здесь): присутствует во всех Cortex по стандарту ARM. Это 32-битное слово, которое "тикает" с частотой ядра.

Счетчик надо проинициализировать (включить):

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

    if (!(DWT_CONTROL & 1))
    {
        SCB_DEMCR  |= 0x01000000;
        DWT_CYCCNT  = 0; 
        DWT_CONTROL|= 1; // enable the counter
    }

 

Задержки можно организовывать так:

 

uint32_t DWT_Get(void)
{
    return DWT_CYCCNT;
}
__inline
uint8_t DWT_Compare(int32_t tp)
{
    return (((int32_t)DWT_Get() - tp) < 0);
}

void DWT_Delay(uint32_t us) // microseconds
{
    int32_t tp = DWT_Get() + us * (SystemCoreClock/1000000));
    while (DWT_Compare(tp));
}

 

Безусловно, по причине задержек исполнения самих инструкций абсолютно точно не будет. Однако же, скажем при 72MHz ядра, даже для 1мкс аддитивная составляющая будет небольшой и постоянной.

Изменено пользователем KnightIgor

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Посмотрите DWT счетчик

Ух ты! Отличная штука, не знал про неё. Проверил на STM32F103 - работает.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Очень жаль, что остальные счётчики все 8-битные.

На оффтопике (LPC17xx) для счётчика циклов достаточно RIT, который остался в наследство от предыдущих LPC а для осевого тика времени в Cortex-M3 стандартизированный таймер нашёлся.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...