Part Number: TMS320F28335
Tool/software: Code Composer Studio
Hello,
I shall be glad if anyone can help me with 3 important questions.
1. From f28335 ADC manual it says that "ADCCLK clock provides the time base for internal process pipeline of ADC". Let's say, I set the ADCCLK as 10MHz and I am also using EPWM_SOC_A to trigger adc conversion. If the epwm is at 500kHz, does that mean my adc conversion is done every 500kHz? (plus: socasel on first event; and socasel on ctr = 0).
2. Is it possible to generate both ISR and SOC from a single epwm module? The material supports this but I'd like to be sure.
3. Incorrect timer0 interrupt count: For clarity and easy assistance I have attached the code I am using below. The code basically uses analogue voltage to control epwm duty cycle. It works. But the major problem I have is with the timers. I am using timer0 and timer1. Timer0 interrupts every 0.4microsecond while timer1 interrupts every 4673microseconds. My expectation is that by the time timer1 interrupts, timer0 would have interrupted about 11682 times. However; this is not so. I get around 7000 counts. In my quest to debug the problem, I discovered that
EPwm4Regs.ETPS.bit.SOCAPRD = 1; and EPwm4Regs.ETSEL.bit.INTEN = 1;
may be the major culprits. When I comment them out, the adc conversion obviously doesn't work anymore but the counter works better as it gives 11488 instead of 11682 (there is still obviously some error here, the reason for this is unclear to me). SOCAPRD and INTEN seems to have messed up the counter. Unfortunately, I cant do without them.
I have searched for days on how to solve it to no avail.
Please assist.
#include "DSP28x_Project.h" // Device Headerfile and Examples Include File
#include "DCL.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
// Prototype statements for functions found within this file.
__interrupt void adc_isr(void);
__interrupt void epwm_isr(void);
__interrupt void cpu_timer0_isr(void);
__interrupt void cpu_timer1_isr(void);
extern void ConfigCpuTimer(struct CPUTIMER_VARS *, float, float);
void Gpio_select(void);
void Setup_EPWM4A(void);
void Setup_Adc(void);
// Global variables used in this example:
float timerIndex, period;
Uint16 LoopCount;
Uint16 Voltage1[10];
volatile float fdb, fdb1, dutycalc;
main()
{
// Step 1. Initialize System Control: // PLL, WatchDog, enable Peripheral Clocks
// This example function is found in the DSP2833x_SysCtrl.c file.
InitSysCtrl();
EALLOW;
SysCtrlRegs.WDCR= 0x00AF; // Re-enable the watchdog
EDIS; // 0x00AF to NOT disable the Watchdog, Prescaler = 64
EALLOW;
#if (CPU_FRQ_150MHZ) // Default - 150 MHz SYSCLKOUT
#define ADC_MODCLK 0x3 // HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 150/(2*3) = 25.0 MHz
#endif
#if (CPU_FRQ_100MHZ)
#define ADC_MODCLK 0x2 // HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 100/(2*2) = 25.0 MHz
#endif
EDIS;
// Define ADCCLK clock frequency ( less than or equal to 25 MHz )
// Assuming InitSysCtrl() has set SYSCLKOUT to 150 MHz
EALLOW;
SysCtrlRegs.HISPCP.all = ADC_MODCLK;
EDIS;
// Step 2. Initialize GPIO:
// This example function is found in the DSP2833x_Gpio.c file and
// illustrates how to set the GPIO to it's default state.
// InitGpio(); // Skipped for this example
Gpio_select();
// 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 DSP2833x_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 DSP2833x_DefaultIsr.c.
// This function is found in DSP2833x_PieVect.c.
InitPieVectTable(); //initialize the pie vector tabe to default ESTOPO isr's
// 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 register
PieVectTable.TINT0 = &cpu_timer0_isr; //point PIE vector table to bespoke CpuTimer0 ISR
PieVectTable.XINT13 = &cpu_timer1_isr; //point PIE vector table to bespoke CpuTimer1 ISR
PieVectTable.ADCINT = &adc_isr; //point PIE vector table to bespoke ADC ISR
PieVectTable.EPWM4_INT = &epwm_isr; //point PIE vector table to bespoke EPWM ISR
EDIS; // This is needed to disable write to EALLOW protected registers
// Step 4. Initialize all the Device Peripherals:
// This function is found in DSP2833x_InitPeripherals.c
// InitPeripherals(); // Not required for this example
InitAdc(); // For this example, init the ADC
Setup_Adc();
//InitEPwm();
Setup_EPWM4A(); //closed loop controlled
InitCpuTimers(); // basic setup CPU Timer0, 1 and 2
ConfigCpuTimer(&CpuTimer0, 150, 0.4);
ConfigCpuTimer(&CpuTimer1, 150, 1000000/214); //4.672897196milliseconds
CpuTimer0Regs.TCR.all = 0x4000; // Use write-only instruction to set TSS bit = 0
CpuTimer1Regs.TCR.all = 0x4000; // Use write-only instruction to set TSS bit = 0
// Step 5. User specific code, enable interrupts:
// Enable ADCINT in PIE
PieCtrlRegs.PIEIER1.bit.INTx7 = 1; //enable tint0 iterrupt in peripheral interrupt expansion table in row 1
PieCtrlRegs.PIEIER1.bit.INTx6 = 1; //enable adcint iterrupt in peripheral interrupt expansion table in row 1
PieCtrlRegs.PIEIER3.bit.INTx4 = 1; //enable epwmISR iterrupt in peripheral interrupt expansion table in row 3
IER |= 0x1005; // Enable CPU Interrupt 1 and 3 and 13
EINT; // Enable Global interrupt INTM
ERTM; // Enable Global realtime interrupt DBGM
LoopCount = 0; timerIndex = 0.0; //initialize dummy loop count
// Assumes ePWM1 clock is already enabled in InitSysCtrl();
// Wait for ADC interrupt
for(;;)
{
EALLOW;
SysCtrlRegs.WDKEY = 0x55; //service watchdog #1
SysCtrlRegs.WDKEY = 0xAA;
EDIS;
LoopCount++; //dummy loop count
if (CpuTimer1.InterruptCount>9){CpuTimer1.InterruptCount = 0;} //clear timer1 dummy count after 10
}
}
void Gpio_select(void)
{
EALLOW;
GpioCtrlRegs.GPAMUX1.all = 0; // GPIO15 ... GPIO0 = General Puropse I/O
GpioCtrlRegs.GPAMUX1.bit.GPIO6 = 1; // Enable epwm on GPIO0 (EPWM4A)
GpioCtrlRegs.GPAMUX2.all = 0; // GPIO31 ... GPIO16 = General Purpose I/O
GpioCtrlRegs.GPBMUX1.all = 0; // GPIO47 ... GPIO32 = General Purpose I/O
GpioCtrlRegs.GPBMUX2.all = 0; // GPIO63 ... GPIO48 = General Purpose I/O
GpioCtrlRegs.GPCMUX1.all = 0; // GPIO79 ... GPIO64 = General Purpose I/O
GpioCtrlRegs.GPCMUX2.all = 0; // GPIO87 ... GPIO80 = General Purpose I/O
GpioCtrlRegs.GPAPUD.bit.GPIO6 = 0; // Enable pull-up on GPIO6 (EPWM4A)
GpioCtrlRegs.GPADIR.all = 0xFFFFFFFF; //floating outputs to prevent linear bias of selected pins *prevent possible overcurrent
GpioCtrlRegs.GPADIR.bit.GPIO6 = 1; // peripheral explorer: Configure GPIO6 as output
GpioCtrlRegs.GPBDIR.all = 0xFFFFFFFF; // GPIO32-63 as floating outputs to prevent linear bias of selected pins *prevent possible overcurrent
GpioCtrlRegs.GPCDIR.all = 0xFFFFFFFF; // GPIO87-64 as floating outputs to prevent linear bias of selected pins *prevent possible overcurrent
EDIS;
}
__interrupt void cpu_timer1_isr(void) //interrupt generated per period (1/214 seconds)
{
//timerIndex = 0; //force synchronism but we lose 7 cycles because cpuTimer1 starts 7 cycles after cpuTimer0
CpuTimer1.InterruptCount++;
//CpuTimer1Regs.TCR.bit.TRB = 1; //reload timers 1 period register
//CpuTimer0Regs.TCR.bit.TRB = 1; //ensure timers 0 period register has been reloaded *it doesn't belong to PIE so no acknowledgement necessary
}
__interrupt void cpu_timer0_isr(void) //interrupt generated at every (1/214/600 seconds)
{
timerIndex++;
CpuTimer0.InterruptCount++; //this procedure is akin to multiplying each the output current by each channel's duty cycle
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // Acknowledge interrupt to PIE to allow for subsequent interrupt
}
__interrupt void adc_isr(void)
{
fdb1 = AdcRegs.ADCRESULT0 >>4; //raw feedback signal
dutycalc = (3*fdb1)/10/4096; //divide by 10 because input was multiplied by 10
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;
}
__interrupt void epwm_isr(void)
{
EPwm4Regs.CMPA.half.CMPA = dutycalc*EPwm4Regs.TBPRD;
EPwm4Regs.ETCLR.bit.INT = 1; //Clear INT SEQ1 bit
PieCtrlRegs.PIEACK.all = PIEACK_GROUP3; //Acknowledge interrupt to PIE
return;
}
void Setup_Adc(void)
{
AdcRegs.ADCMAXCONV.all = 0; // Setup 1 conv's on SEQ1 ie number of conversion - 1
AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0; // Setup ADCINA1 as 2nd SEQ1 conv. //FEEDBACK
AdcRegs.ADCTRL1.bit.CONT_RUN = 1; //Start all over again at the end of the 1st conversion w/o waiting for another trigger input signal
AdcRegs.ADCTRL1.bit.SEQ_CASC = 1; //Cascaded mode
AdcRegs.ADCTRL1.bit.ACQ_PS = 10; //time between multiplexer switch and freezing of samples
AdcRegs.ADCTRL1.bit.CPS = 0; //ADCCLK = FCLK/CPS+1 = FCLK = 2.5MHz
AdcRegs.ADCTRL2.bit.EPWM_SOCA_SEQ1 = 1; // Enable SOCA from ePWM to start SEQ1
AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 1; // Enable SEQ1 interrupt
AdcRegs.ADCTRL2.bit.INT_MOD_SEQ1 = 0; // Enable SEQ1 interrupt every EOS
AdcRegs.ADCTRL3.bit.SMODE_SEL = 0; //SEQUENTIAL SAMPLING
AdcRegs.ADCTRL3.bit.ADCCLKPS = 5; //FCLK = HSPCLK/2*ADCCLKPS = 25/10 = 2.5MHz
}
void Setup_EPWM4A(void)
{
EPwm4Regs.TBCTL.bit.CLKDIV = 0; //SysClkOut/1 ie default
EPwm4Regs.TBCTL.bit.HSPCLKDIV = 0; //SysClkOut/1 but /2 is default //TBCLK = SysClkOut = 150MHz //this is done to avoid scaling in MEP
EPwm4Regs.TBCTL.bit.CTRMODE = 0; //UP COUNT
EPwm4Regs.TBCTL.bit.PRDLD = 0; //TBPRD period shadow, load on ctr = 0
EPwm4Regs.TBPRD = 4989/11; //4989/11 = 330kHz //7499 = 20kHz
EPwm4Regs.CMPA.half.CMPA = 0; //initial CMPA = 0
EPwm4Regs.CMPCTL.bit.LOADAMODE = 0;
EPwm4Regs.CMPCTL.bit.SHDWAMODE = 0;
EPwm4Regs.AQCTLA.all = 0x0012; //ctr = 0 (set), ctr = cmpa on up count (clear)
EPwm4Regs.ETSEL.bit.SOCAEN = 1; //Enable SOC on A group
EPwm4Regs.ETSEL.bit.SOCASEL = 1; //Select SOC from CTR=0
EPwm4Regs.ETPS.bit.SOCAPRD = 1; //Generate pulse on 1st event
EPwm4Regs.ETSEL.bit.INTEN = 1; //enable pwm interrupt
EPwm4Regs.ETSEL.bit.INTSEL = 1; //enable interrupt on ctr = 0
EPwm4Regs.ETPS.bit.INTPRD = 1; //interrupt on 1st event
}
By the way, I am using ezdspf28335.
Thanks.
David.
