打印
[技术问答]

DMA + TIM触发, DAC无输出。

[复制链接]
492|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Sam131208|  楼主 | 2023-6-28 09:51 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 Sam131208 于 2023-7-7 15:12 编辑

     如下图,传输数据到DAC,用tim2做触发,tim2比较中断24KHZ, tim2比较中断正常进入。但是DMA中断一直没有。 换了DMA软件触发就正常了。


static void start_dma(en_dma_channel_t ch, const void *src, const void *dst, uint16_t blk_size)
{
   stc_dma_cfg_t DmaInitStruct;

    Sysctrl_SetPeripheralGate(SysctrlPeripheralDma, TRUE);          ///< 使能DMA模块的外设时钟

    DDL_ZERO_STRUCT(DmaInitStruct);                                 //结构体变量值清零
    DmaInitStruct.enMode =  DmaMskBlock;                            ///< 选择块传输
    DmaInitStruct.u16BlockSize = 1;                                 ///< 块传输个数
    DmaInitStruct.u16TransferCnt = blk_size;                        ///< 块传输次数,一次传输数据大小为 块传输个数*BUFFER_SIZE
    DmaInitStruct.enTransferWidth = DmaMsk16Bit;                    ///< 传输数据的宽度,此处选择字(16Bit)宽度
    DmaInitStruct.enSrcAddrMode = DmaMskSrcAddrInc;                 ///< 源地址自增
    DmaInitStruct.enDstAddrMode = DmaMskDstAddrFix;                 ///< 目的地址自增
    DmaInitStruct.enDestAddrReloadCtl = DmaMskDstAddrReloadDisable; ///< 禁止重新加载传输目的地址
    DmaInitStruct.enSrcAddrReloadCtl = DmaMskSrcAddrReloadDisable;  ///< 使能重新加载传输源地址
    DmaInitStruct.enSrcBcTcReloadCtl = DmaMskBcTcReloadDisable;     ///< 使能重新加载BC/TC值
    DmaInitStruct.u32SrcAddress = (uint32_t)src;                        ///< 源地址
    DmaInitStruct.u32DstAddress = (uint32_t)dst;                    ///< 目标地址:DAC_DHR12R0
    DmaInitStruct.enRequestNum = DmaTIM2ATrig;                      ///< 设置TIM2A触发
    DmaInitStruct.enTransferMode = DmaMskOneTransfer;                        ///< 传输一次,DMAC传输完成时清除CONFA:ENS位
    DmaInitStruct.enPriority = DmaMskPriorityFix;                   ///< 各通道固定优先级,CH0优先级 > CH1优先级   
    Dma_InitChannel(ch,&DmaInitStruct);                                 ///< 初始化dma通道0

    Dma_EnableChannelIrq(ch);                                                                     //传输成功完成时产生中断
    EnableNvic(DMAC_IRQn,IrqLevel3,TRUE);                                                         //NVIC对应DMAC中断位使能   

    Dma_Enable();                                                   ///< 使能DMA
    Dma_EnableChannel(ch);                                              ///< 使能DMA通道0
}



使用特权

评论回复
沙发
MCU@Baize| | 2023-6-29 18:00 | 只看该作者
代码里没有设置DMA的AOS事件,要将DMA通道的触发事件设置为TMER2的事件,并打开TIMER2对应的外设中断使能。

使用特权

评论回复
板凳
Sam131208|  楼主 | 2023-6-30 08:51 | 只看该作者
MCU[url=home.php?mod=space&uid=1542232]@baize 发表于 2023-6-29 18:00[/url]
代码里没有设置DMA的AOS事件,要将DMA通道的触发事件设置为TMER2的事件,并打开TIMER2对应的外设中断使能。 ...

  使用的是HC32L196, 如何设置TIM2 的AOS事件?

void App_Timer2Cfg(uint16_t u16Period, uint16_t u16CHxACompare, uint16_t u16CHxBCompare)
{
    uint16_t                   u16CntValue;
    uint8_t                    u8ValidPeriod;
    stc_bt_mode23_cfg_t        stcBtBaseCfg;
    stc_bt_m23_compare_cfg_t   stcBtPortCmpCfg;
    stc_bt_m23_adc_trig_cfg_t  stcBtTrigAdc;
    stc_bt_m23_dt_cfg_t        stcBtDeadTimeCfg;
   
    DDL_ZERO_STRUCT(stcBtBaseCfg);
    DDL_ZERO_STRUCT(stcBtPortCmpCfg);
    DDL_ZERO_STRUCT(stcBtTrigAdc);
    DDL_ZERO_STRUCT(stcBtDeadTimeCfg);

    Sysctrl_SetPeripheralGate(SysctrlPeripheralBaseTim, TRUE);   //Base Timer外设时钟使能      
        
    stcBtBaseCfg.enWorkMode    = BtWorkMode2;              //三角波模式
    stcBtBaseCfg.enCT          = BtTimer;                  //定时器功能,计数时钟为内部PCLK
    stcBtBaseCfg.enPRS         = BtPCLKDiv1;               //PCLK
    stcBtBaseCfg.enCntDir      = BtCntUp;                  //向上计数,在三角波模式时只读
    stcBtBaseCfg.enPWMTypeSel  = BtIndependentPWM;         //独立输出PWM
    stcBtBaseCfg.enPWM2sSel    = BtSinglePointCmp;         //单点比较功能
    stcBtBaseCfg.bOneShot      = FALSE;                    //循环计数
    stcBtBaseCfg.bURSSel       = FALSE;                    //上下溢更新
   
    Bt_Mode23_Init(TIM2, &stcBtBaseCfg);                   //TIM0 的模式23功能初始化
   
    Bt_M23_ARRSet(TIM2, u16Period, TRUE);                  //设置重载值,并使能缓存

    Bt_M23_CCR_Set(TIM2, BtCCR0A, u16CHxACompare);         //设置比较值A,(PWM互补模式下只需要设置比较值A)
   
    stcBtPortCmpCfg.enCH0ACmpCtrl   = BtPWMMode2;          //OCREFA输出控制OCMA:PWM模式2
    stcBtPortCmpCfg.enCH0APolarity  = BtPortPositive;      //正常输出
    stcBtPortCmpCfg.bCh0ACmpBufEn   = TRUE;                //A通道缓存控制
    stcBtPortCmpCfg.enCh0ACmpIntSel = BtCmpIntNone;        //A通道比较控制:无
   
    stcBtPortCmpCfg.enCH0BCmpCtrl   = BtPWMMode2;          //OCREFB输出控制OCMB:PWM模式2(PWM互补模式下也要设置,避免强制输出)
    stcBtPortCmpCfg.enCH0BPolarity  = BtPortPositive;      //正常输出
    stcBtPortCmpCfg.bCH0BCmpBufEn   = TRUE;                //B通道缓存控制使能
    stcBtPortCmpCfg.enCH0BCmpIntSel = BtCmpIntNone;        //B通道比较控制:无
   
    Bt_M23_PortOutput_Cfg(TIM2, &stcBtPortCmpCfg);         //比较输出端口配置
   
    stcBtTrigAdc.bEnTrigADC    = TRUE;                     //使能ADC触发全局控制
    stcBtTrigAdc.bEnUevTrigADC = TRUE;                     //Uev更新触发ADC
    Bt_M23_TrigADC_Cfg(TIM2, &stcBtTrigAdc);               //触发ADC配置
   
    u8ValidPeriod = 1;                                     //事件更新周期设置,0表示三角波每半个周期更新一次,每+1代表延迟半个周期
    Bt_M23_SetValidPeriod(TIM2,u8ValidPeriod);             //间隔周期设置
   
    stcBtDeadTimeCfg.bEnDeadTime      = TRUE;
    stcBtDeadTimeCfg.u8DeadTimeValue  = 0xFF;
    Bt_M23_DT_Cfg(TIM2, &stcBtDeadTimeCfg);             //死区配置

   
    u16CntValue = 0;
   
    Bt_M23_Cnt16Set(TIM2, u16CntValue);                    //设置计数初值
   
    Bt_ClearAllIntFlag(TIM2);                              //清中断标志
    Bt_Mode23_EnableIrq(TIM2,BtCA0Irq);                    //使能TIM0 UEV更新中断
    EnableNvic(TIM2_IRQn, IrqLevel0, TRUE);                //TIM0中断使能   
}
void Tim2_IRQHandler(void)
{
    //Timer2 模式23 溢出中断
    if(TRUE == Bt_GetIntFlag(TIM2, BtCA0Irq))
    {
        Bt_ClearIntFlag(TIM2,BtCA0Irq); //中断标志清零
    }
}

使用特权

评论回复
地板
MCU@Baize| | 2023-6-30 12:26 | 只看该作者
添加以下代码:
stc_bt_m23_trig_dma_cfg_t stcbtdmatrigCfg;
DDL_ZERO_STRUCT(stcbtdmatrigCfg);
stcbtdmatrigCfg.bCmpATrigDMA = TRUE;
    stcbtdmatrigCfg.bTITrigDMA = TRUE;
    stcbtdmatrigCfg.enCmpUevTrigDMA = TRUE;
    stcbtdmatrigCfg.bUevTrigDMA = TRUE;
   Bt_M23_EnDMA(TIM2, &stcbtdmatrigCfg);


淘宝店铺:白泽开发板
各类国产品牌MCU评估板(小华、GD、极海,持续更新中。。。。。。)

【淘宝】https://m.tb.cn/h.5aCN4a4?tk=sF14dsQXD6p CZ0001 「小华  HC32F448MCTI 核心板  开发板 工程板」
点击链接直接打开 或者 淘宝搜索直接打开

使用特权

评论回复
5
Sam131208|  楼主 | 2023-7-5 16:37 | 只看该作者
MCU@Baize 发表于 2023-6-30 12:26
添加以下代码:
stc_bt_m23_trig_dma_cfg_t stcbtdmatrigCfg;
DDL_ZERO_STRUCT(stcbtdmatrigCfg);

      你好,DMA可以工作了。
      只是DAC似乎没有反应。以下是我的代码。
      tim_trigdma_cfg(TIM2, 16000);
      audio_dac_opa_enable(true);
      start_dma(DmaCh0, dac_tream.mem_block, 0x4000250C, block_size); //输出DAC0 ,左对齐



static void start_dma(en_dma_channel_t ch, const void *src, const void *dst, uint16_t blk_size)
{
        stc_dma_cfg_t DmaInitStruct;

    Sysctrl_SetPeripheralGate(SysctrlPeripheralDma, TRUE);          ///< 使能DMA模块的外设时钟

        DDL_ZERO_STRUCT(DmaInitStruct);                                 //结构体变量值清零
    DmaInitStruct.enMode =  DmaMskBlock;                            ///< 选择块传输
    DmaInitStruct.u16BlockSize = 1;                                 ///< 块传输个数
    DmaInitStruct.u16TransferCnt = blk_size;                        ///< 块传输次数,一次传输数据大小为 块传输个数*BUFFER_SIZE
    DmaInitStruct.enTransferWidth = DmaMsk16Bit;                    ///< 传输数据的宽度,此处选择字(16Bit)宽度
    DmaInitStruct.enSrcAddrMode = DmaMskSrcAddrInc;                 ///< 源地址自增
    DmaInitStruct.enDstAddrMode = DmaMskDstAddrFix;                 ///< 目的地址自增
    DmaInitStruct.enDestAddrReloadCtl = DmaMskDstAddrReloadDisable; ///< 禁止重新加载传输目的地址
    DmaInitStruct.enSrcAddrReloadCtl = DmaMskSrcAddrReloadDisable;  ///< 使能重新加载传输源地址
    DmaInitStruct.enSrcBcTcReloadCtl = DmaMskBcTcReloadDisable;     ///< 使能重新加载BC/TC值
    DmaInitStruct.u32SrcAddress = (uint32_t)src;                        ///< 源地址
    DmaInitStruct.u32DstAddress = (uint32_t)dst;                    ///< 目标地址:DAC_DHR12R0
    DmaInitStruct.enRequestNum = DmaTIM2ATrig;                      ///< 设置TIM2A触发
    DmaInitStruct.enTransferMode = DmaMskOneTransfer;                        ///< 传输一次,DMAC传输完成时清除CONFA:ENS位
    DmaInitStruct.enPriority = DmaMskPriorityFix;                   ///< 各通道固定优先级,CH0优先级 > CH1优先级   
    Dma_InitChannel(ch,&DmaInitStruct);                                 ///< 初始化dma通道0

    Dma_EnableChannelIrq(ch);                                                                     //传输成功完成时产生中断
    EnableNvic(DMAC_IRQn,IrqLevel3,TRUE);                                                         //NVIC对应DMAC中断位使能   

    Dma_Enable();                                                   ///< 使能DMA
    Dma_EnableChannel(ch);                                              ///< 使能DMA通道0
    Dma_ClrStat(ch);                                                    ///< 清零:STAT[2:0]   
}

static void tim_trigdma_cfg(en_bt_unit_t TIMx, uint16_t sample_rate)
{
    uint16_t                   period = Sysctrl_GetPClkFreq() / sample_rate;
    uint8_t                    u8ValidPeriod;
    stc_bt_mode23_cfg_t        stcBtBaseCfg;
        stc_bt_m23_trig_dma_cfg_t  stcbtdmatrigCfg;

    Sysctrl_SetPeripheralGate(SysctrlPeripheralBaseTim, TRUE);   //Base Timer外设时钟使能      

        DDL_ZERO_STRUCT(stcBtBaseCfg);
    stcBtBaseCfg.enWorkMode    = BtWorkMode2;                      //三角波模式
    stcBtBaseCfg.enCT          = BtTimer;                         //定时器功能,计数时钟为内部PCLK
    stcBtBaseCfg.enPRS         = BtPCLKDiv1;                       //PCLK
    stcBtBaseCfg.enCntDir      = BtCntUp;                          //向上计数,在三角波模式时只读
    stcBtBaseCfg.enPWMTypeSel  = BtIndependentPWM;                 //独立输出PWM
    stcBtBaseCfg.enPWM2sSel    = BtSinglePointCmp;                 //单点比较功能
    stcBtBaseCfg.bOneShot      = FALSE;                            //循环计数
    stcBtBaseCfg.bURSSel       = FALSE;                            //上下溢更新
    Bt_Mode23_Init(TIMx, &stcBtBaseCfg);                           //TIM0 的模式23功能初始化

        DDL_ZERO_STRUCT(stcbtdmatrigCfg);
        stcbtdmatrigCfg.bCmpATrigDMA = TRUE;
    stcbtdmatrigCfg.bTITrigDMA = TRUE;
        Bt_M23_EnDMA(TIMx, &stcbtdmatrigCfg);

    Bt_M23_ARRSet(TIMx, period, TRUE);                          //设置重载值,并使能缓存
    Bt_M23_CCR_Set(TIMx, BtCCR0A, period / 2);                         //设置比较值A,(PWM互补模式下只需要设置比较值A)
    Bt_M23_SetValidPeriod(TIMx, 1);                                     //间隔周期设置, 事件更新周期设置,0表示三角波每半个周期更新一次,每+1代表延迟半个周期
    Bt_M23_Cnt16Set(TIMx, 0);                                            //设置计数初值
}

static void audio_dac_opa_enable(bool enable)
{
        if(enable){
                stc_dac_cfg_t  dac_initstruct;

                Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE);            // 使能GPIO模块的时钟
                Sysctrl_SetPeripheralGate(SysctrlPeripheralDac, TRUE);             ///< 使能DAC模块的时钟
                //Sysctrl_SetPeripheralGate(SysctrlPeripheralOpa, TRUE);                     // 使能OPA模块的时钟
                Sysctrl_SetPeripheralGate(SysctrlPeripheralAdcBgr, TRUE);                  // 使能BGR模块的时钟

                Gpio_SetAnalogMode(GpioPortA, GpioPin4);       //PA04作为DAC的模拟输出
               
                dac_initstruct.boff_t = DacBoffEnable;
                dac_initstruct.ten_t  = DacTenDisable;
                dac_initstruct.sref_t = DacVoltageAvcc;
                dac_initstruct.mamp_t = DacMenp4095;
                dac_initstruct.tsel_t = DacSwTriger;      ///< 软件触发方式
                dac_initstruct.align  = DacLeftAlign;     ///< 左对齐
                Dac_Init(&dac_initstruct);
                Dac_Cmd(TRUE);
                Dac_DmaCmd(TRUE);                       ///< DAC通道DMA使能

                //Bgr_BgrEnable();
                //Opa_Cmd(FALSE);                                                                             // 禁止OPA(注:此时的OPA输入时通过DAC的输出提供信号)
                //Opa_CmdBuf(TRUE);                                                                                   // 使能OPABUFEN
        }else{
                Bgr_BgrDisable();
                Sysctrl_SetPeripheralGate(SysctrlPeripheralAdcBgr, TRUE);                  // 使能BGR模块的时钟
                Sysctrl_SetPeripheralGate(SysctrlPeripheralOpa, TRUE);                     // 使能OPA模块的时钟
        }
}

使用特权

评论回复
6
Sam131208|  楼主 | 2023-7-7 15:15 | 只看该作者
   
    有人能解决问题吗

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

29

主题

93

帖子

0

粉丝