Я пытаюсь получить сообщения USART на микроконтроллере, исходящие от ПК, которые будут приказывать ему выполнять определенные тесты. Я использую STM32F4, я решил использовать DMA, поскольку сообщения на том же USART, исходящие от микроконтроллера, должны иметь скорость 2000000 бит/с, поскольку я не мог заставить его работать с более низким битрейтом или без DMA. Я использую двоичный код, а не ASCII для обоих направлений.
То, что я разработал до сих пор, «работает» (обновляется почти в реальном времени) при условии, что скорость отправки сообщений постоянна, поскольку каждое новое сообщение заставляет предыдущее сбрасываться из регистра DMA. Однако при запуске и отправке только одной инструкции/кадра USART, который оказывается меньше объема данных, которые должны быть получены для HAL_UART_Receive_DMA()
, сообщение застревает до тех пор, пока не будет вытеснено следующим сообщением.
Еще худший сценарий был бы, если бы USART_take_size
он был равен 100, а в буфере DMA был бы один кадр размером 10 байт. В этом случае мне нужно будет подождать еще 9 (10 байт) кадров, прежде чем получить их все сразу.
Вот как сейчас выглядит мой обратный вызов.
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
// uart handle, global array, numb of bytes to trigger interrupt
HAL_UART_Receive_DMA (huart, raw_serial, USART_take_size);
// function that adds received bytes to the circular buffer
AppendSerial(raw_serial,USART_take_size);
}
Поток извлекает байты из циклического буфера, перебирает их и на основе байтов SOF и EOF извлекает сообщение внутри кадра.
Моя проблема заключается в том, что поступающие кадры имеют разную длину, если USART_take_size
установлено значение x, а кадр поступает и его длина меньше x, он должен будет находиться в буферном массиве в потоке извлечения до тех пор, пока не прибудет другой кадр, который создает необходимые байты для синтаксического анализатора для получения встроенного сообщения.
Я вижу три способа решения этой проблемы, и каждый из них не кажется правильным:
Установите USART_take_size
на 1, что побеждает весь смысл прямого доступа к памяти.
Иметь фиксированный размер кадра и заполнять содержимое нулями перед EOF, если содержимое меньше, чем USART_take_size
. Это только кажется неряшливым и расточительным. Он также должен запускаться в каждом кадре, даже если общая скорость в этом случае может быть намного выше.
Настройте DMA для запуска ISR для переменного количества полученных байтов, при условии, что перед этим было определенное количество бездействий.
Я мало знаю о DMA, и хотя это кажется компромиссом между тем, сколько ISR запускается, и тем минимальным сообщением, которое вы можете прочитать, я думаю, что должен быть способ получить сообщение после периода бездействия. Любой другой подход к решению этой проблемы был бы замечательным. Спасибо!
У меня была похожая проблема в одном из моих проектов. Я решил эту проблему, создав достаточно длинный буфер для хранения максимально длинного сообщения и используя DMA для передачи из USART. Чтобы определить конец сообщения, я использовал прерывание обнаружения незанятой линии, которое срабатывает, когда приемник USART прекращает прием данных.
DMA STM32 не может делать то, что вы хотите, сам по себе. Чтобы иметь дело с сообщениями переменной длины, он должен иметь возможность разумно анализировать сообщение и определять длину, используя любую схему кодирования, которую вы выбрали. Это далеко за пределами его возможностей.
Я действительно могу думать только о двух вариантах вашей проблемы:
Просто обработайте каждый байт в ISR приема USART. У STM32 довольно низкие накладные расходы на прерывания. Если ваше приложение может справиться с этим, то иногда лучше использовать простое, даже если оно может быть не таким элегантным.
Вы можете легко настроить DMA для работы в качестве буфера FIFO. DMA загрузит байты в буфер, а затем вы установите периодическое прерывание по таймеру для проверки буфера на наличие данных и разбора сообщений. Это промежуточный подход по сравнению с вариантом 1, поскольку он позволяет уменьшить накладные расходы на прерывания за счет задержки. Вы можете настроить период опроса таймера в зависимости от размера FIFO, чтобы сбалансировать свои конкретные потребности в обработке в реальном времени. Есть также трюки, которые вы можете проделать с триггерами уровня DMA, хотя полезность этого будет зависеть от формата вашего сообщения.
pjc50
Питер Смит
mega_creamery
mega_creamery
Питер Смит
mega_creamery
ДКНгуйен