Jump to content

    

Неполадки с очередью в USART

Вот такой код отправки в 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);
}

Судя по тому, что в прерывание после этого уже не попадаем (даже на прием), застряли внутри критической секции с отключенными прерываниями.

Edited by amaora

Share this post


Link to post
Share on other sites
4 hours ago, amaora said:

Судя по тому, что в прерывание после этого уже не попадаем (даже на прием)

Не попадаем, или висим глухо в этом прерывании по флагу ORE, например?

 

Оператор if в USART_putc() смысла не несет. Использование очереди в качестве кольцевого буфера для периферии - не самая удачная идея.

Share this post


Link to post
Share on other sites
24 minutes ago, aaarrr said:

Использование очереди в качестве кольцевого буфера для периферии - не самая удачная идея

+ латентность. По нашим замерам до 800 мкс проиходило между событиями "поместили в очередь" и "приняли из очереди".

5 hours ago, amaora said:

Со стороны прерывания вот так.

Нужно обрабатывать все события от последовательного порта, в т.ч. ошибки (framing error, overrun error и другие).

Share this post


Link to post
Share on other sites
4 hours ago, aaarrr said:

Не попадаем, или висим глухо в этом прерывании по флагу ORE, например?

По другим событиям прерывание я не разрешал. Позже уточню.

3 hours ago, haker_fox said:

+ латентность. По нашим замерам до 800 мкс проиходило между событиями "поместили в очередь" и "приняли из очереди".

Никуда не тороплюсь, это вывод в отладочный usart со скоростью 57600. Для этого и очередь, чтобы данные в ней лежали пока до них дело не дойдет.

Share this post


Link to post
Share on other sites
1 hour ago, amaora said:

Для этого и очередь, чтобы данные в ней лежали пока до них дело не дойдет

Ну таки да) Я просто предупредели, вдруг для вас это важно)

Share this post


Link to post
Share on other sites

Можно посмотреть в HAL обработку прерываний от USART и сделать необходимые изменения в коде.

Полчаса хватит для исправления.

Share this post


Link to post
Share on other sites
5 hours ago, amaora said:

По другим событиям прерывание я не разрешал. Позже уточню.

А их и не надо разрешать - такой вот сюрприз.

Share this post


Link to post
Share on other sites

Очередь для байтов UART'а... чтож, мсье знает толк.

Накладные расходы большие для такого дела. Лучше уж принимать данные в кольцевой буфер, затем копировать их поблочно в динамическую память, и кидать ссылки на неё.

Но это тоже плохой вариант при работе из прерывания.

Я бы рекомендовал описать свой вариант очереди без блокировок и с некоторым кольцевым буфером отправки. У себя использую около 4kiB на отправку и 128 байт на приём. Переполнения не ловил уже давно.

Отправляю посредством DMA, принимаю - тоже. Прекращение отправки происходит по событию DMA-Transfer-Complete, обработка приёма - по USART-IDLE. Но в прерываниях только взводятся флаги и запоминаются новые позиции указателей на буфер, а в основном потоке происходит сравнение новых позиций с их копией в потоке (атомарность операций не нарушается). Быстро, достаточно эффективно, относительно безопасно для критических секций и потоков. Во всяком случае, не вызывает зависаний.

 

Share this post


Link to post
Share on other sites
25 minutes ago, AlanDrakes said:

Накладные расходы большие для такого дела.

Иногда почему бы и нет. Сам для себя давно написал кольцевой буфер на шаблонах, использую его для систем сбора данных, и для коммуникационных протоколов. Но средства сигнализации посредством ОС тоже имеются. Да и DMA при желании имеет возможность в него писать.

Share this post


Link to post
Share on other sites
12 часов назад, haker_fox сказал:

+ латентность. По нашим замерам до 800 мкс проиходило между событиями "поместили в очередь" и "приняли из очереди".

Странная какая-то очередь. Если это задержки именно из-за её работы, то получается ТС вообще не сможет с ней работать ибо:

10/57600 = 174 мкс, а нужно не менее 800 мкс. У Вас там скорее всего или какая-то другая задача занимала процессор в это время. Или что-то не так с раздачей квантов времени задачам и их пробуждением по событиям объектов синхронизации.

2 часа назад, AlanDrakes сказал:

Очередь для байтов UART'а... чтож, мсье знает толк.

Накладные расходы большие для такого дела.

ТСу торопиться некуда (как он сказал). И ничего что сделанный таким образом "вывод в отладочный usart" завалит работу всего остального ПО.

Share this post


Link to post
Share on other sites
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. То же самое я теперь сделал и с новой версией, но с ней проблемы уже нет. :unknw:

Edited by amaora

Share this post


Link to post
Share on other sites
6 часов назад, amaora сказал:

Upd2: Обновился до свежей V10.2.0, теперь проблема не воспроизводится. Буду считать, что была ошибка в RTOS, возможно неосторожно внесенная мной. Делал много правок, которые впрочем не затрагивали ничего важного, только удалял ненужное и адаптировал к своим условиям. Исправил сборку с LTO. То же самое я теперь сделал и с новой версией, но с ней проблемы уже нет. :unknw:

Достаточно долго работаю с FreeRTOS и могу вас заверить, что критических ошибок приводящих к мертвым зависаниям в ней нет(с версии 8 точно). То, что после обновления ОС, ошибка пропала, скорее всего говорит о том, что ошибка была "скрыта", а не решена. Скорее всего при следующих правках кода ошибка снова проявит себя. Посмотрите в сторону прерываний hard_fault, bus_fault и им подобным(они включены в не зависимости от хотелок), предположу: при зависании вылетает в них.

 

ПС: В "обновляторе прошивок" использую только очереди, даже при приеме данных с модема в прерывании(оверхед эпичный), но даже в таком режиме(а данных пересылается достаточно много) никогда нечего не висло. Кроме того внутри одной задачи используется парсер пришедших данных и они раскладываются по разным очередям а после этой же задачей вычитываются(не хотелось добавлять левые буферы) и даже такое издевательство не вешает контроллер.

Edited by Neo_Matrix

Share this post


Link to post
Share on other sites
7 hours ago, amaora said:

Делал много правок,

Просто прекрасно! А сразу упомянуть о такой несущественной мелочи нельзя было? Это просто свинство, если называть вещи своими именами.

Share this post


Link to post
Share on other sites
3 hours ago, Neo_Matrix said:

Посмотрите в сторону прерываний hard_fault, bus_fault и им подобным(они включены в не зависимости от хотелок), предположу: при зависании вылетает в них.

Правильно! А лучше включить один hardfault и написать для него обработчик. И уже в нём смотреть причину вылета. Также я сделал перехватавалки для сишной библиотеки для функций abort(), exit() и подобных. Иногда у меня проги и туда вылетали. Очень удобное, если выводить LR (видно, откуда туда попали). Ну и стековые канарейки иногда тоже спасают, если версия IAR помогает. При этом во FreeRTOS нужно включить всю отладку (configASSERT, stack overflow protection). Дополнительно на неиспользуемые вектора прерываний можно повесить что-то по-умолчанию для сигнализации.

Share this post


Link to post
Share on other sites
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 и им подобным(они включены в не зависимости от хотелок), предположу: при зависании вылетает в них.

Нет, в них не попадаем. Там есть обработчик, я бы узнал об этом.

Edited by amaora

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now