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/TMS320F28027: Using ECap feature for time measurement between two transistions

Part Number: TMS320F28027
Other Parts Discussed in Thread: CONTROLSUITE

Tool/software: Code Composer Studio

Hello,

I want to decode differential manchester code at 125kHz. So I need an interuppt every time a transition low/high or high/low occurs and the time difference to the last transition.

For testing purposes I modified the Example_2802xECap_Capture_Pwm.c a little bit, but it just gives me random numbers independent of the input signal. (Tested with my actual signal and a function generator)

I hope you can give me a hint what I have to change in the code.

//###########################################################################
//
// FILE:    Example_2802xECap_Capture_Pwm.c
//
// TITLE:   Capture EPwm3.
//
// ASSUMPTIONS:
//
//    This program requires the f2802x header files.
//
//    Make the following external connection:
//    EPWM3 on GPIO4 should be connected to ECAP1 on GPIO5.
//
//    As supplied, this project is configured for "boot to SARAM"
//    operation.  The 2802x Boot Mode table is shown below.
//    For information on configuring the boot mode of an eZdsp,
//    please refer to the documentation included with the eZdsp,
//
//    $Boot_Table
//    While an emulator is connected to your device, the TRSTn pin = 1,
//    which sets the device into EMU_BOOT boot mode. In this mode, the
//    peripheral boot modes are as follows:
//
//      Boot Mode:   EMU_KEY        EMU_BMODE
//                   (0xD00)	     (0xD01)
//      ---------------------------------------
//      Wait		 !=0x55AA        X
//      I/O		     0x55AA	         0x0000
//      SCI		     0x55AA	         0x0001
//      Wait 	     0x55AA	         0x0002
//      Get_Mode	 0x55AA	         0x0003
//      SPI		     0x55AA	         0x0004
//      I2C		     0x55AA	         0x0005
//      OTP		     0x55AA	         0x0006
//      Wait		 0x55AA	         0x0007
//      Wait		 0x55AA	         0x0008
//      SARAM		 0x55AA	         0x000A	  <-- "Boot to SARAM"
//      Flash		 0x55AA	         0x000B
//	    Wait		 0x55AA          Other
//
//   Write EMU_KEY to 0xD00 and EMU_BMODE to 0xD01 via the debugger
//   according to the Boot Mode Table above. Build/Load project,
//   Reset the device, and Run example
//
//   $End_Boot_Table
//
//
//
// DESCRIPTION:
//
//    This example configures EPWM3A for:
//    - Up count
//    - Period starts at 2 and goes up to 1000
//    - Toggle output on PRD
//
//    eCAP1 is configured to capture the time between rising
//    and falling edge of the PWM3A output.
//
//###########################################################################
// $TI Release: F2802x Support Library v230 $
// $Release Date: Fri May  8 07:43:05 CDT 2015 $
// $Copyright: Copyright (C) 2008-2015 Texas Instruments Incorporated -
//             http://www.ti.com/ ALL RIGHTS RESERVED $
//###########################################################################

#include "DSP28x_Project.h"     // Device Headerfile and Examples Include File

// Configure the start/end period for the timer
#define PWM3_TIMER_MIN     10
#define PWM3_TIMER_MAX     8000

// Prototype statements for functions found within this file.
__interrupt void ecap1_isr(void);
void InitECapture(void);
void InitEPwmTimer(void);
void Fail(void);

// Global variables used in this example
uint32_t  ECap1IntCount;
uint32_t  ECap1PassCount;
uint32_t  EPwm3TimerDirection;

uint32_t    DutyOnTime1;
uint32_t    DutyOffTime1;
uint32_t    DutyOnTime2;
uint32_t    DutyOffTime2;
uint32_t    Period1;
uint32_t    Period2;


// To keep track of which way the timer value is moving
#define EPwm_TIMER_UP   1
#define EPwm_TIMER_DOWN 0



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
   InitEPwm3Gpio();
   InitECap1Gpio();

// 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();

// Interrupts that are used in this example are re-mapped to
// ISR functions found within this file.
   EALLOW;  // This is needed to write to EALLOW protected registers
   PieVectTable.ECAP1_INT = &ecap1_isr;
   EDIS;    // This is needed to disable write to EALLOW protected registers

// Step 4. Initialize all the Device Peripherals:
   InitEPwmTimer();    // For this example, only initialize the EPwm Timers
   InitECapture();

// Step 5. User specific code, enable interrupts:

// Initialize counters:
   ECap1IntCount = 0;
   ECap1PassCount = 0;

// Enable CPU INT4 which is connected to ECAP1-4 INT:
   IER |= M_INT4;

// Enable eCAP INTn in the PIE: Group 3 interrupt 1-6
   PieCtrlRegs.PIEIER4.bit.INTx1 = 1;

// Enable global Interrupts and higher priority real-time debug events:
   EINT;   // Enable Global interrupt INTM
   ERTM;   // Enable Global realtime interrupt DBGM



// Step 6. IDLE loop. Just sit and loop forever (optional):
   for(;;)
   {

   }
}

void InitEPwmTimer()
{
   EALLOW;
   SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0;
   EDIS;

   EPwm3Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // Count up
   EPwm3Regs.TBPRD = PWM3_TIMER_MIN;
   EPwm3Regs.TBPHS.all = 0x00000000;
   EPwm3Regs.AQCTLA.bit.PRD = AQ_TOGGLE;      // Toggle on PRD

   // TBCLK = SYSCLKOUT
   EPwm3Regs.TBCTL.bit.HSPCLKDIV = 1;
   EPwm3Regs.TBCTL.bit.CLKDIV = 0;

   EPwm3TimerDirection = EPwm_TIMER_UP;

   EALLOW;
   SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1;
   EDIS;
}

void InitECapture()
{
   ECap1Regs.ECEINT.all = 0x0000;             // Disable all capture interrupts
   ECap1Regs.ECCLR.all = 0xFFFF;              // Clear all CAP interrupt flags
   ECap1Regs.ECCTL1.bit.CAPLDEN = 0;          // Disable CAP1-CAP4 register loads
   ECap1Regs.ECCTL2.bit.TSCTRSTOP = 0;        // Make sure the counter is stopped

   // Configure peripheral registers
   ECap1Regs.ECCTL2.bit.CONT_ONESHT = 0;      // Continious Mode
   ECap1Regs.ECCTL2.bit.STOP_WRAP = 3;        // Stop at 4 events
   ECap1Regs.ECCTL1.bit.CAP1POL = 0;          // Rising edge
   ECap1Regs.ECCTL1.bit.CAP2POL = 1;          // Falling edge
   ECap1Regs.ECCTL1.bit.CAP3POL = 0;          // Rising edge
   ECap1Regs.ECCTL1.bit.CAP4POL = 1;          // Falling edge
   ECap1Regs.ECCTL1.bit.CTRRST1 = 1;          // Difference operation
   ECap1Regs.ECCTL1.bit.CTRRST2 = 1;          // Difference operation
   ECap1Regs.ECCTL1.bit.CTRRST3 = 1;          // Difference operation
   ECap1Regs.ECCTL1.bit.CTRRST4 = 1;          // Difference operation
   ECap1Regs.ECCTL2.bit.SYNCI_EN = 0;         // Disable sync in
   ECap1Regs.ECCTL2.bit.SYNCO_SEL = 3;        // Disable
   ECap1Regs.ECCTL1.bit.PRESCALE = 0;         // Prescale = 1 /Disable

   ECap1Regs.ECCTL1.bit.CAPLDEN = 1;          // Enable capture units
   ECap1Regs.ECCTL2.bit.TSCTRSTOP = 1;        // Start Counter
   ECap1Regs.ECEINT.bit.CEVT4 = 1;            // 4 events = interrupt




}

__interrupt void ecap1_isr(void)
{
   DutyOnTime1 = ECap1Regs.CAP2; // Fetch Time-Stamp captured at T2
   DutyOffTime1 = ECap1Regs.CAP3; // Fetch Time-Stamp captured at T3
   DutyOnTime2 = ECap1Regs.CAP4; // Fetch Time-Stamp captured at T4
   DutyOffTime2 = ECap1Regs.CAP1; // Fetch Time-Stamp captured at T1
   Period1 = DutyOnTime1 + DutyOffTime1;
   Period2 = DutyOnTime2 + DutyOffTime2;






   __asm("          NOP");



   ECap1Regs.ECCLR.bit.INT = 1;


   // Acknowledge this interrupt to receive more interrupts from group 4
   PieCtrlRegs.PIEACK.all = PIEACK_GROUP4;



}




//===========================================================================
// No more.
//===========================================================================

  • David,

    I don't see anything obviously wrong with your code. I would recommend starting again with the ControlSuite example and make small incremental changes, testing the code between each change. You should notice what you did wrong when making the incremental changes.

    Be sure to post what you find out, It may help someone in the future!

    If you find out which statement is causing your issues I can help you debug from there.

    Regards,
    Cody

  • Thank you Cody,

    the mistake was not in the code. It was how i read the values. If i used a breakpoint or serial print at the end of the interrupt I just got random values. What works for me now is setting a breakpoint, deleting it and when I hit resume I get the right values.

    What also works is a breakpoint or serial print every time a full data package is received. (I just pass the 4 time differences one by one to a decode routine)

    Regards,
    David

  • Thanks for the update David!

    Feel free to start another thread if you have more questions.

    Regards,
    Cody