2410 DMA初始化代码导读笔记(1)

本文详细介绍了S3C2410 DMA控制器的初始化过程及关键数据结构,包括描述DMA状态的枚举类型、缓存资源状态、操作结果、控制命令等,并列举了使用DMA时可调用的主要函数。

鉴于DMA的重要性花了2天时间读了一下初始化代码,做一下相关笔记。
首先有一些重要的数据结构如下:
typedef enum {
S3C2410_DMA_IDLE, //器件空闲
S3C2410_DMA_RUNNING,//器件运行
S3C2410_DMA_PAUSED //器件暂停
} s3c2410_dma_state_t;//描述DMA器件状态

typedef enum {
S3C2410_DMALOAD_NONE //没有缓存被负载
S3C2410_DMALOAD_1LOADED,//有缓存,但没有被批准使用
S3C2410_DMALOAD_1RUNNING,//缓存被批准运行,且没有完成
S3C2410_DMALOAD_1LOADED_1RUNNING,//当前缓冲运行完后再加载其他缓存
} s3c2410_dma_loadst_t; //用于描述缓存资源状态

typedef enum {
S3C2410_RES_OK, //正常
S3C2410_RES_ERR, //错误
S3C2410_RES_ABORT //中止
} s3c2410_dma_buffresult_t;//用于描述操作结果

enum s3c2410_chan_op_e {//控制dma的操作命令
S3C2410_DMAOP_START, //启动DMA
S3C2410_DMAOP_STOP, //停止
S3C2410_DMAOP_PAUSE, //暂停
S3C2410_DMAOP_RESUME, //恢复
S3C2410_DMAOP_FLUSH, //刷新
S3C2410_DMAOP_TIMEOUT,//超时处理内部信号
};

struct s3c2410_dma_buf_s {//缓存资源描述结构数组
s3c2410_dma_buf_t *next; //下一个缓存
int magic; /* magic */
int size; //缓存大小
dma_addr_t data; //起始地址值
dma_addr_t ptr; //当前地址值
void *id; //客户端id
};

缓存传送完成后回调函数
typedef void (*s3c2410_dma_cbfn_t)(s3c2410_dma_chan_t *, void *buf, int size,
s3c2410_dma_buffresult_t result);
通道工作完成后回调函数
typedef int (*s3c2410_dma_opfn_t)(s3c2410_dma_chan_t *,s3c2410_chan_op_t );

struct s3c2410_dma_stats_s {//缓存加载统计结构体
unsigned long loads; //加载次数
unsigned long timeout_longest; //最大加载次数
unsigned long timeout_shortest;//最短加载次数
unsigned long timeout_avg; //等待累积次数
unsigned long timeout_failed; //失败次数
};

DMA通道描述结构体,4个通道结构体存放在全局数组s3c2410_chans[S3C2410_DMA_CHANNELS]中:
struct s3c2410_dma_chan_s {
unsigned char number; //通道数
unsigned char in_use; //通道已使用标志
unsigned char irq_claimed; //中断声明
unsigned char irq_enabled; //中断使能
unsigned char xfer_unit; //一次传送大小(1或4字节)

s3c2410_dma_state_t state; //dma器件工作状态空闲 运行 暂停
s3c2410_dma_loadst_t load_state; //用于描述缓存加载状态
s3c2410_dma_client_t *client; //该通道上的某客户端

/* channel configuration */
s3c2410_dmasrc_t source; //操作设备类型描述
unsigned long dev_addr; //操作设备物理地址
unsigned long load_timeout; //装载益处时间
unsigned int flags; //标志自动启动或是慢速启动

/* channel's hardware position and configuration */
void __iomem *regs; //通道初始源地址寄存器
void __iomem *addr_reg; //通道初始目的地地址寄存器
unsigned int irq; //通道中断号
unsigned long dcon; //DCON默认值

/* driver handles */
s3c2410_dma_cbfn_t callback_fn; //缓存数据完成后回调函数
s3c2410_dma_opfn_t op_fn; //通道完成后回调函数

/* stats gathering */
s3c2410_dma_stats_t *stats; //指向stats_store成员指针用于描述加载信息
s3c2410_dma_stats_t stats_store;

/* buffer list and information */
s3c2410_dma_buf_t *curr; //目前缓存链表指针
s3c2410_dma_buf_t *next; //下一个待处理链表指针
s3c2410_dma_buf_t *end; //结束处缓存指针

/* system device */
struct sys_device dev; //dma是作为class目录中设备来使用的
};

在使用DMA时可以调用配置DMA的函数如下:
int s3c2410_dma_enqueue(dmach_t channel,s3c2410_dma_client_t *, void *dev);
id 器件驱动的ID信息
data 希望传送数据的物理地址
size 希望传送数据的尺寸大小
此函数用来为传送地址建立一个缓存结构(struct s3c2410_dma_buf_s)。

int s3c2410_dma_request(unsigned int channel, s3c2410_dma_client_t *client,void *dev)
即将某DMA通道上支持的期间作为客户端配置为其添加中断处理功能。

int s3c2410_dma_free(dmach_t channel, s3c2410_dma_client_t *client)
停止DMA后释放客户端占用的中断资源。

int s3c2410_dma_ctrl(dmach_t channel, s3c2410_chan_op_t op)
控制DMA函数有如下一些命令:
S3C2410_DMAOP_START://启动DMA
S3C2410_DMAOP_STOP://停止DMA
S3C2410_DMAOP_PAUSE://暂停
S3C2410_DMAOP_RESUME://恢复
S3C2410_DMAOP_TIMEOUT://超时处理内部信号
S3C2410_DMAOP_FLUSH://停止DMA且释放通道上的传送缓存

int s3c2410_dma_config(dmach_t channel,int xferunit,int dcon)
xfersize:传送单元大小(1,2,4)字节
dcon: DCONx的基础配置值
配置传送尺寸 使能中断和硬件触发DMA功能

int s3c2410_dma_setflags(dmach_t channel, unsigned int flags)
设置标志位

int s3c2410_dma_set_opfn(dmach_t channel, s3c2410_dma_opfn_t rtn)
设置通道完成后回调函数

int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn)
设置缓存数据完成后回调函数

int s3c2410_dma_devconfig(int channel,s3c2410_dmasrc_t source,int hwcfg,
unsigned long devaddr)
设置外设种类 配置值 外设物理首地址

int s3c2410_dma_getposition(dmach_t channel, dma_addr_t *src, dma_addr_t *dst)
获取当前传送指针的源地址和目的地地址

### 关于DMA初始化代码示例 以下是基于STM32微控制器的DMA初始化代码示例,该代码展示了如何配置DMA以实现数据从SRAM到外设的传输: ```c #include "stm32f4xx.h" void DMA_Init(void) { // 启用DMA时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); // 配置DMA通道 DMA_InitTypeDef DMA_InitStruct; // 填充结构体参数 DMA_StructInit(&DMA_InitStruct); DMA_InitStruct.DMA_PeripheralBaseAddr = 0xFFFF; // 设置目标寄存器地址 [^1] DMA_InitStruct.DMA_Memory0BaseAddr = 0x0000; // 要转移的数据的第一个地址 [^1] DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral; // 数据传输方向 SRAM -> 外设 [^1] DMA_InitStruct.DMA_BufferSize = 10000; // 数组大小 [^1] DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设地址不增加 [^1] DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; // 内存地址自动递增 DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; // 循环模式 (适用于双缓冲区切换功能) [^3] DMA_InitStruct.DMA_Priority = DMA_Priority_High; // 初始化DMA通道 DMA_Init(DMA1_Channel5, &DMA_InitStruct); // 启用DMA通道 DMA_Cmd(DMA1_Channel5, ENABLE); } ``` 上述代码实现了基本的DMA初始化过程。其中设置了`DMA_PeriAddr`为目标寄存器地址,`DMA_SramAddr`为源内存地址,并启用了循环模式以便支持硬件双缓冲区切换功能。 --- ### STM32串口DMA发送与接收的具体说明 对于更复杂的场景,例如通过串口使用DMA进行数据发送和接收,可以参考以下扩展功能描述。当涉及硬件双缓冲区切换时,需特别注意以下几点: - **定长接收**:只有接收到指定数量的数据后才会触发中断 。 - **循环模式**:为了支持连续数据流处理,DMA应始终工作在循环模式下 。 #### 扩展代码示例:串口DMA发送 ```c void UART_DMA_Send(uint8_t* pData, uint16_t Size) { USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE); // 启用UART TX DMA请求 DMA_SetCurrDataCounter(DMA1_Stream6, Size); // 设置DMA传输计数器 DMA_MemoryTargetAddress(DMA1_Stream6, pData); // 设置DMA内存基址 DMA_Cmd(DMA1_Stream6, ENABLE); // 启动DMA传输 } // 中断服务程序用于监控完成状态 void DMA1_Stream6_IRQHandler(void) { if (DMA_GetITStatus(DMA1_Stream6, DMA_IT_TCIF6)) { // 检查传输完成标志位 DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_TCIF6); // 清除标志位 // 用户定义的操作... } } ``` 此部分代码演示了如何利用DMA配合串口进行高效的数据发送操作。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值