Speed 400 Speed Control

Theory of Operation

Several people have asked me how the controller works. This is a reasonable question, but a hard task if the technical education of the audience is unknown. However, here is my best shot.

Hardware (see the schematic drawing)

Control Power.

Power from the battery is regulated by U1 to a nominal 5V. This supplies both the speed control circuitry and the radio system; the radio system is supplied through the servo plug + and - wires. Low voltage is detected by a circuit consisting of R1, R2, R3 and Q1. The base of Q1 is tied to the +5V from the regulator, which serves as a reference. The emitter is tied to the battery through R3. Like most silicon PNP transistors, the emitter needs to be about 0.7V positive with respect to the base for current to flow; therefore, Q1 starts to conduct at 5.7V. The current into the emitter is now determined by R3 and the difference in the input and 5.7V; this current flows through to the collector so long as the collector is negative with respect to the base. Since R2 is 10 times the value of R1, a voltage of 10 times the voltage across R3 appears across R2. This voltage is fed into the GP3 input of the processor, which has a threshold of about 2.5-3V; this input is high as long as the battery is above 6V. R1 is used to prevent the processor input from being pulled above Vdd.

Motor Power

Q4 is the main motor control FET. It is controlled directly by the GP2 pin on the processor; when this pin is high, power flows from the + battery terminal to the + motor terminal, through the motor to the -motor terminal, through Q4 and back to the battery terminal. To get partial throttle settings, Q4 is switched on and off at a 3 KHz rate. When Q4 is off, the inductive current from the motor flows through the diode built into Q3. This diode is reverse-biased if the - motor terminal is negative with respect to the + motor terminal. However, when the inductive kick takes the - motor terminal positive, this diode conducts. Although the voltage across the motor looks like a square wave, the current is relatively steady if the motor is under load. This allows the controller to work without throwing away the battery energy.

Propeller Brake

The propeller brake consists of a mechanism for shorting out the motor. Q3 is a P-channel FET (unlike Q4, which is N channel). This means that it requires that the gate be negative with respect to the source, and that the drain is negative when the device is OFF. Q2 turns it on by pulling one end of R5 to ground (- battery), and GP1 controls Q2. (Q2 is a small N-channel FET, so that a positive voltage turns it on.) C4 keeps Q3 from turning on due to the fast switching of Q4, and R5 keeps Q3 from switching fast enough to turn Q4 on. If both FETs ever turn on at the same time, one has a short across the battery; this is to be prevented at all costs.

LED

The D1 consists of two LED chips, one red and one green. When wired in parallel facing opposite directions, they make an indicator which glows red when the current flows one way, and green when it flows the other. R8 limits the current to about 6 milliamperes. The processor outputs GP4 and GP5 control the LED.

Servo Pulse Input

The servo pulse input from the receiver is tied directly to the GP0 bit on the processor.

Software (see the assembly code)

I am going to assume some background in assembly language programming. However, I will also assume that the PIC processor family is new to you.

U2 is a PIC microprocessor with built in clock generator, master clear circuit and watchdog timer. The clock and master clear can be provided externally. However, by programming the processor so that all of these functions are internal, we get 6 IO pins on an 8-pin part. This is set by the __config statement a couple of lines into the file.

The processor itself is a strange one. It uses 12-bit instructions and 8-bit data. These do not share memory addresses, so that the instruction memory cannot store data. The data memory consists of 64 addresses of which 48 addresses are used. Most of the machine registers appear in this space. This includes the lower 8 bits of the program counter, a status register which holds arithmetic result status , an address extension bit and other bits. The GPIO register which appears as pins GP0 through GP5 is also in this file. The OSCCAL register is used to adjust the internal oscillator using a value programmed into the part at manufacture. Most of the rest are general purpose registers used for data memory. The GPIO register can be programmed for input or output on a pin-by-pin basis, except for GP3 which must be an input.

One great advantage of the PIC processor for this type of project is that it is quite easy to write instruction sequences that run in a fixed number of clocks. Take the following snippet:

btfss GPIO, BattOkBit ;btfss = "bit test file register, skip if set."
bsf Flags, BattLow ;bsf = "bit set in file register"

Now, the key is that each instruction takes one instruction clock unless the program counter skips or jumps, in which case it takes two. Therefore, if the first instruction skips the second, it takes two clocks; if it doesn't, it takes two clocks. Note: each clock is 4 oscillator cycles; for the 4 MHz oscillator internal oscillator, each instruction clock is 1 microsecond. That is why there are many skips and few calls or gotos; it takes work to keep the two paths of a goto equal.

This code makes use of macros. A macro is a named sequence of instructions, with one or more arguments to the macro. For example, writing

NO_OP 7

inserts 7 no-op instructions.

I am going to explain this code from the bottom up; that is, I will explain the low level segments first, then try to stitch them together.

DoPwmPulse:

This routine is entered by a call instruction, and returns by a retlw instruction. It performs 3 operations:

This routine uses the assembler to generate the same sequence of instructions 43 times. (PWM_Period = 47 and PWM_Start = 4). By doing this, we save 3 clock cycles; one for the decfsz instruction and 2 for the goto required to go around a loop. This technique is called unrolling a loop; it allows us to perform all of these operations every 7 microseconds. Note that this sets the resolution of both the servo pulse measurement and of the PWM pulse.

This routine does not turn on anything. Therefore, it is sometimes used to waste time when time needs wasting.

Note that the servo pulse width counter only has 8 bits, which can hold numbers between 0 and 255. A little arithmetic shows that the counter will overflow with a pulse of 2 milliseconds; this amounts to 286 counts. We will deal with this later.

ServoLookup:

This routine looks really simple. It is entered by a call, and its purpose is to convert a servo pulse width into a command. The command includes a PWM width, a bit to turn on the brake, and a bit indicating that the pulse width is invalid. How does it do that? Note two things: it turns on the bit 9 address extension bit, and stores the W register in the lower 8 bits of the program counter. When this is done, the program counter is set as follows. Bits 0 through 7 come from the value that was in W, bit 8 is set to 0 and bit 9 is set to the PA0 bit in the status register, which is a 1. This results in an address in the range of H'200' to H'2FF', which is where we jump to. If we look down a couple of lines, there is an ORG H'200, followed by an INCLUDE of the include file. In that file there is nothing but retlw instructions with different return values. These return values correspond to the command translation for the servo count originally stored in PCL. This is how one does lookup tables on this processor.

Note that we mentioned above that the servo count overflows an 8-bit register. With this lookup scheme, we just wrap the table at the overflow point. So long as the servo intervals of interest are separated by less than 256 counts, this scheme works. For this table, the widths of interest go from about 800 microseconds to 2250 microseconds; this corresponds to 214 counts. The only thing we give up is the ability to discriminate badly out of spec pulses; we may take some very wide or very narrow pulses as valid. This has not been a problem so far.

MainPwmLoop:

This is the code that runs except when the end of a servo pulse is detected. In this code, we keep counting the servo interval every 7 microseconds; however, we do not measure the PWM count except when DoPwmPulse is called. The idea is to buy ourselves some time to check for a high to low transition on the servo pulse and to check the battery low flag to see if DoPwmPulse set it. The code also looks at the PwmCount from the last time it processed a servo pulse; if it is not zero, the power FET is turned on; otherwise it is turned off. See the DoRunBit macro for the instructions involved.

If the servo bit was high the last time we were here and it is low now, the code does a goto to the EndOfPulse code. If at any time a low battery condition is detected, it does a goto to the BattLoShutdown code. If neither case is true, it loops back to the top of the loop and calls DoPwmPulse again. Note that the PWM pulse is on longer than the count; this means that it jumps from zero to about 50 microseconds as the throttle is advanced. This is where the time to do the processing comes from.

EndOfPulse:

This code processes the servo pulse interval into an appropriate command. However, while it does this, it keeps the PWM pulse going at the width from the last command. It does not need to keep up with the servo pulse width, since the pulse wire is known to be low, and will stay low for several milliseconds. All we have to do is keep up the DoPwmPulse - DoRunBit cycle going, and we get strips of 9 instructions to do the processing. No process step can take over 9 instructions without upsetting the PWM cycle. First, we clear the watchdog timer. If no servo pulses come in, the watchdog timer fires and resets the chip to the beginning. Then we copy the state of the brake FET drive into the red LED bit. (I know we haven't talked about the brake FET yet; we will get there.) Now, we pick up the servo count and call ServoLookup. The returned value is saved in a file register (Command) for later processing; we need to get ready for another PWM cycle now. The next thing we do is copy the state of the run FET to the green LED; if it is ON at the end of a PWM cycle, we must be at full scale. Next, we look to see if the width was invalid. If it was, the pulse is completely ignored, and the command discarded by jumping back to the PWM loop. Otherwise, we process the LSBs of the command into the PwmWidth value. If the brake bit is set in the command, we carefully turn off the run FET, waste some time, then turn on the brake FET. We jump back to the main PWM loop. However, since the run FET is never turned ON because the PWM width is 0, this loop just counts the servo pulse width. If the brake command bit is OFF, turn off the brake FET (which is probably already off), do one PWM pulse at the prior command value (mainly to waste time if the brake was ON), and go back to the main PWM loop.

BattLoShutdown:

This routine turns off the motor, turns on the brake, updates the LED drives, and jumps almost back to the start of the code.

Coldstart:

This is the start of it all. The startup code is straightforward; we don't have to do more than one thing at a time. Most of the code down to Rearm is out of the PIC book. The tris instruction sets which GPIO pins are inputs and which are outputs; the outputs are set low by the clrf GPIO.

Rearm:

First, the code hangs here if the battery voltage is low. If the voltage is OK, it looks for a whole pulse from the receiver. If it gets one, it measures the width of the next 5 pulses. The loop to do this must be 7 cycles long, so we can use the same lookup routine we did before. Each pulse width is looked up in the command table. If the brake bit is set, this is a legal arming pulse; otherwise, the whole thing starts over. if 5 pulses in a row measure up, the controller is armed, and the code falls into the main PWM loop.

That's all there is to it.

Copyright © 1998 by Michael J. Norton.

May be copied as desired and modified as needed so long as this copyright notice is preserved.

Back to Mike Norton's Hobbies