Reply by Haroldo Filho December 5, 20062006-12-05
Hi! Interesting enough I work with similar app with
the DSP 56F8013. I have a very similar setup as you.
My PWM is center aligned at 27KHz. I have had a lot of
trouble using complex timing to synch 2 ADCs per PWM,
and in the end I just eliminated all interrputs from
my application. I now scan for the PWM flag (which it
set up to trigger twice per period), as opposed to
have it trigger an interrupt. The key here is to have
the half cycle reload enabled in the PWM. This way I
can use only 1 timer to trigger 2 ADCs per PWM period,
each ADCs trigger off the same timer, which in turn
triggers of each PWM reload pulse, one in the
beggining of the period, one in the middle. The one
thing to keep in mind is you need to be carefull to
make sure you collect 2 different samples. In my case,
the first ADC collection (not conversion!) happens in
the beggining of the PWM period, but it corresponds to
the second conversion of the previous period.
--- Mstr wrote:

> Hello,
>
> 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.
>
> For better zero-cross detection I have redesigned
> the controller to
> measure the phase voltages around GND when the top
> transistor is off
> and the bottom transistor is on. I still need to
> measure average
> current synchronously to the PWM, which means I
> would probably continue
> to sample at the center of the ON-time, at the
> trough of the PWM
> carrier.
>
> For phase voltage, however, 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.
>
> As a result of these different requirements, I am
> assuming I need to
> sample twice within each PWM period. I have
> attempted to do so
> 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. 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);
> }
=== message truncated ==
Reply by Mstr December 4, 20062006-12-04
Hello,

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.

For better zero-cross detection I have redesigned the controller to
measure the phase voltages around GND when the top transistor is off
and the bottom transistor is on. I still need to measure average
current synchronously to the PWM, which means I would probably continue
to sample at the center of the ON-time, at the trough of the PWM
carrier.

For phase voltage, however, 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.

As a result of these different requirements, I am assuming I need to
sample twice within each PWM period. I have attempted to do so
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. 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);
}