之前提到过在学习2530的spi模式传输,用flash芯片已经调通,但想用DMA传输数据,之前未接触DMA使用,就做一下DMA调试记录。DMA配置,数据拷贝,无源触发模式已调通,串口触发DMA待解决。下面是测试代码,仅供参考。
1.Dma配置
1.1bspDma.h
#ifndef __BSP_DMA_H__
#define __BSP_DMA_H__
#include "hal_types.h"// Define basic data types:
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned char UINT8;
// Define data
#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或7bit传输,仅仅适合在字节传输模式下
uint8 PRIORITY:2; //优先级选择
}DMA_DESC;
#pragma bitfields = default
#define DMA_IRQ_CH0 1<<0
#define DMA_IRQ_CH1 1<<1
#define DMA_IRQ_CH2 1<<2
#define DMA_IRQ_CH3 1<<3
#define DMA_IRQ_CH4 1<<4
#define DMA_AMOUNT 4
#define DMA_CH0 1<<0
#define DMA_CH1 1<<1
#define DMA_CH2 1<<2
#define DMA_CH3 1<<3
#define DMA_CH4 1<<4
#define DMA_VLEN_USE_LEN 0x00 // Use LEN for transfer count
#define DMA_VLEN_USE_LEN1 0x01 // Transfer number of bytes commanded by LEN + 1
#define DMA_WORDSIZE_BYTE 0x00 // Transfer a byte at a time
#define DMA_WORDSIZE_WORD 0x01 // Transfer a 16-bit word at a time
#define DMA_TMODE_SINGLE 0x00 // Transfer a single byte/word after each DMA trigger 单个传输模式
#define DMA_TMODE_BLOCK 0x01 // Transfer block of data (length len) after each DMA trigger 块传输模式
#define DMA_TMODE_SINGLE_REPEATED 0x02 // Transfer single byte/word (after len transfers, rearm DMA) 重复单个传输模式
#define DMA_TMODE_BLOCK_REPEATED 0x03 // Transfer block of data (after len transfers, rearm DMA) 重复块传输模式
#define DMA_TRIG_NONE 0 // No trigger, setting DMAREQ.DMAREQx bit starts transfer 无触发
#define DMA_TRIG_URX0 0x10 /* USART0 RX complete. */
#define DMA_TRIG_UTX0 0x0F /* USART0 TX complete. */
#define DMA_TRIG_URX1 0x10 /* USART1 RX complete. */
#define DMA_TRIG_UTX1 0x11 /* USART1 TX complete. */
#define DMA_SRCINC_0 0x00 // Increment source pointer by 0 bytes/words after each transfer源地址递增0字节/字
#define DMA_SRCINC_1 0x01 // Increment source pointer by 1 bytes/words after each transfer源地址递增1字节/字
#define DMA_DESTINC_0 0x00 // Increment source pointer by 0 bytes/words after each transfer源地址递增0字节/字
#define DMA_DESTINC_1 0x01 // Increment destination pointer by 1 bytes/words after each transfer目标地址递增1字节/字
#define DMA_IRQMASK_DISABLE 0x00 // Disable interrupt generation 通道的中断屏蔽
#define DMA_IRQMASK_ENABLE 0x01 // Enable interrupt generation upon DMA channel done 通道的中断使能
#define DMA_M8_USE_8_BITS 0x00 // Use all 8 bits for transfer count 采用所有8位作为传输长度
#define DMA_M8_USE_7_BITS 0x01 // Use 7 LSB for transfer count 采用字节地7位作为传输长度
#define DMA_PRI_LOW 0x00 // Low, CPU has priority 低优先级,CPU优先
#define DMA_PRI_GUARANTEED 0x01 // Guaranteed, DMA at least every second try 保证级,DMA至少在每秒一次的尝试中优先
#define DMA_PRI_HIGH 0x02 // High, DMA has priority 高优先级,DMA优先
#define DMA_PRI_ABSOLUTE 0x03 // Highest, DMA has priority. Reserved for DMA port access.
#define ABORT 0x80 // Bit mask for DMA abort bit (DMAARM)
#define DMAARM_DMAARM0 0x01// Bit mask for DMA arm channel 0 bit (DMAARM)
#define DMAARM_DMAARM1 0x02
#define DMAREQ_DMAREQ0 0x01
#define DMAREQ_DMAREQ1 0x02
#define DMAIRQ_DMAIF0 0x01// Bit mask for DMA channel 0 interrupt flag (DMAIRQ)
#define DMAIRQ_DMAIF1 0x02
#define NOP() asm("NOP")
// Define macro for splitting 16 bits in 2 x 8 bits:
#define HIBYTE(a) (BYTE) ((WORD)(a) >> 8)
#define LOBYTE(a) (BYTE) (WORD)(a)
#define SET_WORD(regH, regL, word) \
do { \
(regH) = HIBYTE( word ); \
(regL) = LOBYTE( word ); \
} while(0)
void DMA_Transmission(void);
void DMA_Init(void);
#endif
1.2.bspDma.c
#include "hal_types.h"
#include "bspDma.h"
#include "ioCC2530.h"
#include "hal_dma.h"
#include "uart.h"
uint8 sourcedata[] = "datacopy DMA test!";
#define datacount sizeof(sourcedata)
uint8 destdata[datacount];
DMA_DESC __xdata dmaConfig;
void DMA_Init(void)
{
//测试DMA通道,无源触发,data数据复制到copy,测试成功,DMA传输无误
SET_WORD(dmaConfig.SRCADDRH, dmaConfig.SRCADDRL, &sourcedata);//load address of the dma source
SET_WORD(dmaConfig.DESTADDRH, dmaConfig.DESTADDRL, &destdata);//load address of the dma distanation
SET_WORD(dmaConfig.LENH, dmaConfig.LENL, datacount); //LEN = nmax
dmaConfig.VLEN = DMA_VLEN_USE_LEN; // Transfer number of bytes commanded by n
dmaConfig.WORDSIZE = DMA_WORDSIZE_BYTE; // Each transfer is 8 bits
dmaConfig.TRIG = DMA_TRIG_NONE;//dmaConfig.TRIG = DMA_TRIG_URX1;
dmaConfig.TMODE = DMA_TMODE_BLOCK;// Transfer block of data (length len) after each DMA trigger
dmaConfig.SRCINC = DMA_SRCINC_1; // Increase source addr. by 1 between transfers
dmaConfig.DESTINC = DMA_DESTINC_1; // Keep the same dest. addr. for all transfers
dmaConfig.IRQMASK = DMA_IRQMASK_DISABLE;
dmaConfig.M8 = DMA_M8_USE_8_BITS; // Use all 8 bits of first byte in source data to determine the transfer count
dmaConfig.PRIORITY = DMA_PRI_HIGH; // DMA memory access has high priority
SET_WORD(DMA0CFGH, DMA0CFGL, &dmaConfig);
DMAARM = ABORT; //停止DMA所有通道进行传输
}
void DMA_Transmission(void)
{
//DMA进入工作模式通道0
DMAARM |= DMAARM_DMAARM0;//为了任何DMA传输能够在该通道上发生,该位必须置1,对于非重复传输模式,一旦完成传送,该位自动清0
//一个通道准备工作(即获得配置数据)的时间需要9个系统时钟
NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();
DMAIRQ = 0x00; //清中断标志
//DMA通道0传送请求,即触发DMA传送
DMAREQ |= DMAREQ_DMAREQ0;//设置为1,激活DMA通道0(与一个触发事件具有相同的效果),当DMA传输开始清除该位
//等待DMA通道0传送完毕
//for (; !(DMAIRQ & DMAIRQ_DMAIF0););//当DMA通道0传送完成,DMAIRQ:DMAIF1位置1,与上DMAIRQ_DMAIF1(0x01),取非后为0退出循环
while(!(DMAIRQ&DMAIRQ_DMAIF0)); //等待DMA通道0传输结束
//清除中断标志
DMAIRQ = ~DMAIRQ_DMAIF0;
Uart_Send_String(destdata,sizeof(destdata));
}
2.main.c
#include <iocc2530.h>
#include "hal_types.h"
#include "hal_board.h"
#include "hal_mcu.h"
#include "string.h"
#include "W25Qxx.h"
#include "uart.h"
#include "bspDma.h"
#define LED P2_0
uint8 string[] = "uart DMA test!";
void InitClockTo32M(void)
{
CLKCONCMD &= ~0x40; //设置系统时钟源为 32MHZ晶振
while(!(CLKCONSTA & 0x40)); //等待晶振稳定
CLKCONCMD &= ~0x47; //设置系统主时钟频率为 32MHZ
}
void InitLed(void)
{
P2DIR |= 0x01;
P2_0 = 0;
}
void main(void)
{
InitClockTo32M();
InitLed();
UART_Init();
EA=1;
Uart_Send_String(string,sizeof(string));
while(1)
{
DMA_Init();
DMA_Transmission();
LED = ~LED;
halMcuWaitMs(1000);
}
}
3.串口初始化和发送数据。
选用串口1(p0_4 - TX, p0_5 - RX)作为数据打印口。
// uart1
// p0_4 - TX, p0_5 - RX
// PERCFG &= ~1<<1; //bit0 = 0
// P0SEL |= (1<<4 | 1<<5); //bit4-5 = 1
//
// p1_6 p1_7
// PERCFG |= 1<<1; //bit0 = 1
// P1SEL |= (1<<46 | 1<<7); //bit6-7 = 1
static void uart1Init(void)
{
// uart1 init config
PERCFG &= ~1<<1; //bit1 = 0, uart1 -- postion 1 p0_4, p0_5, bit1 = 1, postion 2 p1_6, p1_7
P0SEL |= (1<<4 | 1<<5);//uart1 p0_4, p0_5:bit4,5 = 1
// P2DIR &= ~1<<7; //bit[7-6] = 01, at P0 port, uart1 get a higher priority than uart0
// P2DIR |= 1<<6;
U1CSR |= 1<<7; //bit7=0 uartMode;1 spiMode
U1GCR |= 11; //U0GCR and U0BAUD set baud rate.
U1BAUD |= 216; //115200
UTX1IF = 0; //clear uart0 TX interrupt flag. //we does not use it.
URX1IF = 0; //clear uart0 RX interrupt flag.
URX1IE = 1; //Enable rx interrupt
U1CSR |= 0X40; //Enable rx
}
void Uart1_Send_String(uint8 *Data,uint8 len)
{
for(uint8 j=0; j<len; j++)
{
U1DBUF=*Data++;
while(UTX1IF==0);
UTX1IF=0;
}
}
4.仿真测试,串口助手接收数据
5.待解决:DMA串口发送问题
void DMA_Init(void)
{
SET_WORD(dmaConfig.SRCADDRH, dmaConfig.SRCADDRL, &sourcedata);//load address of the dma source
SET_WORD(dmaConfig.DESTADDRH, dmaConfig.DESTADDRL, &X_U1DBUF);//load address of the dma distanation
SET_WORD(dmaConfig.LENH, dmaConfig.LENL, datacount); //LEN = nmax
dmaConfig.VLEN = DMA_VLEN_USE_LEN; // Transfer number of bytes commanded by n
dmaConfig.WORDSIZE = DMA_WORDSIZE_BYTE; // Each transfer is 8 bits
dmaConfig.TRIG = DMA_TRIG_NONE;//DMA_TRIG_UTX1; DMA_TRIG_URX1;DMA_TRIG_NONE
dmaConfig.TMODE = DMA_TMODE_BLOCK;// Transfer block of data (length len) after each DMA trigger//DMA_TMODE_SINGLE,DMA_TMODE_BLOCK
dmaConfig.SRCINC = DMA_SRCINC_1; // Increase source addr. by 1 between transfers
dmaConfig.DESTINC = DMA_DESTINC_0; // Keep the same dest. addr. for all transfers
dmaConfig.IRQMASK = DMA_IRQMASK_DISABLE;
dmaConfig.M8 = DMA_M8_USE_8_BITS; // Use all 8 bits of first byte in source data to determine the transfer count
dmaConfig.PRIORITY = DMA_PRI_HIGH; // DMA memory access has high priority
SET_WORD(DMA0CFGH, DMA0CFGL, &dmaConfig);
DMAARM = ABORT; //停止DMA所有通道进行传输
}
void DMA_Transmission(void)
{
//DMA进入工作模式通道0
DMAARM |= DMAARM_DMAARM0;//为了任何DMA传输能够在该通道上发生,该位必须置1,对于非重复传输模式,一旦完成传送,该位自动清0
//一个通道准备工作(即获得配置数据)的时间需要9个系统时钟
NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();
DMAIRQ = 0x00; //清中断标志
//DMA通道0传送请求,即触发DMA传送
DMAREQ |= DMAREQ_DMAREQ0;//设置为1,激活DMA通道0(与一个触发事件具有相同的效果),当DMA传输开始清除该位
//等待DMA通道0传送完毕
//for (; !(DMAIRQ & DMAIRQ_DMAIF0););//当DMA通道0传送完成,DMAIRQ:DMAIF1位置1,与上DMAIRQ_DMAIF1(0x01),取非后为0退出循环
while(!(DMAIRQ&DMAIRQ_DMAIF0)); //等待DMA通道0传输结束
//清除中断标志
DMAIRQ = ~DMAIRQ_DMAIF0;
//Uart_Send_String(destdata,sizeof(destdata));
}
void DMA_Init(void)里更改配置,目的地址为串口1数据缓冲区,传输过程中目的地址不变
void DMA_Transmission(void)里屏蔽串口发送
即://Uart_Send_String(destdata,sizeof(destdata));
启动通道传输,每次只能传输第一个字节,后面全是00.
若void DMA_Init(void)里更改配置,目的地址为串口1数据缓冲区,传输过程中目的地址+1
则什么都不传输。