/* Increasing the number of wait states because of higher CPU frequency */ if (READ_BIT(FLASH->ACR, FLASH_ACR_LATENCY) < FLASH_ACR_LATENCY_4WS) /* Program the new number of wait states to the LATENCY bits in the FLASH_ACR register */ MODIFY_REG(FLASH->ACR, FLASH_ACR_LATENCY, FLASH_ACR_LATENCY_4WS);
while (READ_BIT(RCC->CFGR, RCC_CFGR_SWS) != (RCC_CFGR_SW_PLL << RCC_CFGR_SWS_Pos)) asm("");
/* Set the highest APB divider in order to ensure that we do not go through a non-spec phase whatever we decrease or increase HCLK. */ MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE1, RCC_CFGR_PPRE1_DIV16); MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE2, RCC_CFGR_PPRE2_DIV16); /* Set the new HCLK clock divider */ MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_CFGR_HPRE_DIV1);
Отправка по UART, тут много лишнего для отладки я уже добавлял. Например, обработку RX фейковую, чтобы убедиться, что не из-за неё тормозит. Изначально вообще убирал RX (USART_CR1_RE USART_CR1_RXNEIE) Спойлер
и отправлять через цикл с ожиданием USART_ISR_TXE, то SysTick_Handler работает без проблем. Даже при отладке, пока инициируется переферия, SysTick_Handler успевает несколько раз выполниться. Но как только включается прерывание по UART, всё приехали. Прерывания по UART работают постоянно, а вот SysTick_Handler нет.
При срабатывании прерывания UART регистр ISR вот такой: 0x600080, вместо 8 бывает d и c если делать обработчик проще (оставлять только обработку tx).
Вообще, я это обнаружил случайно, хотел из SysTick для отладки отправлять раз в секунду hello в этот uart, но хотелось бы всё-таки разобраться, что делаю не так.
Я посмотрел на содержимое SysTick_Config(...), которую применяю из cmsis:
Код:
#define __NVIC_PRIO_BITS 4U /*!< STM32G4XX uses 4 Bits for the Priority Levels */ ... NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
Т.е. по умолчанию, если я правильно понимаю, для SysTick_IRQn выставляется наименьший приоритет (максимальное число).
Но что тогда показывают результаты теста с приоритетами? Получается, они подтверждают подозрение, которое было у меня до этого, что вызов USART3_IRQHandler() фигачит в бесконечном цикле и не даёт выполниться более низким прерываниям (таким как SysTick)? Полагаю, что видимо надо доснять флаг какого-то из прерываний. И в эту сторону я и копал, но ни к чему не пришёл.
Логика моя верна? Полагаю, вариант с приоритетами - это костыль, надо видимо решить исходную проблему.
В отладчике через SysTick_Handler(void) проходит??
При исходных параметрах из первого своего сообщения - перестаёт туда заходить, как только включаются прерывания. Т.е. в самом начале выполнения прошивки, отладчик там останавливается. После выполнения NVIC_EnableIRQ(USART3_IRQn); перестаёт там срабатывать.
После смены приоритетов, работа возобновилась. Снова туда заходит.
Прерывание по TXE стоит отключать, если передавать нечего. А так получается, что оно бесконечно шарашит… Лучше вообще при помощи DMA передавать. Да и принимать тоже: во всех "взрослых" STM32 есть прерывание по символу. Вот и ставим прерывание по '\n', да не паримся! Сам так делаю. Протокол, естественно, текстовый. В случае же убогого уродбаса, есть прерывание IDLE, которое и помогает опознать конец фрейма. Тоже использую, благо, этот самый модбас у меня лишь при работе со всякими кривыми китайскими релюшками, которые лень перепрошивать, чтобы туда вменяемый протокол запилить.
_________________ Windows must die! And the users of this crap should either become smarter or become janitors.
Прерывание по TXE стоит отключать, если передавать нечего. А так получается, что оно бесконечно шарашит…
Вот правильный ответ. Только следует не отключать а маскировать в самом UART. Хотя, кто-то скажет что это и есть "отключать". А вообще, бесконечный вызов какого-то прерывания я ловил даже на AVR.
_________________ Репозиторий STM32: https://cloud.mail.ru/public/2i19/Y4w8kKEiZ Актуальность репозитория: 1 сентября 2025 года Если чего-то не хватает с сайта st.com - пишите, докачаю.
linux_rulezz, спасибо! Не знаю, почему мне эта мысль не приходила в голову, но это гениально!
Я ещё раз перекопал HAL-библиотеку, и там, оказывается, делают точно так же - выключают прерывание TXE по окончании прередачи, а перед очередной передачей включают вновь. Сделал так же у себя, работает стабильно.
/бухтёж-on Это вообще писец... я освоил USB, SPI, CAN... везде, блин, "свой путь" в логике работы. Но вот привыкнув уже к тому, что мы, включив прерывание однажды при инициализации, сбрасываем его флагом каждый раз.. И мне казалось, что отключать каждый раз само прерывание - это какая-то дичь, даже не подпускал этой мысли, есть же просто флаги... А оказывается - так МОЖНО было.... и вообще - это НОРМА. /бухтёж-off
Короч... Спасибо за помощь. Видимо, свой вопрос я решил.
где-то в условиях передачи попробуйте вписать начало прерывания: UART->CR1 |= USART_CR1_TXEIE; и остановить прерывание UART->CR1 &= ~USART_CR1_TXEIE; напр.
Отключается оно в NVIC (и глобально в ядре), чтобы ядро вообще не дёргалось в вектор. А в модуле оно маскируется. У некоторых модулей есть отдельные вектора на некоторые запросы. Если же вектор обслуживает несколько запросов, то вам придётся сначала сохранять в локальную переменную регистр флагов SR, затем подтверждать все флаги и после этого анализировать, что там выстрелило.
_________________ Репозиторий STM32: https://cloud.mail.ru/public/2i19/Y4w8kKEiZ Актуальность репозитория: 1 сентября 2025 года Если чего-то не хватает с сайта st.com - пишите, докачаю.
Ещё раз покопал RM, нигде подобной рекомендации не нашёл. И в многочисленных уроках в интернетах - тоже ничего про это. Или на F1 (уроки по теме UART в интернетах все на F103) прерывание TXE срабатывает однократно и его не надо отключать в конце передачи?
Cliff, я подозреваю, что просто мало кому приходит в голову на прерываниях организовывать передачу, если можно подключить для этого DMA. Да, конечно, конкретный канал (если нет DMAMUX, да и с ним каналов очень мало) может быть занят чем-то более важным, а блокировать суперлуп на время передачи с черепашьей скоростью не хочется… Вот в этом случае - да, оправдано. Но в конце - когда полностью передали буфер, либо вообще прерывание запрещаем (маскируем при помощи NVIC), либо в CR1 его отключаем.
А что до "уроков" в интернете - к ним стоит трижды критически подходить. Чаще всего друг у друга тырят какое-нибудь фуфло на основе калокуба.
Добавлено after 6 minutes 38 seconds: О, запустил у себя в дереве
А кто-нибудь флаг ТС (Transmission complete) использует?
В примерах одного из производителей МК встречал такой подход:
- разрешается прерывание TXE и отправляётся всё, кроме последнего байта; - перед отправкой последнего байте запрещается прерывание TXE и тут же разрешается прерывание TCIE; - последний байт улетает, и уже тогда запрещается и прерывание TCIE.
Кто-нибудь так делает?
Оно, конечно, работает, но гложут сомнения - зачем использовать TCIE, когда и без него всё отправляется?
_________________ Платы для HLDI - установки лазерной засветки фоторезиста. ФоторезистыOrdyl Alpha 350 и AM 140. Жидкое олово для лужения плат (видео) - самое лучшее и только у меня. Паяльная маска XV501T-4 и KSM-S6189 (5 цветов). Заказ печатных плат - pcbsmac@gmail.com
smacorp, мне казалось, что TC создавался не для передачи, а вообще для других целей, связанных с общей организацией процессов в проекте. Например, дождаться передачи сообщения на другое устройство, прежде чем его отключить или что-нибудь включить.
Оно, конечно, работает, но гложут сомнения - зачем использовать TCIE, когда и без него всё отправляется?
TC нужен в тех случаях, когда нужно получить уведомление о завершении операции отправки символа, а не о возможности записать следующий символ в буфер передачи. Он полезен для: 1) полудуплексная передача по одной линии (RS-485 и иже с ним); 2) если нужно управление внешним драйвером на TX (например для RS-485), причём - необязательно для полудуплексных интерфейсов, для дуплексных тоже иногда нужно; 3) по UART пришла команда о перезагрузке устройства - устройство отправляет подтверждение и перегружается (только после отправки полностью подтверждения!); 4) нужно отправить наружу по UART кадр данных, после чего уснуть с отключением тактирования UART (уснуть нужно только после отправки последнего бита последнего байта, не ранее); 5) синхронизация передач по UART с приёмами/передачами по каким-то другими интерфейсами; 6) нужно отправить кадр по UART, после чего сразу переключить скорость UART (например - когда вы отправляете внешнему устройству команду установки новой baudrate, а он устанавливает её и отвечает сразу уже на новой скорости); 7) ... + ещё куча подобных случаев.
Задавая вопрос о TC и связанном с ним прерывании, я, конечно, и не сомневался, что они придуманы не зря. И когда используется DMA, как и в некоторых других случаях, использование TCIE понятно.
И зачем так рекомендует делать производитель МК не совсем понятно. Есть ведь tx_size, по которому и так будет ясно, что все данные улетели.
Впрочем, наверное это лишь учебный пример и в реальном коде так делать смысла нет? Или, всё же, есть?
_________________ Платы для HLDI - установки лазерной засветки фоторезиста. ФоторезистыOrdyl Alpha 350 и AM 140. Жидкое олово для лужения плат (видео) - самое лучшее и только у меня. Паяльная маска XV501T-4 и KSM-S6189 (5 цветов). Заказ печатных плат - pcbsmac@gmail.com
smacorp, в этом примере забыли выставить флаг "данные переданы". А в таком виде, понятное дело, отлавливать TC нет смысла. Хотя, можно исхитриться и использовать USART1_TCIE в качестве него: если tx_size равен нулю, и флага нет, то данные улетели, и можно что-нибудь делать (отключаться, менять скорость, переключаться в режим чтения и т.д., и т.п.).
_________________ Windows must die! And the users of this crap should either become smarter or become janitors.
Разница флагов TC и TE очевидна: первый "Transmission Complete" (передача окончена) а второй TE "Transmitter Empty" (передатчик пуст). И задачи у них разные. ТЕ это попытка в оптимизацию для бесшовной передачи. У SPI, например, использование TE приводит к тому, что байты идут сплошным потоком и SCK не прерывается вообще. Передавать надо строго только по ТЕ кроме вышеописанных случаев (полудуплекс, выключение и прочее), когда надо убедиться что передача закончилась и байт улетел в шину весь, вместе со стопами и прочим арбитражом.
_________________ Репозиторий STM32: https://cloud.mail.ru/public/2i19/Y4w8kKEiZ Актуальность репозитория: 1 сентября 2025 года Если чего-то не хватает с сайта st.com - пишите, докачаю.
Такое применение - только в мусорку. Код кривой. Содержит сразу несколько багов: 1) будет передано больше байт, чем tx_size; 2) будут ложные прерывания; 3) будут "гонки"; 4) будет некорректное состояние битов CR1 после завершения передачи (останется стоять TCIE); ... И скорее всего - код вообще зациклится в бесконечной передаче.
И зачем так рекомендует делать производитель МК не совсем понятно. Есть ведь tx_size, по которому и так будет ясно, что все данные улетели.
Значит вы не понимаете назначение флагов статуса UART. С этого и надо было начинать. TXE - сигнал о наличии свободного места в FIFO передатчика; TC - сигнал о завершении передачи символа. Это совершенно разные сигналы и использовать каждый нужно в подходящем ему случае. Потому TC разрешается только для последнего символа (с запретом TXE).
Очевидно, что тут выстроена модель: 1. Корректная побайтная передача 2. Оповещение о завершении передачи всего буфера.
ну т.е. TC гарантировано сработает только при завершении выдачи в порт крайнего бита всего буфера. Видимо, это пример из конкретной задачи. Просто, применение TC тут вырезано, только факт его срабатывания остаётся.
Непонятно, что смущает в данном примере. Либо ваш вопрос сложнее, чем кажется с первого взгляда.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 16
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения