Continue to Site

Reply to thread

Hello everyone!


I have written the following code using a previously working codebase that was originally designed for a different application but the same TI TMS320F28335 DSP.

Some of the code was written by me, some was provided by ChatGPT, I also asked the AI chat to add comments for better clarity of the code lines.


objective:

The DSP receives a digital signal as an input from an XOR phase detector and provide a 50% duty cycle with varying frequency PWM as output.


 The goal is to:

  1. Accurately measure the pulse width of the XOR output (which represents the phase difference between two square waves).
  2. Adjust the PWM output frequency of the DSP accordingly.

Example Calculation:

  • Initial PWM frequency = 200 kHz (Period = 5 µs)
  • If the XOR output is logic ‘1’ for 0.5 µs, this corresponds to a phase difference of (0.5 µs/5 µs)×360°=36°
  • In response, the PWM frequency should update to 200k+36k = 236 kHz.

Implementation:

To ensure precise measurement of the XOR pulse width, I am using the eCAP (Enhanced Capture) module of the DSP.


Questions:

🔹 This is my first time manually writing such a DSP code—could you please review it and let me know if it is suitable for the TMS320F28335?

🔹 Is anything missing or incorrect in my approach?

🔹 How can I validate my code before flashing it onto the DSP?


Any advice, feedback, or suggestions would be greatly appreciated! Thanks in advance! 😊


The code is below:


#include "DSP2833x_Device.h"                 // Include device-specific register definitions

#include "DSP2833x_SysCtrl.h"                // Include system control functions and definitions

#include "DSP2833x_GlobalPrototypes.h"       // Include global prototypes for the DSP

#include <string.h>                          // Include the string library for the memcpy function


//------------------------------------------------------------------------------

// External functions from TI's libraries

//------------------------------------------------------------------------------

extern void InitSysCtrl(void);               // Function to initialize system control (clocks, PLL, etc.)

extern void InitPieCtrl(void);               // Function to initialize the Peripheral Interrupt Expansion (PIE)

extern void InitPieVectTable(void);          // Function to initialize the PIE vector table with default ISRs

extern void InitFlash(void);                 // Function to initialize flash wait states and other flash settings


//------------------------------------------------------------------------------

// Symbols defined by the linker for copying critical functions from Flash to RAM

//------------------------------------------------------------------------------

extern unsigned int RamfuncsLoadStart;       // Start address of functions to be copied from flash to RAM

extern unsigned int RamfuncsLoadEnd;         // End address of functions to be copied from flash to RAM

extern unsigned int RamfuncsRunStart;        // Start address in RAM where functions will run


//------------------------------------------------------------------------------

// Function Prototypes for our custom functions

//------------------------------------------------------------------------------

void Gpio_select(void);                      // Function to configure GPIO pins for PWM and capture input

void Setup_ePWM1(void);                      // Function to configure ePWM1 for PWM output

void Setup_eCAP1(void);                      // Function to configure eCAP1 for capturing sensor pulses


interrupt void ecap1_isr(void);              // Interrupt Service Routine for eCAP1 interrupts


//------------------------------------------------------------------------------

// Global Definitions and Variables

//------------------------------------------------------------------------------

#define SYSCLK             150000000UL      // Define the system clock frequency as 150 MHz (unsigned long literal)

#define INITIAL_PWM_FREQ   200000UL         // Define the initial PWM frequency as 200 kHz (unsigned long literal)

// Calculate the initial time–base period in counts:

// TBPRD = SYSCLK / PWM_frequency = 150,000,000 / 200,000 = 750

#define INITIAL_TBPRD      750              // Define the initial PWM period as 750 counts


// Global variable to store the updated PWM frequency for monitoring or further processing

volatile unsigned long g_newPwmFreq = INITIAL_PWM_FREQ;  // Initialize with the base frequency (200 kHz)


//------------------------------------------------------------------------------

// Main function: entry point of the program

//------------------------------------------------------------------------------

void main(void)

{

    InitSysCtrl();                        // Initialize system control: clocks, PLL, watchdog, etc.


    // Copy critical functions from Flash to RAM for faster execution (if required)

    memcpy(&RamfuncsRunStart,             // Destination: start address in RAM

           &RamfuncsLoadStart,             // Source: start address in flash

           (unsigned long)&RamfuncsLoadEnd - (unsigned long)&RamfuncsLoadStart); // Number of bytes to copy

    InitFlash();                          // Initialize flash memory settings (e.g., wait states)


    EALLOW;                               // Enable access to protected registers

    SysCtrlRegs.WDCR = 0x00AF;              // Configure the watchdog timer (e.g., enable with a specific prescaler)

    EDIS;                                 // Disable access to protected registers


    DINT;                                 // Disable all interrupts during system configuration


    Gpio_select();                        // Configure GPIO pins for PWM output and eCAP input


    Setup_ePWM1();                        // Set up ePWM1: configure PWM output at 200 kHz with 50% duty cycle


    Setup_eCAP1();                        // Set up eCAP1: configure capture module to record sensor pulse edges


    InitPieCtrl();                        // Initialize the PIE control registers for interrupt management


    InitPieVectTable();                   // Initialize the PIE vector table with default ISR addresses


    EALLOW;                               // Enable protected register access for modifying the PIE vector table

    PieVectTable.ECAP1_INT = &ecap1_isr;    // Map the eCAP1 interrupt vector to our custom ISR function

    EDIS;                                 // Disable protected register access


    PieCtrlRegs.PIEIER4.bit.INTx1 = 1;      // Enable the PIE interrupt for eCAP1 (typically in PIE Group 4, INTx1)

 

    IER |= M_INT4;                        // Enable CPU interrupt group 4 (for eCAP interrupts)


    EINT;                                 // Globally enable interrupts

    ERTM;                                 // Enable real-time interrupts


    while(1)                              // Main loop: continuously run background tasks (if any)

    {

        // Currently empty because the processing is handled in the eCAP1 ISR.

    }

}


//------------------------------------------------------------------------------

// Function: Gpio_select

// Purpose:  Configure GPIO pins for PWM output and for eCAP input

//------------------------------------------------------------------------------

void Gpio_select(void)

{

    EALLOW;                               // Enable access to protected registers


    GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1;     // Set GPIO0 to function 1 (ePWM1A) for PWM output

    GpioCtrlRegs.GPAMUX1.bit.GPIO2 = 3;     // Set GPIO2 to function 3 (eCAP1) for sensor capture input


    EDIS;                                 // Disable access to protected registers

}


//------------------------------------------------------------------------------

// Function: Setup_ePWM1

// Purpose:  Configure ePWM1 to generate a PWM signal at 200 kHz with a constant 50% duty cycle

//------------------------------------------------------------------------------

void Setup_ePWM1(void)

{

    EALLOW;                               // Enable access to protected registers


    EPwm1Regs.TBCTL.bit.CTRMODE  = TB_COUNT_UP;  // Set ePWM1 time–base to up–count mode

    EPwm1Regs.TBCTL.bit.PHSEN    = TB_DISABLE;     // Disable phase loading (no external sync)

    EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;        // Set high-speed clock divider to 1 (no division)

    EPwm1Regs.TBCTL.bit.CLKDIV   = TB_DIV1;        // Set clock divider to 1 (no division)


    EPwm1Regs.TBPRD = INITIAL_TBPRD;      // Load the time–base period register with 750 (for 200 kHz PWM)


    EPwm1Regs.CMPA.half.CMPA = INITIAL_TBPRD / 2;  // Set compare value to 375 for 50% duty cycle


    EPwm1Regs.AQCTLA.bit.ZRO = AQ_SET;    // At counter zero (ZRO event), set the PWM output high

    EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR;  // When counter equals CMPA on the up–count (CAU event), clear the PWM output (go low)


    EDIS;                                 // Disable access to protected registers

}


//------------------------------------------------------------------------------

// Function: Setup_eCAP1

// Purpose:  Configure eCAP1 to capture rising and falling edges of the sensor pulse

//------------------------------------------------------------------------------

void Setup_eCAP1(void)

{

    EALLOW;                               // Enable access to protected registers


    ECAP1Regs.ECAPCTL.bit.CAPLDEN = 1;      // Enable shadow loading of capture registers for reliable latching

    ECAP1Regs.ECAPCTL.bit.CONT_ONESHT = 0;    // Set eCAP1 to continuous capture mode (not one-shot)

    ECAP1Regs.ECAPCTL.bit.CAP_APWM = 0;       // Ensure the module is in capture mode (not APWM mode)


    ECAP1Regs.ECAPCTL.bit.CAP1POL = 0;        // Set capture event 1 polarity to rising edge (signal goes high)

    ECAP1Regs.ECAPCTL.bit.CAP2POL = 1;        // Set capture event 2 polarity to falling edge (signal goes low)


    ECAP1Regs.ECCTL2.bit.TSCTRSTOP = 0;       // Stop the time–stamp counter (if running) to reset it

    ECAP1Regs.ECCTL2.bit.TSCTRSTOP = 1;       // Start the time–stamp counter


    ECAP1Regs.ECCTL2.bit.REARM = 1;           // Rearm the eCAP module to start a new capture sequence


    ECAP1Regs.ECEINT.bit.CEVT2 = 1;           // Enable interrupt for capture event 2 (falling edge event)


    ECAP1Regs.ECCLR.all = 0xFFFF;             // Clear any pending eCAP interrupts


    EDIS;                                 // Disable access to protected registers

}


//------------------------------------------------------------------------------

// Interrupt Service Routine: ecap1_isr

// Purpose:  Process the captured rising and falling edge timestamps,

//           calculate the pulse width and phase difference,

//           compute the new PWM frequency, and update ePWM1 accordingly.

//------------------------------------------------------------------------------

interrupt void ecap1_isr(void)

{

    Uint32 cap1, cap2, pulse_width;         // Variables to hold timestamps and pulse width in counts

    float phase_fraction, phase_deg;        // Variables to hold the fraction of the period and phase in degrees

    unsigned long updated_pwm_freq, new_TBPRD; // Variables to hold the updated PWM frequency and new TBPRD


    cap1 = ECAP1Regs.CAP1;                  // Read the timestamp for capture event 1 (rising edge)

    cap2 = ECAP1Regs.CAP2;                  // Read the timestamp for capture event 2 (falling edge)


    if(cap2 > cap1)                         // Check that the falling edge timestamp is greater than the rising edge timestamp

    {

        pulse_width = cap2 - cap1;          // Compute pulse width as the difference between falling and rising edge timestamps

    }

    else

    {

        pulse_width = 0;                    // If an error or rollover occurred, set pulse width to 0 (could add more handling here)

    }


    phase_fraction = (float)pulse_width / (float)EPwm1Regs.TBPRD;  // Calculate the fraction of the PWM period the sensor is high


    phase_deg = phase_fraction * 360.0;       // Convert the high time fraction into a phase difference in degrees


    updated_pwm_freq = INITIAL_PWM_FREQ + (unsigned long)(phase_deg * 1000.0);  // Compute new PWM frequency:

                                                                               // Base frequency (200 kHz) plus (phase in degrees * 1000)


    new_TBPRD = SYSCLK / updated_pwm_freq;    // Calculate the new PWM period (TBPRD) in counts: TBPRD = SYSCLK / updated_pwm_freq


    EPwm1Regs.TBPRD = new_TBPRD;              // Update ePWM1 TBPRD with the new period for the updated frequency

    EPwm1Regs.CMPA.half.CMPA = new_TBPRD / 2;   // Update compare value for a constant 50% duty cycle (half of new TBPRD)


    g_newPwmFreq = updated_pwm_freq;          // Store the new PWM frequency in a global variable for monitoring (optional)


    ECAP1Regs.ECCLR.all = 0xFFFF;             // Clear all eCAP interrupt flags by writing all ones

    ECAP1Regs.ECCTL2.bit.REARM = 1;           // Rearm the eCAP module to prepare for the next capture sequence


    PieCtrlRegs.PIEACK.all = PIEACK_GROUP4;   // Acknowledge the PIE interrupt for group 4 so that further interrupts are recognized

}


Part and Inventory Search

Back
Top