KnightIgor 2 3 июня, 2021 Опубликовано 3 июня, 2021 (изменено) · Жалоба Привет, коллеги. Немного предыстории. С CMx начал работать еще с самого начала их появления (конец нулевых). Когда не было еще всяких HAL, а CMSIS в зародыше, написал свою HAL, которой пользуюсь до сих пор, причем и для CM3, и для CM0. До поры работал под KEIL, теперь частично и в STMCubeIDE, то есть gcc. В моем HAL есть код типа FIFO, работающий с UART. Это была и есть оcнова основ: всякие терминалы, DMX, поддержка других протоколов. Короче, коду сто лет в обед, проверен многократно на STM32 CM3/CM0, EnergyMicro/Silabs EFM32, ATMEL SAM3D. Я в код уже и не заглядываю. И вот нонче, завершив более-менее проект под SMTCubeIDE, где моя HAL используется как странслированная в библиотеку *.a, я собрал его release, при этом подключил HAL.a тоже release, оптимизация -O2. И тут начались непонятки: протокол по UART не работает толком. printf() вообще ведет себя странно: спорадически(!) происходит как бы добавление символов. Например, вместо "V1.0" выводится "V.1.0", вместо, скажем, FPxA - FxPxA, то есть какой-нибудь символ "копируется" на две позиции вперед. Если подключить к проекту release мою HAL.a debug (-O0), то непонятки уходят. Интересно, что HAL.lib под KEIL, тоже с -O2, работает в проектах под KEIL одинаково хорошо с HAL.lib -O0. То есть, проблема только под STMCubeIDE gcc и -O2. Есть у кого идеи/опыт? Ага, STMCubeIDE 1.6.1. Изменено 3 июня, 2021 пользователем KnightIgor Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 69 3 июня, 2021 Опубликовано 3 июня, 2021 · Жалоба 1 hour ago, KnightIgor said: Я в код уже и не заглядываю С высокой вероятностью проблема в нем - симптомы-то указывают на некорректную работу FIFO. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 61 4 июня, 2021 Опубликовано 4 июня, 2021 · Жалоба 5 hours ago, KnightIgor said: Есть у кого идеи/опыт? Ага, STMCubeIDE 1.6.1. Недавно понял, что мой кольцевой буфер, написанный тоже в конце нулевых, не совсем хорошо работает на кортексах. А всё дело во вложенных прерываниях. Ведь я раньше работал с AVR/PIC, где такого не было. Вот и для армов написал буфер, где при работе из прерывания считал, что операция 100%-атомарна. Ведь другое-то прерывание не возникнет. Так эта ошибка и тянулась с десяток лет, будучи замаскированной. Пока недавно не выплыла) Может быть у вас что-то подобное? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 190 4 июня, 2021 Опубликовано 4 июня, 2021 · Жалоба Думаю, нужно показывать исходники буфера... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KnightIgor 2 4 июня, 2021 Опубликовано 4 июня, 2021 · Жалоба 9 hours ago, aaarrr said: С высокой вероятностью проблема в нем - симптомы-то указывают на некорректную работу FIFO. Это явно так, но как оптимизация может порушить код, который до этого работал годы?! Как я указывал, оптимизация под KEIL не портила результат, горя не знал, только под gcc сейчас. Я даже не представляю, где копать. @haker_fox: я изначально писал под CM3, предпринял соответствующие меры для атомарности (даже описывал здесь на формуме в обсуждении подобной темы, как, но очень давно). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 61 4 июня, 2021 Опубликовано 4 июня, 2021 · Жалоба 32 minutes ago, KnightIgor said: Это явно так, но как оптимизация может порушить код, который до этого работал годы?! Поскольку оптимизация не нарушает логику исходно работающего текста, проблема может лежать чуть глубже. Например в особенностях работы какой-либо периферии для которой один компилятор генерировал одну последовательность команд, а другой - другую. Именились времена выполнения и, баг! Ура) Не знаю, что посоветовать. Если есть вомзожность лучше поглядеть листинг на предмет очевидных ляпов компилятора. Но листинги обычно большие. Поэтому добавьте отладку, выводите куда-нибудь переменные буфера: хвост, голову, сам буфер. В общем, трудно что-либо посоветовать конкретное. Ведь и проблема описана очень размыто. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Ruslan1 17 4 июня, 2021 Опубликовано 4 июня, 2021 · Жалоба 11 hours ago, KnightIgor said: Короче, коду сто лет в обед, проверен многократно на STM32 CM3/CM0, EnergyMicro/Silabs EFM32, ATMEL SAM3D. Я в код уже и не заглядываю. ..... Есть у кого идеи/опыт? Ага, STMCubeIDE 1.6.1. Опыт есть такой: даже в старом и проверенном коде случаются ошибки. А что работало до сих пор- так просто звезды так сходились, а теперь вот по-другому сошлись. У меня бывало, что при переходе на другой уровень оптимизации или на другой компилятор код переставал работать- это явно косяк исходников. Еще версия- что-то изменилось в реализации камня, а Ваши исходники по-старинке это обрабатывают, и это "по старинке" уже не прокатывает. Кстати, про зайцев FIFO- это неактуально, DMA гораздо круче. В STM довольно гибкое конфигурирование DMA, можно многое туда переложить и не отвлекаться "по мелочам" на каждый байтик. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 243 4 июня, 2021 Опубликовано 4 июня, 2021 · Жалоба 1 час назад, KnightIgor сказал: Это явно так, но как оптимизация может порушить код, который до этого работал годы?! А как годы не проявлялся баг, найденный мной недавно в IAR? (https://electronix.ru/forum/index.php?app=forums&module=forums&controller=topic&id=159438) Тоже работало годы. И не у одного человека (как в Вашем случае), а у множества пользователей IAR во множестве разного кода. И не проявлялось. Или проявлялось, но причина не понималась. Так же и у Вас - не проявлялось или проявлялось, но списывалось на другие причины. PS: Вы должны быть рады, что баг проявился и его наконец-то можно найти и исправить. Гораздо хуже, когда девайс изредка глючит по непонятной причине.... Потому и советуют: тестить код на всех возможных уровнях оптимизации. А если глючит хоть на каком-то уровне - искать баги. Не бывает безглючного кода. Бывает только код с ещё ненайденными багами. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AVI-crak 0 4 июня, 2021 Опубликовано 4 июня, 2021 · Жалоба 11 hours ago, KnightIgor said: Я в код уже и не заглядываю. Моя история - ошибка с временем жизни в пять лет. За это время главный наладчик успел заработать цирроз печени, а сколько народу на линии сменилось уже не сосчитать... Всё дело в одной пропущенной букве: константа должна быть одинарной точности, а GCC её принудительно делал двойной точности. В очень редких случаях этот код начинал выполнятся, и работал чуть дольше чем с одинарной точностью. В результате лента конвейера успевала продвинуться на пару миллиметров, отчего лапы захвата тары звонко долбились об пластик. Это было громко, намного громче фонового шума всего цеха. Отчего вокруг ленты возникал кипишь, плавно переходящий в панику. Пропущенная буква - "f". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KnightIgor 2 4 июня, 2021 Опубликовано 4 июня, 2021 · Жалоба 3 minutes ago, AVI-crak said: Моя история - ошибка с временем жизни в пять лет. За это время главный наладчик успел заработать цирроз печени, а сколько народу на линии сменилось уже не сосчитать... Всё дело в одной пропущенной букве: константа должна быть одинарной точности, а GCC её принудительно делал двойной точности. В очень редких случаях этот код начинал выполнятся, и работал чуть дольше чем с одинарной точностью. В результате лента конвейера успевала продвинуться на пару миллиметров, отчего лапы захвата тары звонко долбились об пластик. Это было громко, намного громче фонового шума всего цеха. Отчего вокруг ленты возникал кипишь, плавно переходящий в панику. Пропущенная буква - "f". За ответ, даже если он не помогает мне конкретно, просто 5+, особенно за цирроз печени!!! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vlad_new 1 4 июня, 2021 Опубликовано 4 июня, 2021 (изменено) · Жалоба Ищите где Вы забыли volatile объявить глобальные переменные. Именно при включении оптимизации оно и выстреливает. Изменено 4 июня, 2021 пользователем vlad_new Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KnightIgor 2 4 июня, 2021 Опубликовано 4 июня, 2021 (изменено) · Жалоба 53 minutes ago, vlad_new said: Ищите где Вы забыли volatile объявить глобальные переменные. Именно при включении оптимизации оно и выстреливает. Это интересная мысль. В моем (проблемном) коде нет таких переменных, хотя есть буферы, объявленые как static, то есть, доступные локально или по ссылке глобально. Кстати, тема кэширования и многопоточности. Об этом много писалось, что при выходе из прерываний в cortex следует подумать о __DSB(), иначе можно влететь в то же прерывание после выхода из него. Выключенная оптимизация добавляет в код достаточно большую преамбулу и хвост: в gcc это какое-то жонглирование с R3. Оптимизация сокращает эти операции, что ускоряет выход из прерывания, но добавление __DSB() (а также __ISB() и __DMB() и всяких __NOP()) таки не решило мою проблему. Изменено 4 июня, 2021 пользователем KnightIgor Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 190 4 июня, 2021 Опубликовано 4 июня, 2021 · Жалоба Сами буферы объявлять с volatile вовсе не обязательно. Ну а индексы головы и хвоста - вполне. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 69 4 июня, 2021 Опубликовано 4 июня, 2021 · Жалоба 28 minutes ago, KnightIgor said: В моем (проблемном) коде нет таких переменных Может, все-таки показать код? А то тема ни о чем выходит. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KnightIgor 2 4 июня, 2021 Опубликовано 4 июня, 2021 · Жалоба 18 минут назад, aaarrr сказал: Может, все-таки показать код? А то тема ни о чем выходит. Уфф, если хотите повозиться, нет проблем: Скрытый текст /*---------------------------------------------------------------------------- * Name: stm32f10x_io.c (former "serial.c") * Purpose: STDIO over USART implementation * * Version: V1.00, tested on STM32F103RB and -RC *---------------------------------------------------------------------------- * History: * V1.00 Initial Version *----------------------------------------------------------------------------*/ // #include "stm32f10x_proc.h" // #include "stm32f10x_io.h" // include AFTER stm32f10x_proc.h to get project.h #include <HAL_Dispatch.h> // HAL Dispatcher #include <misc.h> #ifdef USB_CDC // defined in "board.h" // USB Virtual COM support #ifndef RL_USB // to define in the PROJECT OPTIONS #include "hw_config.h" #else static uint8_t PendingTX = 0; extern uint8_t USART_To_USB_Send_Data(char c); extern uint8_t USART_To_USB_Ready(void); #endif #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // // Control USART_IT_RXNE bit // static void RXIE(uint8_t enable) { if (enable) USART_RXIE_SET (STDIO_DEVICE); else USART_RXIE_CLEAR(STDIO_DEVICE); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // // Control USART_IT_TXE bit // static void TXIE(uint8_t enable) { if (enable) USART_TXIE_SET (STDIO_DEVICE); else USART_TXIE_CLEAR(STDIO_DEVICE); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // // Reading RXNE bit // static uint8_t RX_Ready(void) { return !!USART_RI_SR(STDIO_DEVICE); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // // Reading TXE bit // static uint8_t TX_Ready(void) { #ifdef USB_CDC // defined in project.h // STDIO -> USB if (!USART_To_USB_Ready()) { PendingTX = 1; TXIE (!PendingTX); // disable TX interrupt to suspend return !PendingTX; // return as if not ready } #endif return !!USART_TI_SR(STDIO_DEVICE); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // // Reading TC bit // static uint8_t TX_Complete(void) { return !!USART_TC_SR(STDIO_DEVICE); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // // Writing DR // static void Write_TX(uint16_t value) { #ifdef USB_CDC // defined in project.h // STDIO -> USB // (char) conversion is very important! USART_To_USB_Send_Data((unsigned char)value); #endif USART_PUT_DR(STDIO_DEVICE, value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // // Reading DR // static int32_t Read_RX(void) { // The read sequence below is necessary to clear the flags, see RM. uint16_t st = READ_BIT(STDIO_DEVICE->SR, USART_RX_FLAGS); int32_t dr = USART_GET_DR(STDIO_DEVICE); if (st) // any RX related flag { if (READ_BIT(st, USART_FLAG_FE) && dr == 0) // BREAK - prepare for DMX { stdioBreakDetected(stdioFIFO()); } } return dr; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // // Driver record and buffer definitions // DEFINE_USART_BUFFERS(FIFO, STDIO_BufferSize, STDIO_BufferSize); // ----------------------------------------------------------------------------- // // Implementation for declared in HAL_UART.h // Returns the pointer to the internal stdio FIFO structure // bufio_FIFO *stdioFIFO(void) {return &FIFO;} // ----------------------------------------------------------------------------- // // Implementation for declared in HAL_UART.h // // USB CDC support, USB CDC clone of STDIO: // The function called every time, the USB subsystem accepted // the STDIO cloned char. // // Should always return TRUE to be used in some conditional expressions! // __attribute__((weak)) uint8_t stdioCharRequest(void) { #ifdef USB_CDC // defined in project.h // STDIO -> USB if (PendingTX) { PendingTX = 0; TXIE(!PendingTX); // reenable the TX interrupt } #endif return true; } #ifdef USB_CDC // ----------------------------------------------------------------------------- // // STRONG for HAL_UART.c // // 'wait before send' routine for the case, the output buffer found // to be full and the char cannot be sent immediately. // // The weak implementation waits 100ms by DWT. For USB COM implementation // WAIT_WHILE(condition, ms_timeout) is recommended. // // Returns the char sent. // int stdioWaitBeforeSend(int c) { // WAIT_TIME(bufio_WriteChar(stdioFIFO(), c) < 0, 100); WAIT_WHILE(bufio_WriteChar(stdioFIFO(), c) < 0, 100); return c; } #endif /******************************************************************************/ // // USART IRQ Handler // /******************************************************************************/ void STDIO_IRQHandler(void) { STDIO_DEVICE->SR; // unbelievable but reading SR before bufio_IRQHandler(&FIFO); // helps to avoid byte loss. 28.04.14. } /******************************************************************************/ void STDIO_ReInit(uint32_t baudrate) { USART_InitTypeDef USART_InitStructure = { baudrate, USART_WordLength_8b, USART_StopBits_1, USART_Parity_No, USART_Mode_Rx | USART_Mode_Tx, USART_HardwareFlowControl_None }; if (!baudrate) baudrate = STDIO_BAUD; USART_InitStructure.USART_BaudRate = baudrate; USART_INIT(STDIO_DEVICE, USART_InitStructure); } /******************************************************************************/ // // Init an USART // __attribute__((weak)) void initialise_monitor_handles(void) {} void Init_STDIO(uint32_t baudrate) { static const RCC_PCLK_TypeDef DeviceClock[] = STDIO_RCC; static const GPIO_PIN_TypeDef DeviceGPIOs[] = STDIO_GPIO; static const NVIC_InitTypeDef NVIC_InitStructure = { STDIO_IRQn, STDIO_IT_Priority, 0, ENABLE }; initialise_monitor_handles(); RCC_Configuration (DeviceClock, sizeof(DeviceClock)); STDIO_ReInit(baudrate); GPIO_Configuration(DeviceGPIOs, sizeof(DeviceGPIOs)); USART_ENABLE(STDIO_DEVICE); IRQ_INIT(NVIC_InitStructure); bufio_Init(&FIFO); } // --- EOF --------------------------------------------------------------------- Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться