This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] TMS320F28379D:当用作 DMA 传输的触发器时、ADCINT1是否通过 CPU? 如果 CPU 为某些其他任务提供更高优先级的中断、DMA 是否仍会被触发?

Guru**** 2463330 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1494578/tms320f28379d-does-adcint1-go-through-cpu-when-used-as-a-trigger-for-dma-transfer-would-dma-still-get-triggered-if-a-higher-priority-interrupt-is-being-served-by-the-cpu-for-some-other-task

部件号:TMS320F28379D

工具/软件:

您好、

我正在使用 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 的触发器、我是否会停止面临该问题?

谢谢

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Vignesh:

    为什么 ADCINT1同时触发中断和 DMA 传输?  

    要使配置正常工作、您需要确保所有这些事件的时间安排非常准确。 您能否首先尝试确定 EPWM2和 EPWM8的作用域(如果添加一些动作限定符以将信号输出到 GPIO)、以验证 EPWM8的频率是否为 EPWM2的32倍?

    如果您可以验证这一点、则将 DMA 传输大小设置为32、并查看是否进入了 DMA 传输结束中断。 这是一种先使用 ADC ISR 验证 DMA 时序的更好方法。

    此致、

    Delaney

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Delaney:

    我按照您的建议操作、代码每32个样本进入一次 DMA ISR、我使用 ADC ISR 的原因是从 ADC 结果寄存器中记录数据、以便能够在 maltab 上绘制数据。

    如果我使用 ADCINT 触发 DMA 和 ISR、会引起问题吗?

    如果我不使用和 ISR 的 ADC 和使用它只用于触发 DMA ADCINT 是否会与 EPWM2 ISR 冲突如在前面的图像?  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Vignesh:

    我意识到我从未正确回答过你的原始问题。 如果 ADCINT 设置为 DMA 通道的触发源、则无需通过 CPU。 如果启用了该触发条件、则将其直接连接到硬件中的 DMA。  在使用相同的条件标志时、ADC 中断和 DMA 触发不应相互影响/导致问题。

    您可能看到的是在处理 PWM ISR 时出现的延迟。 如果 PWM 中断和 ADC 中断同时发送到 PIE、PIE 将首先处理 ADC 中断、因为它在表中具有更高的优先级、请参阅以下内容:

    在这种情况下、我建议尽可能缩短 ADC ISR。 期望的行为是什么? 是否要首先为 PWM ISR 提供服务? 如果是这样、您需要实现更复杂的中断嵌套。

    此致、

    Delaney