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.

[参考译文] TMS320F28027F:简单的 ADC 程序?

Guru**** 2925550 points

Other Parts Discussed in Thread: TMS320F28027F, C2000WARE

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

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1029254/tms320f28027f-simple-adc-program

器件型号:TMS320F28027F
主题中讨论的其他器件: C2000WARE

有没有人有一个非常简单的"入门"程序来将 ADC 与 TMS320F28027F 搭配使用?

2000Ware 中的示例(example_2802xAdc 与 F2802x_adc.c 一起工作)但非常复杂-使用中断进行 SOC、取平均 值等 因此,很难看到什么是必需的。

我只需要一个简单的程序来将 ADC 设置为自由运行模式、监控一个输入上的电压并将值放置在寄存器中。 它将仅使用 ADC 的 EOC 等待循环。

非常感谢

Roger

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

    您好 Roger、

    我已经修改了 C2000Ware 示例_2802xAdc 和示例、以去除中断、从而简化了触发机制。  

    如果您有任何疑问、请告诉我。

    //
    // Included Files
    //
    #include "DSP28x_Project.h"     // Device Headerfile and Examples Include File
    
    //
    // Function Prototypes
    //
    void Adc_Config(void);
    
    //
    // Globals
    //
    uint16_t Voltage1;
    
    //
    // Main
    //
    void main(void)
    {
        //
        // WARNING: Always ensure you call memcpy before running any functions from
        // RAM InitSysCtrl includes a call to a RAM based function and without a 
        // call to memcpy first, the processor will go "into the weeds"
        //
    #ifdef _FLASH
        memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
    #endif
    
        //
        // Step 1. Initialize System Control:
        // PLL, WatchDog, enable Peripheral Clocks
        // This example function is found in the f2802x_SysCtrl.c file.
        //
        InitSysCtrl();
    
        //
        // Step 2. Initialize GPIO:
        // This example function is found in the f2802x_Gpio.c file and
        // illustrates how to set the GPIO to it's default state.
        //
        //InitGpio();  // Skipped for this example
    
        //
        // Step 3. Clear all interrupts and initialize PIE vector table:
        // Disable CPU interrupts
        //
        DINT;
    
        //
        // Initialize the PIE control registers to their default state.
        // The default state is all PIE interrupts disabled and flags
        // are cleared.
        // This function is found in the f2802x_PieCtrl.c file.
        //
        InitPieCtrl();
    
        //
        // Disable CPU interrupts and clear all CPU interrupt flags
        //
        IER = 0x0000;
        IFR = 0x0000;
    
        //
        // Initialize the PIE vector table with pointers to the shell Interrupt
        // Service Routines (ISR).
        // This will populate the entire table, even if the interrupt
        // is not used in this example.  This is useful for debug purposes.
        // The shell ISR routines are found in f2802x_DefaultIsr.c.
        // This function is found in f2802x_PieVect.c.
        //
        InitPieVectTable();
    
        //
        // Initialize all the Device Peripherals
        //
        InitAdc();  // For this example, init the ADC
        AdcOffsetSelfCal();
    
        //
        // Configure ADC
        // Note: Channel ADCINA4  will be double sampled to workaround the ADC 1st 
        // sample issue for rev0 silicon errata
        //
        EALLOW;
        
        // ADCINT1 trips after AdcResults latch
        AdcRegs.ADCCTL1.bit.INTPULSEPOS	= 1;
        
        // Enable ADCINT1
        AdcRegs.INTSEL1N2.bit.INT1E = 1;
    
        // Disable continuous sampling for ADCINT1
        AdcRegs.INTSEL1N2.bit.INT1CONT = 0;
    
        // setup EOC1 to trigger ADCINT1 to fire
        AdcRegs.INTSEL1N2.bit.INT1SEL	= 1;
        
        // set SOC0 channel select to ADCINA4
        AdcRegs.ADCSOC0CTL.bit.CHSEL 	= 4;
        
        // set SOC1 channel select to ADCINA4
        AdcRegs.ADCSOC1CTL.bit.CHSEL 	= 4;
        
        // set SOC0 start on software trigger
        AdcRegs.ADCSOC0CTL.bit.TRIGSEL 	= 0;
    
        // set SOC1 start on software trigger
        AdcRegs.ADCSOC1CTL.bit.TRIGSEL 	= 0;
        
        // set SOC0 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
        AdcRegs.ADCSOC0CTL.bit.ACQPS 	= 6;
        
        // set SOC1 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
        AdcRegs.ADCSOC1CTL.bit.ACQPS 	= 6;
        
        
        //--------- ADC Conversion -------------//
        
        // Software Trigger
        AdcRegs.ADCSOCFRC1.bit.SOC0 = 1;
    
        // Software Trigger
        AdcRegs.ADCSOCFRC1.bit.SOC1 = 1;
        
        // Wait for the conversion to be done
        while (AdcRegs.ADCINTFLG.bit.ADCINT1 == 0){}
    
        // Clear ADCINT1 flag
        AdcRegs.ADCINTFLGCLR.bit.ADCINT1 = 1;
        
        // Store the conversion result
        Voltage1 = AdcResult.ADCRESULT1;
    
        EDIS;
    }
    //
    // End of File
    //

    此致、

    Marlyn

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

    您好、Marlyn、

    非常感谢您的快速回复! 很高兴知道"随时为您提供帮助"!  我已经尝试过您的程序、它运行正常(我将最后一部分"ADC 转换"放入 while (1)循环中以进行连续采样-顺便说一下、这个部分不需要 EALLOW)。 只需回答几个问题:

    (1) 是否需要双采样(SOC0和 SOC1)? 它不会将采样率减半吗? 如果这只是第一个样本的问题、我 可能就能解决这个问题了。 在没有软件触发到 SOC0的情况下、它看起来工作正常。

    (2)现在、该计划更易于理解。 (我被用于使用 ADC 排序的38335。) 但您的程序仍会调用 F2802x_adc.c 中的大量代码、并且(对于我而言)很难理解为什么所有代码都是必需的。 是否可以为这个简单的目的"思考"很多问题?

    (3)与38335相比、似乎没有 ADC 时钟链-只有 SYSCLK 除以2的选项。 因此、ADC 显然只是运行一个完整(或1/2)转换速度。 是否正确理解了这一点?

    此致

    Roger

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

    您好 Roger、

    [引用 userid="496214" URL"~/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1029254/tms320f28027f-simple-adc-program/3806328 #3806328"](1) 是否需要双采样(SOC0和 SOC1)? 它不会将采样率减半吗? 如果这只是第一个样本的问题、我 可能就能解决这个问题了。 在没有软件触发到 SOC0的情况下、它看起来工作正常。

    只需要在一个转换序列内进行第一次转换。 如果您在 while (1)循环中包含转换代码、则只需丢弃第一 个 SOC0结果(代码已经执行了该操作)、然后继续仅触发 SOC1并记录该结果。 或者、您可以同时删除 SOC0触发器和转换、并丢弃第一个 SOC1转换结果。 有关此初始转换的更多信息、请参阅(ADC:初始转换)公告下的 F2802x 勘误表。

    [引用 userid="496214" URL"~/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1029254/tms320f28027f-simple-adc-program/3806328 #3806328"](2)该程序现在更易于理解。 (我被用于使用 ADC 排序的38335。) 但您的程序仍会调用 F2802x_adc.c 中的大量代码、并且(对于我而言)很难理解为什么所有代码都是必需的。 是否可以为这一简单目的"抽稀"其中的许多内容?[/引述]

    我尽量精简它、只留下 必要的代码。 请举个例子说明 哪些代码行难以理解、我可以帮助您了解代码行的执行情况或需要的原因。

    [引用 userid="49624" URL"~/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1029254/tms320f28027f-simple-adc-program/3806328 #3806328"](3)与38335相比、似乎没有 ADC 时钟链-只有将 SYSCLK 除以2的选项。 因此、ADC 显然只是运行一个完整(或1/2)转换速度。 是否正确理解了这一点?

    是的、这个器件只有 CLKDIV2EN (在修订版 A 上)。 如果您需要其他值、则需要更改 SYSCLK、但这也会导致整个器件的工作频率发生变化。

    此致、

    Marlyn

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

    Hej Marlyn、

    非常感谢您的快速回答。

    关于 (2): 现在已经足够清除了带有 main()的新文件 example_adc.c、 但支持文件 F2802x_adc.c 中有很多内容,这似乎是不必要的(并且令人困惑)-但它是从 main()调用的(例如 ,在 AdcConversion()中进行的一些平均值计算,由在 main()中调用的 AcdOffsetSelfCal()调用)。 我想知道 F2802x_adc.c 是否也可以"精简"。

    此致

    Roger

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

    您好 Roger、

    'AdcOffsetSelfCal ()'函数从 main 调用、以重新校准 ADC 零偏移误差。  ADC 的偏移误差是指在对任何输入引脚施加0伏(V)输入时、测得的读数与理想读数(以最低有效位(LSB)为单位)之间的偏差。 通常通过 ADCOFFSETTRIM 寄存器中的 OFFTRIM 位对偏移误差进行校正、从而调整偏移误差。  

    AdcOffsetSelfCal 函数的作用是:

    • 设置将 VREFLO 连接到 B5的内部多路复用器(这种方式在 B5上观察到0V)
    • 应用人工偏移(+80)来计算可能存在的任何负偏移
    • 在 B5上进行转换以找到0V 输入时的平均实际读数
    • 向 ADCOFFSETTRIM 寄存器写入新的偏移值(80 -平均转换)
    • 将 B5设置回正常的 ADC 输入引脚

     为了正确校准偏移、需要有足够大的转换样本大小。 为了执行这些转换,专门调用了 AdcConversion()。 该函数执行256次转换。 在该函数中、通过执行"乒乓"采样来执行转换、这是一种有助于加快转换速度的技术。 本质上、ADCINT1由转换6结束触发、并在 SOC8-15上启动转换。 ADCINT2由 EOC14触发并触发 SOC0-7 (这就是它们将其称为交替采样的原因)。 然后、所有这些转换被汇总并取平均值、以便准确地表示施加0V 时 ADC 的读数。  

    这些函数无需更改。 TI 为这些器件提供了代码、以帮助消除 ADC 偏移误差。  

    此致、

    Marlyn

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

    Hej Marlyn、

    (非常感谢您的快速回复! 我很感兴趣地阅读了您的回复、现在已经开始重新考虑这个主题了。。。)

    好的、我将只使用示例_adc.c 中的代码、其中它调用 InitAdc ()和 AdcOffsetSelfCal ()-并且也在 EALLOW 部分中执行所有配置。

    (1)它可以在 main()中与该循环正常运行:

    while (1)
     {
       //软件触发器- 不使用(Roger)工作
       //AdcRegs.ADCSOCFRC1.bit.SOC0 = 1;

       //软件触发
       AdcRegs.ADCSOCFRC1.bit.SOC1 = 1;
       
       //等待转换完成
       while (AdcRegs.ADCINTFlG.bit.ADCINT1 = 0){}

       //清除 ADCINT1标志
       AdcRegs.ADCINTFLGCLR.bit.ADCINT1 = 1;
       
       //存储转换结果
       Voltage1 = AdcResult.ADCRESULT1;

    //对结果执行一些操作...

     }

    (2)如果我只放置(一次):

    AdcRegs.ADCSOCFRC1.bit.SOC0 = 1;

    在循环之前、并且仅在循环中使用 SOC1、我假设 循环中读取的第一个值 AdcResult.ADCRESULT1将是正确的(但对于第一个值并不重要)。

    (3)如果我将 SOC0和 SOC1触发器置于环路中、这不会使采样率减半?

    (4)但我认为我误解了 SOC 和 ADCRESULT 之间的关系:为什么您执行 SOC0和 SOC1、但只读 AdcResult.ADCRESULT1?

    此致

    Roger

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

    您好 Roger、

    感谢您关注本主题。 触发 SOC0和 SOC1的原因是 ADC 初始转换(ADC: 初始转换) 、其状态为"当 ADC 转换由顺序或同步采样模式下的任何触发源启动时、第一个采样可能不是正确的转换结果"、作为一种权变措施、建议如下: '对于顺序模式、在每个转换序列开始时丢弃第一个采样。 例如、如果应用程序调用一个给定的转换序列、SOC0→SOC1→SOC2来定期启动、那么将该序列改为 SOC0→SOC1→SOC2→SOC3、并且只使用最后三个转换、ADCRESULT1、ADCRESULT2、ADCRESULT3、从而丢弃 ADCRESULT0"。  

    如果您进行了一些测试、ADCRESULT1是正确的、同时仅调用  AdcRegs.ADCSOCFRC1.bit.SOC0 = 1;在环路外、您应该能够以这种方式实现它。 勘误表适用于一系列对话、在第一 个转换结果不正确的情况下、应将权变措施用作预防措施。  

    此致、

    Marlyn

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

    Hej Marlyn、

     感谢大家的持续支持。 我对转换时间有疑问。

    使用此代码(基于您的代码):

    while (1){
                 //软件触发
                AdcRegs.ADCSOCFRC1.bit.SOC1 = 1;

                //等待转换完成
                while (AdcRegs.ADCINTFlG.bit.ADCINT1 = 0){}

                //清除 ADCINT1标志
                AdcRegs.ADCINTFLGCLR.bit.ADCINT1 = 1;

                //存储转换结果
                ad_value=AdcResult.ADCRESULT1;
                IO34_Toggle ();//完成 A/D 转换后的信号(用于监控周期)
        
       }//结束 while

    我测量的 IO 切换时间为2.1微秒。 这似乎比数据表 sprui09-TMS320F2802x-Reference-Manual.pdf 表中的预期时间长得多。406页 ,即333ns (代码中的 ACQPS 设置为6)–甚至允许执行 IO 切换约130ns (我通过在环路中仅进行切换来测量)。 2.1微秒是否是使用代码的预期转换时间?

    此致
    Roger

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

    您好 Roger、

    我注意到您在函数调用中切换了 GPIO。 您能否直接从环路内切换 GPIO 以获得更准确的估算值? 如果要在函数调用中切换 GPIO、则还需要考虑分支到该函数并返回所需的时间。

    另请注意、您将包括清除 ADCINT1标志、存储结果以及触发 SOC 启动所需的时间。 您还可以尝试在启动软件触发器后立即设置 GPIO、然后在转换完成后清除 GPIO。 如果您考虑 GPIO 设置/清除时间、那么这将使您更接近实际采样/转换时间。

    此致、

    Marlyn