DSP56F805 multiple ADC sampes per PWM period

Hello,

First, the quick summary: I'm following Motorola's AN1933 to sample twice in a PWM period, using two timers C0 and C2. For some reason, the ADC doesn't always trigger when C2 compare succeeds.

I've got a sensorless BLDC motor control application on a DSP56F805. I'm sampling the entire ADC bank, including phase currents and voltages, at the trough of the PWM carrier (center aligned PWM) in order to measure average current. I'm using a minimum-ripple PWM scheme in which the top switch turns off and the current circulates around GND for part of the PWM cycle.

So for phase voltage I need to sample at the instant when the top transistor is OFF and the bottom is ON. The time within the PWM cycle therefore will vary with duty cycles.

I have attempted to add a second sampling point according to section 5.4 of Motorola app-note AN1933. I have timer C0 triggered off the PWM sync signal, counting down to zero from half the PWM period:

/* Count down then reinit, primary source ipbusclk, sec source * timer pin C2 (pwm sync signal) */ #define QT_C0_CTRL_INIT 0xD135 /* Inverted output -- active high until compare */ #define QT_C0_SCR_INIT 0x4003

I then have Timer C2 set to count at ipbusclk whenever C0 is high:

/* Count up, continue counting after compare, primary source * ipbusclk, sec source C0 pin */ #define QT_C2_CTRL_INIT 0x7005 #define QT_C2_SCR_INIT 0x0000

C2's compare register is pre-set to the C2 counter value, plus one, so that the first compare happens immediately and the motor current gets sampled. The timer C2 ISR runs when the compare occurs, and presets the C2 compare register to its old value, plus a varying time delay to match the top transistor being off and the bottom being on. When the first ADC acquisition is done, the values are fetched by the ADC interrupt routine. Meanwhile, Timer C2 is counting up to the next compare value to trip the ADC again for the second acquisition. This is exactly what is done in AN1933. After Timer C2 compares the second time, triggering the second ADC acquisition, the ISR turns off the timer by setting the count mode to No Operation (high bits 000 in the CNTL register).

Meanwhile, at the peak of the PWM carrier, after all the ADC should be done, Timer C0 compares and the Timer C0 ISR prepares the C2 timer for the next cycle.

Using a software-toggled testpoint and a scope, I can see that Timer C2 compares very consistently. Unfortunately, it appears the ADC is not triggered every time C2 compare succeeds. My PWM is

16kHz. Even if I allow 20uS between sampling instant 0 and sampling instant 1, sometimes the ADC does not trigger the second time even though I can see on the oscilloscope that the Timer C2 interrupt routine runs every single time.

The only thing I can figure would cause this is that the ADC is still in the middle of the acquisition when the second trigger arrives, and therefore ignores the trigger.

My ADC setup uses a 5MHz clock, which IIRC is the maximum possible acquisition speed, with simultaneous sampling for 26 clocks for the whole ADC bank. I'm still sampling the whole bank and then picking and choosing values in the end-of-scan ISR.

#define ADC_A_ADCR1_INIT 0x4F01 #define ADC_A_ADCR2_INIT 0x0003

I'm going to continue examining the ADC setup, but in the meantime I'm short on ideas on why the ADC would not always trigger when C2 compare succeeds. 20uS should be ample time for it to complete. Any ideas?

Also, is there a simpler way to do two ADC scans per PWM period, using a single timer only?

Here is the source code for the ISRs. Thank you!

Justin

/* Timed to run just before the end of the PWM cycle, to prepare * the sample timer. */ void IsrQTC0(void) { /* Prepare C2 timer for next period */ ioctl(QTIMER_C2, QT_SET_COUNT_MODE, QT_GATED_COUNT_MODE); ioctl(QTIMER_C2, QT_CLEAR_FLAG, QT_COMPARE_FLAG); ioctl(QTIMER_C2, QT_INT_ENABLE, QT_COMPARE_INT );

/* Paranoia */ acq_state = 0;

/* Ack our own flag */ ioctl(QTIMER_C0, QT_CLEAR_FLAG, QT_COMPARE_FLAG); }

/* Called multiple times per PWM period to time samples */ void IsrQTC2(void) { switch (acq_state) { case 0: /* Bump compare value by second-sample delay */ ioctl(QTIMER_C2, QT_WRITE_COMPARE_REG1, ioctl(QTIMER_C2, QT_READ_COMPARE_REG1, NULL) + acq_delay_t1); break;

case 1: /* Stop the timer. Then pre-set for the first * sample delay, for the next cycle. */ ioctl(QTIMER_C2, QT_SET_COUNT_MODE, QT_NO_OPERATION); ioctl(QTIMER_C2, QT_WRITE_COUNTER_REG, 0); ioctl(QTIMER_C2, QT_WRITE_COMPARE_REG1, ioctl(QTIMER_C2, QT_READ_COUNTER_REG, NULL) + acq_delay_t0); break;

default: ioctl(QTIMER_C2, QT_SET_COUNT_MODE, QT_NO_OPERATION); break; }

/* Clears flag */ ioctl(QTIMER_C2, QT_CLEAR_FLAG, QT_COMPARE_FLAG); }

Reply to
jrd
Loading thread data ...

Did you try to initiate "Service Request" at freescale via web interface? if not then i think you should try that, their support team is very cooperative and problem solving.

ali

Reply to
Ali

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.