demiurg_spb 0 14 апреля, 2014 Опубликовано 14 апреля, 2014 · Жалоба А я для таких целей использую функции микросекундных задержек, которая пользуется таймером SysTickDWT таймер более подходит для этой задачи. ИМХО. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 14 апреля, 2014 Опубликовано 14 апреля, 2014 · Жалоба А я для таких целей использую функции микросекундных задержек, которая пользуется таймером SysTick, не мешая ему выполнять свою основную функцию - генерирование системного интервала 1 мс Годится, но только для интервалов короче 1 мс. А для этого ЖКИ есть интервалы и по 30 мс. (Вообще, темный лепс, скачал несколько datasheet-ов на разные ЖКИ, есть такие странные процедуры установки режимов...) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
toweroff 1 14 апреля, 2014 Опубликовано 14 апреля, 2014 · Жалоба Годится, но только для интервалов короче 1 мс. А для этого ЖКИ есть интервалы и по 30 мс. (Вообще, темный лепс, скачал несколько datasheet-ов на разные ЖКИ, есть такие странные процедуры установки режимов...) а у него нет никакого флага BUSY? чтобы не городить с задержками, а когда можно флаг опросить и дальше работать Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 14 апреля, 2014 Опубликовано 14 апреля, 2014 · Жалоба а у него нет никакого флага BUSY? чтобы не городить с задержками, а когда можно флаг опросить и дальше работать Есть, но чтобы его опросить (что и делаю), нужно прочитать байт, по всем правилам, с задержками. :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
toweroff 1 14 апреля, 2014 Опубликовано 14 апреля, 2014 · Жалоба Есть, но чтобы его опросить (что и делаю), нужно прочитать байт, по всем правилам, с задержками. :) ок, можно отдать SysTick генерить все управляющие сигналы по стэйт-машине некой, а из него уже отсылать программный сигнал (или просто флаг) ждущей задаче я так понимаю, этот таймер все равно по микросекундам генерится? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 143 14 апреля, 2014 Опубликовано 14 апреля, 2014 · Жалоба Есть, но чтобы его опросить (что и делаю), нужно прочитать байт, по всем правилам, с задержками. :)Да дайте вы удвоенную от максимальной задержку и забудьте о чтении. Оператор не заметит лишние 10 мс на перерисовку всего экрана, а программа упростится раза в три. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 14 апреля, 2014 Опубликовано 14 апреля, 2014 · Жалоба ок, можно отдать SysTick генерить все управляющие сигналы по стэйт-машине некой, а из него уже отсылать программный сигнал (или просто флаг) ждущей задаче я так понимаю, этот таймер все равно по микросекундам генерится? У меня задержка считается в ns. С точностью до такта микроконтроллера. SysTick Timer считает такты (или поделенные на 8) до 1-10 ms для RTOS (и у меня тоже есть), потом перезагружается. Поэтому более длинные интервалы не получить. Можно большие задержки считать одним способом, а малые другим. А можно все одним. :rolleyes: Да дайте вы удвоенную от максимальной задержку и забудьте о чтении. Оператор не заметит лишние 10 мс на перерисовку всего экрана, а программа упростится раза в три. Так уж в три...? :) Задержка занимает у меня от 3 до 6 ассемблерных команд. Куда уж проще? И выполняется именно столько времени, сколько мне нужно. Там же все обращения к контроллеру ЖКИ идут ногодрыгом, без задержек - никак не обойтись. А для выполнения ЖКИ команд нужны задержки побольше. Зачем мне терять время, если не проверять, когда они закончатся, а тупо ждать больше срока? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 143 14 апреля, 2014 Опубликовано 14 апреля, 2014 · Жалоба Так уж в три...? :) Задержка занимает у меня от 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мс можно с большей пользой отыграть где-то в другом месте. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 14 апреля, 2014 Опубликовано 14 апреля, 2014 · Жалоба А вы и так "тупо ждете больше срока" потому что в вашу задержку вклиниваются прерывания. Зато я могу посылать в ЖКИ символы, когда захочу. Совсем не обязательно "тупо ждать" задержку или флаг Busy, можно заняться чем-нибудь общественно-полезным между выводами, не опасаясь "уже можно посылать, или еще подождать?". Нюанс всплыл - невозможно заинлайнить функцию (DelayCY4), находящуюся в другом файле. Пришлось в один объединить. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
toweroff 1 14 апреля, 2014 Опубликовано 14 апреля, 2014 · Жалоба Нюанс всплыл - невозможно заинлайнить функцию (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 не панацея, конечно, но позволит уйти от асма, тем более что точная задержка как таковая не критична прям уж так а с большими задержками - там и подождать сигнала от таймера не проблема, тем более, что это наверняка в отдельной задаче вертится Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 15 апреля, 2014 Опубликовано 15 апреля, 2014 · Жалоба Нюанс всплыл - невозможно заинлайнить функцию (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 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 143 15 апреля, 2014 Опубликовано 15 апреля, 2014 · Жалоба Прошу помощи у аудитории!cnt у вас меняется в асм-вставке, а компилятору вы об этом не сообщаете. Попробуйте так, если в синтаксисе не ошибся: __asm__ __volatile__ \ ( \ "loop%=: subs %[cnt],#1" "\n\t" \ " bne loop%=" "\n\t" \ : =[cnt]"r"(__x) \ : \ : "cc" \ ); \ Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 15 апреля, 2014 Опубликовано 15 апреля, 2014 · Жалоба 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 даёт такой же результат). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 143 15 апреля, 2014 Опубликовано 15 апреля, 2014 · Жалоба Согласно доке и не должен я об этом ничего сообщать.Здрасьте. А как же он узнает, что вы его испортили и его надо перегрузить? Вы предлагаете использовать cnt как выходной write only регистр: Нет, вы пропустили "=" перед [cnt]. Я его делаю и input и output, коим он фактически и является. Сейчас. сверюсь со своими исходниками. Я допускал эту же ошибку, сейчас найду. В первый раз не туда смотрел, извиняюсь. : [cnt]"+r"(__x) \ Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 15 апреля, 2014 Опубликовано 15 апреля, 2014 · Жалоба Нет, вы пропустили "=" перед [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 Спасибо большое!!! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться