我想请教一下各位大佬,遇到了下面这个问题,恳请提供建议和帮助,谢谢!描述和问题如下:
1.使用了SPIA,作为从机,比特为15M,FIFO的接收和发送的深度都为8,同步收发16位的200个缓存元素的缓存。
2.SPI启用了DMA的CH4(RX)、CH5(TX),都为循环模式,burst_size=8,transfer_size=25,都开启了循环模式。
3.ADC使用了EPWM的SOC触发采样,使用了三个ADC,ADC1、、ADC2、ADC3,分别采样128个数据。
4.ADC分别使用了CH1、CH2、CH3
5.问题现象:现在的工况是工作是开启ADC采样DMA发送触发完成,后函数执行FFT以及触发CLA任务完成后再次开启采样,直到工作接收停止这个循环过程;SPI配置好和主机同步后就一直通过DMA循环接收,中间不停止不重启,现在是只要不启动工作,SPI的通讯收发是正常的,但是只需开启工作,AD一直开始采样,SPI的接收FIFO就会溢出,清除标志位也一样很快还是溢出,调试看DMA的发送完成触发的时间变慢了,一溢出通讯就异常了,是因为DMA接收被ADC一直大量占用了吗,优先级比其他的低导致SPI的中断和DMA的中断响应不及时导致的,尝试了降低比特率和FIFO的阈值都起效果达不到,恳请给出好的建议!!!
下面是程序的一些配置:
void ADC_init(){
//AD_PI初始化
// ADC 初始化:写入 ADC 配置并启动 ADC
// 配置 ADC 模块的失调调整
ADC_setOffsetTrimAll(ADC_REFERENCE_EXTERNAL,ADC_REFERENCE_3_3V);
// 配置模数转换器模块预分频器。
ADC_setPrescaler(AD_PI_BASE, ADC_CLK_DIV_2_0);
// 设置转换结束脉冲的时序
ADC_setInterruptPulseMode(AD_PI_BASE, ADC_PULSE_END_OF_CONV);
// 启动模数转换器核心。
ADC_enableConverter(AD_PI_BASE);
// 延迟 1ms 以允许 ADC 有时间启动
DEVICE_DELAY_US(500);
// SOC 配置:设置 ADC EPWM 通道和触发器设置
// 禁用 SOC 突发模式。ADC_disableBurstMode
(AD_PI_BASE);
// 设置 SOC 的优先级模式。ADC_setSOCPriority
(AD_PI_BASE, ADC_PRI_ALL_ROUND_ROBIN);
// 转换开始 0 配置
// 配置 ADC 中的转换开始 (SOC) 及其中断 SOC 触发器。
// SOC 编号:0
// 触发器:ADC_TRIGGER_EPWM3_SOCA
// 通道:ADC_CH_ADCIN0
// 采样窗口:16 个 SYSCLK 周期
// 中断触发器:ADC_INT_SOC_TRIGGER_NONE
ADC_setupSOC(AD_PI_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM3_SOCA, ADC_CH_ADCIN0, 16U);
ADC_setInterruptSOCTrigger(AD_PI_BASE, ADC_SOC_NUMBER0, ADC_INT_SOC_TRIGGER_NONE);
// ADC 中断 1 配置
// SOC/EOC 编号:0
// 中断源:启用
// 连续模式:启用
ADC_setInterruptSource(AD_PI_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER0);
ADC_enableInterrupt(AD_PI_BASE, ADC_INT_NUMBER1);
ADC_clearInterruptStatus(AD_PI_BASE, ADC_INT_NUMBER1);
ADC_enableContinuousMode(AD_PI_BASE, ADC_INT_NUMBER1);
//AD_SI初始化
// ADC Initialization: Write ADC configurations and power up the ADC
// Configures the ADC module's offset trim
ADC_setOffsetTrimAll(ADC_REFERENCE_EXTERNAL,ADC_REFERENCE_3_3V);
// Configures the analog-to-digital converter module prescaler.
ADC_setPrescaler(AD_SI_BASE, ADC_CLK_DIV_2_0);
// Sets the timing of the end-of-conversion pulse
ADC_setInterruptPulseMode(AD_SI_BASE, ADC_PULSE_END_OF_CONV);
// Powers up the analog-to-digital converter core.
ADC_enableConverter(AD_SI_BASE);
// Delay for 1ms to allow ADC time to power up
DEVICE_DELAY_US(500);
// SOC Configuration: Setup ADC EPWM channel and trigger settings
// Disables SOC burst mode.
ADC_disableBurstMode(AD_SI_BASE);
// Sets the priority mode of the SOCs.
ADC_setSOCPriority(AD_SI_BASE, ADC_PRI_ALL_ROUND_ROBIN);
// Start of Conversion 0 Configuration
// Configures a start-of-conversion (SOC) in the ADC and its interrupt SOC trigger.
// SOC number : 0
// Trigger : ADC_TRIGGER_EPWM3_SOCA
// Channel : ADC_CH_ADCIN4
// Sample Window : 16 SYSCLK cycles
// Interrupt Trigger: ADC_INT_SOC_TRIGGER_NONE
ADC_setupSOC(AD_SI_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM3_SOCA, ADC_CH_ADCIN4, 16U);
ADC_setInterruptSOCTrigger(AD_SI_BASE, ADC_SOC_NUMBER0, ADC_INT_SOC_TRIGGER_NONE);
// ADC Interrupt 1 Configuration
// SOC/EOC number : 0
// Interrupt Source: enabled
// Continuous Mode : enabled
ADC_setInterruptSource(AD_SI_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER0);
ADC_enableInterrupt(AD_SI_BASE, ADC_INT_NUMBER1);
ADC_clearInterruptStatus(AD_SI_BASE, ADC_INT_NUMBER1);
ADC_enableContinuousMode(AD_SI_BASE, ADC_INT_NUMBER1);
//AD_SU initialization
// ADC Initialization: Write ADC configurations and power up the ADC
// Configures the ADC module's offset trim
ADC_setOffsetTrimAll(ADC_REFERENCE_EXTERNAL,ADC_REFERENCE_3_3V);
// Configures the analog-to-digital converter module prescaler.
ADC_setPrescaler(AD_SU_BASE, ADC_CLK_DIV_2_0);
// Sets the timing of the end-of-conversion pulse
ADC_setInterruptPulseMode(AD_SU_BASE, ADC_PULSE_END_OF_CONV);
// Powers up the analog-to-digital converter core.
ADC_enableConverter(AD_SU_BASE);
// Delay for 1ms to allow ADC time to power up
DEVICE_DELAY_US(500);
// SOC Configuration: Setup ADC EPWM channel and trigger settings
// Disables SOC burst mode.
ADC_disableBurstMode(AD_SU_BASE);
// Sets the priority mode of the SOCs.
ADC_setSOCPriority(AD_SU_BASE, ADC_PRI_ALL_ROUND_ROBIN);
// Start of Conversion 0 Configuration
// Configures a start-of-conversion (SOC) in the ADC and its interrupt SOC trigger.
// SOC number : 0
// Trigger : ADC_TRIGGER_EPWM3_SOCA
// Channel : ADC_CH_ADCIN0
// Sample Window : 16 SYSCLK cycles
// Interrupt Trigger: ADC_INT_SOC_TRIGGER_NONE
ADC_setupSOC(AD_SU_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM3_SOCA, ADC_CH_ADCIN0, 16U);
ADC_setInterruptSOCTrigger(AD_SU_BASE, ADC_SOC_NUMBER0, ADC_INT_SOC_TRIGGER_NONE);
// ADC Interrupt 1 Configuration
// SOC/EOC number : 0
// Interrupt Source: enabled
// Continuous Mode : enabled
ADC_setInterruptSource(AD_SU_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER0);
ADC_enableInterrupt(AD_SU_BASE, ADC_INT_NUMBER1);
ADC_clearInterruptStatus(AD_SU_BASE, ADC_INT_NUMBER1);
ADC_enableContinuousMode(AD_SU_BASE, ADC_INT_NUMBER1);
}
void FB_start(void)
{
EPWM_clearADCTriggerFlag(EPWM_AD_BASE, EPWM_SOC_A);
ADC_clearInterruptStatus(AD_PI_BASE, ADC_INT_NUMBER1);
ADC_clearInterruptStatus(AD_SI_BASE, ADC_INT_NUMBER1);
ADC_clearInterruptStatus(AD_SU_BASE, ADC_INT_NUMBER1);
DMA_clearTriggerFlag(DMA_CH1_BASE);
DMA_clearTriggerFlag(DMA_CH2_BASE);
DMA_clearTriggerFlag(DMA_CH3_BASE);
// Clearing all pending interrupt flags & Start DMA
//DMA_clearTriggerFlag(DMA_CH1_BASE);
DMA_startChannel(DMA_CH1_BASE);
//DMA_clearTriggerFlag(DMA_CH2_BASE);
DMA_startChannel(DMA_CH2_BASE);
//DMA_clearTriggerFlag(DMA_CH3_BASE);
DMA_startChannel(DMA_CH3_BASE);
EPWM_enableADCTrigger(EPWM_AD_BASE, EPWM_SOC_A);
}
SPI配置:
SPi_To_N32_Init();
// //
// // 初始化 DMA
// //
// DMA_initController();
DMA_triggerSoftReset(DMA_CH4_BASE);
DMA_triggerSoftReset(DMA_CH5_BASE);
//------------------------------------------------------------------------------------------------------------------------------------------------
// 为 SPI_RX 设置 DMA 通道 4
DMA_configAddresses(DMA_CH4_BASE, (uint16_t *)DSP_RxArray, (uint16_t *)(SCR_SPI_BASE + SPI_O_RXBUF));
// 执行足够的 16 字突发以填充结果缓冲区。数据将以
每次 32 位 // 的速度传输,因此地址步骤如下。DMA_configBurst
(DMA_CH4_BASE, burst_size, 0, 1);
DMA_configTransfer(DMA_CH4_BASE, transfer_size, 0, 1);
DMA_configMode(DMA_CH4_BASE,DMA_TRIGGER_SPIARX,(DMA_CFG_ONESHOT_DISABLE | DMA_CFG_CONTINUOUS_ENABLE | DMA_CFG_SIZE_16BIT));
//
// 配置 DMA Ch4 中断
//
DMA_setInterruptMode(DMA_CH4_BASE, DMA_INT_AT_END);
DMA_enableInterrupt(DMA_CH4_BASE);
DMA_enableTrigger(DMA_CH4_BASE);
// 为 SPI_TX 设置 DMA 通道 5
DMA_configAddresses(DMA_CH5_BASE, (uint16_t *)(SCR_SPI_BASE + SPI_O_TXBUF), (uint16_t *)DSP_TxArray);
// 执行足够的 16 字突发以填充结果缓冲区。数据将以
每次 32 位的速度传输,因此地址步骤如下。DMA_configBurst
(DMA_CH5_BASE, burst_size, 1, 0);
DMA_configTransfer(DMA_CH5_BASE, transfer_size, 1, 0);
DMA_configMode(DMA_CH5_BASE, DMA_TRIGGER_SPIATX, (DMA_CFG_ONESHOT_DISABLE | DMA_CFG_CONTINUOUS_ENABLE | DMA_CFG_SIZE_16BIT));
//
// 配置 DMA Ch5 中断
//
DMA_setInterruptMode(DMA_CH5_BASE, DMA_INT_AT_END);
DMA_enableInterrupt(DMA_CH5_BASE);
DMA_enableTrigger(DMA_CH5_BASE);
//SCR_SPI 初始化
SPI_disableModule(SCR_SPI_BASE);
SPI_clearInterruptStatus(SCR_SPI_BASE, SPI_INT_RXFF | SPI_INT_TXFF);
SPI_setFIFOInterruptLevel(SCR_SPI_BASE, SPI_FIFO_TX8, SPI_FIFO_RX8);
SPI_setConfig(SCR_SPI_BASE, DEVICE_LSPCLK_FREQ, SPI_PROT_POL0PHA1,
SPI_MODE_SLAVE, 15000000, 16);
SPI_disableLoopback(SCR_SPI_BASE);
SPI_enableFIFO(SCR_SPI_BASE);
SPI_setEmulationMode(SCR_SPI_BASE, SPI_EMULATION_STOP_MIDWAY);
SPI_enableInterrupt(SCR_SPI_BASE, SPI_INT_RXFF | SPI_INT_TXFF);
SPI启用模块(SCR_SPI_基座);
//SPI_FIFO
DMA_启动通道(DMA_CH4_BASE);
DMA_启动通道(DMA_CH5_BASE);
}
您好,
DMA模块一次只能为一个通道执行传输。
因此,是的,您提到的问题确实存在,当使用通道1-3时,通道4-5之间的每次传输会有一些延迟,因为其他通道也需要服务。
几个问题:配置的是哪种通道优先级模式 - 通道1优先级模式还是轮询模式?
我认为这两者都有问题,但特别是通道1优先级模式可能会导致其他通道被阻塞。
每个ADC DMA通道传输多少数据?是否可以减少,以使这些通道的操作不需要花费太长时间?
是否可以让发送的SPI设备在发送每8个元素之间插入延迟,以便DMA有时间服务其他通道?
我还建议的另一个选项是使用CLA任务来进行SPI操作,而不是使用DMA。
这样,CLA可以用于SPI操作,并且DMA可以同时处理ADC数据。