一、DMA传输主要特性:
1,数据传输长度,最大65536
2,7个通道,每个通道都配置
3,AHB\APB外设,片上闪存和SRAM都可以作为访问的源端和目的端;
4,支持软件优先级:低、中、高、极高,硬件优先级:通道号越低,优先级越高
5,存储器和外设数据传输支持固定寻址和增量寻址;
6,支持循环传输模式
7,支持外设到存储器,存储器到外设,存储器到存储器的数据传输;
8, 每个通道有 3 种类型的事件标志和独立的中断,支持中断的使能和清除;
9,支持中断使能和清除。
二、功能描述
DMA传输分为两步操作:从源地址读取数据,之后将读取的数据存储到目的地址。
DMA控制器基于DMA_CHxPADDR、 DMA_CHxMADDR、 DMA_CHxCTL寄存器的值计算下一次操作的源/目的地址。
DMA_CHxCNT 寄存器用于控制传输的次数。
DMA_CHxCTL 寄存器的PWIDTH 和 MWIDTH 位域决定每次发送和接收的字节数(字节/半字/字)。
将 DMA_CHxCTL 寄存器的 CHEN 位清零,可以停止DMA 传输。
三、通道配置
要启动一次新的 DMA 数据传输,建议遵循以下步骤进行操作:
1. 读取 CHEN 位,如果为 1(通道已使能),清零该位。当 CHEN 为 0 时,请按照下列步骤
配置 DMA 开始新的传输。
2. 配置 DMA_CHxCTL 寄存器的 M2M 及 DIR 位,选择传输模式;
3. 配置 DMA_CHxCTL 寄存器的 CMEN 位,选择是否使能循环模式;
4. 配置 DMA_CHxCTL 寄存器的 PRIO 位域,选择该通道的软件优先级;
5. 通过DMA_CHxCTL寄存器配置存储器和外设的传输宽度以及存储器和外设地址生成算
法;
6. 通过DMA_CHxCTL寄存器配置传输完成中断,半传输完成中断,传输错误中断的使能位;
7. 通过 DMA_CHxPADDR 寄存器配置外设基地址;
8. 通过 DMA_CHxMADDR 寄存器配置存储器基地址;
9. 通过 DMA_CHxCNT 寄存器配置数据传输总量;
10. 将 DMA_CHxCTL 寄存器的 CHEN 位置1,使能 DMA 通道。
四、DMA寄存器
1,中断标志位寄存器 (DMA_INTF)
2,中断标志位清除寄存器 (DMA_INTC)
3,通道 x 外设基地址寄存器(DMA_CHxPADDR)
4,通道 x 存储器基地址寄存器 (DMA_CHxMADDR)
5,通道 x 计数寄存器 (DMA_CHxCNT)
6,通道 x 控制寄存器 (DMA_CHxCTL)
b0:[CHEN]通道使能
b1:[FTFIE]通道传输完成中断使能位
b2:[HTFIE]通道半传输完成中断使能位
b3:[ERRIE]通道错误中断使能位
b4:[DIR]传输方向:外设到存储器、存储器到外设
b5:[CMEN]循环模式使能
b6:[PNAGA]外设的地址生成算法:固定地址模式、增量地址模式
b7:[MNAGA]存储器的地址生成算法
b8:9:[PWIDTH]外设传输数据宽度
b11:10:[MWIDTH]存储器传输数据宽度
b13:12:[PRIO]软件优先级
b14:[M2M]存储器到存储器模式
四、实例
/* DMA initialize struct */
typedef struct
{
uint32_t periph_addr; /*!<外设的基地址 */
uint32_t periph_width; /*!< 传输外设的数据大小 */
uint32_t periph_inc; /*!< 外设增加模式 */
uint32_t memory_addr; /*!< 存储器基地址 */
uint32_t memory_width; /*!< 存储器传输数据大小 */
uint32_t memory_inc; /*!< 存储器增加模式 */
uint32_t direction; /*!< 通道传输方向 */
uint32_t number; /*!< 通道传输次数 */
uint32_t priority; /*!< 通道优先级 */
} dma_parameter_struct;
/*!
\brief this function handles DMA_Channel0_IRQHandler interrupt
\param[in] none
\param[out] none
\retval none
*/
void DMA_Channel0_IRQHandler(void)
{
if(dma_interrupt_flag_get(DMA_CH0,DMA_INT_FLAG_FTF)){
int_num++;
dma_interrupt_flag_clear(DMA_CH0,DMA_INT_FLAG_FTF);
dma_interrupt_flag_clear(DMA_CH0,DMA_INT_FLAG_G);
}
}
int main()
{
/* unlock the flash bank1 program erase controller */
fmc_unlock();
/* define the number of page to be erased */
pagenum = (BANK1_WRITE_END_ADDR - BANK1_WRITE_START_ADDR) / FMC_PAGE_SIZE;
/* clear all pending flags */
fmc_flag_clear(FMC_FLAG_PGERR | FMC_FLAG_WPERR | FMC_FLAG_END);
/* erase the flash pages */
for(erasenum = 0; erasenum < pagenum; erasenum++){
fmcstatus = fmc_page_erase(BANK1_WRITE_START_ADDR + (FMC_PAGE_SIZE * erasenum));
wperror += (fmcstatus == FMC_WPERR);
fmc_flag_clear(FMC_FLAG_PGERR | FMC_FLAG_WPERR | FMC_FLAG_END);
}
/* unlock the flash bank1 program erase controller */
fmc_lock();
ptrd = (uint32_t*)BANK1_WRITE_START_ADDR;
for(i = 0; i < 256; i++){
if(0xFFFFFFFF != *ptrd){
accessflag = ERROR;
break;
}
ptrd++;
}
/* unlock the flash bank1 program erase controller */
fmc_unlock();
/* define the number of page to be erased */
pagenum = (BANK1_WRITE_END_ADDR - BANK1_WRITE_START_ADDR) / FMC_PAGE_SIZE;
/* clear all pending flags */
fmc_flag_clear(FMC_FLAG_PGERR | FMC_FLAG_WPERR | FMC_FLAG_END);
/* program flash bank1 */
address = BANK1_WRITE_START_ADDR;
wperror2 = 0;
while(address < BANK1_WRITE_END_ADDR){
fmcstatus = fmc_word_program(address, transdata);
address = address + 4;
wperror2 += (FMC_WPERR == fmcstatus);
fmc_flag_clear(FMC_FLAG_PGERR | FMC_FLAG_WPERR | FMC_FLAG_END);
}
fmc_lock();
/* DMA channel0 initialize */
//复位DMA通道0的所有寄存器
dma_deinit(DMA_CH0);
//通道传输方向 : 外设到内存
dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
//目标地址:存储器地址
dma_init_struct.memory_addr = (uint32_t)destdata;
//存储器地址增加方式:增量式
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
//传输宽度:8Bit
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
//传输长度:1024Byte
dma_init_struct.number = ACCESSSUM;
//源地址:外设地址
dma_init_struct.periph_addr = (uint32_t)BANK1_WRITE_START_ADDR;
//外设地址增加方式:增量式
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_ENABLE;
//传输宽度:8Bit
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
//传输优先级:最高级
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_init(DMA_CH0,dma_init_struct);
/* 禁用循环模式 */
dma_circulation_disable(DMA_CH0);
/* 使能内存到内存模式 */
dma_memory_to_memory_enable(DMA_CH0);
/* 中断使能,DMA通道传输完成中断 */
dma_interrupt_enable(DMA_CH0, DMA_INT_FTF);
/* DMA通道0传输使能 */
dma_channel_enable(DMA_CH0);
/* 等待DMA传输中断 */
for(i = 0; i < 10000; i++){
if(int_num)
break;
}
/* 比较外设和内存数据 */
ptrd = destdata;
for(i = 0; i < 256; i++){
if(transdata != *ptrd)
{
accessflag = ERROR;
break;
}
ptrd++;
}
while(1);
}