Finally, the PWM!
‘Light’ introduction into PWM on MCUs
Pulse-width-modulation is a method of generating analog signal from its digital counterparts. The square-formed digital signal is controlled by adjusting its on-off time-period, and another thing called duty-cycle. On MCUs this is done by using count-timers. The timer (counter) will count up to certain value (and then back to zero, over and over), this value is the period, and some register will keep another value to compare with the counter, this value will control/toggle the high (on) signal and latched it until the next comparison matched up, this another value represents our duty-cycle. Here’s example:
An MCU with 12KHz clock.
We will set a PWM with 1s period. It means we have to tell the timer (counter) to count up to 12000 (see it’s match with the clock).
We want a 75% duty cycle, which means in 25% of a single period the digital signal will be off. We need the 75% value for the compare register: 75/100 * 12000 = 9000 equals to ~750ms.
This is how we augment the analog signal.
The effect of this is we now have a wave function as an integral (area under the curve) of its discrete digital signal, and by controlling the period and its duty cycle we may obtain different voltage for the augmented analog signal.
MSP430 comes with varied configuration to control how the PWM signal behave. Including the count-mode: Up, Continuous, Up-Down. and ouput-mode: Set, Reset, Toggle, Set-Reset/Reset-Set. For a complete reference it’s available on the MSP430 Family guide.
So what’s with this PWM thing? Well it’s because most of the actuators devices actually driven by analog signals like motors, speakers, lamp/led dimmers, wireless communication link, etc. While MCUs/CPUs drive digital (discrete) signal, so to drive these devices (actuators) it’s either solving this with DAC, or PWM.
MSP430G2553 PWM Outputs
Unlike arduino-family which is based on Atmel AVR chips, msp430g2553 only has 3 pwm outputs max, or 5 if you’re able to work with continuous mode. While the arduinos has 6 PWM outputs or so.
Most (if not all) tutorials I saw never really mention which pins are able to output PWM signal, fortunately it’s mentioned vaguely at the datasheet.
It’s a bit confusing since the datasheet mentioned that this chip has 2 16bit-timers (Timer_A) with 3 capture/compare (c/c) registers each. While in fact my msp430g2553 only has 2 c/c registers for its timer_A0. It doesn’t clearly stated that the 20-PDIP package of the chip doesn’t have timer_A0.2 pin, apparently it’s only available on msp430g2553 with 28-TSSOP and 32-QFN packages
To control the outputs we may select which pin related to which c/c register we used. As portrayed on the image above, Pin 1.2 can be selected to outputting PWM signal controlled by timer_A0.1.
As for the code, the simplest PWM control looks just like this: (adapted from CCS code example)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
The comment should be clear enough, our first PWM set with the timer_A0 powered by SMCLK (at its default clock 1MHz). We used 512-count period (512µs), with 75% duty cycle (384µs), which will be outputted to the pin1.2.
We can try connecting pin1.2 to LED and see the LED light in dim, try adjusting the duty cycle (TA0CCR1) closer to (but not bigger than) its period value (TA0CCR0) and see the led emits more light. So this is how dimmers work. But that wasn’t even remotely interesting. So let’s try controlling a motor servo instead.
A Servo it is
So there’s 3 types of electric motors (AFAIC), a motor servo, a motor-stepper, and a DC motor (there’s 2 different dc motors, brushed and brushless, but we will leave it at that). What I currently have is a couple of cheap servos from hextronic, HXT900. So the example will be based on that.
To wire the servo with the launchpad board I used single 1K resistor and an LED this is act as a guard for the signal wire to the servo. It’ll much better if we have separated power supply for the servo, but now we’ll just hook the Vcc and Gnd wire directly to the board.
A servo rotates to certain angle when given a particular analog signal with certain frequency. In the case of HXT900, it needs analog signal with 50Hz frequency. To drive the servo we will adjust signal PWM variably and let the servo rotate to some certain angles. the max angle of the servo is 180° (or ±90°).
We will control the servo from the launchpad’s switch button, make use the exact debouncing code from the blinking fizzbuzz code last time. The servo will step at each cycle and we’ll increase the duty cycle as te servo rotates.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
But Stepping isn’t servo good point, should use motor stepper for that. In addition the ISR has 11 cycles latency, and an update at each end of PWM cycles make the servo rotates less smoothly, and slow. Servo more suited for angle-based rotation. so it’s better to directly tell it to move to certain angles rather than stepping to that angle. As usual the above code, and the more smoother servo rotation is available here.
Here’s some crappy demo video of the code (using the servo_pwm.c code not the above)
The sound is a bit out of sync blame my 5-years old phone. But as showed on the video when we push the switch button the servo will rotates 180° before stop, it will rotate back to its start position only when the button is released. With better controller (as joystick) we can control the servo with more precision and hold the servo on any particular position.