Raspberry Pi Pico and Arduino Uno chat via I2C

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello folks my name is tim and welcome back to my channel so recently i've been reading a bunch of articles across the internet that contrast and compare the raspberry pi pico to the various arduino boards and esp controllers now those articles are trying to ask the question which is the best microcontroller and well as hobbyists we understand that the best microcontroller is whichever ones rattling around in your parts box when you need it that being said it is true that each of these ecosystems have their own strengths and weaknesses so today i'm going to show you how to combine the raspberry pi pico with the arduino uno by using the inter integrated circuit communication protocol better known as i squared c we're going to be able to have the best of both worlds so let's get started okay so before we begin we need to understand a little bit of theory about how the i squared c interface actually works we won't be spending very long on this piece because there's a lot of excellent material out on the internet already so if you go do a quick search you'll find plenty to read however we do need to know a little bit of the foundations of this stuff so let's take a look first of all you need to know there are two wires in this communication protocol it's also sometimes called the two-wire serial interface and those wires are sda and scl and you can see the signals that are sent on them mapped out here so initially both signals start out high to trigger a communication the sda line is pulled low followed by the scl line and that's the first step in opening a communication across the i squared c bus once that's done seven bits are pushed out on the sda line with seven corresponding pulses on the scl line those seven bits are a device address so you can have multiple devices on the i squared c bus and each device is identified uniquely by its address and when we want to send a message we need to say which device we're interested in by providing its address following the address the eighth bit of that byte is a read or right indication flag because we can either be writing data to the device that we've identified or reading data back from it so that's how we tell which one of those activities we want to do finally we receive an acknowledge this acknowledge actually comes back from the device that we selected using the address we either get a positive acknowledgement the sda line is pulled low and that means the device exists on the bus and is listening to us or we get a negative acknowledgement and that means we're screaming into the void and the address we've used is incorrect and that's all there is to sending the device address and that's the first step of an i squared c communication now the second step is to send a memory address so to do that all you do is push eight bits out onto the sda line with eight corresponding pulses on the clock line scl and those eight bits specify a memory address within the device that we've previously identified in the first step in order to communicate you give two addresses the device you're interested in and an area of memory within that device that you'd like to either read from or write to so for example if you had several sensors that could detect multiple things you would first identify which sensor you're interested in with the device address and then you might identify which property of that sensor you're interested in with the memory address and that's the second stage of an i squared c communication and again we have an acknowledgement now for the third and final stage of the communication we're basically streaming data so we push out onto the sda line eight bits and eight clock pulses on the scl line to correspond with them and that represents a byte of data that's either going to be written to the target device or is being sent from the target device back to the requester after each byte of data we receive an acknowledgement or we send an acknowledgement depending on which direction we're going in and that indicates that that communicated byte was successfully transferred and you can communicate as many bytes as you're interested in finally once we've sent all the data that we'd like to send we can end the communication by triggering a stop condition and that's the basics of i squared c communication there's a little bit more to it some complexities and edge cases and bits and pieces that we've omitted but that's enough for us to get going and start understanding this in fact you don't really even need to keep all of this information in your head because a lot of it is abstracted by the software libraries that we're going to use in a moment so really knowing this stuff is a good idea but it's not essential so now let's take a look at the circuit we've built to allow our arduino uno to communicate with the raspberry pi pico so let's take a look at how this is put together here on the breadboard we obviously have our raspberry pi pico but just above it you can see this second little module here this is a logic level shifter and it's needed to account for the fact that the pico runs on 3.3 volt logic but the uno runs on 5 volts now putting 5 volts directly into the i o pins of the pico isn't a particularly good idea and we actually risk damaging it if we do that so this module basically converts the uno's 5 volt signal down to 3.3 volts for use by the pico and the pico's 3.3 volt signal up to 5 volts for use by the uno so it basically lets us use whichever voltage these boards are happiest with this particular example is a four channel unit and all you have to do is connect the appropriate voltage and ground to the low side and similarly connect the appropriate voltage and ground for the high side and then it lets you convert up to four signal lines you have a low side pin one and that maps through to the high side pin one and vice versa two goes to two three to three and four to four so it's a very straightforward sort of relay type situation and it's quite easy to use okay so let's trace the wires through and see what connects where now i've made sure to use consistent colors throughout so that should make it a little easier to follow along on the pico side we have our 3.3 volt supply and that's taken from physical pin 31 that's the 3.3 volt output from the pico and that's connected through to the low side voltage input of the logic level shifter we then use the closest round pin and that's physical pin 38 here on the picot and that's just connected through to the ground on the logic shifter as well so that completes the power circuit for this in addition to that we have these two signal lines this first blue wire here is connected to gpio pin 16 that's a physical pin 21 on the picot and it's the i squared c data line and that's just connected through to the first input on the logic level shifter here the second wire this yellow one this is connected between gpio pin 17 physical pin 22 and the second input on the logic level shifter and this is the i squared c clock line now on the 5 volt side for the uno the situation is basically the same only in this case we're taking a 5 volt line and ground from the appropriate pins on the uno side and the two signal pins are connected up to analog input a4 and a5 the clock signal is sent into a5 and the data signal is sent into a4 and those are the input pins you use for i squared c on the uno board so that's all there really is to wiring up this thing it's pretty easy actually the only slightly complicated thing is the little logic level shifter here but even that's not that big a deal before we dive into the software side of things there's a few points we need to talk about firstly the raspberry pi pico has two separate i squared c interfaces and they're broken out at various points amongst the i o pins now that's very handy if you need two independent buses maybe the pico is connected to some downstream peripherals but also needs to receive control signals of its own so it can be quite helpful however you need to make sure you use a matched pair of data and clock pins connecting the clock from one and the data line from another obviously won't work next we need to go over some terminology the i squared c bus was invented back in the 80s and they chose to use some names that we wouldn't find acceptable these days the main device on the bus was called the master and any connected device that isn't the master is referred to as the slave device now for obvious reasons i won't be using those terms but if you read any of the old documents online that's probably what you see for this video i'll be using the terms controller to refer to the master and peripheral to refer to anything that isn't a master and in this example we're going to be using the pico as our controller and the uno will play the role of the peripheral though it makes no real difference as far as the wiring is concerned and it's a very simple change in software if you wanted to reverse those positions so finally let's talk about pull up resistors i squared c is what's called an open drain circuit that basically means the circuit is in the high state normally that is when it's not doing anything to trigger the bus you need to drive it low i.e it's low voltage active to keep the bus in the high state however resistors are usually connected between the voltage line and each of the signal lines and for obvious reasons those are referred to as pull-up resistors because they pull those pins high now some microcontrollers have pull-up resistors built in the arduino mega for example has 100k resistors on its i-squared c interface pins so you may not need any of your own however the arduino uno that we're using here doesn't have any pull-up resistors and i couldn't actually find any information about whether or not the pico had pull-up resistors so in the end i just had to experiment i tried adding resistors on the 5-volt side with the arduino and that worked perfectly fine and i tried again adding them on the 3.3 volt side with the picot and that worked fine so then i tried removing them completely and it still worked fine so that suggests that perhaps the pico has pull-up resistors built in i don't know that for sure and if anyone does please leave a comment because i'd be very interested and i'm sure others would as well but for the sake of simplicity since it all works without pull-ups i'm just going to omit these pull-up resistors and we won't bother with them your mileage may vary and depending on what you're doing with your i-squared c-bus you may need to add some so i've actually linked in the description a document by ti that describes how to calculate the appropriate resistances that you'll need for pull-up resistors depending on what you're doing so hopefully that's useful to anyone who does need to add them okay enough talking time to take a look at the software side of this okay here we are at my raspberry pi 400 desktop and i've loaded up both the micro python program that we're going to be running on our raspberry pi pico and the arduino sketch that we're going to be running on the uno so as you can see they're both very simple programs the source code of both of them fits quite comfortably on a single screen so first of all we'll take a look at what's going on on the pico now we're going to import some modules here just at the top and the interesting one is this i2c module this is the software interface to i squared c that's been provided by the micro python sdk authors and this is a reason why you don't really need to understand how i squared c works at a theoretical level because all of the details are taken care of for you by this little module so there you are it's always a good idea to understand it but um if you can't quite wrap your head around it or you're not really interested in the theory then you don't really need to know it so once we've got the import taken care of then we've got this little message size variable first of all this is just a little constant i'm using and here we actually create a i squared c interface so this little object i2c you create it with this function call what you need to do is you tell it which of the two interfaces on the raspberry pi pico you would like to use in this case we're saying interface zero then you pass it the pin you'd like to use for your clock line and the pin you'd like to use for your data line and we're using pins 17 and 16 that's a gpio pin rather than physical pin and finally you need to pass it the frequency that you would like the bus to operate at now i squared c has a number of different frequencies that it can operate at here we're asking it to run at 100 kilohertz and that's the slowest speed that it supports you can run it much much faster than that but for our demo here 100 kilohertz is plenty okay so once we've created the little interface object the next thing we're going to do here is use this i2c dot scan method now that actually scans the bus and collects the address of all the connected peripherals returning it in a list now because i know that there's only one peripheral on this bus i'm going to take the very first item in that list and store it off as the address of uno so if you don't know what's on your bus or you don't know what the addresses are of those peripherals then this little method will help you to find them so it's quite useful right now that we have the address of our peripheral we can write a message to it so here i'm just using the write to method i'm saying the address of the peripheral on the bus and the message i'd like to send and we're going to introduce ourselves we're going to say hi from pi because that's who we are now immediately following the right we have a little sleep now i needed to add this in because if i attempted to do the next operation which is a read from operation immediately after the write the uno wasn't in the right state to be read from and this just generated an os error so basically we were running it too quickly and the uno hadn't quite caught up to where it needed to be so a little sleep here took care of that and everything worked fine afterwards so here we go i2c dot read from so this is how we get data back from our peripheral now as the controller of the bus we can basically read from any one of our peripherals so we pull data from the peripheral rather than the peripheral pushing data out to us so a peripheral wouldn't do a equivalent to this right to operation it would wait until somebody attempted to read from it and then it would provide the information that was requested of it so that's the difference at the software level between the controller and a peripheral device anyway once we get back our message so we just passed the address here and the message size that's a maximum number of bytes to read back then we just store it into the variable a here and print it out so that's just going to print out into our shell down here the message that we received from whatever peripheral has this address and we know that that is the uno once we're done with that we'll just print a little done message and that just indicates the program has completed and that is it for the raspberry pi pico side of things very very simple little program hardly anything to it really so using i squared c is a very straightforward thing to do okay so let's take a look at what's going on on the uno side of things so here this is our little arduino sketch that we're running first of all we import the wire header file and this wire library is basically equivalent to the i2c module that we're using over here we define a couple of constants here so this uno adr value this is the peripheral address of the uno on the bus i've just picked nine here and this is a very arbitrary choice you can pick any seven bit value you like and put it in there should work so long as it's unique i i gather from reading on this subject that there are some addresses which are reserved by philips the original creators of the i squared c bus but um i haven't ever encountered a situation where an address didn't work so um any seven bit value should be okay for your peripheral so after that we have the rest size that's the response size and that's um 15 bytes because that is the length of this message here hi from arduino and that is going to be our response that we'll send back to the pico when it issues this read from command here on line 12 of the micro python program right so in our setup method this is the first method that's called in a arduino sketch and it's just a one shot setup function um we first of all say serial.begin now that has nothing to do with the i squared c communication that we're creating it's simply so that we can establish a serial link between the arduino board and the raspberry pi 400 the ide that's running here so we can see the output from the from the uno and know that the program is working so immediately after that we then do a wire dot begin and this is where we set up our i squared c communication and we pass in the uno address now if you don't pass in an address when you call this wire.begin then you set yourself up as the controller but because we're passing in an address it knows that we are a peripheral and this is the address we should have finally we create two event handlers now these event handlers are basically methods that will be called automatically by the wire library when various things occur so we don't need to call these things explicitly they will be called for us at the appropriate time so we have an on receive event handler and that will be called when we receive data that's been sent to us from the controller so in this case when we say here in the micropython sketch i2c.write2 that will cause the data receive event handler to be called on the uno so the next event handle we have is the on request and this is called when the controller wishes to read data back from the peripheral device in this case the uno and that corresponds to the i2c dot read from function call here on our micro python side so that's what will happen when you make this call here this event handler will be fired on the uno okay so that's all there is to set up looking at the loop function well there's nothing in there really we've just put a small delay in but that's it and this will just keep looping around and around and around and around for as long as the arduino uno is powered but it's not actually doing anything we're just going to wait until our various event handlers are called so looking at the first of the event handlers this is the data receive event handler first of all we have this little integer that's just a counter we have a buffer here this is a character buffer of rest size bytes because that's where we're going to store the data that we receive as we read it from the i squared c bus we zero it just to make sure that there's no uninitialized memory or other junk in that buffer and then we dive into this little while loop here and this is saying while wire dot available wire dot read a byte of data from the bus and stick it into the buffer this buffer here that we created earlier and increment the counter i so we basically read the first byte into the first slot the second byte into the second and so on and so on and so on until there's no more data available to read now this is okay for our little demo here because i know we are only ever going to receive at most 15 bytes we're actually not going to receive a full 15 bytes we're going to receive the length of this message here but that's less than 15 so that's perfectly okay but if you were doing this in a real situation you wouldn't want to write your loop quite like this because you don't know how many bytes are actually going to be pushed out over the bus and your buffer may not be big enough so we don't do any bounds checking basically here so that could be a source of a bug if you're not careful now once we've received a little message and it's in the data buffer we can just print it out so we do a serial.print receive event then we do a serial.print the content of the event so that just prints out over a serial link just to say hey we got some data and here's what the data was and that is all there is to the data receive event handler so next we move on to the data request now this method again is very simple we have a little byte array which is again of rest size bytes we fill that byte array byte at a time from the string that we stored up here so that just says hi from arduino now we need to do that just to convert between the characters of the string and the raw bytes that we want in the buffer just to make the interface happy uh once we've done that we can then just use this single wire dot write method here we pass it the buffer that we want to send and the size of the buffer so unlike wire.read which always read back a single byte and needed to be done in a loop wire.write just writes the entire payload over the bus and we're done so then we'll just print out a little message here just to say that we sent a response and that is it that's the entire sketch on the arduino side so let's try to run this program and see what happens since the picot here is the controller i'm going to run this side of things and we'll see what we get excellent so there we are we can see we've got the message that we expected to see hi from arduino brilliant so that means that this part at least is working fine we have read from the arduino and it has responded with the message we expected to see okie dokie then let's take a look at what's going on on the arduino side then so what we need to do for this is we have to use our little serial monitor here so i've just opened up the serial monitor tool you can find it under tools serial monitor there we go and this will show us the messages that are being printed back from the arduino so here we are we'll run our controller again and yeah there we go excellent so here we can see we've received an event this first receive event i think corresponds to the bus scanning activities that we're doing here on line eight so we'll ignore that but here we've received the event that we expected to receive and the message hi from pi so there we are we have the raspberry pi talking nicely to the arduino and the arduino talking nicely back to the pi we've successfully communicated between these two boards using the i squared c interface now here obviously i'm just sending over text strings because that makes it nice and easy to see what's going on but of course you can send over binary information or whatever anything you like really to control hardware connected to either of these boards and basically get the best of both worlds you can make use of the wonderfully mature and complete ecosystem offered by arduino and the power of the raspberry pi pico so you can basically have your cake and eat it thanks to i squared c i hope that was interesting and thank you for watching
Info
Channel: Tinker Tech Trove
Views: 3,697
Rating: undefined out of 5
Keywords:
Id: Wkk1aNWj6sQ
Channel Id: undefined
Length: 26min 14sec (1574 seconds)
Published: Sun Mar 07 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.