日狗狂魔 发表于 2025-9-5 16:51

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);
//    }


}


日狗狂魔 发表于 2025-9-5 16:52

调试器能看到ADC2_DAT00x40018000在变动,但DMA 通道 x 目的地址 SPI_TXDATA0x4001A80C无变动,示波器也显示SPI无信号

日狗狂魔 发表于 2025-9-5 17:05

用CPU搬运也不行,难道是芯片坏了,不过例程里SPI发数据又能用
void ADC2_IRQHandler(void){

    if (ADC2_IF & BIT0) // 判断是否发生第一采样完成中断
    {
      ADC2_IF = BIT0;   
      SPI_SendData(SPI0, *(u16*)(0x40018000));
    }
}

日狗狂魔 发表于 2025-9-5 20:20

日狗狂魔 发表于 2025-9-5 17:05
用CPU搬运也不行,难道是芯片坏了,不过例程里SPI发数据又能用
void ADC2_IRQHandler(void){



中断的方法可以了,要加上                NVIC_EnableIRQ(ADC2_IRQn);
DMA的方法还是不行

tpgf 发表于 2025-9-17 09:18

设置为周期性向上计数模式,并配置自动重载值以设定触发间隔
页: [1]
查看完整版本: DMA不工作