DAC-DMA 例程及注意事项@STC32G144K246
STC32G144K246, DAC-DMA 输出, 离散信号输出,足够快成连续信号 !
需要注意以下问题:
1.DMA_DAC1_AMT的单位是16bit的,例如想要DMA传输50个16位的数据(数据最大不能超过12位)
则DMA_DAC1_AMT需要填入49(DMA_DAC1_AMT填0时为传输1字节,所以填入时需要减1)
2.DAC-DMA传输时,DAC1_DIV是和DMA_DAC1_ITV共同作用的
3.传入DAC的DMA数据,需要转换为小端模式,这里提供一个简单的函数,可以进行转换:
//大小端交换,传入数组地址和所需转换数量(以16bit为单位)
void swap_endian_uint16_array(unsigned int *arr, unsigned int count)
{
unsigned int i;
unsigned short temp;
for(i = 0; i < count; i++)
{
temp = arr;
arr = ((temp & 0x00FF) << 8) | ((temp & 0xFF00) >> 8);
}
}
4.需要使用DAC-DMA模式时,DAC1_CR中,需要将转换模式配置为连续转换模式
DMA只管更新DMA_DAT,不会主动触发DAC TG,如果配置为单次转换或者其他定时器触发,仍然需要定时器触发或者软件触发DAC TG才能看到波形
否则,DAC将不会更新输出
5.DMA_DAC1_DONE寄存器,单位仍然为8bit,即一个字节,例如DMA_DAC1_AMT填入49,则全部转换完成后,将可以在DMA_DAC1_DONE读到100
6.DAC1_DIV和DAC1_DAT为16位寄存器,可以直接填入值,不需要拆分成8位填入,寄存器是否支持16位,请看头文件定义,是否为int类型
以下为在STC32G144K246核心板上验证通过的正弦波输出测试程序,上电自动在P63端口输出一个正弦波:
程序运行在120Mhz
程序采用4096点满分辨率输出,无需滤波,输出速度可达2.43KHz,无需RC滤波即可看到非常平滑的波形
想要DAC看不到阶梯感,使用较高的分辨率即可, 或加滤波/毕竟DAC输出是离散信号不是连续信号
高分辨率下,放大后依然是看不出来阶梯感的
以下为完整程序:
#include "STC32G144K246.H"
#include "math.h"
//本例程使用CHIPID内预置参数,设置HIRC为24MHz
//使用HPLL1,提供60Mhz,80Mhz,120Mhz的设置例程
#define Fosc_60Mhz 0 //系统时钟为60Mhz
#define Fosc_80Mhz 1 //系统时钟为80Mhz
#define Fosc_120Mhz 2//系统时钟为120Mhz
#define Main_Fosc Fosc_120Mhz //设置系统时钟为120Mhz
//正弦波表,最大值4095,使用计算方式在初始化的时候生成
unsigned int xdata SinTable_Software;
void CLK_Init(void); //设置系统时钟,由Main_Fosc定义设置
void Io_Init(void); //I/O口初始化函数,设置P32为开漏+打开内部上拉电阻模式
void DAC_Init(void); //DAC部分初始化函数,DAC1由OPA1的缓冲模式作为输出
//大小端交换,传入数组地址和所需转换数量(以16bit为单位)
void swap_endian_uint16_array(unsigned int *arr, unsigned int count)
{
unsigned int i;
unsigned short temp;
for(i = 0; i < count; i++)
{
temp = arr;
arr = ((temp & 0x00FF) << 8) | ((temp & 0xFF00) >> 8);
}
}
void GenerateSinTable(unsigned int *pArray, unsigned int points)
{
unsigned int i;
double angle, sinValue;
for(i = 0; i < points; i++)
{
/* 生成0到2π之间的角度 */
angle = (2.0 * 3.14159265358979323846 * i) / points;
/* 计算sin值 (-1到1) */
sinValue = sin(angle);
/* 映射到0-4095范围 */
/* sinValue从-1到1,先+1变成0到2,除以2变成0到1,再乘4095 */
pArray = (unsigned int)((sinValue + 1.0) * 2047.5 + 0.5);
/* 限制在0-4095范围内 */
if(pArray > 4095)
{
pArray = 4095;
}
}
}
void Delay10ms(void) //@120MHz
{
unsigned long edata i;
_nop_();
_nop_();
i = 299998UL;
while (i) i--;
}
int cnt = 0;
void main(void)
{
EAXFR = 1; //使能访问扩展RAM区特殊功能寄存器(XFR)
CKCON &= ~0x07; //清空,设置外部数据总线等待时钟为0(最快),默认为7
CLK_Init(); //设置HPLL时钟为指定频率
GenerateSinTable(SinTable_Software,4096);
swap_endian_uint16_array(SinTable_Software,4096);
Io_Init(); //初始化I/O口,设置P32等效为原准双向口模式(开漏模式+打开内部上拉电阻)
DAC_Init(); //初始化DAC
EA = 1; //打开总中断
while(1)
{
//用户程序
if(P32 == 0)
{
DAC1_STA = 0x00;//清空状态标志位
DMA_DAC1_STA = 0x00;//清空中断标志位
DMA_DAC1_CR = 0xc0;//触发启动
while(~P32);
}
}
}
void Io_Init(void)
{
P3M0 |= 0x04; P3M1 |= 0x04; //P32设置为开漏输出
P3PU |= 0x04; //打开P32的上拉电阻
//I/O口设置为开漏输出+打开上拉电阻==原准双向口模式,写1可读外部电平
P3M0 |= 0x20; P3M1 &= ~0x20;//设置P35为推挽输出模式,用于观察定时器0的T0CLKO输出
P0M0 = 0x00; P0M1 = 0xff;
}
void CLK_Init(void)
{
#if Main_Fosc == Fosc_120Mhz
WTST = 4;CLKDIV = 2; //设置系统时钟=480MHz/2/2=120MHz,(因为CLKSEL选择时,已经将HPLL/2了)
#elif Main_Fosc == Fosc_80Mhz
WTST = 3;CLKDIV = 3; //设置系统时钟=480MHz/2/3=80MHz
#elif Main_Fosc == Fosc_60Mhz
WTST = 2;CLKDIV = 4; //设置系统时钟=480MHz/2/4=60MHz
#endif
//以下为超过60MHz时,系统时钟使用HPLL方式提供
VRTRIM = CHIPID22; //载入27MHz频段的VRTRIM值
IRTRIM = CHIPID12; //指定当前HIRC为24MHz,此时会覆盖掉ISP设置的时钟频率
IRCBAND &= ~0x03; //清空频段选择
IRCBAND |= 0x01; //选择27Mhz频段
HPLLCR &= ~0x10; //选择HPLL输入时钟源为HIRC
HPLLPDIV = 4; //24MHz/4=6MHz,需要保证输入HPLL的时钟在6MHz附近
HPLLCR |= 0x0e; //HPLL=6MHz*80=480MHz
HPLLCR |= 0x80; //使能HPLL
Delay10ms();
CLKSEL &= ~0x03; //BASE_CLK选择为HIRC,用以提供给HPLL
CLKSEL &= ~0x0c; //清空主时钟源选择
CLKSEL |= 1<<2; //设置主时钟源为内部 HPLL1 输出/2
}
//配置DAC为DMA输出,并且使用OPA1缓冲模式作为输出
void DAC_Init(void)
{
//OPA配置输出
PGA1_CR1 = 0x73;//缓冲模式,DACIO正极输入,P63输出
PGA1_CR2 = 0x04;//允许PGA1输出
//DAC配置
DAC1_DIV = 0;//设置DAC分频系数,防止超过2Mhz推荐最大速度
//DAC1_CR = 0x81;//使能DAC功能,DAC使用DMA模式,单次触发,无法启动DMA
DAC1_CR = 0xb3;//使能DAC功能,DAC使用DMA模式,连续触发,打开DAC1中断
//DAC1_CR = 0x41;//使能DAC功能,连续触发,用于测试无DMA情况下是否正常输出,测试结果:正常
DAC1_STA = 0x00;//清空状态标志位
//DMA配置
DMA_ARB_CFG = (0<<5);//切换到xdata部分
// DMA_DAC1_CFG = 0x00;//关闭DMA_DAC中断
DMA_DAC1_CFG = 0x8f;//使能DMA_DAC中断
DMA_DAC1_STA = 0x00;//清空中断标志位
DMA_DAC1_AMTH = (unsigned char)((4095-1)>>8);
DMA_DAC1_AMT = (unsigned char)(4095-1);//单位是16bit
DMA_DAC1_TXAH = (unsigned char)(((unsigned int)&SinTable_Software)>>8);
DMA_DAC1_TXAL = (unsigned char)((unsigned int)&SinTable_Software);
DMA_DAC1_ITVH = 0x00;//长延时,DAC输出速度主要由此提供
DMA_DAC1_CR = 0xc0;//触发启动
}
void dac1_isr(void) interrupt DAC1_VECTOR
{
DAC1_STA = 0x00;//清空状态标志位
}
void DMA_DAC1_Interrupt(void) interrupt DMA_DAC_VECTOR
{
DMA_DAC1_STA = 0;P35 = ~P35;DMA_DAC1_CR = 0xc0;//触发启动
}
定时17触发源+DAC_DMA,200us步进阶梯波:
STC32G144K246-QFN100/12mm*12mm-0.4mm间距,
走在克服封装困难的道路上;
STC32G144K246-QFN64/8mm*8mm-0.4mm间距,
走在克服封装困难的道路上;
STC32G144K246-LQFP64/12mm*12mm-0.4mm间距,
会下周前立即供应跟上;
{:qiang:} 学习
页:
[1]