Добрый день! Не стал создавать тему ради одного вопроса, поэтому немного расширил. Конкретно сейчас есть такая проблема - есть буфер для приема данных (массив на 100 байт) с UART по DMA в кольцевом режиме. Данные в буфер пишутся, но мне надо знать в какой элемент массива был записан последний принятый байт, а найти это не могу. Не подскажете как решить проблему?
В свободное время у меня проводится поллинг - если индекс последнего проверенного элемента массива меньше чем индекс последнего принятого байта, то эти байты анализируются. А дальше уже при обнаружении символа конца строки происходить определение полученной команды.
Добавлено after 1 minute 14 seconds: На прерываниях все работало как надо, но там индекс инкрементировался в прерывании. Теперь хочу все на ДМА перевести
Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей.
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
isx, можно проверять флаг половины передачи (DMA_ISR_HTIFx) и, пока происходит передача второй половинки буфера, заполнять первую. Ну, а как только получили TCIFx, заполняем вторую половинку, а после окончания заполнения - запускаем опять передачу. А по приему есть смысл DMA без анализа принятых данных запускать лишь если у вас протокол подразумевает постоянную длину пакета. Да и то, нужно по таймауту все равно проверять... Другое дело - если вы обрабатываете прерывание (как в F0) по принятому символу. Тогда можно, скажем, 64 байта на буфер DMA выделить (если строки больше 63 символов не передаете), а на прием '\n' вызывать прерывание, которое остановит прием по DMA, отправит принятую строку в буфер, выставит флаг готовности и заново запустит прием.
_________________ Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда. Я на гитхабе, в ЖЖ
Проверять 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){;}. Это верно или я что-то не так делаю?
isx, можно проверять флаг половины передачи (DMA_ISR_HTIFx) и, пока происходит передача второй половинки буфера, заполнять первую. Ну, а как только получили TCIFx, заполняем вторую половинку, а после окончания заполнения - запускаем опять передачу. А по приему есть смысл DMA без анализа принятых данных запускать лишь если у вас протокол подразумевает постоянную длину пакета. Да и то, нужно по таймауту все равно проверять... Другое дело - если вы обрабатываете прерывание (как в F0) по принятому символу. Тогда можно, скажем, 64 байта на буфер DMA выделить (если строки больше 63 символов не передаете), а на прием '\n' вызывать прерывание, которое остановит прием по DMA, отправит принятую строку в буфер, выставит флаг готовности и заново запустит прием.
Строки произвольной длины. А если анализировать каждый байт в прерывании, то какой тогда смысл в ДМА?
Если строки переменной длины и не имеют маркера окончания, по которому можно прерывание запустить, DMA на прием не нужно.
_________________ Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда. Я на гитхабе, в ЖЖ
Еще такой вопрос. Как узнать, что все данные по ДМА были переданы и можно отправлять следующую партию в 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");}
Если байты принимаются с паузами - можете ловить прерывание USARTx_IDLE Как только наступает событие (с момента приёма байта прошло 9 пустых тайм-слотов) - опрашиваете DMA, считываете DMAx_ChannelY->CNDTR, записываете в VOLATILE переменную. В основном потоке - сравниваете переменную "ДМА_ДОПИСАЛ_ДО_СЮДА", с другой переменной "Я_ДОЧИТАЛ_ДО_СЮДА". Если различаются - считаете сколько байт было принято, обновляете вторую переменную.
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; };
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 11
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения