Страница 1 из 1

STM32 HAL UART DMA

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

Re: STM32 HAL UART DMA

Добавлено: Пн фев 01, 2021 15:57:39
Reflector
Допустим определишь ты последний байт, дальше что делать будешь?

Re: STM32 HAL UART DMA

Добавлено: Пн фев 01, 2021 16:04:32
isx
В свободное время у меня проводится поллинг - если индекс последнего проверенного элемента массива меньше чем индекс последнего принятого байта, то эти байты анализируются. А дальше уже при обнаружении символа конца строки происходить определение полученной команды.

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

Re: STM32 HAL UART DMA

Добавлено: Пн фев 01, 2021 16:10:34
Reflector
У DMA есть регистр CNDTR в который заносится количество принимаемых данных, после приема очередного байта он декрементится.

Re: STM32 HAL UART DMA

Добавлено: Пн фев 01, 2021 16:14:26
isx
О, спасибо!
А я структуру когда разбирал искал в значениях количество принятых байт, а оно тут вон как, от обратного)

Re: STM32 HAL UART DMA

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

Re: STM32 HAL UART DMA

Добавлено: Вт фев 02, 2021 17:18:46
Reflector
Проверять CNDTR на 0, а на более продвинутой версии DMA, как у F4, проверять CR_EN, там DMA сам выключается после передачи.

Re: STM32 HAL UART DMA

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

Re: STM32 HAL UART DMA

Добавлено: Ср фев 03, 2021 12:04:47
isx
[uquote="Reflector",url="/forum/viewtopic.php?p=3972772#p3972772"]Проверять CNDTR на 0, а на более продвинутой версии DMA, как у F4, проверять CR_EN, там DMA сам выключается после передачи.[/uquote]
Провел тесты. Поставил подряд две отправки через 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:
[uquote="Eddy_Em",url="/forum/viewtopic.php?p=3972782#p3972782"]isx, можно проверять флаг половины передачи (DMA_ISR_HTIFx) и, пока происходит передача второй половинки буфера, заполнять первую. Ну, а как только получили TCIFx, заполняем вторую половинку, а после окончания заполнения - запускаем опять передачу.
А по приему есть смысл DMA без анализа принятых данных запускать лишь если у вас протокол подразумевает постоянную длину пакета. Да и то, нужно по таймауту все равно проверять... Другое дело - если вы обрабатываете прерывание (как в F0) по принятому символу. Тогда можно, скажем, 64 байта на буфер DMA выделить (если строки больше 63 символов не передаете), а на прием '\n' вызывать прерывание, которое остановит прием по DMA, отправит принятую строку в буфер, выставит флаг готовности и заново запустит прием.[/uquote]
Строки произвольной длины. А если анализировать каждый байт в прерывании, то какой тогда смысл в ДМА?

Re: STM32 HAL UART DMA

Добавлено: Ср фев 03, 2021 12:34:46
Eddy_Em
Если строки переменной длины и не имеют маркера окончания, по которому можно прерывание запустить, DMA на прием не нужно.

Re: STM32 HAL UART DMA

Добавлено: Чт фев 04, 2021 11:21:15
rezistor2000
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
AlanDrakes
Если байты принимаются с паузами - можете ловить прерывание 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;
};