Вопросы по 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, но там из массива в массив копируют данные.
UART и DMA
Модераторы: ea, dav, bkolbov, Alis, pip, _sva_
Re: UART и DMA
На этом МК не работал с DMA, но по аналогии с другой Российской компанией, которая делает МК с ядром CM3 (не называю конкурентов ).
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 (выполнение заданного числа передач).
DMA может копировать данные из перефирии в ОЗУ и наоборот.
Если DMA имеет привязку к перефирии, то (обычно) в настройках перефирии есть флаги, разрешающие использовать DMA.Надо смотреть описание. И если используется DMA, то, обычно, прерывания от данных источников запрещают.1) В описании UART сказано про сигналы DMA UART UARTRXDMABREQ и UARTRXDMACLR. Запрос блочного обмена данными и сброс запроса на DMA.Мне видимо как-то их надо задействовать. Где находится настройка DMA именно на прерывание от периферии?
Нет, сперва в управляющей структуре DMA нужно задать настройки передачи. Если примитивно, то откуда, куда, каким размером, сколько данных передавать, в каком режиме.2) Или если канал включить, то DMA сразу готов аппаратные запросы отработать?
Начну с конца. Сперва под структуры DMA выделяется буфер (можно статический), затем в регистр настройки DMA записывается адрес буфера. Теперь DMA знает, где находятся структуры управления каналами.3) Не могу понять насчет альтернативной и первичной структуры. Что это за структуры? В описании МК есть такие фразы:
"Каждому каналу DMA соответствуют две структуры управляющих данных: первичная и альтернативная. В ОЗУ должна быть отведена область для хранения этих структур." и "Базовый адрес для первичной структуры управляющих данных возможно установить
путем записи соответствующего значения в регистр CTRL_BASE_PTR."
Какой там адрес в итоге должен быть если я использую USART3 ?
Основная и альтернативная - две независимых структуры управления каналами 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 (выполнение заданного числа передач).
Re: UART и DMA
добрый день!
имею проблему с переинициализацией 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
имею проблему с переинициализацией 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
-
- Сообщения: 209
- Зарегистрирован: 14 дек 2015, 09:21
- Предприятие: АО НИИЭТ
- Откуда: АО НИИЭТ, Воронеж
Re: UART и DMA
Доброго времени суток!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