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.

[参考译文] CCS/CC3200:CC3200 ADC 采样异常

Guru**** 2553450 points
Other Parts Discussed in Thread: CC3200

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

https://e2e.ti.com/support/wireless-connectivity/wi-fi-group/wifi/f/wi-fi-forum/723654/ccs-cc3200-cc3200-adc-sampling-abnormal

器件型号:CC3200

工具/软件:Code Composer Studio

尊敬的先生/女士:

我将 CC3200与 CCS 结合使用、我遇到了一些奇怪的问题、看起来像是 CC3200芯片中的一些硬件问题。 因此、我正在与您联系以寻求帮助。

 我使用 ADC 对标准正弦波进行采样、一个通道用于电压、一个通道用于电流。 ADC 在乒乓模式下持续工作、每 16ms 调用一次中断函数、对一组1000点进行采样、并根据每个中断1000点在中断函数中进行频率计算。 我们检查了原始样本、发现当频率计算的计算复杂性低于5000倍浮点乘法时、样本非常好。 但是、当频率计算的计算复杂性超过5000倍浮点乘法时、采样偶尔会异常、即大约每3-6秒、采样将如下所示。 采样看起来会突然暂停一段时间、然后恢复。  

总之、当中断中的计算复杂性有时可能影响采样时、看起来就像这样。 直接从 ADC 获得的样本不应受到计算的影响、对吗? 这对我来说非常奇怪。 您能帮助解决这个问题吗? 非常感谢您的参与。

 我的代码如下所示。

void InitAdcDma (void){

   无符号短整型状态;

   UDMAInit();

   PinTypeADC (PIN_59、0xFF);

   PinTypeADC (PIN_600xFF);

 

   /*电压通道*/

   pChannelVoltageAdcChannelNum = ADC_CH_2;

   pChannelVoltageDmaChannelNum = UDMA_CH16_ADC_CH2;

 

   /*当前通道*/

   pChannelCurrentAdcChannelNum = ADC_CH_3;

   pChannelCurrentDmaChannelNum = UDMA_CH17_ADC_CH3;  

   //

   //获取与指定通道关联的中断号

   //

   pChannelVoltageAdcIntNum = INT_ADCCH2;

   pChannelCurrentAdcIntNum = INT_ADCCH3;  

   //

   //设置电压 ADC 通道的传输

   //

   map_uDMAChannelAssign (pChannelVoltageDmaChannelNum);

   UDMASetupTransfer (pChannelVoltageDmaChannelNum|UDMA_PRI_SELECT、UDMA_MODE_Pingpong、                     M_TOTAL_DMA_SAMPples、                     UDMA_SIZE 32、UDMA_ARB_1、                      (void *)(0x4402E874+ pChannelVoltageAdcChannelNum)、UDMA_SRC_INC_NONE、                     (void *)&(pChannelVoltageDmaDataDumpPing [0])、UDMA_DST_INC_32);

 

   UDMASetupTransfer (pChannelVoltageDmaChannelNum|UDMA_ALT_SELECT、UDMA_MODE_Pingpong、  M_TOTAL_DMA_SAMPples、UDMA_SIZE 32、UDMA_ARB_1、     (void *)(0x4402E874+ pChannelVoltageAdcChannelNum)、UDMA_SRC_INC_NONE、(void *)&(pChannelVoltageDmaDataDumpPong[0])、UDMA_DST_INC_32);

   //

   //启用 uDMA

   //

   ADCDMAEnable (ADC_base、 pChannelVoltageAdcChannelNum);  

   //

   //设置电压 ADC 通道的传输

   //

   map_uDMAChannelAssign (pChannelCurrentDmaChannelNum);

   UDMASetupTransfer (pChannelCurrentDmaChannelNum|UDMA_PRI_SELECT、UDMA_MODE_pingpong、            m_total_dma_samples、            UDMA_SIZE_32、UDMA_ARB_1、            (void *)(0x4402E874+ pChannelCurrentAdcChannelNum)、UDMA_SRC_INC_NONE、            (void *)&(pChannelCurrentDmaDataDumpPing [0])、UDMA_DST_INC_32);

 

   UDMASetupTransfer (pChannelCurrentDmaChannelNum|UDMA_ALT_SELECT、UDMA_MODE_PINGONG、

                     m_total_dma_samples、            UDMA_SIZE_32、UDMA_ARB_1、            (void *)(0x4402E874+ pChannelCurrentAdcChannelNum)、UDMA_SRC_INC_NONE、            (void *)&(pChannelCurrentDmaDataDumpPong[0])、UDMA_DST_INC_32);

   //

   //启用 uDMA

   //

   ADCDMAEnable (ADC_base、 pChannelCurrentAdcChannelNum);  

   //

   //设置电压 ADC

   //

   //#ifdef sl_platform_multi_threaded

   //   OSI_InterruptRegister (pChannelVoltageAdcIntNum、(P_OSI_INTR_Entry) ADCIntHandlerChV、INT_Priority_LVL_2);

   //#else

   //

   //设置优先级

   //

   IntPrioritySet (pChannelVoltageAdcIntNum、INT_Priority_LVL_0);  

   IntPendClear (pChannelVoltageAdcIntNum);  

   ADCIntRegister (ADC_base、pChannelVoltageAdcChannelNum、ADCIntHandlerChV);

   //#endif

   STATUS = ADCIntStatus (ADC_base、 pChannelVoltageAdcChannelNum);

   ADCIntClear (ADC_base、 pChannelVoltageAdcChannelNum、Status|ADC_DMA_DONE);

   ADCIntEnable (ADC_base、 pChannelVoltageAdcChannelNum、ADC_DMA_DONE);

   ADCChannelEnable (ADC_base、 pChannelVoltageAdcChannelNum);  

   //

   //设置当前 ADC

   //

   //#ifdef sl_platform_multi_threaded

   //   OSI_InterruptRegister (pChannelCurrentAdcIntNum、(P_OSI_INTR_Entry) ADCIntHandlerChI、INT_Priority_LVL_2);

   //#else

   //

   //设置优先级

   //

   IntPrioritySet (pChannelCurrentAdcIntNum、INT_Priority_LVL_2);  

   IntPendClear (pChannelCurrentAdcIntNum);  

   ADCIntRegister (ADC_base、pChannelCurrentAdcChannelNum、ADCIntHandlerChI);

   //#endif

   status = ADCIntStatus (ADC_base、 pChannelCurrentAdcChannelNum);

   ADCIntClear (ADC_base、 pChannelCurrentAdcChannelNum、Status|ADC_DMA_DONE);

   ADCIntEnable (ADC_base、 pChannelCurrentAdcChannelNum、ADC_DMA_DONE);

   ADCChannelEnable (ADC_base、 pChannelCurrentAdcChannelNum);  

   //

   //设置软件中断处理程序以处理城域数据

   //

   //   #ifdef sl_platform_multi_threaded

   //       OSI_InterruptRegister (metrougation_SFT_INT_NUM、(P_OSI_INTR_Entry) ComputeSmartPlugMetrology、INT_Priority_LVL_3);

   ////   #else

   ////       SoftwareIntRegister (metrougation_SFT_INT_NUM、INT_Priority_LVL_3、ComputeSmartPlugMetrology);//1.024秒中断

   //   #endif

   //

   //启用 ADC

   //

   ADCTimerConfig (ADC_base、2^17);

   ADCTimerEnable (ADC_base);

   ADCEnable (ADC_base);

  

void ADCIntHandlerChV (void){

   unsigned long ulChannelStructIndex、ulMode、ulControl;

   tDMAControlTable *pControlTable;

   unsigned long *pDataDumpBuff =空;

   无符号短整型状态;

   //   unsigned short uiIndex;

   STATUS = ADCIntStatus (ADC_base、 pChannelVoltageAdcChannelNum);

   ADCIntClear (ADC_base、 pChannelVoltageAdcChannelNum、Status|ADC_DMA_DONE);

  ulMode = MAP_uDMAChannelModeGet (pChannelVoltageDmaChannelNum | UDMA_PRI_SELECT);

  if (ulMode = UDMA_MODE_STOP)   {

       ulChannelStructIndex = pChannelVoltageDmaChannelNum | UDMA_PRI_SELECT;

       pDataDumpBuff =&(pChannelVoltageDmaDataDumpPing [0]);

   }

   其他

   {

       ulMode = MAP_uDMAChannelModeGet (pChannelVoltageDmaChannelNum | UDMA_ALT_SELECT);

       //

       //如果主控制结构体指示停止,则表示"A"

       //接收缓冲完成。  UDMA 控制器仍应接收

       //将数据输入"B"缓冲区。

       //

       if (ulMode = UDMA_MODE_STOP)

       {

           ulChannelStructIndex = pChannelVoltageDmaChannelNum | UDMA_ALT_SELECT;

           pDataDumpBuff =&(pChannelVoltageDmaDataDumpPong[0]);

       }

   }

   if (pDataDumpBuff!=空)

   {

       pChannelVoltageDmaBlockCount++;

       ulChannelStructIndex &= 0x3f;

       pControlTable = uDMAControlBaseGet ();

       ulControl =(pControlTable[ulChannelStructIndex].ulControl &

               μ~(UDMA_CHCTL_XFERSIZE_M | UDMA_CHCTL_XFERMODE_M));

       ulControl |= UDMA_MODE_PINGONG |((M_TOTAL_DMA_SAMPS_1)<< 4);

       uDMAChannelControlSet (ulChannelStructIndex、ulControl);

 计算频率_EKF (pDataDumpBuff、M_TOTAL_DMA_SAMPLEs、pChannelVoltageDmaBlockCount);

//执行频率计算。

     /*每秒计算原始计量参数*/

       if (M_total_dma_blocks_per_sec = pChannelVoltageDmaBlockCount)     {

           if (pChannelVoltageDmaBlockCount = pChannelCurrentDmaBlockCount)       {

               pChannelVoltageDmaBlockCount = 0;

               pChannelCurrentDmaBlockCount = 0;

           }

       }

       ulChannelStructIndex &= 0x3f;

       pControlTable =(tDMAControlTable *) HWREG (UDMA_BASE + UDMA_O_CTLBASE);

       ulControl =(pControlTable[ulChannelStructIndex].ulControl &

               μ~(UDMA_CHCTL_XFERSIZE_M | UDMA_CHCTL_XFERMODE_M));

 

       ulControl |= UDMA_MODE_PINGONG |((M_TOTAL_DMA_SAMPS_1)<< 4);

       pControlTable[ulChannelStructIndex].ulControl = ulControl;

 

#if 0

       ArrayIndexV = 0;

       printf ("\n\n\r\n\r\n");

       while (ArrayIndexV < M_TOTAL_DMA_SAples)

       {

           printf ("%d\n"、(pDataDumpBuff[ArrayIndexV++]>2)& 0xFFF);

       }

#endif

   }

 

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

    如果在 ADC 中断处理程序中进行数据处理所花费的时间过长、则可能会丢失数据。 在中断处理程序中、您需要重新加载 DMA 传输并为下一个乒乓 DMA 传输排队。 使用 DMA 交替模式、您可以在另一个缓冲区从 ADC 获取数据的同时、对刚刚完成的缓冲区执行处理。 但是、如果处理时间过长、另一个乒乓缓冲区可以在您排队等待下一个 DMA 传输之前完成传输。 这将导致 ADC 数据丢失、因为 DMA 在该时间内将空闲、并且仅在传输在中断处理程序内再次排队时才会恢复传输数据。

    在下一次 DMA 缓冲区传输完成之前、您必须完成数据处理。 如果您注意到、在 ADC 中断处理程序中执行相对较大的处理时、有时会丢失数据、那么您必须减少 ISR 中的处理、或者将数据发送到其他某个器件进行处理。

    如果您有进一步的问题或需要更多帮助、请告诉我。

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

    尊敬的 Michael:

    感谢你的答复。 但我在刚完成的缓冲区上完成了处理、而另一个缓冲区从 ADC 获取数据。 实际上、我进行了多次实验、发现如果在 另一个缓冲区填满之前没有完成刚刚完成的缓冲区的处理、代码根本不会运行。 对于我昨天提到的问题、 在 ADC 中断处理程序中、每次执行相同的计算。 我运行代码的时间足够长、并且发现大多数时候来自 ADC 的数据是正确的、但偶尔数据会是异常的。 具体而言、中断处理程序每16ms 调用一次、因此每4秒 从 ADC 的缓冲区中获取250组样本(每组有1000个点)。  其中只有1组采样异常、 其余249组是正确的。  

    我们尝试了不同的数据输入源、例如波形发生器、dSPACE。 无论数据输入源如何,问题都仍然存在。 这就是为什么我认为这可能是芯片内的问题。 希望 我清楚地解释了这个问题、你们可以帮助解决这个问题。 提前感谢您。

    此致、

    Yingmeng Xiang

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

    尊敬的 Michael:

    为供您参考、我注意到在 SDK 中的 ADC 示例中、从 ADC 采样的前4个点似乎被丢弃。 我不知道为什么要这样做。 但在我的程序中、我保留了前4个要点。 以下是我的代码。  

    void CalculateFrequency_EKF (无符号长整型*pDataDumpBuf,\
    短整型无符号整型 TotalInputSamples、\
    short unsigned int pChannelVoltageDmaBlockCount)

    LoffsetV=0;
    LRMSV=0;

    浮点求和块;
    短整型 unsigned int index、indexcom;
    unsigned long svalue;
    浮点 Avalue;
    索引=0;
    浮点 acvalue;
    acvalue=0;
    indexcom=0;

    sumvalueblock=0;
    while (index < TotalInputSamples)

    sValue=(pDataDumpBuf[索引]>> 2)和0xFFF;
    雪崩=(浮点) svalue/4096.00*1.67;// ADC 校准

    // acvalue=Avalue-averageV;
    acvalue=Avalue;
    pChannelVoltageSamples77float[indexcom]=acvalue;
    索引=索引+50;
    indexcom++;

    sumvalueblock=sumvalueblock+Avalue;
    sumVsquare=sumVsquare+acvalue*acvalue;

    sumvalueblock = sumvalueblock / 20;

    sumV=sumV+sumvalueblock;

    我期待你的答复。 提前感谢您。

    此致、

    Yingmeng Xiang