EmbeddedRelated.com
Forums

DSP56F805 multiple ADC sampes per PWM period

Started by jrd December 4, 2006
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);
}

jrd wrote:
> 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); > }
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