|
#define DELAY(CY), Как задать выбор вариантов определения? |
|
|
|
Apr 9 2014, 07:11
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(Сергей Борщ @ Apr 9 2014, 11:02)  Пробовал лет 8 назад в ИАРе - там тоже работало. Неужели кейл не умел выкидывать мертвый код? У меня о нем тогда сложилось довольно хорошее впечатление, хоть и работал с ним совсем недолго. Сам был неприятно удивлён. Также как и отсутствием возможности вычисления на этапе компиляции cos(const) и т.д. Именно это меня и сподвигло перейти на gcc и на arm платформе. Пробовал на ARM C/C++ Compiler, 4.1
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Apr 9 2014, 15:23
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Сотворил. CODE /*!**************************************************************************** @brief Delay program loop @param NS - время задержки в ns @note Параметр округляется до ближайшего не меньшего, кратного тактам @note 5 тактов в цикле при оптимизации -O3 (-Otime), -O2 6 тактов в цикле при оптимизации -O1 и -O0 + 1 такт перед циклом при оптимизации -O0 @note При проверке условия выхода из цикла компиприлятор отбрасывает одиночный цикл, поэтому счет циклов начинается с 2 @note Формула: D = 5 * (CY5 + 1) + Nnop; 6 * (CY5 + 1) + Nnop (+ 1) */ #define SYSCLK_MHZ 72 #define NS2CY(NS) ((NS * SYSCLK_MHZ + 999) / 1000)
#define DELAY_NS(NS) DELAY_CY(NS2CY(NS)) #define DELAY_CY(CY) \ if (CY % 5 == 1) \ { __nop(); } \ else if (CY % 5 == 2) \ { __nop(), __nop(); } \ else if (CY % 5 == 3) \ { __nop(), __nop(), __nop(); } \ else if (CY % 5 == 4) \ { __nop(), __nop(), __nop(), __nop(); } \ if (CY > 4 && CY < 10) \ { __nop(), __nop(), __nop(), __nop(), __nop(); } \ else if (CY >= 10) \ { __nop(); uint32_t CY5 = (CY - 5) / 5; do { __nop(); } while (CY5--); }
|
|
|
|
|
Apr 10 2014, 01:18
|
Частый гость
 
Группа: Свой
Сообщений: 160
Регистрация: 23-12-04
Из: Уфа
Пользователь №: 1 631

|
Надо бы, наверное, весь макрос поместить внутрь блока, чтобы вставлялся как один оператор, иначе, если применить его после if, будут неприятности. Код do { Текст макроса. } while(0)
|
|
|
|
|
Apr 10 2014, 02:24
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(Shamil @ Apr 10 2014, 04:18)  Надо бы, наверное, весь макрос поместить внутрь блока, чтобы вставлялся как один оператор, иначе, если применить его после if, будут неприятности. Код do { Текст макроса. } while(0) Помню-помню... разговоры. Но я не вставляю после if. P.S. у меня же все ветки в скобках { }, может, их хватит? Другой вопрос всплыл - Как можно определить, с какими параметрами оптимизации задана копмиляция? Что можно было в одном случае в формулу подсунуть 5, а в другом 6.
|
|
|
|
|
Apr 10 2014, 03:15
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(ViKo @ Apr 10 2014, 07:01)  Не с той стороны подходите к решению задачи. Чтобы не было зависимости от уровня оптимизации напишите асмовую вставку. В моём примере она имеется в каком-то виде. И будет вам счастье  Цитата(Shamil @ Apr 10 2014, 05:18)  Надо бы, наверное, весь макрос поместить внутрь блока, чтобы вставлялся как один оператор +1
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Apr 10 2014, 03:24
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(ViKo @ Apr 10 2014, 05:01)  Кейловский, ARMCC из uVision. Я пас. Цитата(demiurg_spb @ Apr 10 2014, 05:15)  Чтобы не было зависимости от уровня оптимизации напишите асмовую вставку. Угу. Вместо последнего цикла. А потом вспомнить про прерывания и забить на эту погрешность.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Apr 10 2014, 06:51
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата Чтобы не было зависимости от уровня оптимизации напишите асмовую вставку. Взялся было... Но мне нужно загрузить переменную цикла в регистр. Где гарантия, это это регистр ничем не занят?  Цитата(Сергей Борщ @ Apr 10 2014, 06:24)  Угу. Вместо последнего цикла. А потом вспомнить про прерывания и забить на эту погрешность. Да, прерывания меня уже смутили, при проверке на больших длительностях. Но эта функция написана для коротких интервалов. Конкретно, для работы с двухстрочным ЖКИ. А для "серьезных" задержек у меня есть макро с таймером. И др. Что-то "не лезет" asm, не принимает его компилятор! В чем дело? Код #define DELAY_CY(CY) \ if (CY >= 10) \ { __asm {"MOVS R1,#CY; LOOP: SUBS R1,R1,#1; BEQ LOOP;"} } (407): error: #2901: Expected an inline assembly instruction (407): error: #3081: expected end of line or a ";" Никак. Из ARM документа: The inline assembler supports ARM assembly language only. The embedded assembler can be used for Thumb and Thumb-2 support. Отдельно писать? Код void DelAsm(uint32_t CY) { uint32_t Reg; __asm { MOVS Reg, #CY LOOP: SUBS Reg, Reg, #1 BEQ LOOP } }
|
|
|
|
|
Apr 10 2014, 07:07
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(ViKo @ Apr 10 2014, 08:51)  Взялся было... Но мне нужно загрузить переменную цикла в регистр. Где гарантия, это это регистр ничем не занят?  "Нормальный" инлайн-асм дает вам возможность сообщить компилятору, что вы испортили регистр. Или попросить компилятор выделить вам свободный в данный момент регистр. Цитата(ViKo @ Apr 10 2014, 08:51)  Но эта функция написана для коротких интервалов. Конкретно, для работы с двухстрочным ЖКИ. Для ЖКИ паузы могут быть и длинее. Поставьте наибольшее значение, 6 циклов и забудьте. Разницу глазом заметить не успеете. Цитата(ViKo @ Apr 10 2014, 08:51)  Что-то "не лезет" asm, не принимает его компилятор! В чем дело? Может ему кавычки не нравятся? Цитата(ViKo @ Apr 10 2014, 08:51)  Из ARM документа: ... uint32_t Reg; Вот - очень наглядно показано как попросить у компилятора регистр.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Apr 10 2014, 09:07
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(ViKo @ Apr 10 2014, 10:51)  Из ARM документа: The inline assembler supports ARM assembly language only. The embedded assembler can be used for Thumb and Thumb-2 support. Отдельно писать? Для CM3 используется Thumb-2. Поэтому нет никакой возможности писать инлайн вставки. Зато можно целиком процедуру: Код static __inline __asm uint32_t get_interrupt_state(void) { mrs r0, primask bx lr } Цитата(ViKo @ Apr 10 2014, 10:51)  Взялся было... Но мне нужно загрузить переменную цикла в регистр. Где гарантия, это это регистр ничем не занят?  http://infocenter.arm.com/help/topic/com.a...0042E_aapcs.pdf пункт 5.1.1
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Apr 10 2014, 09:14
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
В-общем, не помогло. Код __inline void DelAsm(uint32_t CY) { __asm { LOOP: SUBS CY, CY, #1 BNE LOOP } } Превращается при оптимизации -O0 в Код 0000f0 2005 MOVS r0,#5 0000f2 bf00 NOP 0000f4 bf00 NOP |L1.246| 0000f6 1e40 SUBS r0,r0,#1 0000f8 d000 BEQ |L1.252| 0000fa e7fc B |L1.246| |L1.252| 0000fc bf00 NOP Компилятор чудит. И зачем? P.S. Во всех остальных случаях компилируется, как надо. Код 0000ca 2005 MOVS r0,#5 |L1.204| 0000cc 1e40 SUBS r0,r0,#1 0000ce d1fd BNE |L1.204| Цитата(demiurg_spb @ Apr 10 2014, 12:07)  пункт 5.1.1 Вот отсюда ссылки нужные http://www.keil.com/support/docs/3369.htm
|
|
|
|
|
Apr 10 2014, 09:16
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
А вот такая ситуация: Пишу под Keil макрос OUTPIN_PP(port,nbit) который должен в случае , если nbit<8 выполнить Код do { GPIO##port->CRL&=~(GPIO_CRL_CNF##nbit); GPIO##port->CRL|=GPIO_CRL_MODE##nbit; } while (0); а если иначе , то Код do { GPIO##port->CRH&=~(GPIO_CRH_CNF##nbit); GPIO##port->CRH|=GPIO_CRH_MODE##nbit; } while (0) В идеальном варианте на этапе компиляции какимто образом выполнить проверку условия и вставить нужные операторы. Вариант с Код #if nbit<8 OUTPIN_PP(port,nbit) do { GPIO##port->CRL&=~(GPIO_CRL_CNF##nbit); GPIO##port->CRL|=GPIO_CRL_MODE##nbit; } while (0); #endif не прокатывает А с использованием программного вывода: Код #define _OUTPIN_PP(port,nbit) if ((nbit)<8) {do { GPIO##port->CRL&=~(GPIO_CRL_CNF##nbit); GPIO##port->CRL|=GPIO_CRL_MODE##nbit; } while (0); }\ else do { GPIO##port->CRH&=~(GPIO_CRH_CNF##nbit); GPIO##port->CRH|=GPIO_CRH_MODE##nbit; } while (0) выдает ошибку отсутствия предопределенного макроса. Вариант с определением базового адреса и последующим вычислением адреса регистра известен Код #define PORTA ((u32*)(APB2PERIPH_BASE + 0x0800)) #define PORTB ((u32*)(APB2PERIPH_BASE + 0x0C00)) #define PORTC ((u32*)(APB2PERIPH_BASE + 0x1000)) #define PORTD ((u32*)(APB2PERIPH_BASE + 0x1400)) #define PORTE ((u32*)(APB2PERIPH_BASE + 0x1800)) #define PORTF ((u32*)(APB2PERIPH_BASE + 0x1C00)) #define PORTG ((u32*)(APB2PERIPH_BASE + 0x2000)) #define pinOutPP_b(port,bit) {*(port+((bit)/8))|=3UL<<(((bit)-(8*((bit)/8)))<<2); *(port+((bit)/8))&=~(3UL<<((((bit)-(8*((bit)/8)))<<2)+2));} , хочу делать по другому .. собственно вопрос как
|
|
|
|
|
Apr 10 2014, 09:41
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(ViKo @ Apr 10 2014, 13:14)  Вот отсюда ссылки нужные При чём тут нужные или нет? Я вам ответил на вопрос о том какие регистры и как можно использовать, дав ссылку на первоисточник: AAPCS. Зная, что кейл соответствует AAPCS. Вот так никаких вариантов для компилятора изменить что-то при изменении уровня оптимизации нет. Код static __inline __asm void delay_8cycles(uint32_t x) { loop_delay_8cycles: nop nop nop nop subs r0,r0,#1 bne loop_delay_8cycles bx lr } Совет: придумывайте более сложные имена меткам, т.к. могут быть совпадения в одной единице трансляции и вылезет ошибка. Незамеченной она конечно не останется, но зачем заранее закладывать мину? Цитата(MaxiMuz @ Apr 10 2014, 13:16)  А вот такая ситуация: Очень неприлично влезать в чужой топик с вопросом совсем не по теме... Хотите спросить - создайте тему со своим вопросом, или поищите по форуму. Ваш вопрос неоднократно обсуждался...
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Apr 10 2014, 10:08
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(demiurg_spb @ Apr 10 2014, 12:41)  Вот так никаких вариантов для компилятора изменить что-то при изменении уровня оптимизации нет. Вызываю функцию напрямую. Код DelAsm(6);
__forceinline void DelAsm(uint32_t CY) { __asm { LOOP: SUBS CY, CY, #1 BNE LOOP } } Получаю при -O0. Код 0000f2 2006 MOVS r0,#6 0000f4 bf00 NOP 0000f6 bf00 NOP |L1.248| 0000f8 1e40 SUBS r0,r0,#1 0000fa d000 BEQ |L1.254| 0000fc e7fc B |L1.248| |L1.254| 0000fe bf00 NOP А при -O1 Код 0000cc 2006 MOVS r0,#6 |L1.206| 0000ce 1e40 SUBS r0,r0,#1 0000d0 d1fd BNE |L1.206|
|
|
|
|
|
Apr 10 2014, 10:13
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(ViKo @ Apr 10 2014, 13:49)  Не о том был вопрос. Как не о том: Цитата Но мне нужно загрузить переменную цикла в регистр. Где гарантия, это это регистр ничем не занят? Именно на этот вопрос и отвечает AAPCS, а не что-то другое. Ну да ладно. Главное результат... Цитата(ViKo @ Apr 10 2014, 14:08)  Вызываю функцию напрямую. Вы мой пример попробуйте (из сообщения 22) - поймёте в чём разница. Кстати, o0 - это совсем плохой вариант, не нужный НИКОГДА на моей практике. Если вы увлекались ранее avr-gcc то могли бы увидеть такое в файле задержек delay.h: Код #ifndef __OPTIMIZE__ # warning "Compiler optimizations disabled; functions from <util/delay.h> won't work as designed" #endif А для вас возможным выходом из ситуации могло бы стать это решение: http://www.keil.com/support/man/docs/ARMCC...EF_BCFJFGAA.htmили это http://www.keil.com/support/man/docs/ca/ca_optimize.htm
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Apr 10 2014, 10:54
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(demiurg_spb @ Apr 10 2014, 13:13)  Вы мой пример попробуйте - поймёте в чём разница. Если в nop-ах - верю на слово. Цитата Кстати, o0 - это совсем плохой вариант, не нужный НИКОГДА на моей практике. Я тоже не пользуюсь. Здесь вопрос, скорее, теоретический. Компилятор будто назло пихает ненужные команды. Для тех, кто не хочет платить? Цитата Первое попробовал - работает! А эта прагма только на одну функцию будет действовать, или до конца файла?  Вторая ссылка - для старого компилятора. И зачем их только там держат. Ага, есть: #pragma push #pragma O3 function #pragma pop
|
|
|
|
|
Apr 10 2014, 11:52
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(ViKo @ Apr 10 2014, 14:54)  Если в nop-ах - верю на слово. Нет не в них, а в том что у меня __asm задан для всей функции, а у вас для вставки. Цитата Ага, есть: #pragma push #pragma O3 function #pragma pop Отлично! Для изменения "упакованности" обходился двумя строчками прагмы: Код #pragma pack(push, 1) // set 1 and save prev ... #pragma pack(pop) // restore prev Не знаю можно ли это и тут применить...
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Apr 13 2014, 19:24
|

Местный
  
Группа: Участник
Сообщений: 318
Регистрация: 21-07-06
Из: Минск
Пользователь №: 18 986

|
Цитата(ViKo @ Apr 10 2014, 09:51)  Конкретно, для работы с двухстрочным ЖКИ. А я для таких целей использую функции микросекундных задержек, которая пользуется таймером SysTick, не мешая ему выполнять свою основную функцию - генерирование системного интервала 1 мс: Код void TSysTimer::Delay_us(uint16_t d) { uint32_t DelayStart = SysTick->VAL; uint32_t DelayTicks = d * CLK_PER_US; int32_t Delta; do { Delta = DelayStart - SysTick->VAL; if(Delta < 0) Delta += CLK_PER_MS; } while(Delta < DelayTicks); }
--------------------
|
|
|
|
|
Apr 14 2014, 05:52
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(toweroff @ Apr 14 2014, 08:27)  ок, можно отдать SysTick генерить все управляющие сигналы по стэйт-машине некой, а из него уже отсылать программный сигнал (или просто флаг) ждущей задаче я так понимаю, этот таймер все равно по микросекундам генерится? У меня задержка считается в ns. С точностью до такта микроконтроллера. SysTick Timer считает такты (или поделенные на 8) до 1-10 ms для RTOS (и у меня тоже есть), потом перезагружается. Поэтому более длинные интервалы не получить. Можно большие задержки считать одним способом, а малые другим. А можно все одним.  Цитата(Сергей Борщ @ Apr 14 2014, 08:45)  Да дайте вы удвоенную от максимальной задержку и забудьте о чтении. Оператор не заметит лишние 10 мс на перерисовку всего экрана, а программа упростится раза в три. Так уж в три...?  Задержка занимает у меня от 3 до 6 ассемблерных команд. Куда уж проще? И выполняется именно столько времени, сколько мне нужно. Там же все обращения к контроллеру ЖКИ идут ногодрыгом, без задержек - никак не обойтись. А для выполнения ЖКИ команд нужны задержки побольше. Зачем мне терять время, если не проверять, когда они закончатся, а тупо ждать больше срока?
|
|
|
|
|
Apr 14 2014, 06:15
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(ViKo @ Apr 14 2014, 08:52)  Так уж в три...?  Задержка занимает у меня от 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); } Цитата(ViKo @ Apr 14 2014, 08:52)  а тупо ждать больше срока? А вы и так "тупо ждете больше срока" потому что в вашу задержку вклиниваются прерывания. Вывод на дисплей происходит так редко, что будет там задержка 50мкс или 20мкс на байт не заметит никто. Ну пусть у вас дисплей 4*40, пусть обновляете его целиком 4 раза в секунду (быстрее он не успеет отобразить, а оператор воспринять), ну потеряете вы лишних (50-20)*40*4*4=19200 мкс. Ах, 19мс каждую секунду ушло впустую, катастрофа. Зато сэкономлена неделя рабочего времени, за которую эти 19мс можно с большей пользой отыграть где-то в другом месте.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Apr 14 2014, 15:54
|

Гуру
     
Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514

|
Цитата(ViKo @ Apr 14 2014, 19:35)  Нюанс всплыл - невозможно заинлайнить функцию (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 не панацея, конечно, но позволит уйти от асма, тем более что точная задержка как таковая не критична прям уж так а с большими задержками - там и подождать сигнала от таймера не проблема, тем более, что это наверняка в отдельной задаче вертится
|
|
|
|
|
Apr 15 2014, 06:18
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(ViKo @ Apr 14 2014, 19:35)  Нюанс всплыл - невозможно заинлайнить функцию (DelayCY4), находящуюся в другом файле. Пришлось в один объединить. Это не нюанс, это стандартное поведение. Для решения подобных задач нужно всё в заголовочном файле размещать: Код static __inline void delay(int x) { .... } Цитата(toweroff @ Apr 14 2014, 19:54)  не панацея, конечно, но позволит уйти от асма, тем более что точная задержка как таковая не критична прям уж так Не системный подход с кучей сорного кода, заслоняющего основную идею. Здесь асм не столько для точности, а больше для снятия зависимости от уровня оптимизации. Тут у меня самого возник вопрос, касательно задержек в 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
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Apr 15 2014, 06:59
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(demiurg_spb @ Apr 15 2014, 09:18)  Прошу помощи у аудитории! cnt у вас меняется в асм-вставке, а компилятору вы об этом не сообщаете. Попробуйте так, если в синтаксисе не ошибся: Код __asm__ __volatile__ \ ( \ "loop%=: subs %[cnt],#1" "\n\t" \ " bne loop%=" "\n\t" \ : =[cnt]"r"(__x) \ : \ : "cc" \ ); \
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Apr 15 2014, 07:15
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(Сергей Борщ @ Apr 15 2014, 10:59)  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 даёт такой же результат).
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Apr 15 2014, 07:21
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(demiurg_spb @ Apr 15 2014, 10:15)  Согласно доке и не должен я об этом ничего сообщать. Здрасьте. А как же он узнает, что вы его испортили и его надо перегрузить? Цитата(demiurg_spb @ Apr 15 2014, 10:15)  Вы предлагаете использовать cnt как выходной write only регистр: Нет, вы пропустили "=" перед [cnt]. Я его делаю и input и output, коим он фактически и является. Сейчас. сверюсь со своими исходниками. Я допускал эту же ошибку, сейчас найду. В первый раз не туда смотрел, извиняюсь. Код : [cnt]"+r"(__x) \
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Apr 15 2014, 07:31
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(Сергей Борщ @ Apr 15 2014, 11:21)  Нет, вы пропустили "=" перед [cnt]. Я его делаю и input и output, коим он фактически и является.
"=" перед [cnt] не даёт ставить - ошибка компиляции. "=" перед r не то же самое? Цитата(Сергей Борщ @ Apr 15 2014, 11:21)  О! Оно! Код 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 Спасибо большое!!!
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|