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/TMS320F28335: Incorrect timer0 count and ADC start of conversion

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.

  • Hi David,

    (1)The ADCCLK determines how long an ADC conversion takes from trigger to output. If you trigger the ADC at 500KHz your ADC will do a conversion every 1/500kHz and the ADC ISR will also occur at 500KHz, if enabled. The only time this isn't true is if the time to complete all the triggered conversions takes longer than 1/500kHz. This could happen based on some combination of ADCCLK being rather slow, ACQ_PS being large, and the trigger initiating lots of conversions.

    (2) Yeah, you can get both an ISR and ADC trigger from the same ePWM compare event. Usually when this occurs you would choose to not have an ADC ISR since both ePWM and ADC ISR occur at the same frequency.

    (3) The controller is running at 150MHz, so each CPU cycle is 6.667ns. Your CPU ISR occurs every 400ns or every 60 cycles. Context switch to enter or exiting the ISR takes approximately 14 cycles and it probably takes ~10 cycles to run the ISR so this consumes 14+14+10 / 60 = 63% of the CPU bandwidth.

    The ADC and ePWM are each occurring once every ~453 cycles. They each take 14+14 cycles for context switch and the ePWM ISR is probably 10 cycles while the ADC ISR is maybe 20 cycles. This gives 86 cycles, which is longer than the CPU timer period, so you are definitely going to miss some CPU timer ISRs. This also consumes about 86/453 = 19% of available CPU bandwidth.

    Based on this really rough approximation, you are using about 82% of the CPU bandwidth. You can get a better estimate by measuring the execution time of the ISRs using the profiling tool in CCS.

    processors.wiki.ti.com/.../Interrupt_FAQ_for_C2000
  • Thanks Devin, I appreciate your response.

    I am very clear with point 1.

    About point 2, if I got you correctly, instead of having both adc and epwm ISR, it is advisable to have just the epwm ISR as it consumes less cycles. Am I correct? I am using the adc ISR for just extracting adc values and implementing control law, will the epwm ISR be sufficient for this? Just to confirm. 

    About point 3, I understand there will be some interrupt latency but what I am getting is way beyond mere latency. What I discovered was that the SOCAPRD and INTEN seem to be causing unbelievable lag. Without them, I get expected latency i.e 11488 counts instead of 11682 but with those two commands I get around 7000 instead of 11682. That is my MAJOR problem. Is my PWM subroutine incorrect? what do you think caused this and how can I remedy it?

    Additionally, will I be able to use the profiling tool to generate counts for my control law because that's basically what I am using timer0 ISR for. Can you please refer me to the necessary material that will guide me on how implement this.

    Hope to hear from you soon.

    Kind regards.

    David.

  • David Bamgboje said:
    About point 2, if I got you correctly, instead of having both adc and epwm ISR, it is advisable to have just the epwm ISR as it consumes less cycles. Am I correct? I am using the adc ISR for just extracting adc values and implementing control law, will the epwm ISR be sufficient for this? Just to confirm.

    Each ISR will require a similar number of overhead cycles, but both the EPWM and ADC ISRs will trigger very close to each other (based on your current configuration) so you may as well disable one interrupt and combine the contents of both ISRs into the remaining one.

    The advantage of using only the EPWM ISR is that you can update the EPWM registers while the ADC is still converting, which is more cycle-efficient. However, you will need to make sure that the ADC is given sufficient time to convert its signal before reading the ADCRESULT registers.

    On the other hand, using only the ADC ISR will help to ensure that ADCRESULT is ready by the time you enter the ISR. This is easier to implement, but is less cycle-efficient.

    David Bamgboje said:
    About point 3, I understand there will be some interrupt latency but what I am getting is way beyond mere latency. What I discovered was that the SOCAPRD and INTEN seem to be causing unbelievable lag. Without them, I get expected latency i.e 11488 counts instead of 11682 but with those two commands I get around 7000 instead of 11682. That is my MAJOR problem. Is my PWM subroutine incorrect? what do you think caused this and how can I remedy it?

    How are you measuring the cycle count latency?

    One simple approach is to simply read back the EPWM TBCTR value from within your EPWM ISR. You configured the EPWM to interrupt when TBCTR=0 so whatever value is in TBCTR when you read it back from the ISR is the amount of overhead latency.

    Another approach is to declare an array of 32b Timer reads for profiling and record timer values inside of your ISR. You can then read back the time stamps to find out how much time elapsed between ISR executions.

    David Bamgboje said:
    Additionally, will I be able to use the profiling tool to generate counts for my control law because that's basically what I am using timer0 ISR for. Can you please refer me to the necessary material that will guide me on how implement this.

    This might help with getting started for CCS profiling: 

  • Thanks Tommy. I appreciate your response.

    1. Previously I thought the latency will be responsible for the difference between the gotten timer0 interrupt count and the expected count. For this particular case, timer0 is expected to trigger every 0.4microsecond while timer1 is expected to trigger every 4673microsecond so I expected timer0 interrupt count to be about 11682 when timer1 interrupt count is 1.

    2. I took your advice and I have started using the profiler clock. I used the epwm TBCTR and when the isr was triggered, It already had 36 counts. And when timer0 interrupt is triggered, to TBCTR  is 335. I found this fishy because the pwm was designed to have a TBPRD of 454; so, I think by the time the interrupt is triggered, a full period of the pwm should have elapsed (ie 454 counts).

    3. About using a single isr, I totally agree with your advise. it makes more sense. And to ensure the adc has enough time to complete its conversion, my ADCCLK is about 240ns, sampling window is 1920ns (ACQPS is 7) and each adc conversion is done every 3030ns.

    4. Sorry to take you deeper, but I feel I had better explained the genesis of the whole problem if I want to make good progress. So, it goes thus: ab initio I divided my pwm (about 200hz) into 3 with each portion having different control laws (actually it's the same control law but different parameters). I did the division by using the timer0 interrupt count. The interrupt triggers every 3030ns so I am expecting about 1542 counts for each period of the pwm. The partitioning was successful but I discovered that the partitioned pulse was rolling on the oscilloscope, with respected to the original pulse that was partitioned. This led me into blaming interrupt latency for the sync problem. With the explanation I have gotten so far, I figured the timers would not even be necessary and for better sync, I am now doing my counting/partitioning in my epwm isr; however, I am still facing the same rolling pulse problem. This is why I scaled down the whole thing to just pwms in order to see what the latency is like. I still don't know how to overcome the obstacle.

    Kindly advise me on these issues.

    Kind regards.

    David.

  • David Bamgboje said:
    1. Previously I thought the latency will be responsible for the difference between the gotten timer0 interrupt count and the expected count. For this particular case, timer0 is expected to trigger every 0.4microsecond while timer1 is expected to trigger every 4673microsecond so I expected timer0 interrupt count to be about 11682 when timer1 interrupt count is 1.

    2. I took your advice and I have started using the profiler clock. I used the epwm TBCTR and when the isr was triggered, It already had 36 counts. And when timer0 interrupt is triggered, to TBCTR  is 335. I found this fishy because the pwm was designed to have a TBPRD of 454; so, I think by the time the interrupt is triggered, a full period of the pwm should have elapsed (ie 454 counts).

    What if you disable the timer interrupts for now?  An interrupt every 400ns is very burdensome on the CPU -- one interrupt for every 60 cycles at 150MHz!

    I recommend that you resolve the interrupt latency issue before proceeding any further.

  • Thanks.

    I have done exactly what you said, I have disabled the timers completely and I am seeing good improvement. Now when the epwm isr is triggered, the TBCTR is 16.

    What do you think?

    Kind regards.

    David.
  • David,

    This looks much better. I suspect that you were losing synchronization because the timer interrupts were consuming most of your CPU cycles and delaying the EPWM interrupt response times. Toggling GPIO pins in your ISR is a good non-intrusive way to confirm your control sequence on the scope.

    Can you elaborate on why you need to partition the EPWM cycles? Would it be easier to use multiple coherent EPWMs in parallel?

    -Tommy
  • Thanks.
    I using 4 synchronized pwms. The 1st 3 are at the same low freq but they are HIGH at different times (i.e they are phase shifted such that when one is high the other 2 are low. The 4th, the main pwm which is feedback controlled is at 330khz, it is designed to be only operational when any of the 1st 3 are high, otherwise it is low. I have attached a figure to further explain what I mean.

    So my main issue is, the green pulses are always rotating instead of staying fixed with respect to the 1st 3 pwms. After all, I am only counting each epwm isr (which occurs at 330khz) and using that to partition the pulse. The unexpected rotation messes up the whole control process.

    What do you think about this challenge?

    David.

  • David,

    Is the main EPWM only generating an output waveform at 330kHz or is it needing to make calculations as well?

    -Tommy

  • Hello Tommy,

    The main epwm (@ 330k) is the one with the isr, other pwms are constant. So it is the one with the closed loop duty cycle control. The only major difference from normal duty cycle closed loop control of dc converters is that when the other pwms are off, it doesn't function.

    David.

  • David,

    How are you determining the active state of the three slower EPWMs during execution?

    Is it possible that it is drifting because the TBPRD ratios between the EPWMs is not a whole number? For example, I see this assignment for TBPRD:

    EPwm4Regs.TBPRD = 4989/11;

    That result is 453.55. I can see where the rounding error would produce a continuous drift.

    If this is the case, you might be able to take a couple of approaches like updating the TBPRD between 453 and 454 on alternating cycles, or you could periodically SYNC the EPWMs to realign the counters.

    -Tommy
  • About active states, since I know when each state will be on, I simply divided the larger period (210hz) by the smaller period (330khz) to get the total number of counts between them. I then increment an integer when each (330khz) ISR is triggered, that way I specify the active states by defining the range for the number of counts.

    On the other hand, i'll simply try to avoid the round off by using 454 and see if the shift is removed.

    Let me know what you think.

    Thanks.

    David.
  • David,

    Using a set 454 will probably not work either. The problem that I see is that the TBPRD ratios are not whole numbers. The fractional errors will produce drift.

    For example, from your original code snippet:
    (7499+1) / (453+1) = 16.52

    Changing to 454 would still produce a bad result:
    (7499+1) / (454+1) = 16.48

    I was advocating a dynamic TBPRD that changes between 453 and 454 between cycles so that you can keep the counters aligned across multiple cycles. This approach would take some effort to figure out.

    If you have flexible frequencies, a fixed whole ratio like (7499+1) and (499+1) should work better.

    If your frequencies are not flexible but you can tolerate some latency, you might be able to use a 3-input OR-gate on the EPWM1-3 outputs and feed the OR'd signal back into a CBC TZ trip signal for EPWM4. This way, you can leave the EPWM4 output always enabled and the OR-gate will disable (trip) the output when EPWM1-3 are all low.

    -Tommy
  • Thanks for your response.

    I thank God, the drift problem has been resolved. Surprisingly, the 453 worked. I rounded 4989/11 to 453 and 4687393/107 to 43807, now I am getting about 330.6K and 214 resp. I was only trying to ensure more accuracy, I never knew I was introducing drift. I have never seen/read about such a problem before, pls, how is the approx. causing the drift? I would like to understand why.

    Thanks again.

    David.
  • David,

    This sounds more like a potential compilation issue.  Do you get different results from setting the TBPRD using these two approaches:

    • TBPRD = 4687393 / 107;
    • TBPRD = (Uint32)4687393 / 107;

    -Tommy

  • Hello Tommy,

    I just tried using the two TBPRD formats you mentioned and there was no drift. I tried inspecting all other formats in the code and I think the increment I am doing in the epwm ISR is the origin.

    if (timerIndex < (165000/107)/*(350464/227)*/-1) {timerIndex++;}		//since a period has been broken into (1/214)/(1/330000) sections
    else {timerIndex = 0;}

    This is what I think:

    When I used 453 and 43807 the other time I think I considered the round off error in my increment limit as I used the TBPRD's to calculate the frequency before defining the increment limit (350464/227) whereas when I was getting the drift I did not consider the round off error as I used the expected frequencies 214 (from TBPRD = 4687393/107) and 330k (from 4989/11) to calculate my increment limit (330000/214).

    what do you think?

    David.

  • David,

    That makes more sense. Looks like you have things under control now.

    -Tommy
  • Thanks a lot Tommy.

    David.