Controling a TB6612FNG H-Bridge

1. Introduction

As described in this article, the TB6612FNG is a motor controller providing two H-bridges for operating DC motors. In this article I will describe how the TB6612FNG could be wired up to the STM32 Discovery board, and to program the STM32 (in C) to let the user control the motors through three buttons.

2. Prerequisites

3. Parts Needed

To build this example, you need the following parts:

  • STM32 Discovery board
  • Breadboards (since the pins of the STM32 are positioned strange somehow, I use two breadboards to put the STM32 on, and a third one to wire up the TB6612FN with the DC motors)
  • An TB6612FG (I used the breadboard version from sparkfun)
  • Two DC motors (I use some cheap ones with gear box which I operate at 5V)
  • A power supply to drive the motors (something between 5 and 12 Volts)
  • 4 LEDs (I uses 2 blue and 2 green ones)
  • 4 resistors (something between 68 and 100 Ohms)
  • 3 Push buttons
  • A bunch of those breadboard wires to connect everything

4. The Setup

What we want to achieve at the end, is to let a user control two DC motors with the STM32 micro controller. As an user interface we are going to use four push buttons (the build in USER button on the STM32 plus three external buttons) and six LEDs (four external ons, and the two build in ones).

The external buttons we call Sab (“select motor A/B”), Scw (“drive selected motor clock wise”) and Sccw (“drive selected motor counter clock wise”), the USER button we reference to as Sbr (“break selected motor”). The four external LEDs we name Acw (“mode of motor A is clock wise”), Accw(“mode of motor A is counter clock wise”), Bcw, Bccw, the build in blue LED we call A (“currently selected motor is A”), and the green one we call B (“currently selected motor is A”).

Now let me explain, how we use the buttons and LEDs as a user interface. Through button Sab we select which of the two motors (A or B) to operate with the buttons Scw, Sccw and Sbr. The motor currently selected for operation is signaled through the LEDs A (blue) and B (green).

The selected motor is driven clock wise by pushing the button Scw and counter clock wise by pushing Sccw. Breaking the motor is done by pushing Sbr. The mode a motor is currently in, is shown with the LEDs Acw/Accw (the blue ones) for motor A and Bcw/Bccw (the green ones) for motor B. Note, that if the break button Sbr is pressed, both Acw and Accw (or Bcw and Bccw) ar lit up. Also note, that the LEDs for each motor correspond one to one to the bits send to the TB6612FNG motor controller.

The following table gives a summery of the buttons and LEDs from our user interface:

Button Description LEDs
Sab Select the motor to operate A or B is lit, indicating the currently selected motor.
Scw Drive the selected motor clock wise {A|B}cw is lit, {A|B}ccw is off.
Sccw Drive the selected motor counter clock wise {A|B}cw is off, {A|B}ccw is lit.
Sbr Break the selected motor {A|B}cw and {A|B}ccw is lit.
Motor driver schematic

Motor driver schematic

Motor driver breadboard

Motor driver breadboard

5. Wiring up the Hardware

First we put the STM32 Discovery on two breadboards. I use two breadboards because the distances of the pin rows on the discovery are some how odd. Thus I plug each side of the discovery as near as possible to the edge of a breadboard. The six pins on the head of the STM32 are not connected to the breadboards, they just stand off.

1. Wiring the user interface side

The user interface (LEDs and buttons) are connected all at one side of the STM32 (the left side when pointing the USB connector downside).

For the LEDs we wire up the following (for each LED, the long pin (“+”) goes to the STM32 side):

  • Connect pin PA8 and PA9 of the STM32, each through a 68 Ohm resistor to a blue LED. They become Acw/Accw.
  • Connect pin PA11 and PA12 of the STM32, each through a 68 Ohm resistor to a green LED. They become Bcw/Bccw.

Note on the resistors for the LEDs: the STM32 Discovery data sheet says, that VCC is at 3v3. On all of my three boards I only measured about 2v95. So if you want be sure about the resistors, measure the VCC of your board, figure out the power and current of the LEDs you use and recalculate the resistors.

At this point we keep in mind, that the pins PA8, PA9, PA11 and PA12 are the output pins of our user interface. Later on we must configure them in our program accordingly.

Now the wirings for the buttons:

  • Connect PB4 of the STM32 to the one side of a push button. The other side of the button is connected to the ground pin (GND) of the STM32. This button becomes Sab.
  • Connect PB7 and PB9 of the STM32 each to the one side of a push button. The other side of the buttons is again connected to the ground pin (GND) of the STM32. This buttons become Scw and Sccw.

Again we keep in mind, that the pins PB4, PB7 and PB9 are the input pins of our user interface. As we see at the schematic, when a button is pressed the input pin is pulled to ground. Thus we need to configure the inputs later in our program to be inputs using the internal pull-up resistor of the STM32.

The LEDs A/B and the button Sbr are already part of the STM32 Discovery board. So we do not need to wire up anything (we need to configure them later on in our program anyway).

2. Wiring the Motor Driver Side

Now for the motor driver side of our experiment. Since we do not use PWM to control the motor speed, and since we like the TB6612FNG never to go to sleep, we only need to connect the control inputs (AIN1/2, BIN1/2) of the TB6612FNG to the STM32.

For the motor control wire up the following:

  • Connect PA1 and PA2 of the STM32 to the the AIN2/AIN1 pins of the TB6612FNG.
  • Connect PA3 and PA4 of the STM32 to the the BIN2/BIN1 pins of the TB6612FNG.

As mentioned before, we do not use PWMs nor standby. Thus we wire all this pins of the TB6612FNG to 3v3 of the STM32:

  • Connect PWMA, PWMB and STBY of the TB6612FNG to 3v3 of the STM32.

To supply the TB6612FNG with power for the logic levels, we wire up the following:

  • Connect VCC of the TB6612FNG to 3v3 of the STM32.
  • Connect one of the GNDs of the TB6612FNG to one of the GNDs of the STM32.

We are almost done now. They only ting left, are the connections to the power supply of the motors, and the motors them selfs.

For the motors we wire the following:

  • Connect AO1 and AO2 of the TB6612FNG to the motor A.
  • Connect BO1 and BO2 to the TB6612FNG to the motor B.

And for the motors power supply:

  • Connect VM of the TB6612FNG to the motors power supply (I use 5V from a regulated breadboard power supply for that).
  • Connect the ground of the motors power supply to one of the grounds of the TB6612FNG.

Now double check your wirings, and do a first power up by connecting the STM32 Discovery to your USB port, and switch on the motors power supply. Be sensitive about funny smells coming form the STM32 or the TB6612FNG :-).

6. Writing the Software

For this tutorial we are going to program the STM32 on the "bare metal". The only things we use are some header files from the STM32 library to give us the needed register definitions.

Basically out program needs to do the following to make our system behave as described before:

  • board_init: Initialize the board (define IOs, set defaults)

And then in an infinite loop:

  • select_motor: check if Sab is pressed, toggle the selected motor, set A and B LEDs accordingly
  • drive_motor : check if Scw, Sccw or Sbr is pressed, operate the selected motor accordingly and set {A|B}cw, {A|B}ccw LEDs.

I am going to describe the code for those steps in the next sections.

1. board_init

The first thing to do in our program is to enable the clocks for the GPIOs we like to use. This is done trough the
RCC->APB2ENR register:

RCC->APB2ENR = 0
  // Turn on IO Port A
  | RCC_APB2ENR_IOPAEN
  // Turn on IO Port B
  | RCC_APB2ENR_IOPBEN
  // Turn on IO Port C
  | RCC_APB2ENR_IOPCEN
;

We enable ports A and B since we connected the LEDs, buttons and the TB6612FNG to this ports. We also enable port C since the build in LEDs are located on port C.

Next we need to configure the mode for the pins we use. PA0 is our Sbr button. Since the internal button comes with its own external pull-up resistor, we need to configure it as "input" floating". PA1, PA2, PA3 and PA4 are connected to the TB6612FNG, and we need to configure them as digital outputs. All the mentioned pins are configured trough the "low" part (CRL) of the GPIOA control register:

// set PA0 to input floating, set PA1, PA2, PA3, PA4 to output
GPIOA->CRL = 0x00011114;

We do the same for the pins that drive the LEDs, but on th "high" part of GPIOA:

// set PA8, PA9, PA11, PA12 to output
GPIOA->CRH = 0x00011011;

The pins PB4, PB7 and PB9 are connected to our push buttons. We want them to be input pins using the internal pull-up resistors of the STM32:

// set PB4, PB7 to input, using internal pull-ups
GPIOB->CRL = 0x80080000;

// set PB9 to input, using internal pull-ups
GPIOB->CRH = 0x00000080;

To tell the STM32 to enable the pull-ups, we must set the BSRR bits for the above pins to high (otherwise the pull-down is enabled):

// enable pull-ups for PB4, PB7, PB9
GPIOB->BSRR = 1<BSRR = 1<BSRR = 1<

Next we set the initial state for all of our output pins:

// initially switch PA1, P2, PA3, PA4, PA8, PA9, PA11, PA12 off
GPIOA->BSRR = 1<BSRR = 1<BSRR = 1<BSRR = 1<BSRR = 1<BSRR = 1<BSRR = 1<BSRR = 1<BSRR = 1<BSRR = 1<

All the above we put into an operation called "board_init".

2. select_motor

Next we need to poll our buttons Sab, Scw, Sccw and Sbr. This is done by comparing the input data register of the corresponding ports to the bit mask of the pins where the push buttons are connected to. We do this in an operation called "select_motor". Which motor is selected, we keep track of in the global variable "selected_motor". Thus we know which LED (A=PC8/B=PC9) to switch on when PB4 (Sab) is pressed. To avoid toggling, we wait until PB4 is released before we continue:

int b1;

// check state of input pin PB4
b1 = ((GPIOB->IDR & 0b0000000000010000) == 0);

if(b1) {
   if(selected_motor == 0) {
     GPIOC->BSRR = 1 << 24;      GPIOC->BSRR = 1 << 9;      selected_motor = 1;    }    else {      GPIOC->BSRR = 1 << 8;      GPIOC->BSRR = 1 << 25;      selected_motor = 0;    }    // wait until b1 released    do {      b1 = ((GPIOB->IDR & 0b0000000000010000) == 0);
   } while(b1);
}

After that we define an other operation called "driver_motor".

3. drive_motor

This operation drives the selected motor clock wise when the button on PB7 is pressed, or counter clock wise when the button on PB8 is pressed. If the build in button on PA0 is pressed, the selected motor breaks. The mode in which the motors are is indicated trough the LEDs on PA8/PA9 and PA11/PA12.

int b0;
int b2;
int b3;

// b0 is the build in button, since it is "floating" with pull-down, it must be inverted
b0  = !((GPIOA->IDR & 0b0000000000000001) == 0);
b2  =  ((GPIOB->IDR & 0b0000000010000000) == 0);
b3  =  ((GPIOB->IDR & 0b0000001000000000) == 0);

// b0: break
if(b0) {
  if(selected_motor == 0) {
    GPIOA->BSRR = 1<BSRR = 1<BSRR = 1<BSRR = 1<BSRR = 1<BSRR = 1<BSRR = 1<BSRR = 1<IDR & 0b0000000000000001) == 0);
  } while(b0);
}
// b2: cw
else if(b2) {
  if(selected_motor == 0) {
    GPIOA->BSRR = 1<BSRR = 1<BSRR = 1<BSRR = 1<BSRR = 1<BSRR = 1<BSRR = 1<BSRR = 1<IDR & 0b0000000010000000) == 0);
  } while(b2);
}
// b3: ccw
else if(b3) {
  if(selected_motor == 0) {
    GPIOA->BSRR = 1<BSRR = 1<BSRR = 1<BSRR = 1<BSRR = 1<BSRR = 1<BSRR = 1<BSRR = 1<IDR & 0b0000001000000000) == 0);
  } while(b3);
}

4. main

All the above we glue together in a main routine. There we first initialize the board, then in an infinite loop we check if a motor has to be selected or operated:

int main(void){

   board_init();

   while(1) {
     select_motor();
     drive_motor();
   }
}

Thats all. The code sure could use some optimization, but I think it is more readable the way it is.

Note on the down loadable example code: since I am using an ARM Cortex A-9 based Netbook vor development, I do not need a cross-compiler to produce ARM Cortex M3 binaries for the STM32 (my native compiler already supports that target). Thus if you use a cross compiler, you must set the "CC" and "LD" variables in the makefile to your cross compiler.

7. Downloads

Leave a Reply

You must be logged in to post a comment.