CC2530 DMA控制器操作流程图如下:
CC2530中不能用设置寄存器的方式配置DMA的参数,而要使用一种特殊的DMA配置结构体,DMA Configuration Data Structure结构体,IAR编译环境中位域字段默认取向采用小端模式,配置结构体声明前使用
#pragma bitfields=reversed取反向,声明结束后恢复IAR默认方式。
-
// Place the bitfield members from the most significant bit to the least significant bit.
-
#pragma bitfields=reversed
-
typedef struct {
-
uint8 SRCADDRH; //源地址高字节
-
uint8 SRCADDRL; //源地址低字节
-
uint8 DESTADDRH; //目的地址高字节
-
uint8 DESTADDRL; //目的地址低字节
-
uint8 VLEN : 3; //变长传输模式选择
-
uint8 LENH : 5; //传输长度高字节
-
uint8 LENL : 8; //传输长度低字节
-
uint8 WORDSIZE : 1; //字节传输或字传输
-
uint8 TMODE : 2; //传输模式选择
-
uint8 TRIG : 5; //触发时间选择
-
uint8 SRCINC : 2; //源地址增量方式选择
-
uint8 DESTINC : 2; //目的地址增量方式选择
-
uint8 IRQMASK : 1; //中断屏蔽位
-
uint8 M8 : 1; //字节传输模式时用,8或7 bit传输长度
-
uint8 PRIORITY : 2; //优先级选择
-
} DMA_DESC;
-
#pragma bitfields=default
根据CC253x编程手册中的相关介绍:
DMA共有四种传输模式
单次传输模式:触发条件发生后启动一次传输,接着DMA通道等待下次触发发生。当传输长度字段指定的传输次数完成后,设置中断标志位通知CPU并卸载DMA通道配置参数。
块传输模式:触发条件发生后,尽快完成长度字段指定的传输次数,完成后通知CPU并卸载DMA通道配置参数,即执行DMAARMn = 0。
重复单次传输模式:与单次模式前段相同,只是会重装通道配置参数。
重复块传输模式:
与块模式前段相同,只是会重装通道配置参数。
四种方式的差别具体看上边DMA操作流程图。
DMA编程流程:
1.DMA配置结构体赋值
2.将配置结构体内存地址赋值给DMAxCFGH:DMAxCFGL
3.DMAARMx相应通道位置1,装载通道配置参数,根据手册要求,装载通道时需要延迟9个时钟周期使其生效
4.手动触发或等待触发条件
5.清除中断标志位,无论中断屏蔽位关闭与否,传输完成后相应中断标志位都会置位
CC2541_43_44_45_Peripherals_Software_Examples中DMA例程分析
dma_man_trigger.c 该例程展示了如何手动触发DMA,使用DMA方式复制内存数据到内存其他区域中
-
/*******************************************************************************
-
Filename: dma_man_trigger.c
-
-
Description: This example shows how to trigger the DMA manually and use
-
DMA to move data from one area of RAM to another.
-
-
*******************************************************************************/
-
-
/*******************************************************************************
-
* INCLUDES
-
*/
-
-
// Include Name definitions of individual bits and bit-fields in the CC254x device registers.
-
#include <ioCC254x_bitdef.h>
-
#include <hal_types.h>
-
#include <dma.h>
-
// Include device specific file
-
#include "ioCC2530.h"
-
-
-
/*******************************************************************************
-
* CONSTANTS
-
*/
-
-
// String length.
-
#define DATA_AMOUNT 16
-
-
-
/*******************************************************************************
-
* LOCAL VARIABLES
-
*/
-
-
// The data that is to be copied to another place in memory.
-
static char data[DATA_AMOUNT] = "DMA man trigger!";
-
-
// The area where the data is to be copied to.
-
static char copy[DATA_AMOUNT];
-
-
// DMA configuration descriptor used for memory copy.
-
static DMA_DESC dmaConfig0;
-
-
-
/*******************************************************************************
-
* LOCAL FUNCTIONS
-
*/
-
-
-
/*******************************************************************************
-
* @fn main
-
*
-
* @brief Sets up the DMA configuration struct, saves its address, arms the
-
* DMA channel and triggers it manually. After the DMA transfer is
-
* complete, the DMA channel 0 interrupt flag is cleared (it is
-
* automatically set).
-
*
-
* @param void
-
*
-
* @return void
-
*******************************************************************************/
-
void main(void)
-
{
-
/* Configure DMA channel 0. Settings:
-
* SRCADDR: address of the data to be copied (increasing).
-
* DESTADDR: address the data will be copied to (increasing).
-
* VLEN: use LEN for transfer count.
-
* LEN: equal to the number of bytes to be transferred.
-
* WORDSIZE: each transfer should transfer one byte.
-
* TMODE: block mode.
-
* TRIG: let the DMA channel be triggered manually, i.e., by setting the
-
* [DMAREQ.DMAREQ0] bit.
-
* SRCINC: increment by one byte.
-
* DESTINC: increment by one byte.
-
* IRQMASK: disable interrupts from this channel.
-
* M8: 0, irrelevant since we use LEN for transfer count.
-
* PRIORITY: high.
-
*/
-
dmaConfig0.SRCADDRH = ((uint16)data >> 8) & 0x00FF;
-
dmaConfig0.SRCADDRL = (uint16)data & 0x00FF;
-
dmaConfig0.DESTADDRH = ((uint16)copy >> 8) & 0x00FF;
-
dmaConfig0.DESTADDRL = (uint16)copy & 0x00FF;
-
dmaConfig0.VLEN = DMA_VLEN_USE_LEN; //使用固定长度
-
dmaConfig0.LENH = (DATA_AMOUNT >> 8) & 0x00FF;
-
dmaConfig0.LENL = DATA_AMOUNT & 0x00FF;
-
dmaConfig0.WORDSIZE = DMA_WORDSIZE_BYTE; //字节传输
-
dmaConfig0.TMODE = DMA_TMODE_BLOCK; //块传输方式
-
dmaConfig0.TRIG = DMA_TRIG_NONE; //手动触发
-
dmaConfig0.SRCINC = DMA_SRCINC_1;
-
dmaConfig0.DESTINC = DMA_DESTINC_1;
-
dmaConfig0.IRQMASK = DMA_IRQMASK_DISABLE; //关闭DMA中断方式
-
dmaConfig0.M8 = DMA_M8_USE_8_BITS;
-
dmaConfig0.PRIORITY = DMA_PRI_HIGH;
-
-
/* The DMA configuration data structure may reside at any location in
-
* unified memory space, and the address location is passed to the DMA
-
* through DMA0CFGH:DMA0CFGL.
-
*/
-
DMA0CFGH = ((uint16)&dmaConfig0 >> 8) & 0x00FF;
-
DMA0CFGL = (uint16)&dmaConfig0 & 0x00FF;
-
-
/* Arm the DMA channel, so that a DMA trigger can initiate DMA writing,
-
and apply 9 NOPs to allow the DMA arming to actually take effect. */
-
DMAARM |= DMAARM_DMAARM0;
-
NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP(); // 9 NOPs
-
-
// Trigger the DMA channel manually.
-
DMAREQ |= DMAREQ_DMAREQ0;
-
-
// Wait for the DMA transfer to complete.
-
while ( !(DMAIRQ & DMAIRQ_DMAIF0) );
-
-
/* By now, the transfer is completed, so the transfer count is reached.
-
* The DMA channel 0 interrupt flag is then set, so we clear it here.
-
*/
-
-
// Clear interrupt flag by R/W0, see datasheet.
-
DMAIRQ = ~DMAIRQ_DMAIF0;
-
-
// End function with infinite loop (for debugging purposes).
-
while(1);
-
}
dma_pre_trigger.c 通道0采用手动触发方式,通道1追踪通道0完成时触发
-
/*******************************************************************************
-
Filename: dma_prev_trigger.c
-
-
Description: This example shows both how to trigger a DMA channel manually and
-
how to trigger a DMA channel by the completion of the previous
-
channel. Both channels copy data in RAM. Channel 0 makes the
-
first copy and channel 1 makes a copy of the first copy.
-
-
-
*******************************************************************************/
-
-
/*******************************************************************************
-
* INCLUDES
-
*/
-
-
// Include Name definitions of individual bits and bit-fields in the CC254x device registers.
-
#include <ioCC254x_bitdef.h>
-
#include <hal_types.h>
-
#include <dma.h>
-
// Include device specific file
-
#include "ioCC2530.h"
-
-
/*******************************************************************************
-
* CONSTANTS
-
*/
-
-
// String length.
-
#define DATA_AMOUNT 16
-
-
-
/*******************************************************************************
-
* LOCAL VARIABLES
-
*/
-
-
// The data that is to be copied to another place in memory.
-
static char data[DATA_AMOUNT] = "DMA prev trigger";
-
-
// The araes where data is to be copied to.
-
static char copy1[DATA_AMOUNT];
-
static char copy2[DATA_AMOUNT];
-
-
// DMA configuration descriptor used for memory copy.
-
static DMA_DESC dmaConfig0, dmaConfig1;
-
-
-
/*******************************************************************************
-
* LOCAL FUNCTIONS
-
*/
-
-
-
/*******************************************************************************
-
* @fn main
-
*
-
* @brief Sets up DMA configuration structs for both channel 0 and 1, saves
-
* their addresses, arms both DMA channels and triggers channel 0
-
* manually. After the first DMA transfer is completed, the DMA
-
* channel 0 interrupt flag is cleared (it is automatically set).
-
* The completion of the channel 0 transfer triggers the transfer on
-
* channel 1, which copies the same data yet again. After the second
-
* DMA transfer is completed, the DMA channel 0 interrupt flag is
-
* also cleared and the program terminates.
-
*
-
* @param void
-
*
-
* @return void
-
*******************************************************************************/
-
void main(void)
-
{
-
/* Configure DMA channel 0. Settings:
-
* SRCADDR: address of the data to be copied (increasing).
-
* DESTADDR: address the data will be copied to (increasing).
-
* VLEN: use LEN for transfer count.
-
* LEN: equal to the number of bytes to be transferred.
-
* WORDSIZE: each transfer should transfer one byte.
-
* TMODE: block mode.
-
* TRIG: let the DMA channel be triggered manually, i.e., by setting the
-
* [DMAREQ.DMAREQ0] bit.
-
* SRCINC: increment by one byte.
-
* DESTINC: increment by one byte.
-
* IRQMASK: disable interrupts from this channel.
-
* M8: 0, irrelevant since we use LEN for transfer count.
-
* PRIORITY: high.
-
*/
-
dmaConfig0.SRCADDRH = ((uint16)data >> 8) & 0x00FF;
-
dmaConfig0.SRCADDRL = (uint16)data & 0x00FF;
-
dmaConfig0.DESTADDRH = ((uint16)copy1 >> 8) & 0x00FF;
-
dmaConfig0.DESTADDRL = (uint16)copy1 & 0x00FF;
-
dmaConfig0.VLEN = DMA_VLEN_USE_LEN;
-
dmaConfig0.LENH = (DATA_AMOUNT >> 8) & 0x00FF;
-
dmaConfig0.LENL = DATA_AMOUNT & 0x00FF;
-
dmaConfig0.WORDSIZE = DMA_WORDSIZE_BYTE;
-
dmaConfig0.TMODE = DMA_TMODE_BLOCK;
-
dmaConfig0.TRIG = DMA_TRIG_NONE;
-
dmaConfig0.SRCINC = DMA_SRCINC_1;
-
dmaConfig0.DESTINC = DMA_DESTINC_1;
-
dmaConfig0.IRQMASK = DMA_IRQMASK_DISABLE;
-
dmaConfig0.M8 = DMA_M8_USE_8_BITS;
-
dmaConfig0.PRIORITY = DMA_PRI_HIGH;
-
-
/* Configure DMA channel 1. Settings:
-
* Same as for channel 0, except for different source and destination
-
* addresses and let the DMA channel be triggered by the completion of the
-
* previous channel.
-
*/
-
dmaConfig1.SRCADDRH = ((uint16)copy1 >> 8) & 0x00FF;
-
dmaConfig1.SRCADDRL = (uint16)copy1 & 0x00FF;
-
dmaConfig1.DESTADDRH = ((uint16)copy2 >> 8) & 0x00FF;
-
dmaConfig1.DESTADDRL = (uint16)copy2 & 0x00FF;
-
dmaConfig1.VLEN = DMA_VLEN_USE_LEN;
-
dmaConfig1.LENH = (DATA_AMOUNT >> 8) & 0x00FF;
-
dmaConfig1.LENL = DATA_AMOUNT & 0x00FF;
-
dmaConfig1.WORDSIZE = DMA_WORDSIZE_BYTE;
-
dmaConfig1.TMODE = DMA_TMODE_BLOCK;
-
dmaConfig1.TRIG = DMA_TRIG_PREV; //前一个通道传输完成触发该通道
-
dmaConfig1.SRCINC = DMA_SRCINC_1;
-
dmaConfig1.DESTINC = DMA_DESTINC_1;
-
dmaConfig1.IRQMASK = DMA_IRQMASK_DISABLE;
-
dmaConfig1.M8 = DMA_M8_USE_8_BITS;
-
dmaConfig1.PRIORITY = DMA_PRI_HIGH;
-
-
/* The DMA configuration data structures may reside at any location in
-
* unified memory space, and the address locations is passed to the DMA
-
* through DMA0CFGH:DMA0CFGL and DMA1CFGH:DMA1CFGL for channel 0 and 1,
-
* respectively.
-
*/
-
DMA0CFGH = ((uint16)&dmaConfig0 >> 8) & 0x00FF;
-
DMA0CFGL = (uint16)&dmaConfig0 & 0x00FF;
-
DMA1CFGH = ((uint16)&dmaConfig1 >> 8) & 0x00FF;
-
DMA1CFGL = (uint16)&dmaConfig1 & 0x00FF;
-
-
/* Arm DMA channel 0 and 1, so that they can be triggered by their
-
respective triggers, and apply 18 NOPs to allow the DMA arming
-
to actually take effect. */
-
DMAARM |= (DMAARM_DMAARM0 | DMAARM_DMAARM1);
-
NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP(); // 9 NOPs //装载通道的延时时间随装载通道数累加
-
NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP(); // 9 NOPs
-
-
// Trigger the DMA channel 0 manually.
-
DMAREQ |= DMAREQ_DMAREQ0;
-
-
// Wait for DMA transfer on channel 0 to complete.
-
while ( !(DMAIRQ & DMAIRQ_DMAIF0) );
-
-
/* By now, the first transfer is completed. The DMA channel 0 interrupt flag
-
* is then set, so we clear it here.
-
*/
-
-
// Clear interrupt flag by R/W0, see datasheet.
-
DMAIRQ = ~DMAIRQ_DMAIF0;
-
-
/* Wait for DMA transfer on channel 1 to complete. Then clear its interrupt
-
* flag.
-
*/
-
-
while ( !(DMAIRQ & DMAIRQ_DMAIF1) );
-
// Clear interrupt flag by R/W0, see datasheet.
-
DMAIRQ = ~DMAIRQ_DMAIF1;
-
-
// End function with infinite loop (for debugging purposes).
-
while(1);
-
}
调试时将断点打在
DMAREQ |= DMAREQ_DMAREQ0;处,观察数组内存值的变化,可以看到,只要执行该条语句,两个通道的DMA操作接连完成,中断标志位都置位了,while ( !(DMAIRQ & DMAIRQ_DMAIF0) );及后续指令无需等到。
已经将平台修改为CC2530,源代码附件
dma.zip
阅读(5753) | 评论(0) | 转发(0) |