Сергей Борщ 134 10 апреля, 2014 Опубликовано 10 апреля, 2014 · Жалоба Взялся было... Но мне нужно загрузить переменную цикла в регистр. Где гарантия, это это регистр ничем не занят? :laughing:"Нормальный" инлайн-асм дает вам возможность сообщить компилятору, что вы испортили регистр. Или попросить компилятор выделить вам свободный в данный момент регистр. Но эта функция написана для коротких интервалов. Конкретно, для работы с двухстрочным ЖКИ.Для ЖКИ паузы могут быть и длинее. Поставьте наибольшее значение, 6 циклов и забудьте. Разницу глазом заметить не успеете. Что-то "не лезет" asm, не принимает его компилятор! В чем дело?Может ему кавычки не нравятся? Из ARM документа: ... uint32_t Reg; Вот - очень наглядно показано как попросить у компилятора регистр. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 10 апреля, 2014 Опубликовано 10 апреля, 2014 · Жалоба Вот - очень наглядно показано как попросить у компилятора регистр. Это я сам... попросил. :rolleyes: В-общем, путь есть... пойду. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 10 апреля, 2014 Опубликовано 10 апреля, 2014 · Жалоба Из 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 } Взялся было... Но мне нужно загрузить переменную цикла в регистр. Где гарантия, это это регистр ничем не занят? :laughing: http://infocenter.arm.com/help/topic/com.a...0042E_aapcs.pdf пункт 5.1.1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 10 апреля, 2014 Опубликовано 10 апреля, 2014 · Жалоба В-общем, не помогло. __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| пункт 5.1.1 Вот отсюда ссылки нужные http://www.keil.com/support/docs/3369.htm Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MaxiMuz 0 10 апреля, 2014 Опубликовано 10 апреля, 2014 · Жалоба А вот такая ситуация: Пишу под 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));} , хочу делать по другому .. собственно вопрос как Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 10 апреля, 2014 Опубликовано 10 апреля, 2014 · Жалоба #define pinOutPP_b(port,bit) {*(port+((bit)/8))|=3UL<<(((bit)-(8*((bit)/8)))<<2); *(port+((bit)/8))&=~(3UL<<((((bit)-(8*((bit)/8)))<<2)+2));}[/code], хочу делать по другому .. собственно вопрос как /*!**************************************************************************** @brief Bit of Low/High byte Port configuration @details Конфигурация одиночного бита порта @param PORT - имя порта (A..G) @param BIT - номер бита (0..15) @param CM - конфигурация бита @note Используется перечисляемый тип CONF_MODE @note Для IN_PDPU нужный pull-down/pull-up задается в ODR */ #define GPIO_CONFB(PORT, BIT, CM) \ *(uint32_t *)((uint32_t)(GPIO##PORT) + BIT / 8 * 4) = \ *(uint32_t *)((uint32_t)(GPIO##PORT) + BIT / 8 * 4) \ & (~(0xF << (BIT % 8) * 4)) | (CM << (BIT % 8) * 4) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 10 апреля, 2014 Опубликовано 10 апреля, 2014 · Жалоба Вот отсюда ссылки нужныеПри чём тут нужные или нет? Я вам ответил на вопрос о том какие регистры и как можно использовать, дав ссылку на первоисточник: 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 } Совет: придумывайте более сложные имена меткам, т.к. могут быть совпадения в одной единице трансляции и вылезет ошибка. Незамеченной она конечно не останется, но зачем заранее закладывать мину? А вот такая ситуация:Очень неприлично влезать в чужой топик с вопросом совсем не по теме... Хотите спросить - создайте тему со своим вопросом, или поищите по форуму. Ваш вопрос неоднократно обсуждался... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 10 апреля, 2014 Опубликовано 10 апреля, 2014 · Жалоба При чём тут нужные или нет? Я вам ответил на вопрос о том какие регистры и как можно использовать, дав ссылку на первоисточник: AAPCS. Не о том был вопрос. http://infocenter.arm.com/help/topic/com.a...9124245889.html http://infocenter.arm.com/help/topic/com.a..._user_guide.pdf 7.14 Inline assembler and register access in C and C++ code Насчет меток - пока не нашел, думаю, компилятор сам их различает в разных функциях. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 10 апреля, 2014 Опубликовано 10 апреля, 2014 · Жалоба Насчет меток - пока не нашел, думаю, компилятор сам их различает в разных функциях.Ну думайте... Я вам говорю о том, с чем лично УЖЕ сталкивался (не на самой последней версии компилятора). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 10 апреля, 2014 Опубликовано 10 апреля, 2014 · Жалоба Вот так никаких вариантов для компилятора изменить что-то при изменении уровня оптимизации нет. Вызываю функцию напрямую. 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| Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 10 апреля, 2014 Опубликовано 10 апреля, 2014 · Жалоба Не о том был вопрос.Как не о том: Но мне нужно загрузить переменную цикла в регистр. Где гарантия, это это регистр ничем не занят?Именно на этот вопрос и отвечает AAPCS, а не что-то другое. Ну да ладно. Главное результат... Вызываю функцию напрямую.Вы мой пример попробуйте (из сообщения 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 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 10 апреля, 2014 Опубликовано 10 апреля, 2014 · Жалоба Вы мой пример попробуйте - поймёте в чём разница. Если в nop-ах - верю на слово. Кстати, o0 - это совсем плохой вариант, не нужный НИКОГДА на моей практике. Я тоже не пользуюсь. Здесь вопрос, скорее, теоретический. Компилятор будто назло пихает ненужные команды. Для тех, кто не хочет платить? :rolleyes: А для вас возможным выходом из ситуации могло бы стать это решение: http://www.keil.com/support/man/docs/ARMCC...EF_BCFJFGAA.htm или это http://www.keil.com/support/man/docs/ca/ca_optimize.htm Первое попробовал - работает! А эта прагма только на одну функцию будет действовать, или до конца файла? Вторая ссылка - для старого компилятора. И зачем их только там держат. Ага, есть: #pragma push #pragma O3 function #pragma pop Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 10 апреля, 2014 Опубликовано 10 апреля, 2014 · Жалоба Если в nop-ах - верю на слово.Нет не в них, а в том что у меня __asm задан для всей функции, а у вас для вставки. Ага, есть: #pragma push #pragma O3 function #pragma pop Отлично! Для изменения "упакованности" обходился двумя строчками прагмы: #pragma pack(push, 1) // set 1 and save prev ... #pragma pack(pop) // restore prev Не знаю можно ли это и тут применить... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 10 апреля, 2014 Опубликовано 10 апреля, 2014 · Жалоба Сотворил.v2 /*!**************************************************************************** @brief Delay program loop @param NS - время задержки в ns @note Параметр округляется до ближайшего не меньшего, кратного тактам @note 4 такта в цикле при любой оптимизации (принудительно -O3) @note Формула: D = 4 * CY4 - 1 + Nnop */ #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 == 1) { __NOP(); } \ else if (CY == 2) { __NOP(); __NOP(); } \ else if (CY == 3) { __NOP(); __NOP(); __NOP(); } \ else { \ if ((CY + 1) % 4 == 1) { __NOP(); } \ if ((CY + 1) % 4 == 2) { __NOP(); __NOP(); } \ if ((CY + 1) % 4 == 3) { __NOP(); __NOP(); __NOP(); } \ DelayCY4((CY + 1) / 4); } \ /*!**************************************************************************** @brief Delay 4 clocks in cycle @param CY4 - количество 4-тактовых циклов @note Delay = 4 * CY4 - 1 */ #pragma push #pragma O3 __forceinline void DelayCY4(uint32_t CY4) { __asm { LOOP: SUBS CY4, CY4, #1 BNE LOOP } } #pragma pop Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Леонид Иванович 0 13 апреля, 2014 Опубликовано 13 апреля, 2014 · Жалоба Конкретно, для работы с двухстрочным ЖКИ. А я для таких целей использую функции микросекундных задержек, которая пользуется таймером 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); } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться