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.

[参考译文] TMS320F28335:CMPA 值不随 ADC 输入而变化。 闭环 PI 控制

Guru**** 2568565 points
Other Parts Discussed in Thread: C2000WARE, SYSCONFIG

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

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1362678/tms320f28335-cmpa-value-not-changing-according-to-adc-input-close-loop-pi-control

器件型号:TMS320F28335
主题中讨论的其他器件:C2000WARESysConfig

您好!

我将通过函数 DCL.h 使用 PI 控制逻辑

调试代码后、ePWM 的占空比不会根据给定的 ADC 更改到 ADCRESULT0。

请查找以下代码以供参考。

//###########################################################################
//
// FILE:   Example_2833xEPwmDeadBand.c
//
// TITLE:  ePWM Deadband Generation Example
//
//! \addtogroup f2833x_example_list
//! <h1> ePWM Deadband Generation (epwm_deadband)</h1>
//!
//! This example configures ePWM1, ePWM2 and ePWM3 for:
//!   - Count up/down
//!   - Deadband
//! 3 Examples are included:
//!   - ePWM1: Active low PWMs
//!   - ePWM2: Active low complementary PWMs
//!   - ePWM3: Active high complementary PWMs
//!
//! Each ePWM is configured to interrupt on the 3rd zero event
//! when this happens the deadband is modified such that
//! 0 <= DB <= DB_MAX.  That is, the deadband will move up and
//! down between 0 and the maximum value.
//!
//! \b External \b Connections \n
//!  - EPWM1A is on GPIO0
//!  - EPWM1B is on GPIO1
//!  - EPWM2A is on GPIO2
//!  - EPWM2B is on GPIO3
//!  - EPWM3A is on GPIO4
//!  - EPWM3B is on GPIO5
//
//
//###########################################################################
// $TI Release: $
// $Release Date: $
// $Copyright:
// Copyright (C) 2009-2023 Texas Instruments Incorporated - http://www.ti.com/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//   Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
//
//   Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the
//   distribution.
//
//   Neither the name of Texas Instruments Incorporated nor the names of
//   its contributors may be used to endorse or promote products derived
//   from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// $
//###########################################################################

//
// Included Files
//
#include "DSP28x_Project.h"


// Device Headerfile and Examples Include File
#include "DCL.h"
#include "DSP2833x_Device.h"
#include "DSP2833x_Examples.h"
#include "DSP2833x_GlobalPrototypes.h"

#include "DCLF32.h"

#include "DCL_fdlog.h"



//#include "DCLC28.h"

#include "math.h"
//
// Function Prototypes
//
float rk = 20.0f;

float yk;

float lk;

float uk;

float Duty;

DCL_PI pi1 = PI_DEFAULTS;



//

// Function Prototypes

//

Uint16 LoopCount;

Uint16 ConversionCount;

void adc_isr(void);

void gpio_select(void);


void InitAdc(void);
void InitEPwm1(void);

void control_Isr(void);





float voltage1;

float cmpa;





//

// Main

//

void main(void)

{

    InitSysCtrl();

    DINT;

    InitPieCtrl();

    EALLOW;

        #if (CPU_FRQ_150MHZ)     // Default - 150 MHz SYSCLKOUT

            //

            // HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 150/(2*3)   = 25.0 MHz

            //

            #define ADC_MODCLK 0x3

        #endif

        #if (CPU_FRQ_100MHZ)

            //

            // HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 100/(2*2)   = 25.0 MHz

            //

            #define ADC_MODCLK 0x2

        #endif

    EDIS;

    EALLOW;

        SysCtrlRegs.HISPCP.all = ADC_MODCLK;

    EDIS;

    IER = 0x0000;

    IFR = 0x0000;

    InitPieVectTable();



    EALLOW;         // This is needed to write to EALLOW protected registers

        PieVectTable.ADCINT = &adc_isr;

    EDIS;    // This is needed to disable write to EALLOW protected registers





    gpio_select();

    InitEPwm1();
    InitAdc();



    PieCtrlRegs.PIEIER1.bit.INTx6 = 1;

    IER |= M_INT1;







       /* initialise controller variables */

       pi1.Kp=2.0f;

       pi1.Ki=1.0f;

       pi1.Umax=0.8f;

       pi1.Umin=0.2f;



       rk = 20.0f;                             // initial value for control reference

       lk = 1.0f;                              // control loop not saturated



       //

       // Enable SOCA from ePWM to start SEQ1

       //
       // control loop not saturated
       AdcRegs.ADCMAXCONV.all = 0x0001;       // Setup 2 conv's on SEQ1

       AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x3; // Setup ADCINA3 as 1st SEQ1 conv.

       AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 0x2; // Setup ADCINA2 as 2nd SEQ1 conv.
       AdcRegs.ADCTRL2.bit.EPWM_SOCA_SEQ1 = 1;


                AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 1;  // Enable SEQ1 interrupt (every EOS)


    EINT;           // Enable Global interrupt INTM

    ERTM;           // Enable Global realtime interrupt DBGM

    for (;;) ;

}



//

// cpu_timer0_isr -


void gpio_select()


{


        EALLOW;

        GpioCtrlRegs.GPAPUD.bit.GPIO0 = 0;   // Enable pullup on GPIO0

        GpioCtrlRegs.GPAPUD.bit.GPIO1 = 0;   // Enable pullup on GPIO0

        GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1;  // GPIO0 = PWM1A

        GpioCtrlRegs.GPAMUX1.bit.GPIO1 = 1;  // GPIO0 = PWM1A

        EDIS;

}

void InitEPwm1()

{

        EPwm1Regs.TBCTL.bit.CTRMODE = 0; // Count up down

        EPwm1Regs.TBPRD = 37500;       // Set timer period

        EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE;    // Disable phase loading

        EPwm1Regs.TBPHS.half.TBPHS = 0x0000;       // Phase is 0

        EPwm1Regs.TBCTR = 0x0000;                  // Clear counter

        EPwm1Regs.TBCTL.bit.HSPCLKDIV = 0x001;   // Clock ratio to SYSCLKOUT

        EPwm1Regs.TBCTL.bit.CLKDIV = 000;

        EPwm1Regs.TBCTL.bit.SYNCOSEL=1;

        EPwm1Regs.CMPA.half.CMPA =18750;    // Set compare A value

        EPwm1Regs.CMPB = 18750;              // Set Compare B value

        EPwm1Regs.CMPCTL.bit.LOADAMODE=1;

        EPwm1Regs.CMPCTL.bit.SHDWAMODE=0;

/*        EPwm1Regs.DBCTL.bit.OUT_MODE=3;

        EPwm1Regs.DBCTL.bit.POLSEL=2;

        EPwm1Regs.DBCTL.bit.IN_MODE=0;

        EPwm1Regs.DBRED=100;

        EPwm1Regs.DBFED=100;*/

        EPwm1Regs.AQCTLA.bit.ZRO=2;    // Set PWM1A on Zero

        EPwm1Regs.AQCTLA.bit.CAU=1;



            EPwm1Regs.ETSEL.bit.SOCAEN = 1;     // Enable SOC on A group

            EPwm1Regs.ETSEL.bit.SOCASEL = 1;    // Select SOC from from CPMA on upcount

            EPwm1Regs.ETPS.bit.SOCAPRD = 1;     // Generate pulse on 1st event



}

__interrupt void adc_isr(void)

{

    yk=((int)AdcRegs.ADCRESULT0 >>4)*300.0f/4095.0f;



    //Voltage2[ConversionCount] = AdcRegs.ADCRESULT1 >>4;

    //DCL_runClamp_C1(float *data, float Umax, float Umin);

    //





    lk=0.0f;

    uk = DCL_runPI_C2(&pi1, rk, yk);

    if (uk>0.8f){

        uk=0.8f;

    }

    else if (uk<0.1f){

        uk=0.1f;

    }

    //uk=0.5f;



    EPwm1Regs.CMPA.half.CMPA =(EPwm1Regs.TBPRD)*uk;    // Set compare A value

    EPwm1Regs.CMPB = EPwm1Regs.TBPRD*uk;              // Set Compare B value

    // If 40 conversions have been logged, start over

    //

    //

    // Reinitialize for next ADC sequence

    //
 if(ConversionCount == 9)
    {
        ConversionCount = 0;
    }
    else
    {
        ConversionCount++;
    }

    AdcRegs.ADCTRL2.bit.RST_SEQ1 = 1;         // Reset SEQ1

    AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1;       // Clear INT SEQ1 bit

    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;   // Acknowledge interrupt to PIE



    return;

}

请解决此问题。

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

    您好!

    您是否使用了任何参考 C2000Ware 示例? 您能否尝试单步执行代码的每一行、以查看配置/变量值是否按预期变化? 您可以检查 ISR 是否正确发生。 这将有助于缩小当事情与你预期发生的事情不同时的根源。

    此致、

    Allison

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

    您好!

    我将能够在下周前检查寄存器的值是否会对结果产生影响、在此之前请务必确认 CCS 的 Verion 是否也会对结果产生影响? 我使用的是 ccs7.4

    谢谢

    Ayush

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

    尊敬的 Ayush:

    是的、请告诉我发现的任何结果。 CCS 版本应该不会对结果产生任何影响-所以无需担心这个问题(虽然、你还没有尝试较新的 CCS 版本是因为某些原因吗?)。

    尽管这不直接适用于您的用例、但我还是想添加一点、对于新一代器件(通过 DriverLib 和 SysConfig 实现)、我们在 C2000 Academy 上有一个 使用 ADC 转换结果来影响 PWM 输出的演练示例。 相关说明可 在此处找到、实验练习示例 项目可在 {C2000Ware}\training\device\{device}\system_design\lab_systemdesign 找到。 我只是想确保您在未来使用新一代器件时了解这一点、或者您对此很好奇!

    此致、

    Allison

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

    您好、Allison

    很抱歉,我没有访问笔记本电脑,因此达莱.

    我监测了  ADCRESULT0、ADCINT 的实时值、即使在改变 ADC 的输入值后也不会发生变化。 因此、占空比无变化

    占空比。

    PFA 屏幕截图。 然后介绍下一个行动方案。

    此致

    Ayush

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

    尊敬的 Ayush:

    您能否在代码中放置一个 while 循环、并且通过将 AdcRegs.ADCTRL2.bit.SOC_SEQ1写入1来触发 ADC?

    这样、我们可以确保正确设置 ADC SEQ1和中断。 您是否针对 F2833x 器件使用了我们的任何 ADC 示例?   

    此致、

    Ben Collier

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

    你(Ben)好

    我已在代码中添加了 while 循环。 请从您的终端进行验证

    谢谢。此致

    Ayush

     .

    #include "DSP28x_Project.h"     // Device Headerfile and Examples Include File
    #include "DCL.h"
    #include "DCLF32.h"
    #include "DCL_fdlog.h"
    #include "DCLC28.h"
    
    // Function Prototypes
    __interrupt void adc_isr(void);
    
    DCL_PI pi1 = PI_DEFAULTS;
    
    // Globals
    Uint16 LoopCount;
    Uint16 ConversionCount;
    float Voltage1;
    float U = 0.5f;
    float rk = 0.6f;
    float yk;
    float uk = 0.5f;
    
    void InitEPwm1(void);
    void gpio_select(void);
    
    //
    // Main
    //
    void main(void)
    {
        // Step 1. Initialize System Control: PLL, WatchDog, enable Peripheral Clocks
        InitSysCtrl();
    
        EALLOW;
        #if (CPU_FRQ_150MHZ)     // Default - 150 MHz SYSCLKOUT
            #define ADC_MODCLK 0x3
        #endif
        #if (CPU_FRQ_100MHZ)
            #define ADC_MODCLK 0x2
        #endif
        EDIS;
    
        // Define ADCCLK clock frequency ( less than or equal to 25 MHz )
        EALLOW;
        SysCtrlRegs.HISPCP.all = ADC_MODCLK;
        EDIS;
    
        // Step 2. Initialize GPIO:
        // InitGpio();  // Skipped for this example
    
        // Step 3. Clear all interrupts and initialize PIE vector table:
        DINT;
    
        InitPieCtrl();
    
        IER = 0x0000;
        IFR = 0x0000;
    
        InitPieVectTable();
    
        EALLOW;  // This is needed to write to EALLOW protected register
        PieVectTable.ADCINT = &adc_isr;
        EDIS;    // This is needed to disable write to EALLOW protected registers
    
        // Step 4. Initialize all the Device Peripherals:
        InitAdc();  // For this example, init the ADC
    
        // Step 5. User specific code, enable interrupts:
        PieCtrlRegs.PIEIER1.bit.INTx6 = 1;
        IER |= M_INT1;      // Enable CPU Interrupt 1
        EINT;               // Enable Global interrupt INTM
        ERTM;               // Enable Global realtime interrupt DBGM
    
        LoopCount = 0;
        ConversionCount = 0;
    
        // Configure ADC
        AdcRegs.ADCMAXCONV.all = 0x0001;       // Setup 2 conv's on SEQ1
        AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x3; // Setup ADCINA3 as 1st SEQ1 conv.
        AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 0x2; // Setup ADCINA2 as 2nd SEQ1 conv.
    
        AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 1;  // Enable SEQ1 interrupt (every EOS)
    
        // Configure ePWM1
        InitEPwm1();
    
        // Configure GPIO
        gpio_select();
    
        // Main loop
        while (1)
        {
            // Start ADC conversion sequence 1
            AdcRegs.ADCTRL2.bit.SOC_SEQ1 = 1;
    
            // Wait for ADC conversion to complete
            while (AdcRegs.ADCST.bit.INT_SEQ1 == 0);
    
            // Read ADC result from result register (e.g., from the first channel)
            yk = ((int)AdcRegs.ADCRESULT0 >> 4) * 300.0f / 4095.0f;
    
            // Process the ADC result
            uk = DCL_runPI_C2(&pi1, rk, yk);
            if (uk > 0.8f) {
                uk = 0.8f;
            } else if (uk < 0.1f) {
                uk = 0.1f;
            }
    
            EPwm1Regs.CMPA.half.CMPA = (EPwm1Regs.TBPRD) * uk;  // Set compare A value
            EPwm1Regs.CMPB = EPwm1Regs.TBPRD * uk;              // Set Compare B value
    
            // Clear the interrupt flag and reset sequencer
            AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1;
            AdcRegs.ADCTRL2.bit.RST_SEQ1 = 1;
    
            LoopCount++;
        }
    }
    
    void InitEPwm1(void)
    {
        EPwm1Regs.TBCTL.bit.CTRMODE = 0; // Count up down
        EPwm1Regs.TBPRD = 37500;       // Set timer period
        EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE;    // Disable phase loading
        EPwm1Regs.TBPHS.half.TBPHS = 0x0000;       // Phase is 0
        EPwm1Regs.TBCTR = 0x0000;                  // Clear counter
        EPwm1Regs.TBCTL.bit.HSPCLKDIV = 0x001;   // Clock ratio to SYSCLKOUT
        EPwm1Regs.TBCTL.bit.CLKDIV = 000;
        EPwm1Regs.TBCTL.bit.SYNCOSEL = 1;
        EPwm1Regs.CMPA.half.CMPA = 10000;    // Set compare A value
        EPwm1Regs.CMPB = 10000;              // Set Compare B value
        EPwm1Regs.DBCTL.bit.OUT_MODE = 3;
        EPwm1Regs.DBCTL.bit.POLSEL = 2;
        EPwm1Regs.DBCTL.bit.IN_MODE = 0;
        EPwm1Regs.DBRED = 100;
        EPwm1Regs.DBFED = 100;
        EPwm1Regs.ETSEL.bit.SOCAEN = 1;     // Enable SOC on A group
        EPwm1Regs.ETSEL.bit.SOCASEL = 4;    // Select SOC from CPMA on upcount
        EPwm1Regs.ETPS.bit.SOCAPRD = 1;     // Generate pulse on 1st event
    
        EPwm1Regs.AQCTLA.bit.ZRO = 2;    // Set PWM1A on Zero
        EPwm1Regs.AQCTLA.bit.CAU = 1;
    }
    
    void gpio_select(void)
    {
        EALLOW;
        GpioCtrlRegs.GPAPUD.bit.GPIO0 = 0;   // Enable pullup on GPIO0
        GpioCtrlRegs.GPAPUD.bit.GPIO1 = 0;   // Enable pullup on GPIO1
        GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1;  // GPIO0 = PWM1A
        GpioCtrlRegs.GPAMUX1.bit.GPIO1 = 1;  // GPIO1 = PWM1B
        EDIS;
    }
    
    __interrupt void adc_isr(void)
    {
        yk = ((int)AdcRegs.ADCRESULT0 >> 4) * 300.0f / 4095.0f;
    
        uk = DCL_runPI_C2(&pi1, rk, yk);
        if (uk > 0.8f) {
            uk = 0.8f;
        } else if (uk < 0.1f) {
            uk = 0.1f;
        }
    
        EPwm1Regs.CMPA.half.CMPA = (EPwm1Regs.TBPRD) * uk;  // Set compare A value
        EPwm1Regs.CMPB = EPwm1Regs.TBPRD * uk;              // Set Compare B value
    
        if (ConversionCount == 9) {
            ConversionCount = 0;
        } else {
            ConversionCount++;
        }
    
        AdcRegs.ADCTRL2.bit.RST_SEQ1 = 1;         // Reset SEQ1
        AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1;       // Clear INT SEQ1 bit
        PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;   // Acknowledge interrupt to PIE
    
        return;
    }
    

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

    尊敬的 Ayush:

    在您的当前 while (1)循环中、仅当中断未正确设置时才会触发一次 SOC。 您是否可以更改 while (1)循环、使其仅包含软件 SOC 触发器?

    此外、您是否针对 F2833x 器件使用了我们的任何 ADC 示例?

    此致、

    Ben Collier

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

    在此代码中、我通过添加 while 环路、将 rk 从常量更改为100斜率函数0。

    请验证编码是否正确。

    谢谢


    while (1)

    //更新时间计数器
    时间计数器++;

    //确定参考信号值
    if (timeCounter < constantDuration)

    //恒定相位
    Rk = 100.0f;
    }
    设计

    //斜降相位
    Rk = 100.0f + rampRate *(timeCounter - constantDuration);
    如果(rk < 0.0f)

    Rk = 0.0f;//钳位至0以防止低于0
    }
    }

    //启动 ADC 转换序列1
    AdcRegs.ADCTRL2.bit.SOC_SEQ1 = 1;

    //等待 ADC 转换完成
    while (AdcRegs.ADCST.bit.INT_SEQ1 = 0);

    //从 result 寄存器读取 ADC 结果(例如、来自第一个通道)
    Yk =((int) AdcRegs. ADCRESULT0 >> 4)* 300.0f / 4095.0f;

    //处理 ADC 结果
    UK = DCL_runpi_c2 (&pi1、rk、yk);
    如果(英国> 0.8f){
    UK = 0.8f;
    }否则、如果(UK < 0.1f){
    UK = 0.1f;
    }

    //根据控制输出设置 PWM 占空比
    EPwm1Regs.CMPA.half.CMPA =(EPwm1Regs.TBPRD)* UK;
    EPwm1Regs.CMPB = EPwm1Regs.TBPRD * UK;
    }

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

    Ayush

    我无法评论您的控制代码的功能。 我只想确保您的 ADC 按预期触发。

    您是否可以在 while (1)循环中仅包含以下行?  

    AdcRegs.ADCTRL2.bit.SOC_SEQ1 = 1;

    然后、您可以检查 ADC 结果寄存器以确保看到预期的结果吗?  

    谢谢!

    Ben Collier