Beginners Guide to I2C on the Raspberry Pi Pico (BNO055 IMU Example)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello and welcome to a basic guide on i squared c in this video i'll go over some basics about how it works why you would want to use it and most importantly how it works with your pico i will be using a bno005 accelerometer from bosch as a sort of worked example to show you how it works but this guide will be applicable for pretty much any i squared c device that you want to use you will just have to change what you send to the device but i'll show you how to work this out feel free to skip some of the basic sections using this time stamps below if you already know a thing or two about i squared c as always the source code written in this video is available from my website and a written article version is also available both will be linked in the description so let's start with a little background to i squared c i squared c is a two wire communication protocol with each of these two wires supporting multiple peripheral devices these wires are sda and scl sda is the data line and scl is the clock line i squared c is simply a communication interface you will still need to power these peripheral devices using wires extra to these two here you can chain multiple devices together along the sda and scl lines like so there is a theoretical limit of 128 devices on the bus but practically achieving that limit can be challenging for most hobbyist projects you are unlikely to get anywhere close to that limit in order for communication to work correctly there must be pull-up resistors on this bus now i won't get into too much detail about how these work but the rp 2040 chip has some weak ones built in the rp2040 datasheet suggests that we use external pull-up resistors however luckily for us many breakout boards like so have them already included you can check by looking at the breakout board schematic and if you find pull-up resistors then you don't need external ones if you find out that you do need to use external pull-up resistors you can check out the guide by sparkfun linked in the description which explains it all a lot better than i can to connect your i squared c devices to the pico you can use any of the gpio ports labelled i squared c in the pin out diagram both the sda and scl lines must be connected to the same i squared c controller in the case of the pico that's controller one or zero so i'm going to wire up my picot to the breakout board now i'm going to use gpio pins 4 and 5 on the picot which are the physical pins 6 and 7. these pins correspond to the i squared c 0 port i will also power the breakouts using the 3.3 volts output pin which is physical pin 36 and its nearest ground which is pin 33. okay so now you have an idea about how the devices are physically connected let's check out the principle of operation of the i squared c protocol the clock line or scl line allows the data on the data line to be sampled correctly when data is to be sent the sending device brings the clock line low and then transmits data along the sda line then the receiving device will sample the data line each time the clock edge is triggered if there was no clock line present the communicating devices would have no clue at what rate to sample the data line and the whole communication process would break down thankfully the i squared c controllers handle this clock signal so we only have to define the communication rate and the controllers do the rest when we want to send data to a peripheral we send a series of frames each frame contains a series of bits in the message that we send the first frame is a 7-bit address of the peripheral followed by a read 1 or write 0 request this informs the peripherals on the i-square c-bus which device this message is intended for and the read write bit tells the peripheral whether the controller is sending data or requesting data from it after the address frame a series of 8-bit data frames are sent the most significant bit or msb is sent first in a data frame this means that the binary bit which corresponds to the highest value is sent first after all the data frames have been sent a stop frame ends the message and frees up the i2c bus okay hopefully that gave you an idea of the actual operation of i squared c let's briefly cover how you actually implement this most microcontrollers have pre-built libraries or drivers such as the pico sdk for the raspberry pi pico this sdk contains functions which handle most of the low-level hardware interactions so we don't have to we will be using these in this project to set up and initialize the i squared c port for the read and write operations there are three basic functions that we will need to use during this example for most projects these are probably the only functions that you will need firstly we initialize the i squared c communication using the i squared c in its function then we write data to the peripheral device with the i squared c write blocking function and obviously we are going to want to read data from the device and we you do this using the i squared c read blocking function the blocking part simply means that the whole program waits for this communication to occur a bit like the printf statement if you've used that before there are many other functions which are suitable for different applications and you can find them along with explanations on page 115 of the pico sdk documentation for a write request to the peripheral so if we want to write data to it we simply use the write function however for a read operation so we are requesting data we first send the address of the specific register that we want to read then we use the read function to receive this data from that register this might initially sound a little convoluted but you'll be able to see this quite clearly once we start the examples let's get into an example so i can tell you and show you how these functions work we're going to make sure when we create our project that we include the hardware i squared c libraries in our c make lists file as well as the pico standard libraries you can find out more about setting up your project in the video in the cards above in the c file we include the stdio pico standard libraries and the hardware i2c libraries we are going to use two functions in this program our main function and we are also going to create an initialization function for our device in this case the accelerometer our first order of business is to use the std io init all function in our main file our main function this will allow us to print to serial over the usb interface if you want to know more about this there is a video in the cards above where i go through printing over usb serial now let's get into initializing the i squared c communication firstly i'm going to define a constant value called i squared c port this definition takes the value i2c0 which is the port that we wired our peripheral device to then i'm going to create a global variable of the address of the peripheral when looking at the bno005 datasheet the address of the device is 0x28 you can find the address of pretty much any device that you use in its respective datasheet now in our main function we're going to initialize the i squared c using the i squared c in its function whose arguments is the i squared c ports we defined earlier and the speed of the communication in hertz i'm going to use 400 kilohertz bear in mind that the i square c communication protocol on the pico operates as a maximum speed of one megahertz but other controller devices can operate up to five megahertz for most applications one megahertz communication is plenty fast enough now we need to configure the gpio pins that the scl and sda lines are connected to we need to set them to their alternate function i squared c communication and then enable their internal pullup resistors we use the gpio set function with the arguments of the pin number and then the gpio function i squared c then to enable the gpio pull-ups we simply use the gpio pull-up function with the pin number as the argument it is important to note that these pin numbers are the gpio pins not the physical pin numbers on the board see the pico pin out for reference then we are going to call our initialization function that we just created in this initialization function the first thing that we are going to do is check to see if the peripheral device is connected properly pretty much every i squared c device has a chip id usually usually stored in the register with address zero you'll be able to find this in the device data sheet uh usually in the register map as this is a known value we can read this from the register and compare it to its expected value if they match then our chip is connected properly if they don't then we know we have a problem as you can see from the bno005 datasheet we expect this chip to have the id or the hex value of a0 this will be a perfect example of a read operation where we have to use both the write and read function in order to get the data that we want from the chip firstly before i start i will add a short delay to give the bno005 some time to start up and sort of configure itself how it wants to we create a variable called register or reg in this case which takes the value of the register that we want to read from we then create another variable in the form of an array to hold the data we receive then we use the i squared c write blocking function with the arguments of the i squared c port the peripheral device address the address of the variable we stored the register variable in the size of the data transfer one byte in this case and finally true as shown on the screen the boolean true argument means that the controller retains control of the i squared c bus it does this by not sending the stop signal at the end of the message and this sort of functionality is useful when we are performing a read operation as we are using the right function then immediately the read function the read function that we use has many of the same arguments however we use the array we created to store the received data and the amount of data we expect to receive again in this case is one byte and we can set the boolean argument to false to tell the controller to release control of the i squared c bus i will then create a very simple if statement to compare our received value to the one we expected if the address is what we expected then we can say the chip is connected correctly and the i squared c communication is functioning properly you could test the connection now at this point by building and running the program however i already know that my device is connected properly so i'll skip this step the rest of our initialization function can be used to send configuration commands to the device for example i will use the write function to tell the bno005 chip that i want it to use its internal oscillator if we look in the datasheet we can see that by setting the register system trigger which has the address of 3f to a binary value of 0 0 1 0 0 0 0 0 4 0's i think it will use its internal oscillator and trigger a reset it is important to note that some compilers can only handle a hex format so i will use this it is very straightforward to convert from binary to hex and vice versa using the windows calculator app in programmer mode if you want to learn more about sort of bitwise operations binary and hex let me know in the comments and i might create a video about it so for a simple write operation i will create an array of two unsigned 8-bit integers the first value takes the register address that we want to send and the second value is the data that we want to transmit then we simply use the i squared c writes blocking function to send the array to the peripheral note that we have changed the data size to 2 as we are sending the register address and its new value at once as we are using sorry as we aren't using other peripheral i squared c devices it doesn't really matter if we give up control of the bus so we can use the false boolean value at the end of the function when you're using your own device perhaps not the bno005 whatever i squared c device you're using you can use this process to write data to the registers that you need to you will obviously have different values but you can find all of these in the respective data sheets of your peripheral there is a lot more configuration code that i need to do to make this accelerate accelerometer function correctly but as i will use the same process that i just explained i'll copy and paste it in as there is no point repeating myself you can find the source code linked in the description back in our main function i am simply going to create an infinite while loop which constantly reads the x y and z acceleration registers and prints them over the usb serial interface before the loop i will declare some variables to store the x y and z acceleration values both the received 8-bit values and combined floats here we use exactly the same read then write sequence that gave us the chip id except with different registers as each value of the acceleration is stored across two registers and there are three axes we need to read a total of six registers this would be a really clunky process if we had to do a right then read sequence for each register thankfully for us the i squared c registers automatically increment this means that we can change the expected received data amount to six bytes and we'll read the six registers the register address that we send so in our example we want to read the acceleration registers starting at the hex address of 0 8 and ending at 0d we do this simply by sending the start address with the i squared c writes blocking function and then following it up with the read function with six expected bytes with that done the six register values are stored in our data array a little bit of logic is required to combine two registers into one acceleration value we simply shift the most significant bits the most significant eight bits up eight places and using the or function with the lower 8 bits i will divide the acceleration values by 100 to get the correct order of magnitude output i will use the printf function to print the data to the serial monitor and also add a short delay of 100 milliseconds using the sleep ms function now that's the coding finished we can now build this project and upload it to the pico open your serial monitor of choice and point it to the com port which your pico will be interfacing with the baud rate will be 115 200. you should now see the acceleration output change as you move the breadboard around now obviously if you haven't used this accelerometer then the changes of whichever parameter you're measuring say temperature pressure will change on the serial monitor as you adjust them so hopefully this video has helped you learn the basics of i squared c and how to use it on your pico if this video has helped you then please consider leaving a like and subscribing and feel free to leave any feedback or requests in the comments below
Info
Channel: Learn Embedded Systems
Views: 55,999
Rating: undefined out of 5
Keywords:
Id: 092xFEmAS98
Channel Id: undefined
Length: 16min 57sec (1017 seconds)
Published: Thu Feb 11 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.