62871

[i] DMA + периферийное устройство

Дата последнего изменения: 19.01.2026 17:12:50

В статье "[i] Работа с DMA в процессорах серии К1967ВНxx" были рассмотрены основные понятия и принципы работы DMA в процессорах цифровой обработки сигналов серии К1967ВНхх. Теперь рассмотрим работу связки блока прямого доступа к памяти с использованием периферийного устройства. В качестве последнего будем использовать link port. В случае с процессором К1967ВН02BG это единственный модуль периферии, и, следовательно, запросы к dma при использовании каналов на передачу (4-7) и каналов на приём (8-11), выставляет только он. У процессоров К1967ВН044 (К1967ВН04BG) периферия сильно расширена. Рассмотрим работу DMA на примере взаимодействия с всё тем же link-портом на процессоре К1967ВН044.

1. Связь каналов и запросов

В процессоре К1967ВН044 конкретному каналу DMA на приём/передачу указывается источник запроса. Для этого введены два специальных регистра DMACFGL и DMACFGH (таблица 1).

Таблица 1 - Регистр DMACFGx

Номер канала Биты DMACFGx
0 H[16].L[3:0]
1 H[17].L[7:4]
2 H[18].L[11:8]
3 H[19].L[15:12]
4 H[20].L[19:16]
5 H[21].L[23:20]
6 H[22].L[27:24]
7 H[23].L[31:28]
8 H[24].H[3:0]
9 H[25].H[7:4]
10 H[26].H[11:8]
11 H[27].H[15:12]

Рассмотрим, как работают эти регистры - необходимо в 4 бита, соответствующие определенному каналу, записать номер (источника запроса) устройства периферии, от которого DMA будет ждать запроса. Особенность состоит в том, что старший бит для каждого канала вынесен отдельно от основного поля. Ниже приведён рисунок с разбиением полей данных регистров.

Рисунок 1 - Структура регистров DMACFGx

Таким образом, к примеру, чтобы присвоить 4-му каналу источник запроса SPI0, необходимо записать номер устройства (запроса) spi0 (в соответствии с таблицей 2 номер устройства равен 3) в биты [19:16] = 011 и регистра DMACFGL и обнулить 20 бит регистра DMACFGH. Таблицы с номерами устройств в документации разделены на две: одна описывает устройства-приёмники, другая устройства- передатчики. Объединим это всё в одну таблицу, поскольку номер у каждого устройства для DMA совпадает, разница лишь в том работает устройство может работать на приём или передачу. Раздельные таблицы можно найти в спецификации.

Таблица 2 - Соответствие источника номеру запроса

Номер устройства (запроса) Обслуживаемый запрос
0 Определяется номером канала
0 – nDMAR0
1 – nDMAR1
2 – nDMAR2
3 – nDMAR3
4 - LINK 0
5 - LINK 1
6 -
7 -
8 - LINK 0
9 - LINK 1
10 -
11 -
1 UART_1
2 UART_2
3 SPI0
4 LCD/видеокамера
5 SSI0
6 SSI1
7 NANDF
8 UP/DOWN0
9 UP/DOWN1
10 UP/DOWN2
11 UP/DOWN3
12 SPI1
13 SPI2
14 H264_RQ1
15 H264_RQ0
16 Внешний запрос nDMAR[4] (каналы 4-7) или NDMAR[8] (каналы 8-11)
17 Внешний запрос nDMAR[5] (каналы 4-7) или NDMAR[9] (каналы 8-11)
18 Внешний запрос nDMAR[6] (каналы 4-7) или NDMAR[10] (каналы 8-11)
19 Внешний запрос nDMAR[7] (каналы 4-7) или NDMAR[11] (каналы 8-11)
20 Запрос 0 от таймера 0 ШИМ
21 Запрос 1 от таймера 0 ШИМ
22 Запрос 2 от таймера 0 ШИМ
23 Запрос 3 от таймера 0 ШИМ
24 Запрос 4 от таймера 0 ШИМ
25 Запрос 0 от таймера 1 ШИМ
26 Запрос 1 от таймера 1 ШИМ
27 Запрос 2 от таймера 1 ШИМ
28 Запрос 3 от таймера 1 ШИМ
29 Запрос 4 от таймера 1 ШИМ
30 Запрос от таймера 0 контроллера прерываний
31 Запрос от таймера 1 контроллера прерываний

Присвоение источника запросу конкретному каналу в HAL осуществляется с помощью следующей функции HAL_DMA_RqstSet (…)

void HAL_DMA_RqstSet( uint32_t ch_number, DMA_Requester_type dmaRqster )
{
if( ch_number < 8 )
   { *( uint32_t * ) base_DMACFGL &= ~( 0xF << ( ch_number * 4 ) );
     *( uint32_t * ) base_DMACFGH &= ~( 0x10000 << ch_number );
     *( uint32_t * ) base_DMACFGL |= ( ( dmaRqster & 0xF ) << ( ch_number * 4 ) );
     *( uint32_t * ) base_DMACFGH |= ( ( ( dmaRqster & 0x10 ) << 12 ) << ch_number );
    }
else if( ch_number <= 11 )
    { *( uint32_t * ) base_DMACFGH &= ~( 0x10000 << ch_number );
      *( uint32_t * ) base_DMACFGH |= ( ( ( dmaRqster & 0x10 ) << 12 ) << ch_number );
      ch_number *= 4;
      ch_number &= 0x1F;
      *( uint32_t * ) base_DMACFGH &= ~( 0xF << ch_number );
      *( uint32_t * ) base_DMACFGH |= ( ( dmaRqster & 0xF ) << ch_number );
    }
}

Рассмотрим пример передачи данных по link порту с использованием dma. Листинг кода приводить не будем, пример доступен в описании к библиотеке HAL. Остановимся только на важных моментах. Стоит отметить то, что сейчас будем работать с dma по принципу передачи внутренняя память→ периферия и, согласно документации, для этого нужно использовать передающие каналы DMA 4-7 и заполнять квадрослово TCB только передающей структуры DMA:

tcbTx[0] = (unsigned int) data_tx32;
tcbTx[1] = (DATA_SIZE<<16) | 4;
tcbTx[2] = 0;
tcbTx[3] = TCB_INTMEM | TCB_QUAD;

Передающую структуру разбирать особо не имеет смысла, единственное что стоит выделить, что в регистр DX в младшие разряды заносится 4, то есть адрес после каждой транзакции DMA будет увеличиваться на 4, поскольку размер данных при работе с link- портом - квадрослово, что и указывается уже в поле LEN регистра DP.

#define TCB_QUAD (0x06000000)

В качестве приёмника данных от DMA выступает передатчик link-порта. Соответственно, его необходимо связать с каналом с помощью регистров DMACFGx, как показано в пункте выше. Выставив источник периферийного запроса в DMACFGx, затем записываем управляющее квадрослово TCB, тем самым, инициируя DMA сразу приступить к отправке данных по link-порту. Таким образом, периферия выставляет запросы к DMA по классическому сценарию: пустота передатчика или наличие данных в приёмнике. 

3. Пример отправки данных по SPI с использованием DMA

Попробуем теперь воспользоваться DMA для отправки и приёма данных по SPI. На плате соединим два модуля SPI на отладочной плате. Плата, как известно, состоит из отладочного модуля и модуля процессора. В данном конкретном случае использовались:

"Модуль отладочный для микросхемы К1967ВН044" - версия 2.4.1

"Модуль процессора для микросхемы К1967ВН044" - версия 2.2

Cоединяем SPI2 в режиме Master и SPI0 в режиме Slave следующим образом:

Таблица 3 - Соединение блоков SPI0 и SPI2

Master Slave
SPI2_CS ←–> SPI0_CS1
SPI2_DI ←–> SPI0_DI
SPI2_DO ←–> SPI0_DO
SPI2_CLK ←–> SPI0_CLK

Отметим пару моментов:

1) Согласно спецификации, в режиме Slave выходом является вывод SPI_DI.

2) У SPI0 доступна до 6 адресуемых устройств в режиме ведущий, на плате CS0 занят микросхемой Flash, поэтому используем CS1.

Рисунок 2а - Соединение контроллеров SPI на отладочной плате

Рисунок 2б - выводы SPI, используемого в режиме мастера

Рисунок 2в - выводы SPI, используемого в режиме ведомого


Пример проекта доступен в HAL и в рассматриваемой статье не приводится. Обмен осуществляется между блоками с помощью готовой библиотечной функции HAL.

void HAL_SPI_DMA_SendAndReceive( SPI_type *SPI, uint32_t ulChannelRx, uint32_t *pusBuffRx, uint32_t ulChannelTx, uint32_t *pusBuffTx, uint16_t usSize )
{...}

В качестве аргументов, функции передаются следующие параметры: указатель на базовый адрес используемого блока SPI, номер принимающего канала DMA, указатель на массив принимаемых данных, номер передающего канала DMA, указатель на массив данных для передачи, размер передаваемых/принимаемых данных.


Сохранить статью в PDF

Документация

Теги

Была ли статья полезной?