|
Информационный портал технической поддержки Центра проектирования интегральных микросхем |
В статье "[i] Работа с DMA в процессорах серии К1967ВНxx" были рассмотрены основные понятия и принципы работы DMA в процессорах цифровой обработки сигналов серии К1967ВНхх. Теперь рассмотрим работу связки блока прямого доступа к памяти с использованием периферийного устройства. В качестве последнего будем использовать link port. В случае с процессором К1967ВН02BG это единственный модуль периферии, и, следовательно, запросы к dma при использовании каналов на передачу (4-7) и каналов на приём (8-11), выставляет только он. У процессоров К1967ВН044 (К1967ВН04BG) периферия сильно расширена. Рассмотрим работу DMA на примере взаимодействия с всё тем же link-портом на процессоре К1967ВН044.
В процессоре К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 по классическому сценарию: пустота передатчика или наличие данных в приёмнике.
Попробуем теперь воспользоваться 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, указатель на массив данных для передачи, размер передаваемых/принимаемых данных.
| Сайт: | https://support.milandr.ru |
| E-mail: | support@milandr.ru |
| Телефон: | +7 495 221-13-55 |