高级会员
- 积分
- 500
- 威望
- 391
- 贡献
- 79
- 兑换币
- 11
- 注册时间
- 2011-3-17
- 在线时间
- 15 小时
|
8#
楼主 |
发表于 2012-6-12 00:27:10
|
只看该作者
#include "common.h"
#include "HAL_eDMA.h"
DMA_ISR_CALLBACK DMA_ISR[16];
/*
* LPLD_DMA_Init
* DMA模块通用初始化函数--用于源地址到目的地址之间的数据直接传输(不用通过CPU)
* 详细参数在LPLD_eDMA_Cfg_t 结构体中定义(在HAL_eDMA.h)头文件中定义
*/
uint8_t LPLD_DMA_Init(LPLD_eDMA_Cfg_t *DMA_Config)
{
//如果用户没有设置 每一次传输字节的个数 默认为每次传输一个字节
if(DMA_Config->Trans_bytesNum == NULL)
{
DMA_Config->Trans_bytesNum =1;
}
//如果用户没有设置 源地址增加 默认为执行一次DMA请求后源地址不增加
if(DMA_Config->Source_Addr_inc == NULL)
{
DMA_Config->Source_Addr_inc =ADDR_HOLD; //源地址不增加
}
//如果用户没有设置 源数据长度 默认为8位数据长度
if(DMA_Config->Source_Size ==NULL)
{
DMA_Config->Source_Size =DMA_SRC_8BIT; //源数据宽度8bit 一个字节
}
//如果用户没有设置 主循环计数器完成以后 源地址是否调整 默认为设置为源地址不调整
if(DMA_Config->Source_Adj_Addr ==NULL)
{
DMA_Config->Source_Adj_Addr =0;
}
//如果用户没有设置 目的地址增加 默认为执行一次DMA请求后目的地址加一
if(DMA_Config->Dest_Addr_inc ==NULL)
{
DMA_Config->Dest_Addr_inc =ADDR_INCREASE; //针对目的地址的操作执行完毕后加1
}
//如果用户没有设置 源数据长度 默认为8位数据长度
if(DMA_Config->Dest_Size ==NULL)
{
DMA_Config->Dest_Size =DMA_DST_8BIT; //目的数据宽度8bit 一个字节
}
//如果用户没有设置 主循环计数器完成以后 目的地址是否调整 默认为设置为目的地址不调整
if(DMA_Config->Dest_Adj_Addr ==NULL)
{
DMA_Config->Dest_Adj_Addr =0;
}
//如果用户没有设置 中断模式 默认关闭中断
if(DMA_Config->Dma_irqc ==NULL)
{
DMA_Config->Dma_irqc =0; //关闭中断
}
//如果用户没有设置 DMA自动关闭方式 默认开启主循环计数器减为0自动关闭DMA功能
if(DMA_Config->Dma_AutoClose ==NULL)
{
DMA_Config->Dma_AutoClose =0; //开启主循环计数器减为0自动关闭DMA功能
}
if(DMA_Config->isr_func!=NULL)
{
DMA_ISR[DMA_Config->Channelx] = DMA_Config->isr_func;
//在NVIC中使能DMA中断
enable_irq(DMA_Config->Channelx);
}
//配置DMA寄存器
return LPLD_eDMA_Config(DMA_Config);
}
uint8_t LPLD_eDMA_Config(LPLD_eDMA_Cfg_t *DMA_Config)
{
//=====配置eDMA模块时钟===========
SIM_SCGC6|=SIM_SCGC6_DMAMUX_MASK; //打开DMA通道多路复用器时钟
SIM_SCGC7|=SIM_SCGC7_DMA_MASK; //打开DMA模块时钟
//================================
if(DMA_Config->Channelx>15)
{
return 0;
}
else
{
//选择 通道x 配置外设的DMA source requestNumber
DMAMUX_BASE_PTR->CHCFG[DMA_Config->Channelx]=DMAMUX_CHCFG_SOURCE(DMA_Config->Peri_DmaReq);
}
/*设置源地址信息*/
//设置源地址
DMA_BASE_PTR->TCD[DMA_Config->Channelx].SADDR=DMA_Config->Source_Addr;
//在执行完针对源地址的操作之后,是否在原地址的基础上累加
DMA_BASE_PTR->TCD[DMA_Config->Channelx].SOFF =DMA_Config->Source_Addr_inc;
//先清零数据长度寄存器
DMA_BASE_PTR->TCD[DMA_Config->Channelx].ATTR=0;
//设置源地址的传输宽度
DMA_BASE_PTR->TCD[DMA_Config->Channelx].ATTR |=DMA_Config->Source_Size;
//主的计数次数(major iteration count)达到后,是否重新更改源地址
DMA_BASE_PTR->TCD[DMA_Config->Channelx].SLAST =DMA_Config->Source_Adj_Addr;
/*设置目的地址信息*/
//设置目的地址
DMA_BASE_PTR->TCD[DMA_Config->Channelx].DADDR=DMA_Config->Dest_Addr;
//在执行完针对目的地址的操作之后,是否在原地址的基础上累加
DMA_BASE_PTR->TCD[DMA_Config->Channelx].DOFF =DMA_Config->Dest_Addr_inc;
//设置源地址的传输宽度
DMA_BASE_PTR->TCD[DMA_Config->Channelx].ATTR |=DMA_Config->Dest_Size;
//主的计数次数(major iteration count)达到后,是否重新更改目的地址
DMA_BASE_PTR->TCD[DMA_Config->Channelx].DLAST_SGA =DMA_Config->Dest_Adj_Addr;
if(DMA_Config->Minor_loop_Length>32767) //主循环计数器的次数在0---32767之间
{
return 0;
}
else
{
//===============设置主计数器长度,循环次数====================================
//设置数据长度,长度每次递减。也可以称为 当前主循环计数器 current major loop count
DMA_BASE_PTR->TCD[DMA_Config->Channelx].CITER_ELINKNO=DMA_CITER_ELINKNO_CITER(DMA_Config->Minor_loop_Length);
//起始循环计数器,当主循环计数器为零的时候,将装载起始循环计数器的值
DMA_BASE_PTR->TCD[DMA_Config->Channelx].BITER_ELINKNO=DMA_CITER_ELINKNO_CITER(DMA_Config->Minor_loop_Length);
//设置每一次传输字节的个数,个数达到上限时,DMA便将数据存入memory
DMA_BASE_PTR->TCD[DMA_Config->Channelx].NBYTES_MLNO=DMA_NBYTES_MLNO_NBYTES(DMA_Config->Trans_bytesNum);
}
//============设置DMA TCD控制寄存器==========================//
DMA_BASE_PTR->TCD[DMA_Config->Channelx].CSR =0; //清空CSR的设置
//===========设置DMA中断===================================//
if(!DMA_Config->Dma_irqc)
{
DMA_INT &=~(1<<DMA_Config->Channelx); //关闭相应通道的中断请求
}
else if(DMA_Config->Dma_irqc==1)
{
DMA_INT |=(1<<DMA_Config->Channelx); //开启相应通道的中断请求
DMA_BASE_PTR->TCD[DMA_Config->Channelx].CSR |=DMA_CSR_INTHALF_MASK;//使能DMA 主循环计数器减到一半 中断
}
else if(DMA_Config->Dma_irqc==2)
{
DMA_INT |=(1<<DMA_Config->Channelx); //开启相应通道的中断请求
DMA_BASE_PTR->TCD[DMA_Config->Channelx].CSR |=DMA_CSR_INTMAJOR_MASK;//使能DMA 主循环计数器减到零 中断
}
if(!DMA_Config->Dma_AutoClose)
{
DMA_BASE_PTR->TCD[DMA_Config->Channelx].CSR |=DMA_CSR_DREQ_MASK; //主循环计数器等于零后,自动关闭DMA
}
else
{
DMA_BASE_PTR->TCD[DMA_Config->Channelx].CSR &=(~DMA_CSR_DREQ_MASK); //主循环计数器等于零后,不关闭DMA
}
//注:使能此寄存器DMA开始工作
//关闭通道x硬件DMA请求
DMA_ERQ&=~(1<<DMA_Config->Channelx);
//DMA通道使能
DMAMUX_BASE_PTR->CHCFG[DMA_Config->Channelx]|=DMAMUX_CHCFG_ENBL_MASK;
return 1;
}
/*
* LPLD_DMA_Start
* 此函数根据isEnable的值,开启或关闭通道x的DMA请求,
* 一旦开启通道x的DMA请求,DMA模块就开始工作
*
* 参数:
* ChxNum--DMA通道值 一共16个DMA通道
* |__0 DMA_Channel_0
* |__1 DMA_Channel_1
* .....
* |__15 DMA_Channel_15
*
* isEnable--
* |__0 关闭通道x的外设DMA请求
* |__1 开启通道x的外设DMA请求
*/
void LPLD_DMA_Start(uint8_t ChxNum,uint8_t isEnable)
{
if(isEnable)
{
//开启通道x的外设DMA请求
DMA_ERQ|=(1<<ChxNum);
}
else
{
//关闭通道x的外设DMA请求
DMA_ERQ&=~(1<<ChxNum);
}
}
/*
* LPLD_DMA_Reload
* 当完成一次DMA主循环之后,调用此函数可以调整目的地址,并重新设置主循环计数器的次数
* 调整之后 新的目的地址=原来目的地址+下一次主循环的次数
*
* 参数:
* ChxNum--DMA通道值 一共16个DMA通道
* |__0 DMA_Channel_0
* |__1 DMA_Channel_1
* .....
* |__15 DMA_Channel_15
*
* Dest_Base_Addr-- 目的存储区的首地址,可以是数组的首地址,也可以是数据寄存器的地址
*
* Dest_Addr_Offset--目的地址的偏移量,一般情况下目的地址的偏移量等于主循环计数器的次数
*
* Minor_Loop_Length--主循环计数器的次数
*
*/
void LPLD_DMA_Reload(uint8_t ChxNum,uint32_t Dest_Base_Addr,uint32_t Dest_Addr_Offset,uint16_t Minor_Loop_Length)
{
//重新设置目的地址
DMA_BASE_PTR->TCD[ChxNum].DADDR =(uint32_t)(Dest_Base_Addr+Dest_Addr_Offset);
//设置数据长度,长度每次递减。也可以称为 当前主循环计数器 current major loop count
DMA_BASE_PTR->TCD[ChxNum].CITER_ELINKNO=DMA_CITER_ELINKNO_CITER(Minor_Loop_Length);
//起始循环计数器,当主循环计数器为零的时候,将装载起始循环计数器的值
DMA_BASE_PTR->TCD[ChxNum].BITER_ELINKNO=DMA_CITER_ELINKNO_CITER(Minor_Loop_Length);
}
/*
* LPLD_DMA_Isr
* dma_ch15中断底层入口函数
*
* 用户无需修改,程序自动进入对应通道中断函数
*/
void LPLD_DMA_Isr(void)
{
#define DMA_VECTORNUM (*(volatile uint8_t*)(0xE000ED04))
uint8_t dma_ch = DMA_VECTORNUM - 16;
//调用用户自定义中断服务
DMA_ISR[dma_ch]();
//清除中断标志位
DMA_INT |= 0x1u<<dma_ch;
}
|
|