工具/软件:
您好、
我正在使用 ADC 和 DMA 来计算应用中电感器电流的 RMS 值。
我使用 EPWM2通过加减计数器以20kHz 的频率驱动开关。
我在640kHz (32 *开关频率)下使用 EPWM8作为 ADC 的 SOC、以便在每个开关周期获取32个样本
在 EOC 处生成 ADCINT。
然后、我使用 ADCINT 作为 DMA 的触发器、将这些样本从 ADCRESULT 寄存器传输到缓冲区。
存储在该缓冲器中的样本用于计算 EMPWM2 ISR 内的 RMS 值。
为了验证我是否能够在一个开关周期内收集32个样本、我在用于收集样本的 ADC 的 ISR 内写入了数据日志。
当我在 MATLAB 中绘制它时、我注意到我采集的是25个样本、而不是每周期32个样本。
为了进一步研究这一点、我设置了 GPIO 以在 ePWM ISR 和 ADC ISR 内设置和清除、我注意到了这一点

我的问题是、我是否在观察到这一点是因为 ADC ISR 中正在进行数据记录、还是在提供 EPWM2 ISR 时 ADCINT 不会触发 DMA 传输?
我附加了 DMA 和 ADC 配置以供参考。
ADC 配置
AdcdRegs.ADCCTL2.bit.PRESCALE = 6; // Set ADCCLK divider; ADCCLK=SYSCLK/4 -> standard
AdcSetMode(ADC_ADCA, ADC_RESOLUTION_12BIT, ADC_SIGNALMODE_SINGLE); // Set the resolution and signal mode for a given ADC
AdcdRegs.ADCCTL1.bit.INTPULSEPOS = 1; // generates EOC ***.Set pulse positions to late (after conversion instead of after acquisition window).
AdcdRegs.ADCCTL1.bit.ADCPWDNZ = 1; // Power up the ADC
DELAY_US(1000); // Delay for 1ms to allow ADC time to power up
AdcdRegs.ADCSOC0CTL.bit.CHSEL = 4; // SOC0 will convert ADCINA2 [LINE CURRENT], result is ADCRESULT0
AdcdRegs.ADCSOC0CTL.bit.ACQPS = ADCACQ_12Bit; // Acquisition window is ACQPS+1 SYSCLK cycles.
AdcdRegs.ADCSOC0CTL.bit.TRIGSEL = 19; // Trigger on ePWM5 SOCA -> sampling counter
AdcdRegs.ADCSOCPRICTL.bit.SOCPRIORITY = 1; // SOC0 is high priority
AdcdRegs.ADCINTSEL1N2.bit.INT1SEL = 0; // EOC0 will set ADCINT1 flag -> signal that all conversions are complete
AdcdRegs.ADCINTSEL1N2.bit.INT1CONT =1; // ADCaINT1 on each EOC pulse regardless of the flag bit (to avoid having to clear flag in adca1_isr)
// AdcdRegs.ADCINTSEL1N2.bit.INT1E = 1; // Enable ADCaINT1 flag for DMA -> now enabled in PWM1isr first entry
AdcdRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // Make sure INT1 flag is cleared; not important here because of INT1CONT.
DMA 配置
EALLOW;
// Configure CH1 -> transfer all ADCa results and store in a buffer (change between ping-pong buffers)
// Set up MODE Register
DmaClaSrcSelRegs.DMACHSRCSEL1.bit.CH1 = 16; // Select the Trigger and Sync Source of DMACH1 to ADCAINT1 -> after all 6 conversions are finished DMA can transfer?
DmaRegs.CH1.MODE.bit.PERINTSEL = 1; // Set to channel number
DmaRegs.CH1.MODE.bit.PERINTE = 1; // Peripheral interrupt enabled (allow peripheral to cause DMA transfer)
DmaRegs.CH1.MODE.bit.ONESHOT = 0; // Channel only performs one burst per trigger -> goes to second channel -> waits for another trigger (until transfer cnt < transfer size)
DmaRegs.CH1.MODE.bit.CONTINUOUS = 0; // Stop after each transfer - I will re-enable it only after I have entered PWM1 interrupt and have changed buffer from ping to pong
DmaRegs.CH1.MODE.bit.DATASIZE = 0; // 16-bit data size transfers -> must be used even if ADC results are 12 bit
DmaRegs.CH1.MODE.bit.CHINTMODE = 1; // Generate ePIE interrupt at the end of transfer. Not important as I do not use interrupt!
DmaRegs.CH1.MODE.bit.CHINTE = 0; // Channel Interrupt to CPU disabled
// Set up BURST registers
DmaRegs.CH1.BURST_SIZE.all = 0; // 1 Number of 16-bit words per burst (N-1) -> 1 currents from ADCa
DmaRegs.CH1.SRC_BURST_STEP = 0; // Adcaresult 0 -> 1 -> 2 _> 3 .... -> 5 -> each step is 16 bit increment! -> ADC result regs are stored 16 bits apart (like array members)
DmaRegs.CH1.DST_BURST_STEP = 0; // After each current is read - do nothing (it is handled by transfer regs)
// Set up TRANSFER registers
DmaRegs.CH1.TRANSFER_SIZE = NOVS_TC_INV - 1; // (n-1) samples per Tc
DmaRegs.CH1.SRC_TRANSFER_STEP = 0; // Go back to ADCa.Result0
DmaRegs.CH1.DST_TRANSFER_STEP = 1; // Start filling next member of first array
// Set up WRAP registers - we do not use these!
DmaRegs.CH1.SRC_WRAP_SIZE = NOVS_TC_INV - 1 + 10; // (wrapping disabled because wrap_size > transfer_size)
DmaRegs.CH1.DST_WRAP_SIZE = NOVS_TC_INV - 1 + 10; // (wrapping disabled because wrap_size > transfer_size)
DmaRegs.CH1.SRC_WRAP_STEP = 0;
DmaRegs.CH1.DST_WRAP_STEP = 0;
// Set up SOURCE address
DmaRegs.CH1.SRC_BEG_ADDR_SHADOW = (Uint32)&AdcdResultRegs.ADCRESULT0; // Wrap register - not used
DmaRegs.CH1.SRC_ADDR_SHADOW = (Uint32)&AdcdResultRegs.ADCRESULT0; // Source address
// Set up DESTINATION address
DmaRegs.CH1.DST_BEG_ADDR_SHADOW = (Uint32)&I_inv_dma_ping[0]; // Wrap register - not used
DmaRegs.CH1.DST_ADDR_SHADOW = (Uint32)&I_inv_dma_ping[0]; // Toggle destination address in ISR
// Clear any spurious flags & errors
DmaRegs.CH1.CONTROL.bit.PERINTCLR = 1; // Clear any spurious interrupt flags
DmaRegs.CH1.CONTROL.bit.ERRCLR = 1; // Clear any spurious sync error
EDIS;
ePWM ISR 内的 DMA 传输
if (dma_ping==1) // DST ADDRESS FOR NEXT DMA CYCLE (currently reading from previously active buffer)
{
EALLOW;
DmaRegs.CH1.DST_ADDR_SHADOW = (Uint32)&I_inv_dma_ping[0]; // Toggle destination address in ISR
EDIS;
dma_ping = 0; // read pong buffer in this isr
}
else
{
EALLOW;
DmaRegs.CH1.DST_ADDR_SHADOW = (Uint32)&I_inv_dma_pong[0]; // Toggle destination address in ISR
EDIS;
dma_ping = 1; // read ping buffer in this isr
}
// ******************************
EALLOW;
AdcdRegs.ADCINTSEL1N2.bit.INT1E = 1; // CH1 DMA TRIGGER -> Enable ADCaINT1 -> so that DMA starts synchronized
EDIS;
while(DmaRegs.CH1.CONTROL.bit.RUNSTS == 1){} // if stuck here, enable ADC INT in adc_init
GpioDataRegs.GPCCLEAR.bit.GPIO64 = 1;
// RUN DMA FOR NEW BATCH OF SAMPLES TO BE READ IN THE FOLLOWING ISR
EALLOW;
DmaRegs.CH1.CONTROL.bit.RUN = 1;
EDIS;
// ************** end of time critical functions ***********************
// ************** rest of the control ***********************
// ****************************** OVERSAMPLED READ AND FILTERING
I_INV_raw_avg = 0;
I_INV_raw_rmsSqr = 0;
if (dma_ping == 1) // which buffer are we using right now to find mean (MAF) and ac RMS
{
I_INV_raw_tmp = I_inv_dma_ping[NOVS_TC_INV - 1];
// Collect data to be averaged -> oversampled data between this and previous Tc
for (itr_tmp = 0; itr_tmp < NOVS_TC_INV; itr_tmp++)
{
I_INV_raw_avg += (unsigned long)I_inv_dma_ping[itr_tmp];
I_INV_raw_rmsSqr += (unsigned long)I_inv_dma_ping[itr_tmp] * (unsigned long)I_inv_dma_ping[itr_tmp];
}
}
else
{
I_INV_raw_tmp = I_inv_dma_pong[NOVS_TC_INV - 1];
// Collect data to be averaged -> oversampled data between this and previous Tc
for (itr_tmp = 0; itr_tmp < NOVS_TC_INV; itr_tmp++)
{
I_INV_raw_avg += (unsigned long)I_inv_dma_pong[itr_tmp];
I_INV_raw_rmsSqr += (unsigned long)I_inv_dma_pong[itr_tmp] * (unsigned long)I_inv_dma_pong[itr_tmp];
}
}
如果我使用 CPU1的 CLA 而不是带有 ADCINT1的 DMA 作为 CLA 的触发器、我是否会停止面临该问题?
谢谢
