UART и DMA

32-разрядные микроконтроллеры разработки АО "НИИЭТ"

Модераторы: dav, bkolbov, Alis, pip, _sva_, dav, bkolbov, Alis, pip, _sva_, dav, bkolbov, Alis, pip, _sva_

Ответить
ezlydnev
Сообщения: 10
Зарегистрирован: 11 фев 2021, 11:50
Предприятие: НИИИТ-РК

UART и DMA

Сообщение ezlydnev » 18 фев 2022, 12:26

Вопросы по 1921ВК01Т.

Хочу использовать DMA при работе с UART. В частности UART 3.
Задача принять данные по UART. После принятия посылки переписать данные в массив с помощью DMA.
Собственно вопросы:
1) В описании UART сказано про сигналы DMA UART UARTRXDMABREQ и UARTRXDMACLR. Запрос блочного обмена данными и сброс запроса на DMA.
Мне видимо как-то их надо задействовать.
Что это за сигналы, где они находятся? В каком регистре? В K1921VK01T.h не нашел.
2) Где находится настройка DMA именно на прерывание от периферии? Или если канал включить, то DMA сразу готов аппаратные запросы отработать?
3) Не могу понять насчет альтернативной и первичной структуры. Что это за структуры? В описании МК есть такие фразы:
"Каждому каналу DMA соответствуют две структуры управляющих данных: первичная и альтернативная. В ОЗУ должна быть отведена область для хранения этих структур." и "Базовый адрес для первичной структуры управляющих данных возможно установить
путем записи соответствующего значения в регистр CTRL_BASE_PTR."
Какой там адрес в итоге должен быть если я использую USART3 ?
4) В прерываниях USART 3 есть тайм аут приемника. Судя по описанию для dma он не формирует такое прерывание ? То есть можно настроить так чтобы dma начинал копировать данные из FIFO в массив когда наступил таймаут приемника, и заканчивал когда полностью его опустошил?
5) Есть возможно какой-то пример с подобным функционалом? Желательно без использования библиотек. Хочу детальнее разобраться.
Видел в sdk как используют dma, но там из массива в массив копируют данные.

редактор
Сообщения: 25
Зарегистрирован: 08 ноя 2016, 09:10

Re: UART и DMA

Сообщение редактор » 21 фев 2022, 12:12

На этом МК не работал с DMA, но по аналогии с другой Российской компанией, которая делает МК с ядром CM3 (не называю конкурентов ;) ).
DMA может копировать данные из перефирии в ОЗУ и наоборот.
1) В описании UART сказано про сигналы DMA UART UARTRXDMABREQ и UARTRXDMACLR. Запрос блочного обмена данными и сброс запроса на DMA.Мне видимо как-то их надо задействовать. Где находится настройка DMA именно на прерывание от периферии?
Если DMA имеет привязку к перефирии, то (обычно) в настройках перефирии есть флаги, разрешающие использовать DMA.Надо смотреть описание. И если используется DMA, то, обычно, прерывания от данных источников запрещают.
2) Или если канал включить, то DMA сразу готов аппаратные запросы отработать?
Нет, сперва в управляющей структуре DMA нужно задать настройки передачи. Если примитивно, то откуда, куда, каким размером, сколько данных передавать, в каком режиме.
3) Не могу понять насчет альтернативной и первичной структуры. Что это за структуры? В описании МК есть такие фразы:
"Каждому каналу DMA соответствуют две структуры управляющих данных: первичная и альтернативная. В ОЗУ должна быть отведена область для хранения этих структур." и "Базовый адрес для первичной структуры управляющих данных возможно установить
путем записи соответствующего значения в регистр CTRL_BASE_PTR."
Какой там адрес в итоге должен быть если я использую USART3 ?
Начну с конца. Сперва под структуры DMA выделяется буфер (можно статический), затем в регистр настройки DMA записывается адрес буфера. Теперь DMA знает, где находятся структуры управления каналами.
Основная и альтернативная - две независимых структуры управления каналами DMA. Для каждого канала свой набор структур. То есть в ОЗУ выделяется память, в которой находятся "виртуальные регистры" управления каналом DMA
Когда в UART будет сформирован запрос на передачу (буфер пуст или FIFO ниже заданного порога) - должен сформироваться запрос к модулю DMA на пересылку указанного числа байт из адреса источника DMA в адрес приемника DMA. Адрес источника - это буфер ОЗУ откуда брать данные, адрес приемника - регистр передачи UART.
При приеме данных - ситуация аналогична. При заполнениии входного регистраили превышении уровня FIFO премника формируется запрос к DMA на пересылку данных. Но в этом случае адрес источника - регистр данных UART, адрес приемника - буфер ОЗУ.
Запрос от UART будет направлен "привязанному" каналу управления модулем DMA/
В описании МК другой фирмы модуль ДМА тоже расписан не лучшим образом, но у них есть дополнительные статьи с описанием, советую посмотреть для лучшего понимания.

Если вы хоттие сделать связку DMA-UART тогда вам надо.
1. Выделить память под структуры управления DMA (как мимнимум под основные).
2. Указать модулю DMA адрес структуры.
3. Проинициализировать основную структуру, которая "привязана" к модулю UART.
4. Проинициализировать модуль UART и разрешить в нем работу через DMA.
5. Включить канал DMA.
Контролировать завершение цикла DMA (выполнение заданного числа передач).

avsmirnov
Сообщения: 1
Зарегистрирован: 18 апр 2022, 13:11
Предприятие: НИЦ БУЛАТ

Re: UART и DMA

Сообщение avsmirnov » 18 апр 2022, 13:18

добрый день!

имею проблему с переинициализацией UART-DMA после завершения первого цикла передачи
после приема и заполнения буфера прерывание DMA срабатывает успешно и вроде как запускает новый цикл. но после приема одного символа прерывание вновь срабатывает и зацикливается
прошу помочь.

код инициализации:

static void UART1_DMA_Init( void )
{
DMA_Init_TypeDef DMA_InitStruct;
DMA_ChannelInit_TypeDef DMA_ChannelInitStruct;

/* Базовый указатель */
DMA_BasePtrConfig( (uint32_t)( &DMA_CONFIGDATA ) );

/* Инициализация контроллера DMA */
DMA_StructInit( &DMA_InitStruct );
DMA_InitStruct.DMA_Channel = DMA_Channel_UART1_RX | DMA_Channel_UART1_TX;
DMA_InitStruct.DMA_ChannelEnable = ENABLE;
DMA_Init( &DMA_InitStruct );
DMA_MasterEnableCmd( ENABLE );

/* Инициализация канала DMA5 - UART1 RX */
DMA_ChannelStructInit( &DMA_ChannelInitStruct );
DMA_ChannelInitStruct.DMA_SrcDataSize = DMA_DataSize_8;
DMA_ChannelInitStruct.DMA_DstDataSize = DMA_DataSize_8;
DMA_ChannelInitStruct.DMA_TransfersTotal = RS485_RX_BUFFER_SIZE;
DMA_ChannelInitStruct.DMA_Mode = DMA_Mode_Basic;
DMA_ChannelInitStruct.DMA_SrcDataInc = DMA_DataInc_Disable;
DMA_ChannelInitStruct.DMA_DstDataInc = DMA_DataInc_8;
DMA_ChannelInitStruct.DMA_SrcDataEndPtr = (uint32_t*) (&NT_UART1->DR);
DMA_ChannelInitStruct.DMA_DstDataEndPtr = &(RxBuffer.buffer[RS485_RX_BUFFER_SIZE - 1]);
DMA_ChannelInit( &DMA_CONFIGDATA.PRM_DATA.CH[5], &DMA_ChannelInitStruct );
UART_DMACmd( NT_UART1, UART_Dir_Rx, ENABLE );

Энвик_SetPriority( DMA_Stream5_IRQn, Энвик_EncodePriority( Энвик_GetPriorityGrouping(), 4, 0 ) );
Энвик_EnableIRQ( DMA_Stream5_IRQn );

return;
} //UART1_DMA_Init

обработчик прерывания:

void DMA_Stream5_IRQHandler()
{
/* запустить заново */
UART_DMACmd( NT_UART1, UART_Dir_Rx, DISABLE ); // стоп

/* перенициализация канала DMA5 - UART1 RX */
DMA_ChannelDeInit( &DMA_CONFIGDATA.PRM_DATA.CH[5] );

DMA_ChannelInit_TypeDef DMA_ChannelInitStruct;
DMA_ChannelStructInit( &DMA_ChannelInitStruct );
DMA_ChannelInitStruct.DMA_SrcDataSize = DMA_DataSize_8;
DMA_ChannelInitStruct.DMA_DstDataSize = DMA_DataSize_8;
DMA_ChannelInitStruct.DMA_TransfersTotal = RS485_RX_BUFFER_SIZE;
DMA_ChannelInitStruct.DMA_Mode = DMA_Mode_Basic;
DMA_ChannelInitStruct.DMA_SrcDataInc = DMA_DataInc_Disable;
DMA_ChannelInitStruct.DMA_DstDataInc = DMA_DataInc_8;
DMA_ChannelInitStruct.DMA_SrcDataEndPtr = (uint32_t*) (&NT_UART1->DR);
DMA_ChannelInitStruct.DMA_DstDataEndPtr = &(RxBuffer.buffer[RS485_RX_BUFFER_SIZE - 1]);
DMA_ChannelInit( &DMA_CONFIGDATA.PRM_DATA.CH[5], &DMA_ChannelInitStruct );
UART_DMACmd( NT_UART1, UART_Dir_Rx, ENABLE );

return;
} //DMA_Stream5_IRQHandler

dav
Сообщения: 134
Зарегистрирован: 14 дек 2015, 09:21
Предприятие: АО НИИЭТ
Откуда: АО НИИЭТ, Воронеж

Re: UART и DMA

Сообщение dav » 18 апр 2022, 17:12

avsmirnov писал(а):
18 апр 2022, 13:18
добрый день!

имею проблему с переинициализацией UART-DMA после завершения первого цикла передачи
после приема и заполнения буфера прерывание DMA срабатывает успешно и вроде как запускает новый цикл. но после приема одного символа прерывание вновь срабатывает и зацикливается
прошу помочь.
Доброго времени суток!
Для периинициализации каналов DMA необходимо выключить DMA, сбросив бит MASTEREN в регистре CFG, а затем включить, установив бит MASTEREN в регистре CFG, чтобы обновить управляющие структуры DMA.

Более правильный подходит для изменения настроек передач DMA заключается в выборе не основного режима канала, а, например, режима "сборка-разборка". Тогда первичная структура будет хранить настройки для конфигурации альтернативной структуры, по которой будет выполняться основной цикл обмена DMA.

В случае использования основного режима обработчик прерывания должен быть следующим:

Код: Выделить всё

void DMA_Stream5_IRQHandler()
{
  /* запустить заново */
  UART_DMACmd( NT_UART1, UART_Dir_Rx, DISABLE );            // стоп

  /* перенициализация канала DMA5 - UART1 RX */
  DMA_ChannelDeInit( &DMA_CONFIGDATA.PRM_DATA.CH[5] );

  DMA_ChannelInit_TypeDef   DMA_ChannelInitStruct;
  DMA_ChannelStructInit( &DMA_ChannelInitStruct );
  DMA_ChannelInitStruct.DMA_SrcDataSize = DMA_DataSize_8;
  DMA_ChannelInitStruct.DMA_DstDataSize = DMA_DataSize_8;
  DMA_ChannelInitStruct.DMA_TransfersTotal = RS485_RX_BUFFER_SIZE;
  DMA_ChannelInitStruct.DMA_Mode = DMA_Mode_Basic;
  DMA_ChannelInitStruct.DMA_SrcDataInc = DMA_DataInc_Disable;
  DMA_ChannelInitStruct.DMA_DstDataInc = DMA_DataInc_8;
  DMA_ChannelInitStruct.DMA_SrcDataEndPtr = (uint32_t*) (&NT_UART1->DR);
  DMA_ChannelInitStruct.DMA_DstDataEndPtr = &(RxBuffer.buffer[RS485_RX_BUFFER_SIZE - 1]);
  DMA_ChannelInit( &DMA_CONFIGDATA.PRM_DATA.CH[5], &DMA_ChannelInitStruct );
  
  DMA_MasterEnableCmd( DISABLE );
  DMA_MasterEnableCmd( ENABLE );
  UART_DMACmd( NT_UART1, UART_Dir_Rx, ENABLE );

  return;
} //DMA_Stream5_IRQHandler

Ответить

Вернуться в «32-разрядные микроконтроллеры»

Пользователи онлайн

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость