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.

How do I scale an input value in proportion to a timer period on a 16-bit system?

Other Parts Discussed in Thread: DRV8844, MSP-EXP430F5529LP

I am using timer A0 in up-down mode to generate PWM signals with dead time. One ADC input sets the timer period. Another input sets the pulse width. The period input works but the pulse width does not. The pulse width takes the form of toggle-set and toggle-reset as explained in section 17.2.3.5 of the family data sheet. The entire code was posted previously here, and it is still the same except for the while(1) block which I post below:

    while(1)
    {
    	ADC12_A_startConversion(ADC12_A_BASE,
                                ADC12_A_MEMORY_0,
                                ADC12_A_SEQOFCHANNELS);
    	timer_period = (frequency_input + 100) * 4;
        TA0CCR0 = timer_period;
    	toggle_reset = (timer_period * acceleration_input) >> 13;
//    	if (toggle_reset > (timer_period/2 - 100))
//    			toggle_reset = timer_period/2 - 100;
    	toggle_set = timer_period - toggle_reset;
    	TA0CCR1 = toggle_set;
    	TA0CCR2 = toggle_reset;

//        __bis_SR_register(LPM4_bits + GIE);
        __bis_SR_register(GIE);
        //For debugger
        __no_operation();
    }

The 12-bit duty cycle input is in the acceleration_input variable. I need to continually proportion toggle_reset to the timer period, and it also needs to be less than 1/2 of the timer period. I do this by multiplying the timer period by acceleration_input, then right-shifting the result 13 bits. The problem is that toggle_reset almost never (but sometimes does) show up in CCS watch expressions. When it does, it is the same as the timer period. I previously was dividing the product by 8192, but got the same buggy behavior as right-shifting when running debug. Any suggestions on how I may accomplish this bit of math?

  • Otto,

    could you please provide an calculation example with some values that show what you expect from your code. Otherwise it isn't quite easy to say what's wrong. You want two independent PWMs based on the same frequency? Are these signals for setting R/C servos / ESCs with 20ms frequency and 1 to 2 ms duty cycle? Or ist it some sort of H-bridge motor control (because you mention a dead time)?

    Dennis
  • You are not telling which MCU you are using.

    You Start your ADC to do a conversion, I don’t see how you wait until the ADC is ready. When the conversion is ready somewhere during the next code lines, you partly using the previous ADC result and partly the new ADC result in your calculation.

    You are not using any way of synchronization when updating the timer values. Are you aware that updating the CCR values can generate a new Toggle before the output is set to an absolute value?
  • Hi Dennis and Leo,
    I am using the MSP-EXP430F5529LP launchpad and TI's compiler. My code is intended to drive the DRV8844 half bridges which then drive coils of a bench-top shaker. That is why I need dead time.

    The timer period updates as expected in real time via the frequency_input variable that came from the ADC memory. When the user increases timer frequency (decreases timer period) the output duty cycle needs stay the same which means that the toggle_set (TA0CCR1) and toggle_reset (TA0CCR2) values need to scale with the timer_period (TA0CCR0) value. TA0CCR1 and TA0CCR2 also need to produce the same output pulse width, which means TA0CCR2 must always equal TA0CCR0 - TAOCCR1.

    TA0CCR0 is initially set to 0x100 0000 and TA0CCR2 is set to 0x10 000 and so TA0CCR1 is set to 0xF0 000. Now the user reduces TA0CCR0 to 0x80 0000. TA0CCR2 must now become 0x8 0000 and TA0CCR1 must now be 0x78 0000. If the period is reduced by half, then the pulse widths must also be reduced by half.
  • Otto Hunt said:
    TA0CCR0 is initially set to 0x100 0000 and TA0CCR2 is set to 0x10 000 and so TA0CCR1 is set to 0xF0 000. Now the user reduces TA0CCR0 to 0x80 0000. TA0CCR2 must now become 0x8 0000 and TA0CCR1 must now be 0x78 0000.

    Are you sure about those values? They're all too big to fit into a 16-bit register (maximum value is 0xFFFF). Also some of them have a block of four trailing zeroes and others only have three.

  • Otto,

    Once you get your A/D sampling worked out, please read the following post regarding how to perform the multiplication that you need, specifically the replies by me and Jens-Michael.

    Your ADC reading can be a Q0.12 value that you multiply and shift against your timer period (a Q15.0 number), then divide by two to make it 50% or less. Then subtract your required dead time.

**Attention** This is a public forum