My board: TMS320F28027F
I am generating a signal through PWM and I want to measure the period and the duty cycle via capture. I also want to be able to communicate with my device via serial port. For this I have basically thrown together 2 of the examples from the controlSUITE with some modifications (Example_F2802xECap_Capture_Pwm and Example_F2802xSci_Echoback)...
I have 2 (possibly related) problems in my project:
1. I want to measure the signal continuously, without skipping edges (so for example starting at a falling edge, measuring at the rising edge and then measuring at the falling edge and restarting the measurement, without skipping the 2nd falling edge). Is it possible? If yes, what should I do to achieve that?
To solve this I tried all configurations for CAP_setStopWrap(), CAP_enableInt() and CAP_setCapContinuous()/CAP_setCapOneShot() that I thought made sense, with no luck (in the included code I get the data I need, but one period is always skipped).
2. When I set CAP_setStopWrap() and CAP_enableInt() to anything other than CAP_Stop_Wrap_CEVT4 and CAP_Int_Type_CEVT4 respectively, serial communication with the device doesn't work. But for my measurement I essentially only need 2 or 3 events, so setting it to 4 would be a waste. What is the problem here?
Here is my code:
#include "DSP28x_Project.h" // Device Headerfile and Examples Include File
#include "f2802x_common/include/clk.h"
#include "f2802x_common/include/flash.h"
#include "f2802x_common/include/gpio.h"
#include "f2802x_common/include/pie.h"
#include "f2802x_common/include/pll.h"
#include "f2802x_common/include/sci.h"
#include "f2802x_common/include/pwm.h"
#include "f2802x_common/include/cap.h"
//
#define EPWM3_TIMER_TBPRD 2000 // Period register
#define EPWM3_INIT_CMPA 0
#define EPWM3_INIT_CMPB 1950
// Prototype statements for functions for serial communication.
void scia_echoback_init(void);
void scia_fifo_init(void);
void scia_xmit(int a);
void scia_msg(char *msg);
// Prototype statements for functions for CAP/PWM.
__interrupt void ecap1_isr(void);
void InitECapture(void);
void InitEPwmTimer(void);
CLK_Handle myClk;
FLASH_Handle myFlash;
GPIO_Handle myGpio;
PIE_Handle myPie;
SCI_Handle mySci;
CAP_Handle myCap;
PWM_Handle myPwm;
// Global variables for CAP/PWM
uint32_t ECap1IntCount;
uint32_t CAP_DATA[] = {0,0,0,0};
void main(void)
{
uint16_t ReceivedChar;
CPU_Handle myCpu;
PLL_Handle myPll;
// Initialize all the handles needed for this application
myClk = CLK_init((void *)CLK_BASE_ADDR, sizeof(CLK_Obj));
myCpu = CPU_init((void *)NULL, sizeof(CPU_Obj));
myFlash = FLASH_init((void *)FLASH_BASE_ADDR, sizeof(FLASH_Obj));
myGpio = GPIO_init((void *)GPIO_BASE_ADDR, sizeof(GPIO_Obj));
myPie = PIE_init((void *)PIE_BASE_ADDR, sizeof(PIE_Obj));
myPll = PLL_init((void *)PLL_BASE_ADDR, sizeof(PLL_Obj));
mySci = SCI_init((void *)SCIA_BASE_ADDR, sizeof(SCI_Obj));
myPwm = PWM_init((void *)PWM_ePWM3_BASE_ADDR, sizeof(PWM_Obj));
myCap = CAP_init((void *)CAPA_BASE_ADDR, sizeof(CAP_Obj));
// Perform basic system initialization
CLK_enableAdcClock(myClk);
(*Device_cal)();
//Select the internal oscillator 1 as the clock source
CLK_setOscSrc(myClk, CLK_OscSrc_Internal);
// Setup the PLL for x10 /2 which will yield 50Mhz = 10Mhz * 10 / 2
PLL_setup(myPll, PLL_Multiplier_12, PLL_DivideSelect_ClkIn_by_2);
// Disable the PIE and all interrupts
PIE_disable(myPie);
PIE_disableAllInts(myPie);
CPU_disableGlobalInts(myCpu);
CPU_clearIntFlags(myCpu);
// If running from flash copy RAM only functions to RAM
#ifdef _FLASH
memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
#endif
// Initialize GPIO (Serial)
GPIO_setPullUp(myGpio, GPIO_Number_28, GPIO_PullUp_Enable);
GPIO_setPullUp(myGpio, GPIO_Number_29, GPIO_PullUp_Disable);
GPIO_setQualification(myGpio, GPIO_Number_28, GPIO_Qual_ASync);
GPIO_setMode(myGpio, GPIO_Number_28, GPIO_28_Mode_SCIRXDA);
GPIO_setMode(myGpio, GPIO_Number_29, GPIO_29_Mode_SCITXDA);
// Initialize GPIO (Capture/PWM)
GPIO_setPullUp(myGpio, GPIO_Number_4, GPIO_PullUp_Disable);
GPIO_setMode(myGpio, GPIO_Number_4, GPIO_4_Mode_EPWM3A);
GPIO_setPullUp(myGpio, GPIO_Number_5, GPIO_PullUp_Enable);
GPIO_setQualification(myGpio, GPIO_Number_5, GPIO_Qual_Sync);
GPIO_setMode(myGpio, GPIO_Number_5, GPIO_5_Mode_ECAP1);
// Setup a debug vector table and enable the PIE
PIE_setDebugIntVectorTable(myPie);
PIE_enable(myPie);
// Register interrupt handlers in the PIE vector table
PIE_registerPieIntHandler(myPie, PIE_GroupNumber_4, PIE_SubGroupNumber_1,
(intVec_t)&ecap1_isr);
// Setup peripherals for CAP/PWM
InitEPwmTimer();
InitECapture();
// Initialize counters:
ECap1IntCount = 0;
// Enable CPU INT4 which is connected to ECAP1-4 INT:
CPU_enableInt(myCpu, CPU_IntNumber_4);
// Enable eCAP INTn in the PIE: Group 3 interrupt 1-6
PIE_enableCaptureInt(myPie);
// Enable global Interrupts and higher priority real-time debug events:
CPU_enableGlobalInts(myCpu);
CPU_enableDebugInt(myCpu);
scia_echoback_init(); // Initialize SCI for echoback
scia_fifo_init(); // Initialize the SCI FIFO
for(;;)
{
// Wait for inc character
while(SCI_getRxFifoStatus(mySci) < SCI_FifoStatus_1_Word)
{
}
// Get character
ReceivedChar = SCI_getData(mySci);
if(ReceivedChar != '\r'){
scia_xmit(ReceivedChar);
}else{
scia_msg("\n\r");
}
//Here I decide what to do with the input.
}
}
// Test 1,SCIA DLB, 8-bit word, baud rate 0x000F, default, 1 STOP bit, no parity
void scia_echoback_init()
{
CLK_enableSciaClock(myClk);
// 1 stop bit, No loopback
// No parity,8 char bits,
// async mode, idle-line protocol
SCI_disableParity(mySci);
SCI_setNumStopBits(mySci, SCI_NumStopBits_One);
SCI_setCharLength(mySci, SCI_CharLength_8_Bits);
SCI_enableTx(mySci);
SCI_enableRx(mySci);
SCI_enableTxInt(mySci);
SCI_enableRxInt(mySci);
// SCI BRR = LSPCLK/(SCI BAUDx8) - 1
#if (CPU_FRQ_60MHZ)
SCI_setBaudRate(mySci, (SCI_BaudRate_e)194);
#elif (CPU_FRQ_50MHZ)
SCI_setBaudRate(mySci, (SCI_BaudRate_e)162);
#elif (CPU_FRQ_40MHZ)
SCI_setBaudRate(mySci, (SCI_BaudRate_e)129);
#endif
SCI_enable(mySci);
return;
}
// Transmit a character from the SCI
void scia_xmit(int a)
{
while(SCI_getTxFifoStatus(mySci) != SCI_FifoStatus_Empty)
{
}
SCI_putDataBlocking(mySci, a);
}
void scia_msg(char * msg)
{
int i;
i = 0;
while(msg[i] != '\0')
{
scia_xmit(msg[i]);
i++;
}
}
// Initialize the SCI FIFO
void scia_fifo_init()
{
SCI_enableFifoEnh(mySci);
SCI_resetTxFifo(mySci);
SCI_clearTxFifoInt(mySci);
SCI_resetChannels(mySci);
SCI_setTxFifoIntLevel(mySci, SCI_FifoLevel_Empty);
SCI_resetRxFifo(mySci);
SCI_clearRxFifoInt(mySci);
SCI_setRxFifoIntLevel(mySci, SCI_FifoLevel_4_Words);
return;
}
void InitEPwmTimer()
{
CLK_disableTbClockSync(myClk);
CLK_enablePwmClock(myClk, PWM_Number_3);
// Setup TBCLK
PWM_setCounterMode(myPwm, PWM_CounterMode_Up); // Count up
PWM_setPeriod(myPwm, EPWM3_TIMER_TBPRD); // Set timer period
PWM_disableCounterLoad(myPwm); // Disable phase loading
PWM_setPhase(myPwm, 0x0000); // Phase is 0
PWM_setCount(myPwm, 0x0000); // Clear counter
PWM_setHighSpeedClkDiv(myPwm, PWM_HspClkDiv_by_1); // Clock ratio to SYSCLKOUT
PWM_setClkDiv(myPwm, PWM_ClkDiv_by_1);
// Setup shadow register load on ZERO
PWM_setShadowMode_CmpA(myPwm, PWM_ShadowMode_Shadow);
PWM_setShadowMode_CmpB(myPwm, PWM_ShadowMode_Shadow);
PWM_setLoadMode_CmpA(myPwm, PWM_LoadMode_Zero);
PWM_setLoadMode_CmpB(myPwm, PWM_LoadMode_Zero);
// Set Compare values
PWM_setCmpA(myPwm, EPWM3_INIT_CMPA); // Set compare A value
PWM_setCmpB(myPwm, EPWM3_INIT_CMPB); // Set Compare B value
// Set Actions
PWM_setActionQual_CntUp_CmpA_PwmA(myPwm, PWM_ActionQual_Set); // Set PWM3A on event B, up count
PWM_setActionQual_CntUp_CmpB_PwmA(myPwm, PWM_ActionQual_Clear); // Clear PWM3A on event B, up count
PWM_setActionQual_Zero_PwmB(myPwm, PWM_ActionQual_Toggle); // Toggle EPWM3B on Zero
// Interrupt where we will change the Compare Values
PWM_setIntMode(myPwm, PWM_IntMode_CounterEqualZero); // Select INT on Zero event
PWM_enableInt(myPwm); // Enable INT
PWM_setIntPeriod(myPwm, PWM_IntPeriod_ThirdEvent); // Generate INT on 3rd event
CLK_enableTbClockSync(myClk);
}
void InitECapture()
{
CLK_enableEcap1Clock(myClk);
CAP_disableInt(myCap, CAP_Int_Type_All); // Disable all capture interrupts
CAP_clearInt(myCap, CAP_Int_Type_All); // Clear all CAP interrupt flags
CAP_disableCaptureLoad(myCap); // Disable CAP1-CAP4 register loads
CAP_disableTimestampCounter(myCap); // Make sure the counter is stopped
// Configure peripheral registers
//CAP_setCapOneShot(myCap); // One-shot
CAP_setCapContinuous(myCap);
CAP_setStopWrap(myCap, CAP_Stop_Wrap_CEVT3);// Stop at _ events
CAP_setCapEvtPolarity(myCap, CAP_Event_1, CAP_Polarity_Falling); // Falling edge
CAP_setCapEvtPolarity(myCap, CAP_Event_2, CAP_Polarity_Rising); // Rising edge
CAP_setCapEvtPolarity(myCap, CAP_Event_3, CAP_Polarity_Falling); // Falling edge
//CAP_setCapEvtPolarity(myCap, CAP_Event_4, CAP_Polarity_Rising); // Rising edge
CAP_setCapEvtReset(myCap, CAP_Event_1, CAP_Reset_Enable); // Difference operation
CAP_setCapEvtReset(myCap, CAP_Event_2, CAP_Reset_Enable); // Difference operation
CAP_setCapEvtReset(myCap, CAP_Event_3, CAP_Reset_Enable); // Difference operation
//CAP_setCapEvtReset(myCap, CAP_Event_4, CAP_Reset_Enable); // Difference operation
CAP_enableSyncIn(myCap); // Enable sync in
CAP_setSyncOut(myCap, CAP_SyncOut_SyncIn); // Pass through
CAP_enableCaptureLoad(myCap);
CAP_enableTimestampCounter(myCap); // Start Counter
CAP_rearm(myCap); // arm one-shot
CAP_enableCaptureLoad(myCap); // Enable CAP1-CAP4 register loads
CAP_enableInt(myCap, CAP_Int_Type_CEVT3); // _ events = interrupt
}
__interrupt void ecap1_isr(void)
{
CAP_DATA[0] = CAP_getCap1(myCap);
CAP_DATA[1] = CAP_getCap2(myCap);
CAP_DATA[2] = CAP_getCap3(myCap);
CAP_DATA[3] = CAP_getCap4(myCap);
ECap1IntCount++;
CAP_clearInt(myCap, CAP_Int_Type_CEVT4);
CAP_clearInt(myCap, CAP_Int_Type_Global);
CAP_rearm(myCap);
// Acknowledge this interrupt to receive more interrupts from group 4
PIE_clearInt(myPie, PIE_GroupNumber_4);
}