Здравствуйте!
IAR ARM 6.30.7 STM32F100
Делаю слейв Modbus RTU c RS485 интерфейсом. Всё было бы "ОК", но по 2-м UARTAM одновременно нужно работать, а при этом моя
реализация на прерываниях, начинает то на один то другой UART данные не до давать при интенсивном обмене с мастерами (ещё все АЦП задействованы на макс. скорости с прерываниями DMA по заверш. передачи оцифровки, но их отключение не помогает).
Решил сделать на связке UART-DMA.
Просмотрел на эту тему все топики здесь, погуглил, мануалы почитал... сделал - но очень зыбко работает моя реализация протокола, какой-то мелочи я не просекаю.
Для начала я хочу реализовать приём по-байтный, а отправку через DMA.
Начинается всё с приёма запроса от мастера, uart и драйвер настроен на приём:
1) принял байтик -> положил в буфер -> перезагрузил таймер (отсчёт frame end длительность 1,5-3 байт завершения пакета) и так каждый байтик, до срабатывания таймера (срабатывает когда пауза в 1,5-3 байта (как настрою))
2) таймер отсчитал framе end, сработало его прерывание -> останавливаю таймер-> блокирую приёмник UARTа (чтобы не реагировал на входящие)
3) разбор входящего сообщения (можно вынести из прерывания во внешний цикл и сигнализировать от пришедшем пакете через какие-нибудь битики) включает в себя проверку адреса слейва и контрольной суммы (потом делается более детальный разбор, но для начала самое-то)
4) реакция на входящее сообщение:
4.1) чужое или "по-дороге битое" -> перевод uart в режим ожидания входящих байт (исходное состояние)
4.2) достойное ответа -> формирование ответа в буфере
5) когда буфер заполнен ответом, запускаю таймер на отсчёт времени переключения драйвера из режима "приём" в режим "передача" (например для ADM2587E 2,5мкСек)
6) сработало прерывание таймера (драйвер переключился в "передача")->останавливаю таймер->настраиваю DMA на передачу подготовленного буфера и запускаю передачу DMA1_Channel7->CCR |= DMA_CCR7_EN; (всё, данные должны автоматом вылетать с ножки TX, до опустошения буфера)
7) по опустошению буфера срабатывает прерывание DMA_ISR_TCIFx (если разрешено)(или таймера USART_CR1_TCIE .. в этом есть вопрос ??) данные (как-бы) переданы и можно переключаться на приём
8) запускаю таймер на отсчёт времени переключения драйвера из режима "передача" в режим "приём"
9) сработало прерывание таймера (драйвер переключился в "приём")-> перевод uart в режим ожидания входящих байт (исходное состояние)
Трабл:
Сейчас получается, до п.7 всё норм.,запускаю DMA... бывает что весь буфер приходит (длина ответа в среднем 64 байта), а зачастую 1 байт (левый!!!) и срабатывает DMA или UART "Transmission Complete" (я с ними экспериментировал)
Ещё из наблюдений:
1) Если я разрешаю DMA_ISR_TCIFx (но при этом USART_CR1_TCIE запрещён) и запускаю DMA, то мне приходится к DMA1_Channelх->CNDTR дополнительно "+2" делать, но имею при этом лишний байт "0" он либо затирает последний значащий байт пакета данных (если CNDTR = кол-ву передаваемых байт), либо просто лишний (если CNDTR = кол-ву передаваемых байт + 2)
2) Если я разрешаю USART_CR1_TCIE (но DMA_ISR_TCIFx при этом запрещён или разрешён но просто чистит флаги) и запускаю DMA, то с DMA1_Channelх->CNDTR всё "ок" равно кол-ву передаваемых байт.
В общем надеюсь с вашей помощь найти решение своего трабла и увековечить тему "STM32 DMA UART" в FAQ опубликовав полученный рабочий код с каментами