у тебя не правильный алгоритм. Ты должен запускать таймер в режиме OPM сразу после загрузки UART_DR, а внутри обработчиков запрещать оба прерывания и сбрасывать, например, в обработчике от таймера запрос от UART и наоборот. Тогда будет работать. Только, по-сути, так ты просто повторяешь алгоритм формирования IDLE в UART.
Заголовок сообщения: Re: STM32 новичку в ARM что к чему
Добавлено: Ср май 25, 2022 16:03:02
Открыл глаза
Зарегистрирован: Ср сен 24, 2014 12:30:09 Сообщений: 62
Рейтинг сообщения:0
Весь день проковырялся с этой штукой, выяснил кое-что странное. Оказывается, таймер вообще тут не при чем - зря его обвиняли. Вешаю светодиод на любую ногу МК и беру простейшее прерывание USART1 (для исключения влияния чего-либо даже задержку делаю на цикле):
Код:
void USART1_IRQHandler(void) {
uint32_t i = 0;
USART1->SR &=~ USART_SR_RXNE; // Clear USART1 RXNE Interrupt flag
GPIOC->ODR |= GPIO_ODR_ODR12; // Enable LED
for (i = 0; i < 65535; i++); // Delay
GPIOC->ODR &=~ GPIO_ODR_ODR12; // Disable LED
for (i = 0; i < 65535; i++); // Delay
}
Шлю один любой символ через терминал - светодиод моргает, как положено, 1 раз. Шлю его несколько раз вручную - все работает отлично. Но стоит только отправить через терминал не один символ (например, "Q"), а два или более подряд ("QE"), то светодиод начинает моргать бесконечно. То есть МК не может выйти из прерывания вообще, и гоняет его в цикле. Я так понимаю это из-за того, что следующий символ приходит раньше, чем закончилось предыдущее прерывание. Из-за чего такое может происходить?
Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей.
Уберите задержки из прерывания! Перед сбросом флага проверяйте из-за него вы туда попали или нет. Проверяйте как настроены прерывания от UART - по каким причинам они могут возникнуть. Могут ли, например, из-за ошибок.
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
У тебя не правильный алгоритм. Ессно, у тебя так будет. Тебе надо разрешать прерывание после загрузки DR, а в обработчике, после окончания передачи, его запрещать.
Есть вопрос. У меня возникает глюк и я не могу выцепить в чем причина. Поэтому пытаюсь всё проверять. Сейчас на подозрении - стек. Глюк появлялся у меня спустя около 20 секунд после начала хода. Я увеличил размер стека с 4096 до 8192 байт и один проход выполнился нормально. Второй тоже нормально, но на третьем проходе - опять появился глюк. На подозрении прерывания. Их у меня толпы.
И вот вопрос про прерывание PendSV - оно у меня довольно длинное. Но имеет самый низкий приоритет. Может ли быть так, что оно вызовется снова не завершив текущее. А как он знает, что текущее завершилось? Собственно, я иногда и в самом этом обработчике взвожу запрос на PendSV, чтобы обработчик перезапустился (там у меня машина состояний).
Код:
void PendSV_Handler(void) { profiler(); }
void profiler(void) { ... SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; // перезапуск, чтобы начать двигаться сразу ... }
Это влияет только на предупреждение при компиляции. Физически во время работы МК размер стека не контролируется. Можно посмотреть только в аналитике (Static Stack Analyzer) величину максимального потребления стека функциями. В ОЗУ вот так всё это укладывается: Каждый вызов вложенной функции или прерывания увеличивает потребление стека. При возврате из вложенных функций и прерываний потребление стека уменьшается. А если стек увеличивается слишком сильно, он наползет на область хранения статических переменных и повредит их содержимое. В этом и будет проявляться косяк - в повреждении значений статических переменных. Для контроля положения вершины стека есть регистр ядра SP (Stack Pointer). Регистр не имеет адреса и доступен либо через ассемблер, либо через сишную обертку __get_MSP(), возвращается текущий адрес вершины стека. Поскольку вы используете динамическое выделение памяти, под него будет выделяться место, начиная от конца хранения статических переменных (по рисунку выше - в белой части). И вот тут возможно взаимное столкновение динамического выделения памяти (которое идет вверх по адресам) и стека (который идет вниз по адресам). В чем именно проявляется глюк? В каком поведении? Проанализируйте, что конкретно портится.
Цитата:
Может ли быть так, что оно вызовется снова не завершив текущее. А как он знает, что текущее завершилось?
Нет, то же самое прерывание имеет тот же самый приоритет и вытеснить само себя не может. Поэтому, флаг запроса будет выставлен, но как только произойдет выход из текущего прерывания, МК снова войдет в это прерывание с его начала. Более подробно о работе прерываний прочтите в Programming Manual.
Спасибо за подсказку. попробую вставить контроль значений вершины стека в журнал, чтобы узнать в этом ли проблема.
Расположение стека я показал. Причем в отличии от того, что делал Keil, у силабов стек расположен внизу памяти и данные запортить не может. Он может только наехать на область где мог бы быть флеш. Но тогда, если бы адрес возврата был бы записан в пустоту, я бы наверняка получил бы HardFault.
Ок, проведу тесты и посмотрю, может зря я на стек бочку качу.
Уберите задержки из прерывания! Перед сбросом флага проверяйте из-за него вы туда попали или нет. Проверяйте как настроены прерывания от UART - по каким причинам они могут возникнуть. Могут ли, например, из-за ошибок.
Специально проверил - все прерывания кроме RX отключены. Даже пошел в лоб вот так:
Симптомы те же: если к моменту прихода следующей посылки предыдущее прерывание USART1 еще не закончило свое выполнение (например, внутри прерывания оказалась большая задержка, как у меня), тогда это самое прерывание начнет бесконечно крутиться в цикле, хоть флаги обобнуляйся. Я понимаю, что это не правильно пихать в прерывание задержки, но я хочу понять, из-за чего это, и как с этим бороться.
UPD: разобрался.
Чтобы отработать такую ситуацию, есть флаг ORE - "Overrun error". Прерывание по этому флагу то же самое, что и для RX - RXNEIE. Поэтому оно и вылезает у меня всегда. Проблема была в том, что этот флаг невозможно сбросить простым обнулением, нужно выполнить сначала чтение из USART1->DR, а затем чтение из USART1->SR. Только тогда он сбрасывается.
Здесь проверяется флаг RXNE (хотя, в любом случае мы попали в это прерывание именно через него, но если в друг включены другие прерывания, то проверять его нужно), и флаг ORE не должен быть равен единице. Если все нормально, читаем данные. Если Overrun, то просто сбрасываем все флаги и ничего не делаем. Ну, либо, выдаем ошибку.
Заголовок сообщения: Re: STM32 новичку в ARM что к чему
Добавлено: Чт май 26, 2022 10:34:17
Открыл глаза
Зарегистрирован: Ср сен 24, 2014 12:30:09 Сообщений: 62
Рейтинг сообщения:0
Проблема была в том, что на одном бите разрешения прерывания RXNEIE висело два флага от разных событий - RXNE и ORE. И чтобы сбросить один из этих флагов, ORE, нужно не просто считать регистр, а выполнить определенную последовательность действий. В итоге, я получаю 10 символов по USART1 вот таким кодом:
for (i = 0; i < 11; i++) { ReceivedCommand[i] = ReceivedText[i]; }
ReceivedCommand[11] = 0;
(void)USART1->DR; (void)USART1->SR;
} } }
}
Вроде все работает как надо, но после приема 10 символов почему-то еще один лишний раз срабатывает прерывание и выдается одна ошибка Time out. Как будто принимается один лишний символ. В счетчике SymbolCount на тот момент оказывается число 1, а должно быть 0.
нужно выполнить сначала чтение из USART1->DR, а затем чтение из USART1->SR.
Даташиты то когда будем читать?
SR дополнительно читать не надо, так как вы делает это при проверке статуса (правильная последовательность чтения - сначала SR, затем DR). А в вашем случае даже затрудняюсь посчитать сколько раз SR прочитан. Я приводил вот в этом сообщении скелет прерывания. Больше там ничего не нужно.
Код получился %цензор%. Ну что это? Что ещё за "&"?
Уберите всё. Сделайте приём с минимальным количеством кода без таймаутов. После этого добавьте обнуление и запуск таймера при приёме каждого байта. В прерывании от таймера реакция на таймаут. Это всё.
Код получился %цензор%. Ну что это? Что ещё ща "&"?
Но, как ни странно, работать будет. Потому что остальные условия тоже по-дурацки написаны и выставляют только младший бит. Это не отменяет, разумеется, того, что переписать по-человечески надо. Lum1noFor, проверка отдельного бита делается так:
Код:
(USART1->SR & USART_SR_RXNE)
И все - никаких сдвигов не нужно.
Цитата:
Даташиты то когда будем читать?
Где ж вы раньше были? Сейчас-то, когда ТС сам нашел упоминание этого бита (который он вообще не трогал!), легко тыкать в документацию.
Где ж вы раньше были? Сейчас-то, когда ТС сам нашел упоминание этого бита (который он вообще не трогал!), легко тыкать в документацию.
Я где раньше был? Я уже давно скелет прерывания показал. В нём ORE автоматом скидывается. Да и откуда ему возникнуть, если прерывание короткое как полёт пули. Разве что приоритет задушить и сидеть в каком-нибудь другом прерывании. Ну так это ССЗБ.
Заголовок сообщения: Re: STM32 новичку в ARM что к чему
Добавлено: Чт май 26, 2022 16:56:20
Открыл глаза
Зарегистрирован: Ср сен 24, 2014 12:30:09 Сообщений: 62
Рейтинг сообщения:0
Ну уж извините, туповат я, я и не спорю. Не в том я уже возрасте, чтобы все сходу понимать. Был бы крутым программистом - не обращался бы в тему для новичков. Спасибо Вам за критику и помощь. Учту все. Но, согласитесь, если просто взять чужое решение, ничего в голове не останется. Надо вникать, почему именно так. Что я и пытаюсь сделать.
Где ж вы раньше были? Сейчас-то, когда ТС сам нашел упоминание этого бита (который он вообще не трогал!), легко тыкать в документацию.
Я где раньше был? Я уже давно скелет прерывания показал. В нём ORE автоматом скидывается. Да и откуда ему возникнуть, если прерывание короткое как полёт пули. Разве что приоритет задушить и сидеть в каком-нибудь другом прерывании. Ну так это ССЗБ.
А раз уж Вы решили сразу код мне привести готовый, можно Вас попросить написать все это вместе с таймером таймаута? Тогда уж буду анализировать все вместе и думать, почему так и где я был не прав. Сегодня 6 часов просидел уже - все равно не работает нормально.
Быть может, стоило бы прочесть Reference Manual, раздел USART? Потому что там очень доходчиво, даже с диаграммами, расписано всё. Можете через гугл-переводчик, если проблемы с английским
Мне страшно представить, когда ты начнёшь осваивать UART+DMA... А ведь там без IDLE или RTO никак...
У меня UART работает через DMA: где-то только передача, где-то - и передача, и прием. И я ни разу в жизни ни IDLE, ни RTO не использовал. ЧЯДНТ? Ну и код приема в прерывании с контролем таймаутов я уже приводил, если кому интересно. Прием через DMA с таймаутами тоже несложно реализуется: достаточно в поллинге время проверять.
_________________ Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда. Я на гитхабе, в ЖЖ
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 35
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения