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