I2C-based H-bridge controller with PWM
During development of my Sumo robot, I ran into some problems around controlling the H-bridges:
- If you're going to use PWM, the PWM signals on each input of the H-bridge need to be synchronised (phase-coherent), and there's no such guarantee when using an AVR to drive them. If they're not phase-coherent, the H-bridge will get hot and not drive the motor properly.
- I wanted to use braking on the H-bridge, which means I need independent control of all four H-bridge inputs. The ATMega32 that I was using has four PWM channels - more than most microcontrollers - but still only enough to run a single H-bridge.
- Reprogramming the PWM channels on-the-fly was impossible while guaranteeing there would be no shorts.
I decided to use a slave microcontroller to solve these problems. I used a PIC16F84A, mostly out of convenience. It has enough I/O pins to run all four inputs of two H-bridges, plus a few left over for configuration and control. It generates phase-coherent PWM drive signals that are suitable to directly control an H-bridge. It's controlled by an I2C bus; a simple serial bus that is commonly implemented on microcontrollers. The AVR has hardware support for it (although it calls it TWI), making programming simple.
Device pinout
Device pinout
The address bits let you have multiple motor controllers on the same bus. Each I2C device on a bus has a unique 7-bit address. This device has that split into a five-bit prefix ('10000') and a two-bit suffix, set by these pins. They should be tied high or low depending on the address that you want the chip to have.
The I2C pins are used to control the chip. They're covered in more detail below.
The Status LED is lit while an I2C transfer is taking place. It's mostly useful for debugging.
The H-bridge outputs are on PORTB. If you don't need braking, you can just connect the A and B outputs from the chip to A and B on your H-bridge. Most H-bridges will just melt if you try to brake them, so check before you connect!
You can control a motor directly from the A output, too (with a buffer or FET or power transistor!)
Control
The device has a fairly limited vocabulary as far as I2C transactions goes: it only responds to writes, addressed directly to it (no global calls), using the normal (fast) START condition (no slow STARTs) and 7-bit addresses. The default address is b'10000xx', where 'xx' is the value of the pin straps on PORTA. The device will accept an eight-bit data transfer in the format '0cdbpppp', where:
- c is the channel number (0 or 1)
- d is the direction (0 is forward, 1 is reverse)
- b is whether or not to apply braking (0 is no brake, 1 is brake). This overrides the direction.
- pppp is the level of power to apply (0 is no power, 0xf is full power, with values in between). This works for braking, too; 'full power' in this context means 'maximum braking'. 0 means that the motor should coast, regardless of braking or direction.
The device has a 10MHz clock by default, which gives a maximum I2C frequency of 8kHz. It can go faster, but will become less reliable. The most common symptom of a too-fast I2C bus is that transfers won't be ACKed. This is a recoverable condition; the device won't ACK unless it received all data bits intact. It won't (shouldn't!) receive the wrong data and destroy your H-bridge. Of course, if you want to run the bus faster, you can give it a faster clock - the PIC16F84A is specced up to 20MHz.
The default PWM output frequency is about 300Hz with a 10MHz clock. This appears to be a good number for small DC motors. The firmware can be tweaked to give higher or lower rates - or again, you can twiddle the clock rate.
A bit more on I2C
The I2C bus (also referred to as TWI, or Two Wire Interface) uses, unsurprisingly, two wires. It's pretty neat; there's a data (DATA) and clock (CLK) line that is shared amongst all of the devices on the bus. A few simple rules govern data transfer; the original spec from Philips is short and well-written. The clock rate (for standard-rate devices) is up to 400kHz, which is more than enough. Since the PIC uses a bit-banging I2C implementation, the highest clock rate is about 8kHz - still plenty for robotics applications.
The gist of how I2C works is:
- Devices connect to the bus using open-drain outputs (they can pull the bus low, but can't drive it high). Bus lines connect to the Vcc line via resistors, so the bus state when no devices are connected is 'high'. The 'asserted' state is still high. In this way, many devices can use the bus, and nothing bad happens if multiple devices drive the bus at the same time.
- When you're transferring a bit, transitions on DATA happen while the CLK is low. While CLK is high, DATA must be stable.
- To transfer data, you put a START condition onto the bus (CLK high, DATA transitions from high to low). Transfer seven bits for the address and an eighth for the read/write flag. The slave must acknowledge the transfer by pulling DATA low during the ninth CLK pulse. Send your data, send a STOP condition (CLK high, DATA transitions low->high) and you're done!
There, wasn't that easy? :-)
