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

А я для таких целей использую функции микросекундных задержек, которая пользуется таймером SysTick
DWT таймер более подходит для этой задачи. ИМХО.

 

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


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

А я для таких целей использую функции микросекундных задержек, которая пользуется таймером SysTick, не мешая ему выполнять свою основную функцию - генерирование системного интервала 1 мс

Годится, но только для интервалов короче 1 мс.

А для этого ЖКИ есть интервалы и по 30 мс. (Вообще, темный лепс, скачал несколько datasheet-ов на разные ЖКИ, есть такие странные процедуры установки режимов...)

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


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

Годится, но только для интервалов короче 1 мс.

А для этого ЖКИ есть интервалы и по 30 мс. (Вообще, темный лепс, скачал несколько datasheet-ов на разные ЖКИ, есть такие странные процедуры установки режимов...)

а у него нет никакого флага BUSY? чтобы не городить с задержками, а когда можно флаг опросить и дальше работать

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


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

а у него нет никакого флага BUSY? чтобы не городить с задержками, а когда можно флаг опросить и дальше работать

Есть, но чтобы его опросить (что и делаю), нужно прочитать байт, по всем правилам, с задержками. :)

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


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

Есть, но чтобы его опросить (что и делаю), нужно прочитать байт, по всем правилам, с задержками. :)

ок, можно отдать SysTick генерить все управляющие сигналы по стэйт-машине некой, а из него уже отсылать программный сигнал (или просто флаг) ждущей задаче

я так понимаю, этот таймер все равно по микросекундам генерится?

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


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

Есть, но чтобы его опросить (что и делаю), нужно прочитать байт, по всем правилам, с задержками. :)
Да дайте вы удвоенную от максимальной задержку и забудьте о чтении. Оператор не заметит лишние 10 мс на перерисовку всего экрана, а программа упростится раза в три.

 

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


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

ок, можно отдать SysTick генерить все управляющие сигналы по стэйт-машине некой, а из него уже отсылать программный сигнал (или просто флаг) ждущей задаче

я так понимаю, этот таймер все равно по микросекундам генерится?

У меня задержка считается в ns. С точностью до такта микроконтроллера. SysTick Timer считает такты (или поделенные на 8) до 1-10 ms для RTOS (и у меня тоже есть), потом перезагружается. Поэтому более длинные интервалы не получить.

Можно большие задержки считать одним способом, а малые другим. А можно все одним. :rolleyes:

 

Да дайте вы удвоенную от максимальной задержку и забудьте о чтении. Оператор не заметит лишние 10 мс на перерисовку всего экрана, а программа упростится раза в три.

Так уж в три...? :) Задержка занимает у меня от 3 до 6 ассемблерных команд. Куда уж проще? И выполняется именно столько времени, сколько мне нужно.

Там же все обращения к контроллеру ЖКИ идут ногодрыгом, без задержек - никак не обойтись.

А для выполнения ЖКИ команд нужны задержки побольше. Зачем мне терять время, если не проверять, когда они закончатся, а тупо ждать больше срока?

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


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

Так уж в три...? :) Задержка занимает у меня от 3 до 6 ассемблерных команд. Куда уж проще?
Выкинуть чение Busy, дав задержки на выполнение команд дисплеем вдвое от максимальных в даташите (50мкс на все команды кроме очистки экрана, на нее 2мс или вообще не использовать). Уже только избавление он необходимости переключать порт на ввод и анализивровать Busy сводит все управление дисплеем к трем примитивнейшим функциям:

void hd44780::write_tetrade(uint8_t tetrade)    // assume data in upper tetrade, lower tetrade is all zeros
{
    ON(LCD_EN);
    LCD_PORT = (LCD_PORT & 0x0F) | tetrade;
    _delay_us(1);
    OFF(LCD_EN);
    _delay_us(1);
}

void hd44780::write_data(uint8_t byte)
{
    write_tetrade(byte & 0xF0);
    write_tetrade(byte << 4);
    _delay_us(50);
    ON(LCD_RS);
}

void hd44780::write_command(uint8_t command)
{
    OFF(LCD_RS);
    write_data(command);
}

Сравните со своим ногодрыгом с чтением Busy.

 

Ну хорошо, еще инициализация:

inline hd44780::hd44780()
{
    OFF(LCD_RS);
    _delay_ms(200);
    write_tetrade(3 << 4);      // set 8-bit mode
    _delay_ms(50);
    write_tetrade(3 << 4);      // set 8-bit mode again
    _delay_ms(50);
    write_tetrade(3 << 4);      // set 8-bit mode again, see http://electronix.ru/forum/index.php?s=&showtopic=19594&view=findpost&p=143374
    _delay_us(50);              // delay slightly longer than typical command execution time.
    write_tetrade(2 << 4);      // set 4-bit mode
    _delay_us(50);
    write_command(CURSOR_HOME);
    _delay_ms(2);
    write_command(0x06);        // increment cursor position during data write, disable display shift
    write_command(CURSOR_OFF);
}

 

а тупо ждать больше срока?
А вы и так "тупо ждете больше срока" потому что в вашу задержку вклиниваются прерывания. Вывод на дисплей происходит так редко, что будет там задержка 50мкс или 20мкс на байт не заметит никто. Ну пусть у вас дисплей 4*40, пусть обновляете его целиком 4 раза в секунду (быстрее он не успеет отобразить, а оператор воспринять), ну потеряете вы лишних (50-20)*40*4*4=19200 мкс. Ах, 19мс каждую секунду ушло впустую, катастрофа. Зато сэкономлена неделя рабочего времени, за которую эти 19мс можно с большей пользой отыграть где-то в другом месте.

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


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

А вы и так "тупо ждете больше срока" потому что в вашу задержку вклиниваются прерывания.

Зато я могу посылать в ЖКИ символы, когда захочу. Совсем не обязательно "тупо ждать" задержку или флаг Busy, можно заняться чем-нибудь общественно-полезным между выводами, не опасаясь "уже можно посылать, или еще подождать?".

 

Нюанс всплыл - невозможно заинлайнить функцию (DelayCY4), находящуюся в другом файле. Пришлось в один объединить.

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


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

Нюанс всплыл - невозможно заинлайнить функцию (DelayCY4), находящуюся в другом файле. Пришлось в один объединить.

с месяц назад где-то здесь обсуждался вопрос вставки inline из другого файла, кстати

 

с задержками я делал вот так

void HD44780_delay(int ns10)
{
volatile unsigned int trash_out;
volatile unsigned int trash_in;
int i;
    
    for (i=0; i<ns10; i++)
        trash_in = trash_out;
}

что-то типа того. Нужно посмотреть, сколько займет выборка из RAM и из FLASH

не панацея, конечно, но позволит уйти от асма, тем более что точная задержка как таковая не критична прям уж так

 

а с большими задержками - там и подождать сигнала от таймера не проблема, тем более, что это наверняка в отдельной задаче вертится

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


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

Нюанс всплыл - невозможно заинлайнить функцию (DelayCY4), находящуюся в другом файле. Пришлось в один объединить.
Это не нюанс, это стандартное поведение.

Для решения подобных задач нужно всё в заголовочном файле размещать:

static __inline void delay(int x)
{
    ....
}

не панацея, конечно, но позволит уйти от асма, тем более что точная задержка как таковая не критична прям уж так
Не системный подход с кучей сорного кода, заслоняющего основную идею.

Здесь асм не столько для точности, а больше для снятия зависимости от уровня оптимизации.

 

Тут у меня самого возник вопрос, касательно задержек в gcc.

Вот такой код упорно приводит проект в нерабочее состояние:

#define delay_4cycles(cy)                \
(__extension__({                         \
    uint32_t __x = (uint32_t)(cy);       \
    __asm__ __volatile__                 \
    (                                    \
        "loop%=: subs %[cnt],#1"  "\n\t" \
        "        bne  loop%="     "\n\t" \
        :                                \
        : [cnt]"r"(__x)                  \
        : "cc"                           \
    );                                   \
}))

for(;;)
{
    delay_4cycles(1);
    pin_toggle(LED_RED);
}

А именно не производится перезагрузка счётчика цикла внутри цикла for.

В данном примере 1 загружается в регистр единожды перед циклом for, что собственно является нежелательным поведением:

 8001df6:    f04f 0001     mov.w    r0, #1
...
8001e0a:    3801          subs    r0, #1
8001e0c:    d1fd          bne.n    8001e0a
8001e0e:    682b          ldr    r3, [r5, #0]
8001e10:    ea6f 0703     mvn.w    r7, r3
8001e14:    6037          str    r7, [r6, #0]
8001e16:    e7f8          b.n    8001e0a

А без использования асм всё нормально:

 8001e04:    bf00          nop
8001e06:    bf00          nop
8001e08:    bf00          nop
8001e0a:    bf00          nop
8001e0c:    6806          ldr    r6, [r0, #0]
8001e0e:    ea6f 0306     mvn.w    r3, r6
8001e12:    602b          str    r3, [r5, #0]
8001e14:    e7f6          b.n    8001e04

Прошу помощи у аудитории!

 

arm-none-eabi-gcc.EXE (GNU Tools for ARM Embedded Processors / bleeding-edge-toolchain-131005) 4.7.4 20130913 (prerelease)

CFLAGS += -flto

CFLAGS += -fomit-frame-pointer

CFLAGS += -falign-functions=16

CFLAGS += -fgraphite

CFLAGS += -funroll-loops

CFLAGS += -ffunction-sections

CFLAGS += -fdata-sections

CFLAGS += -O3

#CFLAGS += -O1

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


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

Прошу помощи у аудитории!
cnt у вас меняется в асм-вставке, а компилятору вы об этом не сообщаете.

Попробуйте так, если в синтаксисе не ошибся:

    __asm__ __volatile__                 \
    (                                    \
        "loop%=: subs %[cnt],#1"  "\n\t" \
        "        bne  loop%="     "\n\t" \
        : =[cnt]"r"(__x)                 \
        :                   \
        : "cc"                           \
    );                                   \

 

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


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

cnt у вас меняется в асм-вставке, а компилятору вы об этом не сообщаете.
Согласно доке и не должен я об этом ничего сообщать.

Вы предлагаете использовать cnt как выходной write only регистр:

#define delay_4cycles(cy)                \
(__extension__({                         \
    uint32_t __x = (uint32_t)(cy);       \
    __asm__ __volatile__                 \
    (                                    \
        "loop%=: subs %[cnt],#1"  "\n\t" \
        "        bne  loop%="     "\n\t" \
        : [cnt]"=r"(__x)                 \
        :                                \
        : "cc"                           \
    );                                   \
}))

что на мой взгляд несколько неверно, т.к. компилятор его вообще перестал инициализировать:

 8001e06:    3b01          subs    r3, #1
8001e08:    d1fd          bne.n    8001e06 <loop3411>
8001e0a:    6806          ldr    r6, [r0, #0]
8001e0c:    ea6f 0306     mvn.w    r3, r6
8001e10:    602b          str    r3, [r5, #0]
8001e12:    e7f8          b.n    8001e06 <loop3411>

На мой взгляд cnt - это input, а не output операнд (кстати =&r даёт такой же результат).

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


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

Согласно доке и не должен я об этом ничего сообщать.
Здрасьте. А как же он узнает, что вы его испортили и его надо перегрузить?

Вы предлагаете использовать cnt как выходной write only регистр:
Нет, вы пропустили "=" перед [cnt]. Я его делаю и input и output, коим он фактически и является.

 

Сейчас. сверюсь со своими исходниками. Я допускал эту же ошибку, сейчас найду.

 

В первый раз не туда смотрел, извиняюсь.

        : [cnt]"+r"(__x)                 \

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


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

Нет, вы пропустили "=" перед [cnt]. Я его делаю и input и output, коим он фактически и является.
"=" перед [cnt] не даёт ставить - ошибка компиляции.

"=" перед r не то же самое?

        : [cnt]"+r"(__x)                 \

О! Оно!
 8001df6:    f04f 0001     mov.w    r0, #1
...
8001e0a:    4603          mov    r3, r0
8001e0c:    3b01          subs    r3, #1
8001e0e:    d1fd          bne.n    8001e0c
8001e10:    682f          ldr    r7, [r5, #0]
8001e12:    ea6f 0407     mvn.w    r4, r7
8001e16:    6034          str    r4, [r6, #0]
8001e18:    e7f7          b.n    8001e0a

Спасибо большое!!!

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


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

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

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

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

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

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

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

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

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