[技术问答] 华大单片机的DMA为啥搞个块大小出来?一次最多只能16个数...

[复制链接]
7780|36
 楼主| GZZXB 发表于 2019-4-15 22:08 | 显示全部楼层 |阅读模式
算是阉割版DMA吗? STM32多爽想传多少就传多少,华大最多只能一次传16吧,超过16就得用软件+中断实现了。

评论

确实有点阉割  发表于 2025-4-27 16:22
je段 发表于 2019-4-18 15:08 | 显示全部楼层
技术呢,出来帮忙解释下啊我只负责卖

评论

快把你们公司的技术拽出来上论坛呦~会加大销量的~  发表于 2019-4-18 15:40
smartpower 发表于 2019-4-18 21:13 | 显示全部楼层
1. 设置块数:(从 1 至 16 中选择)
2. 设置传输长度:(从 1 至 65536 中选择)
3. 总传输长度可达为  16 * 65536 个字节。
operating 发表于 2019-4-28 16:31 | 显示全部楼层
应该可以多传的吧
martinhu 发表于 2019-4-29 09:40 | 显示全部楼层
547985cc654fb05841.png
229415cc65518200c9.png
BC块数:(从 1 至 16 中选择)
TC传输长度:(从 1 至 65536 中选择)
BC和TC合理使用,可以实现很多种传输组合
 楼主| GZZXB 发表于 2019-5-2 13:11 | 显示全部楼层
martinhu 发表于 2019-4-29 09:40
BC块数:(从 1 至 16 中选择)
TC传输长度:(从 1 至 65536 中选择)
BC和TC合理使用,可以实现很多种 ...

需要软件+中断 才能实现。不像STM32设置好了,不用中断不用写代码处理。
martinhu 发表于 2019-5-5 08:48 | 显示全部楼层
GZZXB 发表于 2019-5-2 13:11
需要软件+中断 才能实现。不像STM32设置好了,不用中断不用写代码处理。

有硬件模式,只要有对应的触发事件就可以触发DMA传送,不需要非得软件+中断才可以
 楼主| GZZXB 发表于 2019-5-5 09:03 | 显示全部楼层
martinhu 发表于 2019-5-5 08:48
有硬件模式,只要有对应的触发事件就可以触发DMA传送,不需要非得软件+中断才可以 ...

比如我扫描采集3个AD通道0 1 2,一共采集255*3个数据到buff。 不使用DMA中断,你能实现?

评论

@martinhu :测试了DMA,地址重新装载只能在全部完成后,不能触发一次 源地址重新装载。是哪里设置错误了吗?  发表于 2020-4-3 11:41
如果DMA传送完成中断和ADT的AOS功能,你都不想用,按上述的设置方法,DMAC寄存器CONFBx的MSK位设置为0,那么DMA传送255次之后自然清除了该通道的使能位,你只需要在下次使用时候配置和使能就好了  发表于 2019-5-7 10:56
能啊,BC设置为2(block数据为3),TC设置为254(传送255次),模式为硬件块传输,使用timer0~6其中之一触发ADC转换3个通道,ADC转换结束后触发DMA搬运,ADC转换255次(也就是DMA搬运255次)之后,可以使用DMA转换完成中断,结束你要的255*3次的采样操作。如果你实在不想要中断,那么用ADT0(timer4)触发ADC采样,ADT1(timer5)通过AOS的硬件计数采样次数,到255次之后timer5通过AOS停止timer4!  发表于 2019-5-7 10:51
mtbf 发表于 2020-4-6 21:26 | 显示全部楼层
想ADC每1ms扫描采集10通道,每10ms处理一次数据,用DMA搬运数据,TC只能设置成0,即一次扫描采集完成,源地址重新装载。产生一次DMA中断。TC不能设置成9,即每10次扫描转换产生一次DMA中断。现在程序里是设置TC为0,目的地址不重新装载,记录到10次中断后,重新加载一次目的地址。这样设置中断比较频繁。
DMA控制器只能在TC减到0以后才能完成一次源地址,目的地址,BC,TC重新装载?

  1. #define ADC_BC 10
  2. #define ADC_TC 10

  3. uint32_t ADC_Result_Array[ADC_BC*10] = {0};
  4. uint16_t ADC_array_write_index = 0;
  5. uint32_t u32AdcRestult_VSEN;
  6. uint32_t u32AdcRestult_I1;
  7. uint32_t u32AdcRestult_I2;
  8. extern QXSemaphore  sema_adc;

  9. uint16_t current_prev_1, current_prev_2;
  10. uint16_t current_flag_1, current_flag_2;

  11. void App_DmaCfg(void);
  12. void App_Timer0Cfg(uint16_t u16Period);
  13. void Adc_IRQHandler(void)
  14. {
  15.     if(TRUE == Adc_GetIrqStatus(AdcMskIrqSqr))
  16.     {
  17.         Adc_ClrIrqStatus(AdcMskIrqSqr);
  18. //        u16AdcRestult_VSEN = Adc_GetSqrResult(AdcSQRCH0MUX);
  19. //        u16AdcRestult_I1 = Adc_GetSqrResult(AdcSQRCH1MUX);;
  20. //        u16AdcRestult_I1_buf[0] = Adc_GetSqrResult(AdcSQRCH1MUX);
  21. //        u16AdcRestult_I1_buf[1] = Adc_GetSqrResult(AdcSQRCH2MUX);
  22. //        u16AdcRestult_I1_buf[2] = Adc_GetSqrResult(AdcSQRCH3MUX);
  23. //        u16AdcRestult_I1_buf[3] = Adc_GetSqrResult(AdcSQRCH4MUX);
  24. //        u16AdcRestult_I2 = Adc_GetSqrResult(AdcSQRCH5MUX);
  25. //        u16AdcRestult_I2_buf[0] = Adc_GetSqrResult(AdcSQRCH5MUX);
  26. //        u16AdcRestult_I2_buf[1] = Adc_GetSqrResult(AdcSQRCH6MUX);
  27. //        u16AdcRestult_I2_buf[2] = Adc_GetSqrResult(AdcSQRCH7MUX);
  28. //        u16AdcRestult_I2_buf[3] = Adc_GetSqrResult(AdcSQRCH8MUX);
  29. //        (void)QXSemaphore_signal(&sema_adc);
  30.     }
  31. }
  32. void Dmac_IRQHandler(void)
  33. {   
  34.     if(DmaTransferComplete == Dma_GetStat(DmaCh0))
  35.     {
  36.         //等待传输完成
  37.         //(void)QXSemaphore_signal(&sema_adc);
  38.         Dma_ClrStat(DmaCh0);
  39.         if(ADC_array_write_index < 9){
  40.             //M0P_DMAC->DSTADR0 = (uint32_t)&ADC_Result_Array[ADC_array_write_index*10];
  41.             ADC_array_write_index++;
  42.         }else{
  43.             ADC_array_write_index = 0;
  44.             M0P_DMAC->DSTADR0 = (uint32_t)&ADC_Result_Array[ADC_array_write_index];
  45.             IO_SET(LED_1, 1);
  46.             (void)QXSemaphore_signal(&sema_adc);
  47.         }
  48.     }
  49.     if(DmaTransferComplete == Dma_GetStat(DmaCh1))
  50.     {
  51.         //等待传输完成
  52.         //IO_SET(LED_1, 1);
  53.         //(void)QXSemaphore_signal(&sema_adc);
  54.         Dma_ClrStat(DmaCh1);
  55.         //IO_SET(LED_1, 0);
  56.     }
  57.     if((DmaAccSCRErr == Dma_GetStat(DmaCh0)) || (DmaAccDestErr == Dma_GetStat(DmaCh0)))
  58.     {
  59.         Dma_ClrStat(DmaCh0);
  60.     }
  61.    
  62. }
  63. void Tim0_IRQHandler(void)
  64. {
  65.     //Timer0 模式0 溢出中断
  66.     if(TRUE == Bt_GetIntFlag(TIM0, BtUevIrq))
  67.     {        
  68.         Bt_ClearIntFlag(TIM0,BtUevIrq); //中断标志清零        
  69.         //IO_SET(LED_1, 1);
  70.     }
  71. }
  72. void App_Timer0Cfg(uint16_t u16Period)
  73. {
  74.     uint16_t                  u16ArrValue;
  75.     uint16_t                  u16CntValue;
  76.     stc_bt_mode0_cfg_t     stcBtBaseCfg;
  77.     stc_bt_m23_adc_trig_cfg_t  stcBtTrigAdc;
  78.     DDL_ZERO_STRUCT(stcBtBaseCfg);
  79.     DDL_ZERO_STRUCT(stcBtTrigAdc);
  80.     Sysctrl_SetPeripheralGate(SysctrlPeripheralBaseTim, TRUE); //Base Timer外设时钟使能
  81.    
  82.     stcBtBaseCfg.enWorkMode = BtWorkMode0;                  //定时器模式
  83.     stcBtBaseCfg.enCT       = BtTimer;                      //定时器功能,计数时钟为内部PCLK
  84.     stcBtBaseCfg.enPRS      = BtPCLKDiv8;                 //PCLK/256
  85.     stcBtBaseCfg.enCntMode  = Bt16bitArrMode;               //自动重载16位计数器/定时器
  86.     stcBtBaseCfg.bEnTog     = FALSE;
  87.     stcBtBaseCfg.bEnGate    = FALSE;
  88.     stcBtBaseCfg.enGateP    = BtGatePositive;
  89.     Bt_Mode0_Init(TIM0, &stcBtBaseCfg);                     //TIM0 的模式0功能初始化
  90.    
  91.     u16ArrValue = 0x10000 - u16Period;
  92.     Bt_M0_ARRSet(TIM0, u16ArrValue);                        //设置重载值(ARR = 0x10000 - 周期)
  93.    
  94.     u16CntValue = 0x10000 - u16Period;
  95.     Bt_M0_Cnt16Set(TIM0, u16CntValue);                      //设置计数初值
  96.    
  97.     stcBtTrigAdc.bEnTrigADC    = TRUE;                     //使能ADC触发全局控制
  98.     stcBtTrigAdc.bEnUevTrigADC = TRUE;                     //Uev更新触发ADC
  99.     Bt_M23_TrigADC_Cfg(TIM0, &stcBtTrigAdc);               //触发ADC配置
  100.    
  101.     Bt_ClearIntFlag(TIM0,BtUevIrq);                         //清中断标志   
  102.     //Bt_Mode0_EnableIrq(TIM0);                               //使能TIM0中断(模式0时只有一个中断)
  103.     //EnableNvic(TIM0_IRQn, IrqLevel3, TRUE);                 //TIM0中断使能
  104. }
  105. void aio_init(void)
  106. {
  107.     stc_adc_cfg_t stcAdcCfg;
  108.     stc_adc_sqr_cfg_t stcAdcSqrCfg;
  109.     DDL_ZERO_STRUCT(stcAdcCfg);
  110.     DDL_ZERO_STRUCT(stcAdcSqrCfg);
  111.    
  112.    
  113.     Gpio_SetAnalogMode(GpioPortB, GpioPin0);
  114.     Gpio_SetAnalogMode(GpioPortB, GpioPin1);
  115.     Gpio_SetAnalogMode(GpioPortB, GpioPin11);
  116.    
  117.     if (Ok != Sysctrl_SetPeripheralGate(SysctrlPeripheralAdcBgr, TRUE))
  118.     {
  119.         Q_onAssert("adc_err", 999);
  120.     }  
  121.     Bgr_BgrEnable();        ///< 开启BGR
  122.     //ADC配置   
  123.         
  124.     stcAdcCfg.enAdcMode         = AdcScanMode;              ///<采样模式-扫描
  125.     stcAdcCfg.enAdcClkDiv       = AdcMskClkDiv8;            ///<采样分频-8
  126.     stcAdcCfg.enAdcSampCycleSel = AdcMskSampCycle12Clk;      ///<采样周期数-8
  127.     stcAdcCfg.enAdcRefVolSel    = AdcMskRefVolSelInBgr2p5;   ///<参考电压选择-2.5V
  128.     stcAdcCfg.enAdcOpBuf        = AdcMskBufDisable;         ///<OP BUF配置-
  129.     stcAdcCfg.enInRef           = AdcMskInRefEnable;       ///<内部参考电压使能-关
  130.     stcAdcCfg.enAdcAlign        = AdcAlignRight;               ///<转换结果对齐方式-右
  131.     Adc_Init(&stcAdcCfg);
  132.    
  133.     stcAdcSqrCfg.bSqrDmaTrig = TRUE;
  134.     stcAdcSqrCfg.enResultAcc = AdcResultAccDisable;
  135.     stcAdcSqrCfg.u8SqrCnt    = 10;
  136.     Adc_SqrModeCfg(&stcAdcSqrCfg);
  137.    
  138.     Adc_CfgSqrChannel(AdcSQRCH0MUX, AdcExInputCH8);
  139.     Adc_CfgSqrChannel(AdcSQRCH9MUX, AdcExInputCH8);
  140.     Adc_CfgSqrChannel(AdcSQRCH1MUX, AdcExInputCH9);
  141.     Adc_CfgSqrChannel(AdcSQRCH2MUX, AdcExInputCH9);
  142.     Adc_CfgSqrChannel(AdcSQRCH3MUX, AdcExInputCH9);
  143.     Adc_CfgSqrChannel(AdcSQRCH4MUX, AdcExInputCH9);
  144.     Adc_CfgSqrChannel(AdcSQRCH5MUX, AdcExInputCH18);
  145.     Adc_CfgSqrChannel(AdcSQRCH6MUX, AdcExInputCH18);
  146.     Adc_CfgSqrChannel(AdcSQRCH7MUX, AdcExInputCH18);
  147.     Adc_CfgSqrChannel(AdcSQRCH8MUX, AdcExInputCH18);
  148.    
  149.     Adc_ClrIrqStatus(AdcMskIrqSqr);
  150.     Adc_SqrExtTrigCfg(AdcMskTrigTimer0, TRUE);         //Timer0触发扫描转换   
  151.    
  152.     App_DmaCfg();
  153.     //Adc_EnableIrq();
  154.     //EnableNvic(ADC_IRQn, IrqLevel3, TRUE);
  155.    
  156.     delay10us(5);
  157.     App_Timer0Cfg(3000);
  158. }
  159. void App_DmaCfg(void)
  160. {
  161.     stc_dma_cfg_t           stcDmaCfg;   
  162.    
  163.     DDL_ZERO_STRUCT(stcDmaCfg);                     //结构体变量 初始值清零
  164.    
  165.     // 使能 DMA时钟
  166.     Sysctrl_SetPeripheralGate(SysctrlPeripheralDma,TRUE);
  167.    
  168.     stcDmaCfg.enMode =  DmaMskBlock;                            //选择块传输
  169.     stcDmaCfg.u16BlockSize = 10;                             //块传输个数
  170.     stcDmaCfg.u16TransferCnt = 1;                           //Block模式,一次传输数据大小为 10,传输1次
  171.     stcDmaCfg.enTransferWidth = DmaMsk32Bit;                    //传输数据的宽度,此处选择字(32Bit)宽度
  172.     stcDmaCfg.enSrcAddrMode = DmaMskSrcAddrInc;                 //源地址自增
  173.     stcDmaCfg.enDstAddrMode = DmaMskDstAddrInc;                 //目的地址自增
  174.     stcDmaCfg.enDestAddrReloadCtl = DmaMskDstAddrReloadDisable; //不重新加载传输目的地址
  175.     stcDmaCfg.enSrcAddrReloadCtl = DmaMskSrcAddrReloadEnable;   //使能重新加载传输源地址
  176.     stcDmaCfg.enSrcBcTcReloadCtl = DmaMskBcTcReloadEnable;      //使能重新加载BC/TC值
  177.     stcDmaCfg.u32SrcAddress = (uint32_t)&(M0P_ADC->SQRRESULT0);//指定传输源地址
  178.     stcDmaCfg.u32DstAddress = (uint32_t)&ADC_Result_Array[0];   //指定传输目的地址
  179.     stcDmaCfg.enTransferMode = DmaMskContinuousTransfer;        //DMAC 在传输完成时不清除 CONFA:ENS 位。这个功能允许连续传输而不需要 CPU 干预。
  180.     stcDmaCfg.enRequestNum = DmaADCSQRTrig;                     //设置为ADC SQR触发
  181.    
  182.     Dma_InitChannel(DmaCh0,&stcDmaCfg);       //初始化DMA通道0
  183.    
  184. //    stcDmaCfg.enMode =  DmaMskBlock;                            //选择块传输
  185. //    stcDmaCfg.u16BlockSize = ADC_BC;                             //块传输个数
  186. //    stcDmaCfg.u16TransferCnt = ADC_TC;                           //Block模式,一次传输数据大小为 3,传输三次
  187. //    stcDmaCfg.enTransferWidth = DmaMsk32Bit;                    //传输数据的宽度,此处选择字(32Bit)宽度
  188. //    stcDmaCfg.enSrcAddrMode = DmaMskSrcAddrInc;                 //源地址自增
  189. //    stcDmaCfg.enDstAddrMode = DmaMskDstAddrInc;                 //目的地址自增
  190. //    stcDmaCfg.enDestAddrReloadCtl = DmaMskDstAddrReloadEnable; //使能重新加载传输目的地址
  191. //    stcDmaCfg.enSrcAddrReloadCtl = DmaMskSrcAddrReloadEnable;   //使能重新加载传输源地址
  192. //    stcDmaCfg.enSrcBcTcReloadCtl = DmaMskBcTcReloadEnable;      //使能重新加载BC/TC值
  193. //    stcDmaCfg.u32SrcAddress = (uint32_t)&ADC_Result_Array[0];//指定传输源地址
  194. //    stcDmaCfg.u32DstAddress = (uint32_t)&ADC_Result_buf_Array[0];   //指定传输目的地址
  195. //    stcDmaCfg.enTransferMode = DmaMskContinuousTransfer;        //DMAC 在传输完成时不清除 CONFA:ENS 位。这个功能允许连续传输而不需要 CPU 干预。
  196. //    stcDmaCfg.enRequestNum = DmaADCSQRTrig;                     //设置为ADC SQR触发
  197. //    Dma_InitChannel(DmaCh1,&stcDmaCfg);
  198.     //使能DMA,使能DMA0
  199.     Dma_Enable();
  200.     Dma_EnableChannel(DmaCh0);
  201.     Dma_EnableChannelIrq(DmaCh0);
  202.     Dma_EnableChannelErrIrq(DmaCh0);
  203.     //Dma_EnableChannel(DmaCh1);
  204.     //Dma_EnableChannelIrq(DmaCh1);
  205.    
  206.     EnableNvic(DMAC_IRQn, IrqLevel2, TRUE);
  207. }
mtbf 发表于 2020-4-9 22:21 | 显示全部楼层
不好意思,有技术支持能确认下吗?
liaotian001 发表于 2020-4-13 10:58 | 显示全部楼层
1. 设置块数:(从 1 至 16 中选择)
2. 设置传输长度:(从 1 至 65536 中选择)
3. 总传输长度可达为  16 * 65536 个字节。
HC32L136 使用了DMA,可以实现想传多少就传多少。以上传输模式对于客户而言是透明的,在总线架构上面为了满足系统对于实时性的需求,每次传16个数据,就会让总线,DMA进行一次仲裁,如果CPU无操作需求,DMA继续传输数据,也可以传大量数据,也不需要软件处理。
友商想传多少就传多少,会屏蔽CPU对于实时操作的能力,只有等DMA把所有数据传输完成之后,CPU才能继续响应中断,这对于系统而言,基本属于无实时性可言。
每种总线架构,有每种架构的需求,每个设计者考虑的东西也不一样,彼此都有优先级考虑的。我们考虑的是,DMA传输可能比友商慢一点点,但是整个系统对于实时响应性能强,DMA不会卡死CPU。
mtbf 发表于 2020-4-13 21:00 | 显示全部楼层
liaotian001 发表于 2020-4-13 10:58
1. 设置块数:(从 1 至 16 中选择)
2. 设置传输长度:(从 1 至 65536 中选择)
3. 总传输长度可达为  16 ...

你描述的是软件Block传输或硬件Burst传输情况,从ADC扫描转换结果寄存器 到内存不适合用。从ADC_SqrResult0 - 15传送一批数据到内存适合硬件Block传输。
liaotian001 发表于 2020-4-23 11:47 | 显示全部楼层
mtbf 发表于 2020-4-13 21:00
你描述的是软件Block传输或硬件Burst传输情况,从ADC扫描转换结果寄存器 到内存不适合用。从ADC_SqrResul ...

ADC_SqrResult0 - 15,一共16个数据,我们的DMA可以支持一次搬运完成的。硬件设计中,ADC采样完成最后一个buffer地址的采样,ADC 硬件 trigger DMA request, DMA就会完成一次16笔数据的搬运。
詹求实 发表于 2020-4-29 18:51 | 显示全部楼层
liaotian001 发表于 2020-4-23 11:47
ADC_SqrResult0 - 15,一共16个数据,我们的DMA可以支持一次搬运完成的。硬件设计中,ADC采样完成最后一 ...

DMA一次搬运的数据可以单独设置吗?
mtbf 发表于 2020-4-29 22:49 | 显示全部楼层
liaotian001 发表于 2020-4-23 11:47
ADC_SqrResult0 - 15,一共16个数据,我们的DMA可以支持一次搬运完成的。硬件设计中,ADC采样完成最后一 ...

定时器触发ADC完成16通道扫描,10KHz,想做到10次扫描以后参数16X10数据,DMA搬运到内存,产生一次中断。现在只能做到每扫描一次产生中断,也就是16次中断,中断频率跟定时器一样,10KHz。
舒伯特玫瑰 发表于 2020-4-30 17:55 | 显示全部楼层
不是必须中断吧,那样太费事了
lesheng002 发表于 2020-5-7 20:21 | 显示全部楼层
本帖最后由 lesheng002 于 2020-5-7 20:24 编辑
liaotian001 发表于 2020-4-13 10:58
1. 设置块数:(从 1 至 16 中选择)
2. 设置传输长度:(从 1 至 65536 中选择)
3. 总传输长度可达为  16 ...

照这个说法,DMA传输影响MCU的工作了,难怪我设计的ADC检测,用DMA传输结果,启动就死机了
liaotian001 发表于 2020-5-8 09:35 | 显示全部楼层
lesheng002 发表于 2020-5-7 20:21
照这个说法,DMA传输影响MCU的工作了,难怪我设计的ADC检测,用DMA传输结果,启动就死机了 ...

请仔细看一下我的说明,DMA传输数据,启动就死机,那我认为100%是你软件的问题了。
CharryW 发表于 2020-5-8 11:32 | 显示全部楼层
liaotian001 发表于 2020-4-13 10:58
1. 设置块数:(从 1 至 16 中选择)
2. 设置传输长度:(从 1 至 65536 中选择)
3. 总传输长度可达为  16 ...

这也太不专业了,DMA和CPU都作为主机会保证CPU有至少一半的AHB总线带宽,DMA即使连续传输中间也是有间隔的
lesheng002 发表于 2020-5-8 11:58 | 显示全部楼层
本帖最后由 lesheng002 于 2020-5-8 12:00 编辑
liaotian001 发表于 2020-5-8 09:35
请仔细看一下我的说明,DMA传输数据,启动就死机,那我认为100%是你软件的问题了。 ...

我不清楚你们是怎么做的,从目前的情况看,说不清楚到底是哪里的问题,不一定是DMA传输造成死机问题,可能是ADC转换,可能 是DMA,我使用贵公司FAE提供的代码(用TIM2触发ADC转换,转换结果用DMA传输到RAM),这个基础上简单的加上系统滴答,加上一个蜂鸣器,系统滴答用于延时,没有初始化ADC转换,DMA传输,蜂鸣器就不停的滴滴叫,打开ADC部分,就不吭声了,你说是我的代码问题还是MCU有问题?我将代码附上,麻烦你看看, 芯片型号是HC32L176KATA

dma_hw_trigger_block.zip

2.13 MB, 下载次数: 33

您需要登录后才可以回帖 登录 | 注册

本版积分规则

96

主题

331

帖子

10

粉丝
快速回复 在线客服 返回列表 返回顶部