ohad0262
Junior Member level 2

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.
The goal is to:

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
}
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:
- Accurately measure the pulse width of the XOR output (which represents the phase difference between two square waves).
- 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:



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
}
Last edited: