Кто любит RISC в жизни, заходим, не стесняемся.
Пн фев 01, 2021 15:42:34
Добрый день!
Не стал создавать тему ради одного вопроса, поэтому немного расширил.
Конкретно сейчас есть такая проблема - есть буфер для приема данных (массив на 100 байт) с UART по DMA в кольцевом режиме. Данные в буфер пишутся, но мне надо знать в какой элемент массива был записан последний принятый байт, а найти это не могу.
Не подскажете как решить проблему?
Пн фев 01, 2021 15:57:39
Допустим определишь ты последний байт, дальше что делать будешь?
Пн фев 01, 2021 16:04:32
В свободное время у меня проводится поллинг - если индекс последнего проверенного элемента массива меньше чем индекс последнего принятого байта, то эти байты анализируются. А дальше уже при обнаружении символа конца строки происходить определение полученной команды.
Добавлено after 1 minute 14 seconds:
На прерываниях все работало как надо, но там индекс инкрементировался в прерывании. Теперь хочу все на ДМА перевести
Пн фев 01, 2021 16:10:34
У DMA есть регистр CNDTR в который заносится количество принимаемых данных, после приема очередного байта он декрементится.
Пн фев 01, 2021 16:14:26
О, спасибо!
А я структуру когда разбирал искал в значениях количество принятых байт, а оно тут вон как, от обратного)
Вт фев 02, 2021 17:10:51
Еще такой вопрос.
Как узнать, что все данные по ДМА были переданы и можно отправлять следующую партию в HAL_UART_Transmit_DMA?
Вт фев 02, 2021 17:18:46
Проверять CNDTR на 0, а на более продвинутой версии DMA, как у F4, проверять CR_EN, там DMA сам выключается после передачи.
Вт фев 02, 2021 17:40:09
isx, можно проверять флаг половины передачи (DMA_ISR_HTIFx) и, пока происходит передача второй половинки буфера, заполнять первую. Ну, а как только получили TCIFx, заполняем вторую половинку, а после окончания заполнения - запускаем опять передачу.
А по приему есть смысл DMA без анализа принятых данных запускать лишь если у вас протокол подразумевает постоянную длину пакета. Да и то, нужно по таймауту все равно проверять... Другое дело - если вы обрабатываете прерывание (как в F0) по принятому символу. Тогда можно, скажем, 64 байта на буфер DMA выделить (если строки больше 63 символов не передаете), а на прием '\n' вызывать прерывание, которое остановит прием по 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, отправит принятую строку в буфер, выставит флаг готовности и заново запустит прием.
Строки произвольной длины. А если анализировать каждый байт в прерывании, то какой тогда смысл в ДМА?
Ср фев 03, 2021 12:34:46
Если строки переменной длины и не имеют маркера окончания, по которому можно прерывание запустить, 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");}
Пт фев 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;
};
Powered by phpBB © phpBB Group.
phpBB Mobile / SEO by Artodia.