直接内存访问(DMA)¶
1、简介¶
DMA(Direct Memory Access,直接内存访问)是一种不经过CPU而直接进行内存数据存取的技术。DMA方式通过硬件为RAM与I/O设备开辟一条直接传送数据的通路,使CPU在数据传送期间不必干预,从而大幅减轻CPU的负担。
CI14LP芯片内置2通道通用DMA控制器(DMA_CHANNEl_0、DMA_CHANNEl_1),特性包括:
- 支持 M2M(内存到内存)、M2P(内存到外设)、P2M(外设到内存)、P2P(外设到外设)四种传输方向
- 支持8/16/32bit传输宽度、1~256突发长度(burst)
- 支持源/目的地址递增控制
- 支持链表(LLI)传输模式
- 支持传输完成、链表传输、传输错误三类中断
- 支持FLASH专用DMA通道配置
支持的外设请求源:
| 外设 | 说明 |
|---|---|
| DMA_PERIPHERAL_FLASH | FLASH专用SPI |
| DMA_PERIPHERAL_SPI_TX / SPI_RX | 通用SPI收/发 |
| DMA_PERIPHERAL_UART0/½_RX / TX | 三路UART收/发 |
| DMA_PERIPHERAL_I2C0/1_RX / TX | 两路IIC收/发 |
2、API¶
2.1 通道使能与状态¶
| 函数名 | 描述 |
|---|---|
| dma_en | DMA控制器使能/关闭 |
| dma_channel_enable | DMA通道使能 |
| dma_channel_disable | DMA通道关闭 |
| dma_channel_enable_status | 查询通道使能状态 |
| dma_channel_halt | DMA通道暂停/恢复 |
| dma_channel_left_transfer_size | 查询通道剩余传输数据量 |
| dma_clear_translate_flag | 清除传输完成标志 |
| dma_wait_translate_flag | 等待传输完成(超时参数) |
| dma_irq_handler | DMA中断处理函数(驱动内部实现) |
2.2 通道配置¶
| 函数名 | 描述 |
|---|---|
| dma_channel_source_addr | 设置源地址 |
| dma_channel_dest_addr | 设置目的地址 |
| dma_channel_source_config | 源端配置(递增/master/宽度/突发长度) |
| dma_channel_dest_config | 目的端配置(递增/master/宽度/突发长度) |
| dma_channel_transfer_size | 设置传输数据量 |
| dma_channel_flowctrl_config | 通道流控配置(外设方向+流控类型) |
| dma_master_endianmode_config | master字节序配置(大端/小端) |
2.3 组合传输配置¶
| 函数名 | 描述 |
|---|---|
| dma_m2m_mode_config | 内存到内存传输配置 |
| dma_m2p_p2m_mode_config | 内存到外设/外设到内存传输配置 |
| dma_p2p_mode_config | 外设到外设传输配置 |
| dma_lli_mode_config | 链表(LLI)模式传输配置 |
| dma_lli_master_sel | 链表master选择 |
| dma_set_lli_control / dma_get_lli_control_value | 链表控制寄存器配置/生成 |
2.4 中断¶
| 函数名 | 描述 |
|---|---|
| dma_channel_irq_mask_config | 通道中断屏蔽配置(完成/链表/错误) |
| dma_get_irq_raw_status | 获取原始中断状态 |
| dma_get_irq_mask_status | 获取屏蔽后中断状态 |
| dma_clear_irq | 清除中断标志 |
3、关键类型¶
| 类型 | 说明 |
|---|---|
| dma_channel_t | 通道选择:DMA_CHANNEl_0、DMA_CHANNEl_1、DMA_CHANNEl_ALL |
| dma_ahb_master_t | AHB master接口:DMA_AHB_MASTER_1、DMA_AHB_MASTER_2 |
| dma_endian_mode_t | 字节序:LITTLE_ENDIAN_MODE、BIG_ENDIAN_MODE |
| dma_increment_t | 地址递增:INCREMENT、NOINCREMENT |
| dma_transfer_width_t | 传输宽度:TRANSFER_WIDTH_8B、16B、32B |
| dma_burst_size_t | 突发长度:BURST_SIZE_1、4、8、16、32、64、128、256 |
| dma_irq_t | 中断类型:DMA_IRQ_TRANS_DONE(传输完成)、DMA_IRQ_LLI_TRANS_DONE(链表传输)、DMA_IRQ_ERROR(传输错误) |
| dma_flowctrl_t | 传输方向:M2M_DMA、M2P_DMA、P2M_DMA、P2P_DMA |
| dma_peripheral_t | 外设请求源:FLASH、SPI、UART0/½、I2C0/1的RX/TX |
| dma_lli_config_t | 链表配置结构体(源/目的递增、master、宽度、突发、单次传输大小) |
| dma_lli_transfer_t | 链表传输结构体(源地址、目的地址、下一链表地址、控制值) |
| dma_callback_func_ptr_t | DMA完成回调函数指针 |
4、示例¶
1) 以下代码使用DMA完成内存到内存的数据搬运:
#include "ci14lp_dma.h"
uint32_t src_buf[256] = {0};
uint32_t dst_buf[256] = {0};
void dma_m2m_demo(void)
{
int i;
for (i = 0; i < 256; i++)
{
src_buf[i] = i;
}
//配置通道0:内存到内存搬运,搬运1024字节
dma_m2m_mode_config(DMA_CHANNEl_0, (uint32_t)src_buf,
(uint32_t)dst_buf, 256 * 4, DMA_AHB_MASTER_1);
//启动通道
dma_channel_enable(DMA_CHANNEl_0);
//等待搬运完成
if (RETURN_ERR == dma_wait_translate_flag(DMA_CHANNEl_0, 0xffffff))
{
mprintf("dma transfer err\n");
}
}
2) 以下代码使用DMA配合UART0完成发送(内存到外设):
#include "ci14lp_dma.h"
#include "ci14lp_uart.h"
unsigned char buf_send[2048] = {0};
void uart_dma_send_demo(void)
{
//初始化UART0(DMA模式)
uart_dma_config(UART0, 115200, UART_DMAWIDTH_BYTE);
//DMA发送数据(内存到外设)
dma_m2p_p2m_mode_config(DMA_CHANNEl_0, DMA_PERIPHERAL_UART0_TX, M2P_DMA,
(uint32_t)buf_send, UART0_DMA_ADDR, 2048,
TRANSFER_WIDTH_8B, BURST_SIZE_1, DMA_AHB_MASTER_1);
//等待DMA传输完成
dma_wait_translate_flag(DMA_CHANNEl_0, 0xffffff);
}
3) 以下代码以链表(LLI)模式进行分段搬运:
#include "ci14lp_dma.h"
#define LLI_NUM (3)
dma_lli_transfer_t lli_buf[LLI_NUM] __attribute__((aligned(4)));
void dma_lli_demo(void)
{
//配置3段链表,每段独立源/目的地址
lli_buf[0].src_addr = (uint32_t)src_buf;
lli_buf[0].dest_addr = (uint32_t)dst_buf;
lli_buf[0].next_lli_addr = (uint32_t)&lli_buf[1];
lli_buf[0].control_value = dma_get_lli_control_value(...);
//...依次配置lli_buf[1]、lli_buf[2],最后一段next_lli_addr为0
dma_lli_mode_config(DMA_CHANNEl_0, lli_buf, DMA_AHB_MASTER_1);
dma_channel_enable(DMA_CHANNEl_0);
}
5、其它¶
- 突发传输(burst)不能跨越1KB地址边界,通常设置为外设FIFO大小的一半。
- 传输数据量(transfer_size)以传输宽度为单位,如8bit宽度时1024表示1024字节。
- 同一DMA通道同一时刻只能服务一个外设,多外设并发需求请合理分配DMA_CHANNEl_0/1。
- 音频IIS通路使用独立的IISDMA(见外设API-IIS),不占用通用DMA通道资源。
6、API 参考¶
本模块接口声明于 driver\ci14lp_chip_driver\inc\ci14lp_dma.h,实现位于 driver\ci14lp_chip_driver\src\ci14lp_dma.c。