Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

STM32 HAL UART DMA

Пн фев 01, 2021 15:42:34

Добрый день!
Не стал создавать тему ради одного вопроса, поэтому немного расширил.
Конкретно сейчас есть такая проблема - есть буфер для приема данных (массив на 100 байт) с UART по DMA в кольцевом режиме. Данные в буфер пишутся, но мне надо знать в какой элемент массива был записан последний принятый байт, а найти это не могу.
Не подскажете как решить проблему?

Re: STM32 HAL UART DMA

Пн фев 01, 2021 15:57:39

Допустим определишь ты последний байт, дальше что делать будешь?

Re: STM32 HAL UART DMA

Пн фев 01, 2021 16:04:32

В свободное время у меня проводится поллинг - если индекс последнего проверенного элемента массива меньше чем индекс последнего принятого байта, то эти байты анализируются. А дальше уже при обнаружении символа конца строки происходить определение полученной команды.

Добавлено after 1 minute 14 seconds:
На прерываниях все работало как надо, но там индекс инкрементировался в прерывании. Теперь хочу все на ДМА перевести

Re: STM32 HAL UART DMA

Пн фев 01, 2021 16:10:34

У DMA есть регистр CNDTR в который заносится количество принимаемых данных, после приема очередного байта он декрементится.

Re: STM32 HAL UART DMA

Пн фев 01, 2021 16:14:26

О, спасибо!
А я структуру когда разбирал искал в значениях количество принятых байт, а оно тут вон как, от обратного)

Re: STM32 HAL UART DMA

Вт фев 02, 2021 17:10:51

Еще такой вопрос.
Как узнать, что все данные по ДМА были переданы и можно отправлять следующую партию в HAL_UART_Transmit_DMA?

Re: STM32 HAL UART DMA

Вт фев 02, 2021 17:18:46

Проверять CNDTR на 0, а на более продвинутой версии DMA, как у F4, проверять CR_EN, там DMA сам выключается после передачи.

Re: STM32 HAL UART DMA

Вт фев 02, 2021 17:40:09

isx, можно проверять флаг половины передачи (DMA_ISR_HTIFx) и, пока происходит передача второй половинки буфера, заполнять первую. Ну, а как только получили TCIFx, заполняем вторую половинку, а после окончания заполнения - запускаем опять передачу.
А по приему есть смысл DMA без анализа принятых данных запускать лишь если у вас протокол подразумевает постоянную длину пакета. Да и то, нужно по таймауту все равно проверять... Другое дело - если вы обрабатываете прерывание (как в F0) по принятому символу. Тогда можно, скажем, 64 байта на буфер DMA выделить (если строки больше 63 символов не передаете), а на прием '\n' вызывать прерывание, которое остановит прием по DMA, отправит принятую строку в буфер, выставит флаг готовности и заново запустит прием.

Re: STM32 HAL UART DMA

Ср фев 03, 2021 12:04:47

Проверять CNDTR на 0, а на более продвинутой версии DMA, как у F4, проверять CR_EN, там DMA сам выключается после передачи.

Провел тесты. Поставил подряд две отправки через HAL_UART_Transmit_DMA.
Если поставить while (huart->hdmatx->Instance->CNDTR != 0){;}, (huart->hdmatx->State != HAL_DMA_STATE_READY) или (huart->TxXferCount != 0) перед HAL_UART_Transmit_DMA, то второй пакет не передается. Помогло только использование while (huart->gState != HAL_UART_STATE_READY){;}.
Это верно или я что-то не так делаю?

Добавлено after 2 minutes 26 seconds:
isx, можно проверять флаг половины передачи (DMA_ISR_HTIFx) и, пока происходит передача второй половинки буфера, заполнять первую. Ну, а как только получили TCIFx, заполняем вторую половинку, а после окончания заполнения - запускаем опять передачу.
А по приему есть смысл DMA без анализа принятых данных запускать лишь если у вас протокол подразумевает постоянную длину пакета. Да и то, нужно по таймауту все равно проверять... Другое дело - если вы обрабатываете прерывание (как в F0) по принятому символу. Тогда можно, скажем, 64 байта на буфер DMA выделить (если строки больше 63 символов не передаете), а на прием '\n' вызывать прерывание, которое остановит прием по DMA, отправит принятую строку в буфер, выставит флаг готовности и заново запустит прием.

Строки произвольной длины. А если анализировать каждый байт в прерывании, то какой тогда смысл в ДМА?

Re: STM32 HAL UART DMA

Ср фев 03, 2021 12:34:46

Если строки переменной длины и не имеют маркера окончания, по которому можно прерывание запустить, DMA на прием не нужно.

Re: STM32 HAL UART DMA

Чт фев 04, 2021 11:21:15

isx писал(а):Еще такой вопрос.
Как узнать, что все данные по ДМА были переданы и можно отправлять следующую партию в HAL_UART_Transmit_DMA?

Попробуйте
f4: while (READ_BIT(huartPtr->Instance->SR),USART_SR_TC)==0){asm("nop");}
f7: while (READ_BIT(huartPtr->Instance->ISR),USART_ISR_TC)==0){asm("nop");}

Re: STM32 HAL UART DMA

Пт фев 05, 2021 12:48:00

Если байты принимаются с паузами - можете ловить прерывание USARTx_IDLE
Как только наступает событие (с момента приёма байта прошло 9 пустых тайм-слотов) - опрашиваете DMA, считываете DMAx_ChannelY->CNDTR, записываете в VOLATILE переменную.
В основном потоке - сравниваете переменную "ДМА_ДОПИСАЛ_ДО_СЮДА", с другой переменной "Я_ДОЧИТАЛ_ДО_СЮДА". Если различаются - считаете сколько байт было принято, обновляете вторую переменную.

Вот пример кода:
Код:

uint8_t RX_BUF[128];
volatile uint8_t RX_DONE;
volatile uint16_t LastPos;

void USART1_IRQHandler(void) {
   if (USART1->SR & USART_SR_IDLE) {
      (void)USART1->DR;      // Очистка флага IDLE. Мне лично кажется такой подход странным.
      RX_DONE = 1; // Флаг, чтобы не сравнивать переменные
      LastPos = sizeof(RX_BUF) - DMA2_Stream5->NDTR; // Вычисляем позицию в буфере. NDTR считает ВНИЗ.
   };
};


Соответственно, в основном коде проверяете:
Код:
IF (RX_DONE) {
   n = (LastPos - PrevPos);
   PrevPos = LastPos;
   RX_DONE = 0;
};
Ответить