There was a 4-part series published in Servo Magazine starting in 2008 featuring contributions from three authors centered around the capabilities and uses of a Propeller Multicontroller board; a DIY multi-purpose control board. This is part 4.
The 4-part series included the following articles / authors:
Part 1 – Introduction and Design of the Propeller Multicontroller Board – Chris Savage
Part 2 – Servo Control – David Carrier
Part 3 – Stepper Motor Control – Kevin McCullough
Part 4 – PWM Control of Motors and Lamps/Lights with Example Code – Chris Savage
Unfortunately I did not write part 2 or part 3 and unable to distribute those articles. However you can order them from Servo Magazine if you’re interested. The parts listed here originated on this site during development.
This month we wrap up our 4-part series by covering practical use of PWM on the Propeller using our Multicontroller board. In last month’s article Kevin McCullough covered stepper motor control and made schematics available on the project web page. These schematics use the L293D Quad Half-H Driver IC which provides bi-directional drive currents of up to 600mA from 4.5V to 36V. We will use the L293D in this article for both motor control and light dimming. This IC is included on the Propeller™ Professional Development Board as well, so those who have the PPDB can follow along even if they haven’t built a multicontroller board.
Controlling the speed of a motor or dimming a light can be done by varying the voltage going to the device. More voltage and the motor goes faster or the light gets brighter. Less voltage and the motor slows down or the light gets dimmer. Using analog control is inefficient for this because power is typically wasted while the driver (usually a BJT or MOSFET) operates in its linear (or active) region when not fully on or off. When this happens the driver has to supply necessary current while limiting the voltage on the output. The power dissipated is wasted in the form of heat which could also be harmful to the driver or other nearby components and often requires large heat sinks.
By using the driver as a switch it is either on or off at any given time. This reduces the voltage drop across the device and therefore the amount of power dissipated as heat. In order to control the speed of a motor or the brightness of a light we have to modulate the output to vary the power to the load. PWM can accomplish this and reduce the total amount of power to the load without the losses typical of resistive / analog means. In the off state the driver is not conducting any current, and in the on state there is little voltage drop across it.
Using PWM we will essentially modulate our signal at a fixed period with a varying duty cycle. By varying the duty cycle we will be varying the ratio of on-time to off-time at a given rate or frequency. This will allow us to control the speed of a motor or the brightness of a lamp much more efficiently.
Our Multicontroller board is Propeller-based so we can take advantage of the counters to help generate our PWM signal. The Propeller has 8 cogs (processors) and each cog has two counters for a total of sixteen. The counters operate completely independently of each other and are advanced modules having 32 modes of operation. For this article we’ll be using the PWM mode which will be explained below.
PWM Generation Using the Counters
The CTR.spin object (included with the Propeller Tool) does a good job of going into the details of the counters and all their modes and parameters, so I will focus on a small piece of example code that will provide a working example of using a counter to generate a PWM signal for the L293D. First let’s have a look at the code line by line. Please refer to Figure 2 for the code listing. This code can also be downloaded from the project downloads link toward the bottom of this page.
Line 2 sets the clock mode and sets the PLL multiplier to 16x. Line 3 sets the frequency of the crystal we are using, which is a 5 MHz crystal. With the PLL at 16x the Propeller is now running at 80 MHz (5 MHz x 16). CLKFREQ is a command which returns the current system clock frequency in Hertz. This means your programs can determine what speed the Propeller is running at, as well as make calculations based on this value. Line 6 declares a global variable called parameter, which we will use to change the duty cycle of the signal by setting it to some percentage of the period.
Line 8 starts our program code and defines the name of this method as Main. It also declares a local variable named index which will be used as a counter. Line 9 launches the core PWM code into a new cog and passes the code address (entry) as well as the address of the global variable where it will obtain the duty cycle. The @ symbol specifies that we’re passing the address of a symbol. Line 10 starts a repeat loop that never ends. The lines indented below it will run indefinitely or until the Propeller is reset. Line 11 starts a repeat loop which uses the local variable index to count from 0 to the current period. Each pass through the loop, index is copied into parameter and there is a small delay before the loop continues. When index equals period the routine will fall down into the next repeat loop, which is essentially the same as the first, except that we’re counting back down. The effect is that we’re ramping the duty cycle from 0% to 100% and back to 0% in a continuous loop. To ramp faster you can reduce the waitcnt value from 80_000 down to a lower value. Likewise a higher value will cause it to ramp slower.
Line 20 is the entry point to the assembly code that handles our PWM signal. The first thing we need to do is to set the direction register of the output pin we will be using to make it an output. This is accomplished by moving the value of diraval into DIRA. If you look down at line 30 this value was set using the decode operator. This effectively sets bit 16 high in the 32 bit variable (all other bits are low). Now our PWM pin is set to output so we drop down to line 21 which moves the value of ctraval into CTRA. This value was calculated down on line 31 by taking the bit pattern we want for the PWM mode (%00100), shifting it left 26 bits to get it into the correct field of the counter A control register and adding 16 to specify which I/O pin to use for output. This works because the APIN is specified by the lower 6 bits of the control register.
Line 22 moves a 1 into the FRQA register which tells the counter to increment every clock cycle. Line 23 moves the current contents of cnt into a variable called time. The cnt value is a 32-bit counter incremented every clock cycle. In line 24 we add our period to time. This calculates the value of cnt one period from the time cnt was read. To summarize, lines 20 through 24 set up all the parameters we will need in our assembly routine before running the loop. This includes setting up the direction register for the output pin, setting up the configuration register for counter A (which sets the mode and output pin), and calculating the target cnt value for timing using the system counter.
At this point we enter the main assembly loop at line 25. This line reads the current value from the address passed in the par register, which, as you may recall points to the global variable parameter where our main code can alter the duty cycle. Line 26 causes the cog to wait for the target cnt value which was stored in time. Once reached, period is added to time again to recalculate the new target and the code proceeds to the next line. Line 27 takes the variable value and makes it negative before loading it into PHSA. The reason for this is that in order for the output to be high, bit 31 must be set. By making value a negative number we set bit 31 and our output goes high. Because value is set to our duty cycle and the counter will increment every clock cycle, once the counter reaches 0 the output will go low. Line 28 loops back to line 25 where we fetch a new duty cycle value and wait. So as you can see the output stays high for the duty cycle, which is a percentage of the period and then goes low. The cycle restarts at exactly the number of cycles in the period. This happens indefinitely or until the cog is reset. Since this routine runs in its own cog the Main method can change the duty cycle at any time and the PWM assembly code will update at the end of the current period.
Connecting the L293D
In this example I will be driving a 7.2V DC Gear Motor from a robot. This motor draws approximately 190mA @ no load, which is well within the specifications of the L293D. If you look at line 32 of the code you will see that we have specified a period of 8000 cycles. This gives us a PWM frequency of 10 kHz and a period of 125 µS, which is commonly used for motor control using an H-Bridge and is well within the frequency range of the L293D.
Due to the impedance of the inputs on the L293D we cannot use P0 through P15 on the Multicontroller because of the 3.9K series resistors. Instead we will use P16 which has no series resistor. If you’re using the PPDB you can simply connect P16 to Input 0 and tie the Enable (0, 1) connection to the 5V just below it to keep it enabled. Optionally the enable line could be controlled by an I/O pin but we’re keeping it simple for now.
If you are using the Multicontroller board you can breadboard this circuit and connect the ground and I/O lines using pluggable wires. Please follow the schematic shown in Figure 3. PPDB users will still require an external motor supply and ground connection as shown in the schematic. When you run the code it should start ramping your motor up and down between stopped and full speed.
Dimming lamps is done in the same manner as the motors, with the exception of not requiring such a high PWM frequency. For dimming lamps you can connect a bulb in place of the motor and make the following changes to the code. Change the period in line 32 to 40_000 instead of 8_000. This will reduce the frequency down to 2 kHz and a period of 500 µS. You can also change the 80_000 cycle delay in lines 13 and 16 to 4_000 to adjust the ramping rate. A MOSFET is another option to drive a lamp and there are additional circuits and code available to do this.
So now you have a good foundation to start generating PWM on the Propeller and add functionality to the Multicontroller board we’ve been working with. While this article covered the basics, more advanced code with bi-directional motor control will be available here. We may even go so far as to integrate all three types of control into one demo. For now, experiment, build and learn. Don’t be afraid to try new things. The chips are socketed and easily replaceable if you should make a mistake that results in letting out the magic blue smoke. Remember you can always visit the Parallax Object Exchange if you need additional code. Take care and have fun!
servo 2008 12
This project was published in the December 2008 issue of Servo Magazine.