21ic问答首页 - TMS320F280049使用SPI作为从机通讯和ADC采样冲突问题
TMS320F280049使用SPI作为从机通讯和ADC采样冲突问题 赏300家园币
我想请教一下各位大佬,遇到了下面这个问题,恳请提供建议和帮助,谢谢!描述和问题如下:
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的通讯收发是正常的,但是只要开启工作,ADC一直开始采样,SPI的接收FIFO就会溢出,清除标志位也一样很快溢出,调试看DMA的发送完成中断触发的时间变慢了,一溢出通讯就异常了,是因为DMA总线被ADC一直大量占用了吗,还是中断的优先级比其他的低导致SPI的中断和DMA的中断相应不及时导致的,试了降低比特率和FIFO的阈值都起不到效果, 恳请给出好的建议!!!
一下是程序的一些配置:
void ADC_init(){
//AD_PI initialization
//AD_PI 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_PI_BASE, ADC_CLK_DIV_2_0);
// Sets the timing of the end-of-conversion pulse
ADC_setInterruptPulseMode(AD_PI_BASE, ADC_PULSE_END_OF_CONV);
// Powers up the analog-to-digital converter core.
ADC_enableConverter(AD_PI_BASE);
// Delay for 1ms to allow ADC time to power up
DEVICE_DELAY_US(500);
// 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_PI_BASE, ADC_CLK_DIV_2_0);
// Sets the timing of the end-of-conversion pulse
ADC_setInterruptPulseMode(AD_PI_BASE, ADC_PULSE_END_OF_CONV);
// Powers up the analog-to-digital converter core.
ADC_enableConverter(AD_PI_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_PI_BASE);
// Sets the priority mode of the SOCs.
ADC_setSOCPriority(AD_PI_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_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 Interrupt 1 Configuration
// SOC/EOC number : 0
// Interrupt Source: enabled
// Continuous Mode : enabled
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);
// Disables SOC burst mode.
ADC_disableBurstMode(AD_PI_BASE);
// Sets the priority mode of the SOCs.
ADC_setSOCPriority(AD_PI_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_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 Interrupt 1 Configuration
// SOC/EOC number : 0
// Interrupt Source: enabled
// Continuous Mode : enabled
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 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_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);
// 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);
// 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);
// 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);
// 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);
{
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);
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);
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();
// //
// // Initialize DMA
// //
// DMA_initController();
DMA_triggerSoftReset(DMA_CH4_BASE);
DMA_triggerSoftReset(DMA_CH5_BASE);
//----------------------------------------------------------------------------------------------------------------------------------
// DMA channel 4 set up for SPI_RX
DMA_configAddresses(DMA_CH4_BASE, (uint16_t *)DSP_RxArray, (uint16_t *)(SCR_SPI_BASE + SPI_O_RXBUF));
// Perform enough 16-word bursts to fill the results buffer. Data will be
// transferred 32 bits at a time hence the address steps below.
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));
// //
// // Initialize DMA
// //
// DMA_initController();
DMA_triggerSoftReset(DMA_CH4_BASE);
DMA_triggerSoftReset(DMA_CH5_BASE);
//----------------------------------------------------------------------------------------------------------------------------------
// DMA channel 4 set up for SPI_RX
DMA_configAddresses(DMA_CH4_BASE, (uint16_t *)DSP_RxArray, (uint16_t *)(SCR_SPI_BASE + SPI_O_RXBUF));
// Perform enough 16-word bursts to fill the results buffer. Data will be
// transferred 32 bits at a time hence the address steps below.
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));
//
// Configure DMA Ch4 interrupts
//
DMA_setInterruptMode(DMA_CH4_BASE, DMA_INT_AT_END);
DMA_enableInterrupt(DMA_CH4_BASE);
DMA_enableTrigger(DMA_CH4_BASE);
// Configure DMA Ch4 interrupts
//
DMA_setInterruptMode(DMA_CH4_BASE, DMA_INT_AT_END);
DMA_enableInterrupt(DMA_CH4_BASE);
DMA_enableTrigger(DMA_CH4_BASE);
// DMA channel 5 set up for SPI_TX
DMA_configAddresses(DMA_CH5_BASE, (uint16_t *)(SCR_SPI_BASE + SPI_O_TXBUF), (uint16_t *)DSP_TxArray);
// Perform enough 16-word bursts to fill the results buffer. Data will be
// transferred 32 bits at a time hence the address steps below.
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_configAddresses(DMA_CH5_BASE, (uint16_t *)(SCR_SPI_BASE + SPI_O_TXBUF), (uint16_t *)DSP_TxArray);
// Perform enough 16-word bursts to fill the results buffer. Data will be
// transferred 32 bits at a time hence the address steps below.
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));
//
// Configure DMA Ch5 interrupts
//
DMA_setInterruptMode(DMA_CH5_BASE, DMA_INT_AT_END);
DMA_enableInterrupt(DMA_CH5_BASE);
DMA_enableTrigger(DMA_CH5_BASE);
// Configure DMA Ch5 interrupts
//
DMA_setInterruptMode(DMA_CH5_BASE, DMA_INT_AT_END);
DMA_enableInterrupt(DMA_CH5_BASE);
DMA_enableTrigger(DMA_CH5_BASE);
//SCR_SPI initialization
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_enableModule(SCR_SPI_BASE);
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_enableModule(SCR_SPI_BASE);
// SPI_FIFO
DMA_startChannel(DMA_CH4_BASE);
DMA_startChannel(DMA_CH5_BASE);
DMA_startChannel(DMA_CH4_BASE);
DMA_startChannel(DMA_CH5_BASE);
}

问答
赞0
评论
2025-11-13
赞0
是的,还是要先梳理一下代码,然后分模块进行调试。
评论
2025-10-31
赞0
1. DMA总线带宽竞争:ADC三个通道同时采样,每个通道128个数据,加上SPI的15Mbps高速传输,导致DMA总线过载
2. 中断优先级冲突:ADC采样完成中断、SPI DMA中断、CLA任务可能产生优先级冲突
3. 内存访问冲突:多个DMA通道同时访问内存造成瓶颈
解决方案建议
1. 优化DMA配置
// 降低SPI DMA的burst size,减少单次传输占用总线时间
DMA_configBurst(DMA_CH4_BASE, 4, 0, 1); // 从8降到4
DMA_configBurst(DMA_CH5_BASE, 4, 1, 0);
// 调整transfer size,分更小的块传输
DMA_configTransfer(DMA_CH4_BASE, 50, 0, 1); // 25->50,但每次传输量减半
DMA_configTransfer(DMA_CH5_BASE, 50, 1, 0);
2. 调整中断优先级
// 提高SPI相关中断优先级
Interrupt_register(INT_DMA_CH4, &SPI_RX_DMA_ISR);
Interrupt_register(INT_DMA_CH5, &SPI_TX_DMA_ISR);
// 设置更高的优先级(数值越小优先级越高)
Interrupt_setPriority(INT_DMA_CH4, 0);
Interrupt_setPriority(INT_DMA_CH5, 1);
// 降低ADC相关中断优先级
Interrupt_setPriority(INT_DMA_CH1, 4);
Interrupt_setPriority(INT_DMA_CH2, 5);
Interrupt_setPriority(INT_DMA_CH3, 6);
3. 优化ADC采样策略
// 考虑交错ADC采样,减少同时进行的DMA传输
void FB_start_optimized(void) {
// 先启动一个ADC,延迟后再启动其他的
DMA_startChannel(DMA_CH1_BASE);
DEVICE_DELAY_US(10); // 微小延迟
DMA_startChannel(DMA_CH2_BASE);
DEVICE_DELAY_US(10);
DMA_startChannel(DMA_CH3_BASE);
EPWM_enableADCTrigger(EPWM_AD_BASE, EPWM_SOC_A);
}
4. 优化SPI配置
void optimize_SPI_config(void) {
SPI_disableModule(SCR_SPI_BASE);
// 降低FIFO阈值,更频繁但更小的DMA传输
SPI_setFIFOInterruptLevel(SCR_SPI_BASE, SPI_FIFO_TX4, SPI_FIFO_RX4);
// 如果可能,适当降低SPI比特率
SPI_setConfig(SCR_SPI_BASE, DEVICE_LSPCLK_FREQ, SPI_PROT_POL0PHA1,
SPI_MODE_SLAVE, 10000000, 16); // 15M->10M
SPI_enableModule(SCR_SPI_BASE);
}
5. 添加流量控制机制
// 在SPI接收中断中添加溢出保护
__interrupt void SPI_RX_DMA_ISR(void) {
if(SPI_getRxFIFOStatus(SCR_SPI_BASE) == SPI_FIFO_RXOVER) {
// 紧急处理:暂停ADC采样,清空FIFO
EPWM_disableADCTrigger(EPWM_AD_BASE, EPWM_SOC_A);
SPI_clearRxFIFO(SCR_SPI_BASE);
SPI_clearInter
EPWM_enableADCTrigger(EPWM_AD_BASE, EPWM_SOC_A);
}
DMA_clearInterruptStatus(DMA_CH4_BASE);
}
6. 内存访问优化
确保DMA缓冲区在内存中的位置不会产生冲突
// 使用不同的内存段存放不同DMA通道的数据
#pragma DATA_SECTION(DSP_RxArray, "DMARAM4");
#pragma DATA_SECTION(DSP_TxArray, "DMARAM5");
#pragma DATA_SECTION(AD_PI_Results, "DMARAM1");
#pragma DATA_SECTION(AD_SI_Results, "DMARAM2");
#pragma DATA_SECTION(AD_SU_Results, "DMARAM3");
7. 监控和调试建议
添加调试代码来确认问题
// 在关键位置添加时间戳监控
uint32_t get_time_stamp(void) {
return CPU_TIMER2_TIM->TIMH; // 使用一个定时器作为时间基准
}
// 在ISR中记录时间
__interrupt void SPI_RX_DMA_ISR(void) {
uint32_t enter_time = get_time_stamp();
// ... ISR处理
uint32_t exit_time = get_time_stamp();
if((exit_time - enter_time) > MAX_ISR_TIME) {
// 记录ISR执行时间过长
}
}
推荐实施顺序
首先调整中断优先级(方案2)
2. 然后优化DMA burst size(方案1)
3. 接着交错ADC启动(方案3)
4. 最后如果问题依旧,考虑降低SPI速率(方案4)
这种分层优化应该能显著改善SPI FIFO溢出问题。如果实施后仍有问题,可能需要考虑硬件层面的优化,
评论
2025-10-27
赞0
评论
2025-07-21
您需要登录后才可以回复 登录 | 注册