华大单片机的DMA为啥搞个块大小出来?一次最多只能16个数...
算是阉割版DMA吗? STM32多爽想传多少就传多少,华大最多只能一次传16吧,超过16就得用软件+中断实现了。技术呢,出来帮忙解释下啊我只负责卖 1. 设置块数:(从 1 至 16 中选择)
2. 设置传输长度:(从 1 至 65536 中选择)
3. 总传输长度可达为16 * 65536 个字节。 应该可以多传的吧
BC块数:(从 1 至 16 中选择)
TC传输长度:(从 1 至 65536 中选择)
BC和TC合理使用,可以实现很多种传输组合 martinhu 发表于 2019-4-29 09:40
BC块数:(从 1 至 16 中选择)
TC传输长度:(从 1 至 65536 中选择)
BC和TC合理使用,可以实现很多种 ...
需要软件+中断 才能实现。不像STM32设置好了,不用中断不用写代码处理。 GZZXB 发表于 2019-5-2 13:11
需要软件+中断 才能实现。不像STM32设置好了,不用中断不用写代码处理。
有硬件模式,只要有对应的触发事件就可以触发DMA传送,不需要非得软件+中断才可以 martinhu 发表于 2019-5-5 08:48
有硬件模式,只要有对应的触发事件就可以触发DMA传送,不需要非得软件+中断才可以 ...
比如我扫描采集3个AD通道0 1 2,一共采集255*3个数据到buff。 不使用DMA中断,你能实现? 想ADC每1ms扫描采集10通道,每10ms处理一次数据,用DMA搬运数据,TC只能设置成0,即一次扫描采集完成,源地址重新装载。产生一次DMA中断。TC不能设置成9,即每10次扫描转换产生一次DMA中断。现在程序里是设置TC为0,目的地址不重新装载,记录到10次中断后,重新加载一次目的地址。这样设置中断比较频繁。
DMA控制器只能在TC减到0以后才能完成一次源地址,目的地址,BC,TC重新装载?
#define ADC_BC 10
#define ADC_TC 10
uint32_t ADC_Result_Array = {0};
uint16_t ADC_array_write_index = 0;
uint32_t u32AdcRestult_VSEN;
uint32_t u32AdcRestult_I1;
uint32_t u32AdcRestult_I2;
extern QXSemaphoresema_adc;
uint16_t current_prev_1, current_prev_2;
uint16_t current_flag_1, current_flag_2;
void App_DmaCfg(void);
void App_Timer0Cfg(uint16_t u16Period);
void Adc_IRQHandler(void)
{
if(TRUE == Adc_GetIrqStatus(AdcMskIrqSqr))
{
Adc_ClrIrqStatus(AdcMskIrqSqr);
// u16AdcRestult_VSEN = Adc_GetSqrResult(AdcSQRCH0MUX);
// u16AdcRestult_I1 = Adc_GetSqrResult(AdcSQRCH1MUX);;
// u16AdcRestult_I1_buf = Adc_GetSqrResult(AdcSQRCH1MUX);
// u16AdcRestult_I1_buf = Adc_GetSqrResult(AdcSQRCH2MUX);
// u16AdcRestult_I1_buf = Adc_GetSqrResult(AdcSQRCH3MUX);
// u16AdcRestult_I1_buf = Adc_GetSqrResult(AdcSQRCH4MUX);
// u16AdcRestult_I2 = Adc_GetSqrResult(AdcSQRCH5MUX);
// u16AdcRestult_I2_buf = Adc_GetSqrResult(AdcSQRCH5MUX);
// u16AdcRestult_I2_buf = Adc_GetSqrResult(AdcSQRCH6MUX);
// u16AdcRestult_I2_buf = Adc_GetSqrResult(AdcSQRCH7MUX);
// u16AdcRestult_I2_buf = Adc_GetSqrResult(AdcSQRCH8MUX);
// (void)QXSemaphore_signal(&sema_adc);
}
}
void Dmac_IRQHandler(void)
{
if(DmaTransferComplete == Dma_GetStat(DmaCh0))
{
//等待传输完成
//(void)QXSemaphore_signal(&sema_adc);
Dma_ClrStat(DmaCh0);
if(ADC_array_write_index < 9){
//M0P_DMAC->DSTADR0 = (uint32_t)&ADC_Result_Array;
ADC_array_write_index++;
}else{
ADC_array_write_index = 0;
M0P_DMAC->DSTADR0 = (uint32_t)&ADC_Result_Array;
IO_SET(LED_1, 1);
(void)QXSemaphore_signal(&sema_adc);
}
}
if(DmaTransferComplete == Dma_GetStat(DmaCh1))
{
//等待传输完成
//IO_SET(LED_1, 1);
//(void)QXSemaphore_signal(&sema_adc);
Dma_ClrStat(DmaCh1);
//IO_SET(LED_1, 0);
}
if((DmaAccSCRErr == Dma_GetStat(DmaCh0)) || (DmaAccDestErr == Dma_GetStat(DmaCh0)))
{
Dma_ClrStat(DmaCh0);
}
}
void Tim0_IRQHandler(void)
{
//Timer0 模式0 溢出中断
if(TRUE == Bt_GetIntFlag(TIM0, BtUevIrq))
{
Bt_ClearIntFlag(TIM0,BtUevIrq); //中断标志清零
//IO_SET(LED_1, 1);
}
}
void App_Timer0Cfg(uint16_t u16Period)
{
uint16_t u16ArrValue;
uint16_t u16CntValue;
stc_bt_mode0_cfg_t stcBtBaseCfg;
stc_bt_m23_adc_trig_cfg_tstcBtTrigAdc;
DDL_ZERO_STRUCT(stcBtBaseCfg);
DDL_ZERO_STRUCT(stcBtTrigAdc);
Sysctrl_SetPeripheralGate(SysctrlPeripheralBaseTim, TRUE); //Base Timer外设时钟使能
stcBtBaseCfg.enWorkMode = BtWorkMode0; //定时器模式
stcBtBaseCfg.enCT = BtTimer; //定时器功能,计数时钟为内部PCLK
stcBtBaseCfg.enPRS = BtPCLKDiv8; //PCLK/256
stcBtBaseCfg.enCntMode= Bt16bitArrMode; //自动重载16位计数器/定时器
stcBtBaseCfg.bEnTog = FALSE;
stcBtBaseCfg.bEnGate = FALSE;
stcBtBaseCfg.enGateP = BtGatePositive;
Bt_Mode0_Init(TIM0, &stcBtBaseCfg); //TIM0 的模式0功能初始化
u16ArrValue = 0x10000 - u16Period;
Bt_M0_ARRSet(TIM0, u16ArrValue); //设置重载值(ARR = 0x10000 - 周期)
u16CntValue = 0x10000 - u16Period;
Bt_M0_Cnt16Set(TIM0, u16CntValue); //设置计数初值
stcBtTrigAdc.bEnTrigADC = TRUE; //使能ADC触发全局控制
stcBtTrigAdc.bEnUevTrigADC = TRUE; //Uev更新触发ADC
Bt_M23_TrigADC_Cfg(TIM0, &stcBtTrigAdc); //触发ADC配置
Bt_ClearIntFlag(TIM0,BtUevIrq); //清中断标志
//Bt_Mode0_EnableIrq(TIM0); //使能TIM0中断(模式0时只有一个中断)
//EnableNvic(TIM0_IRQn, IrqLevel3, TRUE); //TIM0中断使能
}
void aio_init(void)
{
stc_adc_cfg_t stcAdcCfg;
stc_adc_sqr_cfg_t stcAdcSqrCfg;
DDL_ZERO_STRUCT(stcAdcCfg);
DDL_ZERO_STRUCT(stcAdcSqrCfg);
Gpio_SetAnalogMode(GpioPortB, GpioPin0);
Gpio_SetAnalogMode(GpioPortB, GpioPin1);
Gpio_SetAnalogMode(GpioPortB, GpioPin11);
if (Ok != Sysctrl_SetPeripheralGate(SysctrlPeripheralAdcBgr, TRUE))
{
Q_onAssert("adc_err", 999);
}
Bgr_BgrEnable(); ///< 开启BGR
//ADC配置
stcAdcCfg.enAdcMode = AdcScanMode; ///<采样模式-扫描
stcAdcCfg.enAdcClkDiv = AdcMskClkDiv8; ///<采样分频-8
stcAdcCfg.enAdcSampCycleSel = AdcMskSampCycle12Clk; ///<采样周期数-8
stcAdcCfg.enAdcRefVolSel = AdcMskRefVolSelInBgr2p5; ///<参考电压选择-2.5V
stcAdcCfg.enAdcOpBuf = AdcMskBufDisable; ///<OP BUF配置-
stcAdcCfg.enInRef = AdcMskInRefEnable; ///<内部参考电压使能-关
stcAdcCfg.enAdcAlign = AdcAlignRight; ///<转换结果对齐方式-右
Adc_Init(&stcAdcCfg);
stcAdcSqrCfg.bSqrDmaTrig = TRUE;
stcAdcSqrCfg.enResultAcc = AdcResultAccDisable;
stcAdcSqrCfg.u8SqrCnt = 10;
Adc_SqrModeCfg(&stcAdcSqrCfg);
Adc_CfgSqrChannel(AdcSQRCH0MUX, AdcExInputCH8);
Adc_CfgSqrChannel(AdcSQRCH9MUX, AdcExInputCH8);
Adc_CfgSqrChannel(AdcSQRCH1MUX, AdcExInputCH9);
Adc_CfgSqrChannel(AdcSQRCH2MUX, AdcExInputCH9);
Adc_CfgSqrChannel(AdcSQRCH3MUX, AdcExInputCH9);
Adc_CfgSqrChannel(AdcSQRCH4MUX, AdcExInputCH9);
Adc_CfgSqrChannel(AdcSQRCH5MUX, AdcExInputCH18);
Adc_CfgSqrChannel(AdcSQRCH6MUX, AdcExInputCH18);
Adc_CfgSqrChannel(AdcSQRCH7MUX, AdcExInputCH18);
Adc_CfgSqrChannel(AdcSQRCH8MUX, AdcExInputCH18);
Adc_ClrIrqStatus(AdcMskIrqSqr);
Adc_SqrExtTrigCfg(AdcMskTrigTimer0, TRUE); //Timer0触发扫描转换
App_DmaCfg();
//Adc_EnableIrq();
//EnableNvic(ADC_IRQn, IrqLevel3, TRUE);
delay10us(5);
App_Timer0Cfg(3000);
}
void App_DmaCfg(void)
{
stc_dma_cfg_t stcDmaCfg;
DDL_ZERO_STRUCT(stcDmaCfg); //结构体变量 初始值清零
// 使能 DMA时钟
Sysctrl_SetPeripheralGate(SysctrlPeripheralDma,TRUE);
stcDmaCfg.enMode =DmaMskBlock; //选择块传输
stcDmaCfg.u16BlockSize = 10; //块传输个数
stcDmaCfg.u16TransferCnt = 1; //Block模式,一次传输数据大小为 10,传输1次
stcDmaCfg.enTransferWidth = DmaMsk32Bit; //传输数据的宽度,此处选择字(32Bit)宽度
stcDmaCfg.enSrcAddrMode = DmaMskSrcAddrInc; //源地址自增
stcDmaCfg.enDstAddrMode = DmaMskDstAddrInc; //目的地址自增
stcDmaCfg.enDestAddrReloadCtl = DmaMskDstAddrReloadDisable; //不重新加载传输目的地址
stcDmaCfg.enSrcAddrReloadCtl = DmaMskSrcAddrReloadEnable; //使能重新加载传输源地址
stcDmaCfg.enSrcBcTcReloadCtl = DmaMskBcTcReloadEnable; //使能重新加载BC/TC值
stcDmaCfg.u32SrcAddress = (uint32_t)&(M0P_ADC->SQRRESULT0);//指定传输源地址
stcDmaCfg.u32DstAddress = (uint32_t)&ADC_Result_Array; //指定传输目的地址
stcDmaCfg.enTransferMode = DmaMskContinuousTransfer; //DMAC 在传输完成时不清除 CONFA:ENS 位。这个功能允许连续传输而不需要 CPU 干预。
stcDmaCfg.enRequestNum = DmaADCSQRTrig; //设置为ADC SQR触发
Dma_InitChannel(DmaCh0,&stcDmaCfg); //初始化DMA通道0
// stcDmaCfg.enMode =DmaMskBlock; //选择块传输
// stcDmaCfg.u16BlockSize = ADC_BC; //块传输个数
// stcDmaCfg.u16TransferCnt = ADC_TC; //Block模式,一次传输数据大小为 3,传输三次
// stcDmaCfg.enTransferWidth = DmaMsk32Bit; //传输数据的宽度,此处选择字(32Bit)宽度
// stcDmaCfg.enSrcAddrMode = DmaMskSrcAddrInc; //源地址自增
// stcDmaCfg.enDstAddrMode = DmaMskDstAddrInc; //目的地址自增
// stcDmaCfg.enDestAddrReloadCtl = DmaMskDstAddrReloadEnable; //使能重新加载传输目的地址
// stcDmaCfg.enSrcAddrReloadCtl = DmaMskSrcAddrReloadEnable; //使能重新加载传输源地址
// stcDmaCfg.enSrcBcTcReloadCtl = DmaMskBcTcReloadEnable; //使能重新加载BC/TC值
// stcDmaCfg.u32SrcAddress = (uint32_t)&ADC_Result_Array;//指定传输源地址
// stcDmaCfg.u32DstAddress = (uint32_t)&ADC_Result_buf_Array; //指定传输目的地址
// stcDmaCfg.enTransferMode = DmaMskContinuousTransfer; //DMAC 在传输完成时不清除 CONFA:ENS 位。这个功能允许连续传输而不需要 CPU 干预。
// stcDmaCfg.enRequestNum = DmaADCSQRTrig; //设置为ADC SQR触发
// Dma_InitChannel(DmaCh1,&stcDmaCfg);
//使能DMA,使能DMA0
Dma_Enable();
Dma_EnableChannel(DmaCh0);
Dma_EnableChannelIrq(DmaCh0);
Dma_EnableChannelErrIrq(DmaCh0);
//Dma_EnableChannel(DmaCh1);
//Dma_EnableChannelIrq(DmaCh1);
EnableNvic(DMAC_IRQn, IrqLevel2, TRUE);
}
不好意思,有技术支持能确认下吗? 1. 设置块数:(从 1 至 16 中选择)
2. 设置传输长度:(从 1 至 65536 中选择)
3. 总传输长度可达为16 * 65536 个字节。
HC32L136 使用了DMA,可以实现想传多少就传多少。以上传输模式对于客户而言是透明的,在总线架构上面为了满足系统对于实时性的需求,每次传16个数据,就会让总线,DMA进行一次仲裁,如果CPU无操作需求,DMA继续传输数据,也可以传大量数据,也不需要软件处理。
友商想传多少就传多少,会屏蔽CPU对于实时操作的能力,只有等DMA把所有数据传输完成之后,CPU才能继续响应中断,这对于系统而言,基本属于无实时性可言。
每种总线架构,有每种架构的需求,每个设计者考虑的东西也不一样,彼此都有优先级考虑的。我们考虑的是,DMA传输可能比友商慢一点点,但是整个系统对于实时响应性能强,DMA不会卡死CPU。 liaotian001 发表于 2020-4-13 10:58
1. 设置块数:(从 1 至 16 中选择)
2. 设置传输长度:(从 1 至 65536 中选择)
3. 总传输长度可达为16 ...
你描述的是软件Block传输或硬件Burst传输情况,从ADC扫描转换结果寄存器 到内存不适合用。从ADC_SqrResult0 - 15传送一批数据到内存适合硬件Block传输。 mtbf 发表于 2020-4-13 21:00
你描述的是软件Block传输或硬件Burst传输情况,从ADC扫描转换结果寄存器 到内存不适合用。从ADC_SqrResul ...
ADC_SqrResult0 - 15,一共16个数据,我们的DMA可以支持一次搬运完成的。硬件设计中,ADC采样完成最后一个buffer地址的采样,ADC 硬件 trigger DMA request, DMA就会完成一次16笔数据的搬运。 liaotian001 发表于 2020-4-23 11:47
ADC_SqrResult0 - 15,一共16个数据,我们的DMA可以支持一次搬运完成的。硬件设计中,ADC采样完成最后一 ...
DMA一次搬运的数据可以单独设置吗? liaotian001 发表于 2020-4-23 11:47
ADC_SqrResult0 - 15,一共16个数据,我们的DMA可以支持一次搬运完成的。硬件设计中,ADC采样完成最后一 ...
定时器触发ADC完成16通道扫描,10KHz,想做到10次扫描以后参数16X10数据,DMA搬运到内存,产生一次中断。现在只能做到每扫描一次产生中断,也就是16次中断,中断频率跟定时器一样,10KHz。 不是必须中断吧,那样太费事了 本帖最后由 lesheng002 于 2020-5-7 20:24 编辑
liaotian001 发表于 2020-4-13 10:58
1. 设置块数:(从 1 至 16 中选择)
2. 设置传输长度:(从 1 至 65536 中选择)
3. 总传输长度可达为16 ...
照这个说法,DMA传输影响MCU的工作了,难怪我设计的ADC检测,用DMA传输结果,启动就死机了 lesheng002 发表于 2020-5-7 20:21
照这个说法,DMA传输影响MCU的工作了,难怪我设计的ADC检测,用DMA传输结果,启动就死机了 ...
请仔细看一下我的说明,DMA传输数据,启动就死机,那我认为100%是你软件的问题了。 liaotian001 发表于 2020-4-13 10:58
1. 设置块数:(从 1 至 16 中选择)
2. 设置传输长度:(从 1 至 65536 中选择)
3. 总传输长度可达为16 ...
这也太不专业了,DMA和CPU都作为主机会保证CPU有至少一半的AHB总线带宽,DMA即使连续传输中间也是有间隔的 本帖最后由 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
页:
[1]
2