amaora 17 11 апреля, 2019 Опубликовано 11 апреля, 2019 (изменено) · Жалоба Вот такой код отправки в USART мертво застревает при большой нагрузке, когда большую часть времени задача блокирована на вызове xQueueSendToBack. Проявляется только при оптимизации -O3 -flto. void USART_putc(int c) { char xC = (char) c; GPIO_set_HIGH(GPIO_LED); if (xQueueSendToBack(hal_USART.xTX, &xC, portMAX_DELAY) == pdTRUE) { USART3->CR1 |= USART_CR1_TXEIE; } GPIO_set_LOW(GPIO_LED); } Со стороны прерывания вот так. void irq_USART3() { BaseType_t xWoken = pdFALSE; unsigned int SR; char xC; SR = USART3->SR; if (SR & USART_SR_RXNE) { xC = USART3->DR; xQueueSendToBackFromISR(hal_USART.xRX, &xC, &xWoken); GPIO_set_LOW(GPIO_LED); // это для проверки, попадем ли сюда когда все застряло (результат отрицательный) } if (SR & USART_SR_TXE) { if (xQueueReceiveFromISR(hal_USART.xTX, &xC, &xWoken) == pdTRUE) { USART3->DR = xC; } else { USART3->CR1 &= ~USART_CR1_TXEIE; } } portYIELD_FROM_ISR(xWoken); } Судя по тому, что в прерывание после этого уже не попадаем (даже на прием), застряли внутри критической секции с отключенными прерываниями. Изменено 11 апреля, 2019 пользователем amaora Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 53 11 апреля, 2019 Опубликовано 11 апреля, 2019 · Жалоба 4 hours ago, amaora said: Судя по тому, что в прерывание после этого уже не попадаем (даже на прием) Не попадаем, или висим глухо в этом прерывании по флагу ORE, например? Оператор if в USART_putc() смысла не несет. Использование очереди в качестве кольцевого буфера для периферии - не самая удачная идея. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 55 12 апреля, 2019 Опубликовано 12 апреля, 2019 · Жалоба 24 minutes ago, aaarrr said: Использование очереди в качестве кольцевого буфера для периферии - не самая удачная идея + латентность. По нашим замерам до 800 мкс проиходило между событиями "поместили в очередь" и "приняли из очереди". 5 hours ago, amaora said: Со стороны прерывания вот так. Нужно обрабатывать все события от последовательного порта, в т.ч. ошибки (framing error, overrun error и другие). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
amaora 17 12 апреля, 2019 Опубликовано 12 апреля, 2019 · Жалоба 4 hours ago, aaarrr said: Не попадаем, или висим глухо в этом прерывании по флагу ORE, например? По другим событиям прерывание я не разрешал. Позже уточню. 3 hours ago, haker_fox said: + латентность. По нашим замерам до 800 мкс проиходило между событиями "поместили в очередь" и "приняли из очереди". Никуда не тороплюсь, это вывод в отладочный usart со скоростью 57600. Для этого и очередь, чтобы данные в ней лежали пока до них дело не дойдет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 55 12 апреля, 2019 Опубликовано 12 апреля, 2019 · Жалоба 1 hour ago, amaora said: Для этого и очередь, чтобы данные в ней лежали пока до них дело не дойдет Ну таки да) Я просто предупредели, вдруг для вас это важно) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
x893 32 12 апреля, 2019 Опубликовано 12 апреля, 2019 · Жалоба Можно посмотреть в HAL обработку прерываний от USART и сделать необходимые изменения в коде. Полчаса хватит для исправления. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 53 12 апреля, 2019 Опубликовано 12 апреля, 2019 · Жалоба 5 hours ago, amaora said: По другим событиям прерывание я не разрешал. Позже уточню. А их и не надо разрешать - такой вот сюрприз. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AlanDrakes 1 12 апреля, 2019 Опубликовано 12 апреля, 2019 · Жалоба Очередь для байтов UART'а... чтож, мсье знает толк. Накладные расходы большие для такого дела. Лучше уж принимать данные в кольцевой буфер, затем копировать их поблочно в динамическую память, и кидать ссылки на неё. Но это тоже плохой вариант при работе из прерывания. Я бы рекомендовал описать свой вариант очереди без блокировок и с некоторым кольцевым буфером отправки. У себя использую около 4kiB на отправку и 128 байт на приём. Переполнения не ловил уже давно. Отправляю посредством DMA, принимаю - тоже. Прекращение отправки происходит по событию DMA-Transfer-Complete, обработка приёма - по USART-IDLE. Но в прерываниях только взводятся флаги и запоминаются новые позиции указателей на буфер, а в основном потоке происходит сравнение новых позиций с их копией в потоке (атомарность операций не нарушается). Быстро, достаточно эффективно, относительно безопасно для критических секций и потоков. Во всяком случае, не вызывает зависаний. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 55 12 апреля, 2019 Опубликовано 12 апреля, 2019 · Жалоба 25 minutes ago, AlanDrakes said: Накладные расходы большие для такого дела. Иногда почему бы и нет. Сам для себя давно написал кольцевой буфер на шаблонах, использую его для систем сбора данных, и для коммуникационных протоколов. Но средства сигнализации посредством ОС тоже имеются. Да и DMA при желании имеет возможность в него писать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 166 12 апреля, 2019 Опубликовано 12 апреля, 2019 · Жалоба 12 часов назад, haker_fox сказал: + латентность. По нашим замерам до 800 мкс проиходило между событиями "поместили в очередь" и "приняли из очереди". Странная какая-то очередь. Если это задержки именно из-за её работы, то получается ТС вообще не сможет с ней работать ибо: 10/57600 = 174 мкс, а нужно не менее 800 мкс. У Вас там скорее всего или какая-то другая задача занимала процессор в это время. Или что-то не так с раздачей квантов времени задачам и их пробуждением по событиям объектов синхронизации. 2 часа назад, AlanDrakes сказал: Очередь для байтов UART'а... чтож, мсье знает толк. Накладные расходы большие для такого дела. ТСу торопиться некуда (как он сказал). И ничего что сделанный таким образом "вывод в отладочный usart" завалит работу всего остального ПО. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
amaora 17 12 апреля, 2019 Опубликовано 12 апреля, 2019 (изменено) · Жалоба 10 hours ago, aaarrr said: А их и не надо разрешать - такой вот сюрприз. И может быть чтобы ORE=1 а при этом RXNE=0 ? В любом случае, 1) Остальные прерывания по ошибкам отключены; 2) В проблемный момент USART ничего не принимает, только передает; 3) Каким-то образом это проявляется только с -O3 и -flto; 4) Добавлю проверку на USART_SR_ORE и понаблюдаю еще; 10 hours ago, AlanDrakes said: Я бы рекомендовал описать свой вариант очереди без блокировок и с некоторым кольцевым буфером отправки. У себя использую около 4kiB на отправку и 128 байт на приём. Переполнения не ловил уже давно. И вылавливать там race condition несколько лет. Переполнения это часть нормальной работы, на все что выводится памяти не хватит. Upd: Добавил проверку. if (SR & (USART_SR_ORE | USART_SR_NE | USART_SR_FE | USART_SR_PE)) { GPIO_set_LOW(GPIO_LED); lowTRACE(EOL "** USART_ERR **" EOL); } Ни разу не сработала, и так же застряло во время нагрузки. Upd2: Обновился до свежей V10.2.0, теперь проблема не воспроизводится. Буду считать, что была ошибка в RTOS, возможно неосторожно внесенная мной. Делал много правок, которые впрочем не затрагивали ничего важного, только удалял ненужное и адаптировал к своим условиям. Исправил сборку с LTO. То же самое я теперь сделал и с новой версией, но с ней проблемы уже нет. Изменено 12 апреля, 2019 пользователем amaora Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Neo_Matrix 0 12 апреля, 2019 Опубликовано 12 апреля, 2019 (изменено) · Жалоба 6 часов назад, amaora сказал: Upd2: Обновился до свежей V10.2.0, теперь проблема не воспроизводится. Буду считать, что была ошибка в RTOS, возможно неосторожно внесенная мной. Делал много правок, которые впрочем не затрагивали ничего важного, только удалял ненужное и адаптировал к своим условиям. Исправил сборку с LTO. То же самое я теперь сделал и с новой версией, но с ней проблемы уже нет. Достаточно долго работаю с FreeRTOS и могу вас заверить, что критических ошибок приводящих к мертвым зависаниям в ней нет(с версии 8 точно). То, что после обновления ОС, ошибка пропала, скорее всего говорит о том, что ошибка была "скрыта", а не решена. Скорее всего при следующих правках кода ошибка снова проявит себя. Посмотрите в сторону прерываний hard_fault, bus_fault и им подобным(они включены в не зависимости от хотелок), предположу: при зависании вылетает в них. ПС: В "обновляторе прошивок" использую только очереди, даже при приеме данных с модема в прерывании(оверхед эпичный), но даже в таком режиме(а данных пересылается достаточно много) никогда нечего не висло. Кроме того внутри одной задачи используется парсер пришедших данных и они раскладываются по разным очередям а после этой же задачей вычитываются(не хотелось добавлять левые буферы) и даже такое издевательство не вешает контроллер. Изменено 12 апреля, 2019 пользователем Neo_Matrix Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 53 12 апреля, 2019 Опубликовано 12 апреля, 2019 · Жалоба 7 hours ago, amaora said: Делал много правок, Просто прекрасно! А сразу упомянуть о такой несущественной мелочи нельзя было? Это просто свинство, если называть вещи своими именами. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 55 13 апреля, 2019 Опубликовано 13 апреля, 2019 · Жалоба 3 hours ago, Neo_Matrix said: Посмотрите в сторону прерываний hard_fault, bus_fault и им подобным(они включены в не зависимости от хотелок), предположу: при зависании вылетает в них. Правильно! А лучше включить один hardfault и написать для него обработчик. И уже в нём смотреть причину вылета. Также я сделал перехватавалки для сишной библиотеки для функций abort(), exit() и подобных. Иногда у меня проги и туда вылетали. Очень удобное, если выводить LR (видно, откуда туда попали). Ну и стековые канарейки иногда тоже спасают, если версия IAR помогает. При этом во FreeRTOS нужно включить всю отладку (configASSERT, stack overflow protection). Дополнительно на неиспользуемые вектора прерываний можно повесить что-то по-умолчанию для сигнализации. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
amaora 17 13 апреля, 2019 Опубликовано 13 апреля, 2019 (изменено) · Жалоба 6 hours ago, aaarrr said: Просто прекрасно! А сразу упомянуть о такой несущественной мелочи нельзя было? Это просто свинство, если называть вещи своими именами. Правки это например убрал include string.h и заменил на свои объявления mem* функций. Удалил файлы croutine, timers, и другие что не планирую использовать никогда. Добавил аттрибут used одной функции и одной переменной. Исправил инлайн асм вставки в port.c, заменив загрузку адреса через ldr на две movw/movt. Последнюю часть делал из необходимости а не по желанию, лучшего решения не нашел. В остальном стараюсь ничего не править. А не так, чтобы решил убрать вот здесь критическую сеецию для ускорения. И да, действительно есть опасения, что проблема скрылась и может проявиться когда-то снова. Ведь причину я не понял. 7 hours ago, Neo_Matrix said: Посмотрите в сторону прерываний hard_fault, bus_fault и им подобным(они включены в не зависимости от хотелок), предположу: при зависании вылетает в них. Нет, в них не попадаем. Там есть обработчик, я бы узнал об этом. Изменено 13 апреля, 2019 пользователем amaora Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться