DMA不工作
UTIMER定时触发ADC0,1,2,ADC2采样完成后触发DMA,把ADC2数据从SPI发送出去,现在UTIMER定时触发ADC可以了,但是DMA不工作,大家看看咋回事
#include "hardware_init.h"
void UTimer_init(void)
{
UTIMER_InitTypeDef TIM_InitStruct;
UTIMER_StructInit(&TIM_InitStruct); /* Timer结构体初始化*/
TIM_InitStruct.EN = ENABLE; // Timer 模块整体使能,高有效
TIM_InitStruct.ETON = 0; // Timer 计数器计数使能配置 0:自动运行 1:等待外部事件触发计数
TIM_InitStruct.CLK_DIV= UTIMER_Clk_Div2; // Timer 计数器分频设置
TIM_InitStruct.CLK_SRC= UTIMER_CLK_SRC_MCLK; // Timer 时钟源
TIM_InitStruct.CH0_POL= 0; // Timer通道1在比较模式下的输出极性控制,当计数器计数值回零时的输出值
TIM_InitStruct.CH0_MODE = UTIMER_MODE_CMP; // Timer通道1的工作模式选择,默认值为0
TIM_InitStruct.TH = 48000; // Timer 计数器计数门限。
TIM_InitStruct.CMP0 = 24000; // Timer 通道0工作在比较模式时,当计数器计数值等于CMP0时,发生比较事件。
TIM_InitStruct.FLT = 10; // 通道0/1信号滤波宽度选择。取值范围0~255
TIM_InitStruct.IE = UTIMER_IE_CH0 | UTIMER_IE_ZERO; /* 开启Timer模块比较中断*/
UTIMER_Init(UTIMER1, &TIM_InitStruct);
}
void OPA_init(void)
{
AFE_ModuleClockCmd(AFE_MODULE_OPA0, ENABLE); // 打开OPA0
AFE_OpaGainConfig(AFE_MODULE_OPA0,AFE_OPA_RES_160_10);
AFE_ModuleClockCmd(AFE_MODULE_OPA1, ENABLE); // 打开OPA1
AFE_OpaGainConfig(AFE_MODULE_OPA1,AFE_OPA_RES_160_10);
AFE_ModuleClockCmd(AFE_MODULE_OPA2, ENABLE); // 打开OPA2
AFE_OpaGainConfig(AFE_MODULE_OPA1,AFE_OPA_RES_20_10);
}
void ADC0_init(void)
{
ADC_InitTypeDef ADC_InitStruct;
ADC_StructInit(&ADC_InitStruct);
ADC_InitStruct.IE = DISABLE; // ADC中断使能
ADC_InitStruct.RE = DISABLE; // ADC触发DMA使能
ADC_InitStruct.Align = ADC_ALIGN_RIGHT; // 采样数据对齐方式
// ADC_InitStruct.GAIN= ADC_GAIN_HIGH_DAT0; // 通道增益 高增益(1 倍)和低增益(2/3 倍),默认低增益
ADC_InitStruct.TROVS = ADC_TROVS_ONES; // 过采样触发模式
ADC_InitStruct.OVSR= ADC_OVSR_1; // 过采率,过采样可以提高信噪比
ADC_InitStruct.CSMP= ADC_CSMP_DISABLE; // 连续采样模式
ADC_InitStruct.TCNT= ADC_TCNT_1; // 触发次数
ADC_InitStruct.S1 = ADC_S1_1; // 第一段采样的通道数
ADC_InitStruct.S2 = ADC_S2_1; // 第二段采样总通道数,两段采样通道数之和最大为16
ADC_InitStruct.NSMP= ADC_NSMP_1; // ADC 触发模式 单段或双段
ADC_InitStruct.TRIG= ADC_TRIG_NONE; // UTIMER1比较事件0触发ADC采样使能,高有效
ADC_InitStruct.GEN0= ADC_GEN0_NONE; // 看门狗 0 通道使能
ADC_InitStruct.HTH0= 0; // 看门狗 0 上阈值
ADC_InitStruct.LTH0= 0; // 看门狗 0 下阈值
ADC_InitStruct.GEN1= ADC_GEN1_NONE; // 看门狗 1 通道使能
ADC_InitStruct.HTH1= 0; // 看门狗 1 上阈值
ADC_InitStruct.LTH1= 0; // 看门狗 1 下阈值
ADC_Init(ADC0, &ADC_InitStruct);
ADC_SetPChanne(ADC0, ADC_DAT_0, ADC_CHN_0); // ADC正端信号选择
}
void ADC1_init(void)
{
ADC_InitTypeDef ADC_InitStruct;
ADC_StructInit(&ADC_InitStruct);
ADC_InitStruct.IE = DISABLE; // ADC中断使能
ADC_InitStruct.RE = DISABLE; // ADC触发DMA使能
ADC_InitStruct.Align = ADC_ALIGN_LEFT; // 采样数据对齐方式
// ADC_InitStruct.GAIN= ADC_GAIN_HIGH_DAT0; // 通道增益 高增益(1 倍)和低增益(2/3 倍),默认低增益
ADC_InitStruct.TROVS = ADC_TROVS_ONES; // 过采样触发模式
ADC_InitStruct.OVSR= ADC_OVSR_128; // 过采率,过采样可以提高信噪比
ADC_InitStruct.CSMP= ADC_CSMP_ENABLE; // 连续采样模式
ADC_InitStruct.TCNT= ADC_TCNT_1; // 触发次数
ADC_InitStruct.S1 = ADC_S1_1; // 第一段采样的通道数
ADC_InitStruct.S2 = ADC_S2_1; // 第二段采样总通道数,两段采样通道数之和最大为16
ADC_InitStruct.NSMP= ADC_NSMP_1; // ADC 触发模式 单段或双段
ADC_InitStruct.TRIG= ADC_TRIG_NONE; // UTIMER1比较事件0触发ADC采样使能,高有效
ADC_InitStruct.GEN0= ADC_GEN0_NONE; // 看门狗 0 通道使能
ADC_InitStruct.HTH0= 0; // 看门狗 0 上阈值
ADC_InitStruct.LTH0= 0; // 看门狗 0 下阈值
ADC_InitStruct.GEN1= ADC_GEN1_NONE; // 看门狗 1 通道使能
ADC_InitStruct.HTH1= 0; // 看门狗 1 上阈值
ADC_InitStruct.LTH1= 0; // 看门狗 1 下阈值
ADC_Init(ADC1, &ADC_InitStruct);
ADC_SetPChanne(ADC1, ADC_DAT_0, ADC_CHN_1); // ADC正端信号选择
}
void ADC2_init(void)
{
ADC_InitTypeDef ADC_InitStruct;
ADC_StructInit(&ADC_InitStruct);
ADC_InitStruct.IE = DISABLE; // ADC中断使能
ADC_InitStruct.RE = ENABLE; // ADC触发DMA使能
ADC_InitStruct.Align = ADC_ALIGN_LEFT; // 采样数据对齐方式
// ADC_InitStruct.GAIN= ADC_GAIN_HIGH_DAT0; // 通道增益 高增益(1 倍)和低增益(2/3 倍),默认低增益
ADC_InitStruct.TROVS = ADC_TROVS_ONES; // 过采样触发模式
ADC_InitStruct.OVSR= ADC_OVSR_1; // 过采率,过采样可以提高信噪比
ADC_InitStruct.CSMP= ADC_CSMP_DISABLE; // 连续采样模式
ADC_InitStruct.TCNT= ADC_TCNT_1; // 触发次数
ADC_InitStruct.S1 = ADC_S1_1; // 第一段采样的通道数
ADC_InitStruct.S2 = ADC_S2_1; // 第二段采样总通道数,两段采样通道数之和最大为16
ADC_InitStruct.NSMP= ADC_NSMP_1; // ADC 触发模式 单段或双段
ADC_InitStruct.TRIG= ADC_TRIG_UTIMER1_CMP0_EN; // UTIMER1比较事件0触发ADC采样使能,高有效
ADC_InitStruct.GEN0= ADC_GEN0_NONE; // 看门狗 0 通道使能
ADC_InitStruct.HTH0= 0; // 看门狗 0 上阈值
ADC_InitStruct.LTH0= 0; // 看门狗 0 下阈值
ADC_InitStruct.GEN1= ADC_GEN1_NONE; // 看门狗 1 通道使能
ADC_InitStruct.HTH1= 0; // 看门狗 1 上阈值
ADC_InitStruct.LTH1= 0; // 看门狗 1 下阈值
ADC_Init(ADC2, &ADC_InitStruct);
ADC_SetPChanne(ADC2, ADC_DAT_0, ADC_CHN_2); // ADC正端信号选择
}
void DAC_init(void)
{
AFE_ModuleClockCmd(AFE_MODULE_DAC0, ENABLE); // 打开DAC0
AFE_DacSetRange(AFE_MODULE_DAC0, AFE_DAC_RANGE_1_2V); // 设置DAC0的量程为1.2V
AFE_DacSetVoltage(AFE_MODULE_DAC0, 0); // DAC0输出0
AFE_Dac0OutGpio3Pin4(ENABLE); // 将DAC0输出到P3.4
AFE_ModuleClockCmd(AFE_MODULE_DAC1, ENABLE); // 打开DAC1
AFE_DacSetRange(AFE_MODULE_DAC1, AFE_DAC_RANGE_3_0V); // 设置DAC1的量程为3V
AFE_DacSetVoltage(AFE_MODULE_DAC1, 0); // DAC1输出0
AFE_Dac1OutGpio4Pin7(ENABLE); // 将DAC1输出到P4.7
}
void DMA_init(void)
{
DMA_Enable();
DMA_InitTypeDef DMAInitStruct;
DMAInitStruct.DMA_Channel_EN = ENABLE; /* DMA 通道使能*/
DMAInitStruct.DMA_IRQ_EN = DISABLE; /* DMA 中断使能 */
DMAInitStruct.DMA_RMODE = DISABLE; /* 多轮传输使能 */
DMAInitStruct.DMA_CIRC = DISABLE; /* 循环模式使能 */
DMAInitStruct.DMA_SINC = DISABLE; /* 源地址递增使能 */
DMAInitStruct.DMA_DINC = DISABLE; /* 目的地址递增使能 */
DMAInitStruct.DMA_SBTW = 1; /* 源地址访问位宽, 0:byte, 1:half-word, 2:word */
DMAInitStruct.DMA_DBTW = 1; /* 目的地址访问位宽, 0:byte, 1:half-word, 2:word */
DMAInitStruct.DMA_REQ_EN = DMA_REQ_ADC2; /* 通道 x 硬件 DMA 请求使能,高有效 */
DMAInitStruct.DMA_TIMES = 1; /* DMA 通道 x 数据搬运次数 */
DMAInitStruct.DMA_SADR = 0x40018000; /* DMA 通道 x 源地址 ADCx_DAT0 x=2*/
DMAInitStruct.DMA_DADR = 0x4001A80C; /* DMA 通道 x 目的地址 SPI_TXDATA*/
DMA_Init(DMA_CH0, &DMAInitStruct);
DMA_CH0->REN |= DMA_REQ_ADC2;
}
//void DMA_IRQHandler(void){
// SPI_SendData(SPI0,0); // 触发发送,这里的0可以写任意值
//}
void SPI_init(void)
{
GPIO_Config(GPIO1, 6, GPIO_Mode_OUT, GPIO_AF_SPI);
GPIO_Config(GPIO1, 13, GPIO_Mode_OUT, GPIO_AF_SPI);
SPI_InitTypeDef spiconfig;
spiconfig.EN = 1; //SPI模块使能:0,关闭;1,开启
spiconfig.CPHA = 0; //相位选择:0对应0;1对应1
spiconfig.CPOL = 0; //极性选择:0对应0;1对应1
spiconfig.ByteLength = 16; //SPI传输数据长度 8 - 16 有效
spiconfig.BaudRate = 3; //波特率设置 注意,这里的波特率指的是用户手册里的SPI传输波特率配置寄存器,SPI 实际传输速度计算公式为:SPI 传输速度 = 系统时钟 / (2*(BAUD + 1))
spiconfig.DataOrder= 0; //传输顺序:0,高位先传;1,低位先传
spiconfig.IRQEna = 0; //SPI中断使能:0,关闭;1,开启
spiconfig.Mode = 1; //主从模式选择:0,从模式;1,主模式
spiconfig.Duplex = 2; //全双工、半双工工作模式选择:0,全双工;2,半双工仅发送;3,半双工仅接收
spiconfig.CS = 0; //从设备下片选信号来源 0,恒有效 1,来源于主设备
spiconfig.Trig = 0; //传输触发选择:0,内部自动执行(仅主模式有效);1,外部触发
spiconfig.TRANS_MODE = 0; //SPI数据搬运方式:0,DMA搬运;1,MCU搬运
SPI_Init(SPI0, &spiconfig);
SPI_SetBaudRate(SPI0, 24000000);
// for (;;) {
// SPI_SendData(SPI0, 0xaf);
// UTIMER_DelayUs(UTIMER0, 100);
// }
}
调试器能看到ADC2_DAT00x40018000在变动,但DMA 通道 x 目的地址 SPI_TXDATA0x4001A80C无变动,示波器也显示SPI无信号 用CPU搬运也不行,难道是芯片坏了,不过例程里SPI发数据又能用
void ADC2_IRQHandler(void){
if (ADC2_IF & BIT0) // 判断是否发生第一采样完成中断
{
ADC2_IF = BIT0;
SPI_SendData(SPI0, *(u16*)(0x40018000));
}
} 日狗狂魔 发表于 2025-9-5 17:05
用CPU搬运也不行,难道是芯片坏了,不过例程里SPI发数据又能用
void ADC2_IRQHandler(void){
中断的方法可以了,要加上 NVIC_EnableIRQ(ADC2_IRQn);
DMA的方法还是不行 设置为周期性向上计数模式,并配置自动重载值以设定触发间隔
页:
[1]