| Terms of service | ||||
|  | Brokking | .net | Let's keep it simple |  | 
| 
 | Arduino for STM32 + MPU-6050 == Improve your programming skills!This page contains the full script that I used for making this video. This page contains the full script that I used for making this video. This is the STM32F103C8T6 microcontroller board. To keep it simple I will refer to it as the STM32 during this video. It's a powerful 32bit microcontroller that runs on 72MHz. The beauty of it is, that after some simple modifications in the Arduino IDE the STM32 can be programmed by using just a FTDI programmer. I already explained the simple modifications of the Arduino IDE that are needed in a previous video that I will link in the description below. In this video I will connect this MPU-6050 gyro to the STM32 and poll data from it via the I2C bus. And of course I will discuss some issues and problems that you might run into when doing this. But as always once you know what you are doing it's very simple. So, let's get started. As already explained in the previous video the STM32 microcontroller runs on 3.3V and not 5V like the Arduino Uno. Despite this 3.3V core voltage the STM32 has a very convenient feature that is explained in the datasheet. In this pinout diagram the various pin functions are described. For example the function of the PB6 and PB7 pins. As you can see here PB6 represents the I2C1-clock pin and the PB7 pin represents the I2C1-data pin. These are the pins that will be used for connecting the MPU-6050 gyro. The notation FT that is added to most of the IO pins holds a key feature. When we scroll down we can see that the FT notation means that the pin is 5V tolerant. In short, it's possible to connect a 5V signal to every pin that has the FT-notation. Now, there is only one thing to keep in mind as you can see here. When connecting a higher voltage the internal pull-up and pull-down resistors must be disabled. These resistors can only handle 3.3V and not 5V. So, the question is: are the pull-up and pull-down resistors enabled when the PB6 and PB7 ports are configured as an I2C bus. Well, let's have a look at the datasheet. In the general-purpose IO section we can see that the ports are configured as open drain when the alternate function I2C is enabled. Meaning that the pullup and pulldown resistors are disabled and that we can use a 5V I2C bus voltage. Ok, with this information it's time to connect the MPU-6050 gyro to the STM32. Because the pins are 5V tolerant the following connections will do the job. Connect the VCC of the gyro to the +5V of the FTDI programmer. Connect ground to ground. Connect the SCL or clock from the gyro to pin B6 of the STM32. And finally connect the SDA or data from the gyro to pin B7 of the STM32. And that's it. The MPU-6050 is now ready to use. For testing I will use this very simple program that I originally made for the Arduino Uno. Here the wire library is included so we can use the I2C functionality of the STM32. Next 3 integers are declared that will be used to store the gyro information. The serial port of the Arduino is used to print the results to the serial monitor of the Arduino IDE. With the wire.setClock function we can set the I2C clock frequency to 400kHz. This function needs to be called before the wire.begin function. Otherwise the I2C clock will run at the default speed of 100kHz. Next the I2C bus is initialized with the wire begin function. After this function the I2C bus is ready for use. First the program will set the power management register of the MPU-6050 to 0. This will wake up the MPU-6050 and activates the gyro's. In the main loop the program sends the register from which the data should be polled. As you can see here in the datasheet the 0x43 register holds the first gyro output byte. Now that the MPU-6050 knows from which register we want to start reading a request is send for 6 bytes. Meaning that these 6 bytes are polled form the gyro and are stored in the memory of the microcontroller. Now that the 6 bytes from the MPU-6050 are in the memory of the Arduino we can retrieve them with the wire read function. In the datasheet of the MPU-6050 we can find that the result of the 2 bits is a 16bit two's complement value. This can be achieved by combining the high byte and the low byte value together into one 16 bit signed value. And for the X-axis that is done in this line. As you can see the first byte that was polled from register 43 is shifted 8 positions to the left. The other byte that was polled from register 44 is added to the most right side of the Gyro_X variable. And now integer Gyro_X holds the raw 16 bit two's complement value from the gyro. In this part the Gyro_X, Y and Z values are printed on the serial monitor of the Arduino IDE. And that is all there is to know about the code. For convenience I will first show you the normal serial output by uploading this program to an Arduino Uno. As you can see the positive and negative numbers nicely follow the movement of the gyro. After this test it's time to upload this code to the STM32 as explained in my previous video. I will make no modifications to the code and just click upload and open the serial monitor. Ok, these last two values look ok, but this first one is definitely off. And look what happens when I move the gyro. All the axis seems to be acting weird. So what is going on here? Well, it's called a two's compliment problem. But before we can fully understand the problem we need to know what two's complement is. Here I have an byte where this most right bit represents a value of 1. The second bit represents the double value of the previous bit. So 1 times 2 equals 2, the third bit will be 2 times 2 equals 4, the forth equals 2 times 4 and so on. When the third and fifth bits are set the decimal value can be calculated by adding the values of the bits. As you can see the result is 20. And when all the bits are set the total result will be 255. Ok, this makes sense so far. The second challenge is negative numbers. Most computers and microcontrollers are using the so called two's compliment method. The simples way to understand this method is to invert the value of the most left bit. So 128 becomes -128 in this 8 bit example. Have a look at this example where all bits are set. By adding all the bit values the result becomes -1. And here is another example. In short, the most left bit plays a key role when it comes to negative numbers. As already explained the output of the gyro is a 16 bit two's complements value. So, when the gyro outputs -100 the binary representation becomes…. Now let's have a look at our problem. At the beginning of the program we declared some variables as integers for storing the gyro data. When using the Arduino Uno integers are declared as 16 bit two's complement variables. But when using the STM32 an integer represents a 32 bit two's compliment datatype. And that's a problem. Because look what happens when the 16 bit gyro value is loaded into the 32 bit variable. The most left bit of the 32 bit two's complement variable can never be set to one. As a result the gyro's output in the serial monitor will never be negative. The solution for this problem is to declare the storage variables as 16 bit signed variable and not as an integer. So when I change int into int16_t the variables are declared as 16 bit instead of 32 bit. And when I run the modified program the outputs are the same as with the Arduino Uno. So, now that everything is working as expected it is time for a final check. I will connect the oscilloscope and have a look at the quality of the clock and data lines. Something that I always do when designing a new circuit. And in my humble opinion so should you. Now, most people will not see these clock and data signals because they don't have an oscilloscope. But depending on the requirements the I2C bus normally runs on 100 or 400kHz. And when I check the clock frequency with the oscilloscope we can see that the clock frequency is….. well… almost 400kHz. And that's great, we got another problem that we have to solve. To get a better understanding of what is going on we will have a look at the basic I2C schematic. Here you can see the PB6 and PB7 pins of the STM32. And on the other side we can see the MPU-6050. As already discussed the outputs of the STM32 and MPU-6050 are configured as open drain. As a result, the only thing that the STM32 and MPU-6050 can do is close these switches and connect the data and clock lines to ground. This will represent a logic low or 0. To create a logic high or 1 these two pull-up resistors are needed. When the switches of the STM32 and MPU-6050 are open these resistors increase the voltage of the clock and data line. To generate a clock pulse the STM32 will close this switch and connect the clock line to ground. As a result the voltage on this clock line will drop to 0V and a timer is started. After a predefined time the switch is opened. Now the STM32 will wait again for a predefined time. After this so called rise time the voltage on the clock line is checked to see if it has reached the "standard IO input high level" that can be found in the datasheet of the STM32. In this case approximately 1.5V. This check is done because a slave device can hold the clock pulse low when it needs more time for processing. If the voltage has not yet reached the 1.5V threshold voltage level the STM32 will keep measuring the voltage of the clock line. During the measurements the timer is set to hold. When the voltage reaches the 1.5V threshold the timer starts counting again. After another predefined time the STM32 will close the switch again and generate the next pulse. Ok, here's the problem. The clock and data lines can be compared with very small capacitors. Via the pullup resistors these capacitors are charged after the switch of the STM32 is opened. When the resistor values are too high in comparison to the capacitance values of the clock an data lines, the charging of the lines will take longer until it reaches the standard IO input high level of 1.5V. The predefined rise time is easily exceeded. As a result the STM32 has to wait before it can close the switch to generate the next clock pulse. And that is why the clock frequency is of. On the breakout board of the MPU-6050 there are 2 10k pullup resistors. In short, these resistors values are too large. When I add 2 extra pullup resistors of 4.7k the clock and data lines are charged more quickly. As we can see on the oscilloscope, the STM32 does not have to wait anymore and the clock frequency is 400kHz spot-on. The last thing that I want to address is that there have been some changes in the STM32 for Arduino add-on between this video and my previous video. In the past the software based I2C library was used as the standard library because there were some problems with the hardware based I2C library. The downside was that due to inefficient programming the software I2C library was not capable of generating a 400kHz clock. As it turns out the problems with the hardware based I2C library are fixed. As from now the standard wire library uses the hardware interface of the STM32. This makes it possible to use the 400kHz clock function. So make sure to update the STM32 for Arduino so you can use the 400kHz I2C clock speed. And that wraps it up for this video. As always I hope you learned something and if so please take the time to give this video a thumbs up. Thank you for watching and see you next time. 
 |   |