Using I2C for any device on STM32 with HAL | VIDEO 26

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey everybody welcome to my next video and in this one I'm gonna show you how to use the ITRC peripheral on the stm32 platform many other thoughts we're gonna say today can be also applied to the Arduino and the actual inspiration for this video is from my best days when I use the Arduino and heavily relied on libraries released by different manufacturer of these cute little boards that includes the IC in choice and then they included the library and I relied on those libraries that are pre-written by certain people but if those libraries weren't available I weren't going to choose that appropriate part but then came the days when I had to use a certain IC because it was the best for the job and it didn't have the profit library along with it so that's when I needed to learn the I squared C and how to use it by myself and on the a string 32 along with Hall it's very simple to include your own libraries and to make your own I screwed C interface type libraries and I'm going to show you today on two examples on two different parts if you're here just for the different commands and the hardware installation you can jump to the links down below there are gonna be time stamps but for everyone else that just want to learn how it works so you can do this on your own stick to the video and let's go this is a lovely page that I found it's an analogue devices page on the I squared C so most of the images from this video are gonna be from this page and this is what I'm gonna be using to describe the ice crystal referral and I'm gonna also include this link in the description so you can read it by yourself so the ice crystal peripheral is very simple to use from a hardware perspective at least it comprised but only two pills called SDA or silver data and SEL or serial clock these spins are for only thing that you need for the connection of all the devices in the I screwed see net the ice curtsy is a bi-directional line so the data can flow both ways and it's a half-duplex so the data can only flow one way at a time so it's not like UART where the data can flow one way and another at the same time or like SPI but it also has a transmit and receive line separately it has a hierarchy where there's a master or multiple masters and a slave and why do we have this pull-up resistors that's because there could be many devices parallel as you can see connected to the same line the same master or two masters and this is done by having the lines all the time on high pulled passively by these two resistors over here and all the devices including the master can only pull these lines low but the difference is that the master is the only one that can control the clock line and make it go up and down at a different rate at the standard rate which is called is a hundred bits a second or the 100 kilohertz and the fast mode which is 400 kilohertz there are also the ultra-fast ones that can go into multiple megabits per second so you can have multiple slaves one master or multiple of those so the idea is that master is the only one that can speak and when the appropriate slave is addressed by its own unique address then the slave can respond with data so I Square C runs also in packets of 8 bits much like all the difference interface like spi and UART so in order for the slave to know when the master is going to talk there is a start and stop condition the start condition is described over here so when the data line goes low and the clock line is high and the same for the stop condition with a stop condition when the data goes high and the clock is already high so these are two conditions that the slaves can use to know whether the master is talking or not and because we have so many different devices parallel on the same network how does each slave know when it's being addressed to well that is solved with the addresses so each slave has its own unique address in the same network so you can only have different address devices in the same network otherwise that could talk over each other that's why each different device has to has its own address and as it solved by each device having its own same with address although the data packet is beat the address of the device it's only the first seven bit the last or the least significant bit is the read or write bit this is the bit that the master uses to let the slave that is being addressed with this unique address whether the master is going to read from the slave or write to it so this is one differentiator so the slave knows whether the data is going into it or out of it so when the master is sending or receiving data from the slaves this is how it shouldn't look like so the first bit or the first byte that is being sent from the master is the command byte while the master is addressing the particular slave so the first seven bits of this byte are the dress bits and the least significant is the read/write bit after that the slave responds with an acknowledgment so that how the master knows that slave received it and over here you can see that this part of the data is low which would otherwise be high because the data line is pulled naturally high with those resistors after the master sees that the slave responded it's gonna continue transmitting data and this data is sent right after it with an acknowledge and then the stop condition but devices don't just have maybe one register many do I have an example over here when one device has one register and the other has four so the master or otherwise the slave needs to know which part of its memory the master wants to read or write to so that's why we have different sequences of the data so again the first part is the slave address whether the master wants to read or write and the next is the address usually so this is the address of the memory inside of the slave device so if the snare device has four different registers numbered 0 1 2 3 then this byte should include that number so that the slave knows from which or to which of its registers the master wants to read or write to and then following that should be the data into or out of those registers here is an example for LTC two nine four six I think this is a data or battery in monitoring and this is the one way that it can go so the first swing is the start condition address of the device either reading or writing in this case we want to write to it then the device responds with the acknowledge and then it's the command in this case it would be the memory location of the device so we are writing this memory location okay it acknowledges then again we start in the next setting again we're going to address the device by its address but now the readwrite register is readwrite bit is going to be one so now we want to read and then the slave responds with the data from the register at this location that was accessed before and again acknowledge and start a stop condition and that's it if you having trouble understanding the protocol heart work just go back in the video in front until you understand it so basically it's a sequence of letting each part you know what is going on it's a very simple and primitive process and it's the simplest kind of communication even people would have if there was an alien coming from the space so it's really who I'm writing or reading to from where from your place we're reading the writing tour so this is basically the structure of I squared C sequence but we're gonna see how each each manufacturer implements this depending on the device specification so for first example let's see the max 302 or 5 which is the temperature sensor that we cannot be using this is a fairly modern this datasheet was at least revised in 2016 and this is the schematic for this part as you can see here the data lines here is the output signal pin that can be current used for certain triggers supply pins and the data pins these data pins are used to configure the address of this device this is very handy if you want to use many of same devices on the same as could see network because each device has to have its own unique address that's why it's important to distinguish them that's why this kind of devices can or some don't come with different address configuration pins these pins configure the internal address of this device and in this case we'll go to pinch a line the different connections of these three pins to either grant or supply or the data pins can yield the different address in this case we have two by four by four different choices so 32 different address for this I see so here you can have 32 of this exact same part number Isis on the same data line which is very handy now for the contrary let's go to this one so this is the ADC that we're going to be using it's an ad a seven eight two eight it's a 12 bit 8 channel SAR ADC exactly uses the I squared C but as you can see this is a beurre Brown part so this is right after the merge so it's a very early part so it's revised by 2005 and published in 2001 so it's kinda old but it's very simple and it works so this one only has you could say 3 bytes of registers or two different registers the first is the configuration register which is this on this page this is the command byte it's called so this is the configuration of the part and then there are 2 pi 2 bytes for the data because the data is 12 bit because this is a 12 bit ADC there has to be two 8-bit registers for the 12 bits of information and the first four of the first byte are just 0 and this part also has two data pins as you see by the block diagram of this device it also has two pins for setting its address a 0 and a 1 and we go down to the comment byte the address bar can be configured by a fixed number over here and then these two pins so either these pins are high or low the address of this device changes so case four of these exact devices that have this kind of start can be implemented on the same data line the next one I want to emphasize and it's really important is that addresses are seven bit okay so the first seven bit so from most significant bit to the bit one those are the address bits because the least significant bit or the bit 0 is the read/write bit so when we are applying the address of the device this it implies this whole byte so this whole byte is called the address of the device although this one is the actual address of the device and this one is the function you could call it like that because it describes the function of what we're gonna do with the device so when you address the device you have to take the 7 bits and left-shift them by one place so they have an empty space over here and the other seven bits of the byte populated by at address so you can pop in your read or write bit over here and if we look what I mean by that with these two manufacturers over here we can see already the address of the device is over here but the whole address but that gonna be sent to the device is this whole byte and if you take all these numbers and we take them and convert them into hex and have these two pins let's say default to ground so it's gonna be 1 0 0 1 0 0 0 this whole address of the device will be X 48 in hex and let's go to this other device and look what's it default configuration if all the distress means are at ground it's 90 but wait it's the slave address byte it's not the 7 bit address of the device it's the whole bite so this 90 is already left shift at address of this device so if we just remove the last 0 of the binary representation of this address or we write shifted to get the raw device address it's it gets out to be 48 which is the same as this one so that's why for this device I have a 0 on high so this the address of this device is now instead of 48 it's 49 so this device has the address of zero zero zero so 48 and when it's left sheeted it's gonna become 90 and then the first byte it's manipulated either one full read and 0 4 right whereas with this one we put in the 48 or disguise 49 and then left fitted by one place and apply the read right so you have the point of this is that different manufacturers can already provide you with the 7 bit address which you can see it over here or the already left shifted address like here but you should always consider it like this plus you also have to manually add the 1 or 0 bit and I'm gonna show you in the STM next now I mean my ID I have a sample project which is just a blank project that only has the clock and programming lines over here nothing else so before selecting the appropriate pin we have to know which pins can hold the I screwed see a line for that and for this pin I used a simple drawing that can display different functions of pins and we can see in red these are the I squared C lines over here I squared C 3 2 1 and 1 over here and for my case I'm using b6 and b7 so we can go to our I see over here and select b6 and we can see I squared C 1 0 'clock and PB 7 D I square C 1 zeros data but these pins are now yellow because we haven't configured the peripheral yet so let's go to connectivity I squared C 1 and I squared C and here we have the settings and the pins are now in green so the peripheral is initiated you see that in this case for this processor we have 2 mode standard and fast mode so the fast mode is the 400 kilohertz one that we talked about before but for the sake of standards and maybe some people have bored the don't include the fast mode and because we're not really concerned with really fast transfers as not all peripheral support this one but all fits the standard one because it's named standard so let's leave it at 100 kilohertz let's save it and this is gonna generate our folder structure for our project now let's firstly for those who came just for the comments let's see all the different commands that you will be able to use for the I squared C for manual mode so we're not talking any DMA or interrupts or those special functionalities those would be for another video so let me write out all the functions that you should be using and let's describe each one of them okay so these are the functions that you're gonna be using let's start with the first one which are the simpler ones the as curtsy Master transmit and receive so this one are the same so everything are gonna say for this one is the same for this one but for sending and receiving so when transmitting data firstly we have to put in the device address so this is the whole address so this is the whole 8-bit address that's why we have to firstly left-shift it so we give room for the first bit to be the read alright or if the dress is ready live we only have to apply the read write bit so in the case of this ADC we have to take let's say 48 so this is what we will do let's say 0 48 and then we would left shoot it by 1 let's put it in the parenthesis so this is the actual address of this device but now the first bit or the least significant bit in this string is 0 so this would mean that this is for writing and yes we have a transmit factor so yes we would have to transmit to the receiving end so this is alright but when you're receiving data then you should use the same notation but you should add a 1 at the beginning so this is the first bit of the 8-bit address that is actively set to 1 so that the ice-crazy prefer knows that it should be sending data from the to master so when receiving data you have to put in one while sending data you don't need to put it and the next pins are self-explanatory this is a pointer to the data that is being transmitted so if you have some where a single 8-bit register or a variable you just put in its pointer so like this and the size would be one if you have multiple bytes to send for whatever reason and you have an array of all those bytes and it's called P data then we just put in the name of that array because it's already a pointer to the beginning of the array and then the size of the array I'll know for seven or to be universal its size of function of P data so this would be a universal way to send number of elements of your array of choosing for time out but for testing purposes put 50 because this is really long but for testing purposes if you have any loose wire this is a nice time out but for your application or for real Rory this should be lower and for receiving it's exactly the same just this data is the data that is coming back so this data is now pointer to the data where the data from the I squared C bus will be flowing into and the size of how many bytes the I square C peripheral this microcontroller should expect and the time out at the same time now when we have simple and simple devices like in our case this is this a DC this a DC only has a comment byte and only 2 bytes for all its data these are 2 8 bits and these are used for all the 12 bit data of the ADC so when we're writing into this one we're selecting its address this pin to 0 and then just plugging in the data and they should fill up this register when reading the data from this device we should again address it with the address along with one over here and then it will return 2 bytes so we would use the mast receive function in this arrangement with a proper register that has at least two bytes of size and here we have a two so we are expecting two bytes but it complicates when you have devices that have many registers in this case this one let's go to page 9 No okay so here we have all the registers that it has so in fact has four registers of different sizes so now we have to tell the device which register we want the data from now it has a temperature data so this is the one that you will intuitively think that it would be automatically returned when we initiate the master read but it doesn't happen we firstly have to tell it from which register we want the data and how large it is we have to know beforehand and what's lovely I guess by the maxim later sheet is that it also has a handy drawing so how this is done to write the configuration right in this case the configuration right has its own address of one in this case it is 0 8 by a bit long or 1 byte so this very handy again we address it with its address these pins show that there can be set by the a 1 a 2 and a 0 and this is the readwrite so you want to write into it this pin would be 0 this would be pointer or the address of the register we want to read all right toe so this is this number in this case or if you have a datasheet of a part number that has multiple registers you put him usually the number of the register you want to read and write to and then it follows the data if you're reading from this part then that part will return data over here if we're writing into the part the part should be reading the data from the master over here and if you're reading the temperature like in this case because it's a temperature sensor here is the whole protocol for that so let's see over here we again send its address the rich should be on one if you're reading but in this case we want to firstly tell it where we want to read from that's why we're writing into appropriate register with this may and with reading into the first register which is the one that's responsible for the temperature data that way we put in here 0 0 and then again we come back we initiate the read this time because now we're reading and the device note that it's will this time returned to parts of data from the register 0 and then we're gonna be reading 2 bytes over here and now you can do this manually or there are those to another function over here it's called memory write and memory read and it's exactly for this purpose that's why the hall is so amazing because it automates a lot of things again I pointed the pointer to the device handler again the device address this should be the same way if we are writing you should put in without with the 0 is the first bit and if you're reading you should put the 1 as the first bit again the memory address is the address of internal memory of the device we're reading from or writing to so in this case if we are let's say writing into the configuration register that we know that is one byte long and it's at the address of 1 we would put in memory dress 1 memory address size of 1 because it's only one byte long and the data is well it's a pointer to the data that has the 8 bits that you need for this buffer the size is also 1 because the target memory is only 1 byte long and the timer is let say 50 the same so in the end it would look like for this particular case with an 8 bit something like this and 1 and memory address size of 1 and memory address of 1 so lots of ones for this case and device address of in this case we know the default configuration is 90 which is 48 already left shifted by 1 and we're writing so 0 is the last bit and over here I said that the last bit is set to 1 so this one should be 9 for first part and the read is the same we're reading from this device so it should be 90 with the one for the first one memory address again if you're reading from the configuration register is the same number and the same P data we're returning the data into which will be only one in size and the time out of 15 so these are all the functions and how they work and the philosophy of how the configuration and reading a writing works with the I squared C now if you're still around we're gonna go through the physical examples and let's see if we can get the temperature in the ADC reading from our sensors so I'm gonna pull on some code that are already written for this answer so we can go through it and see how it works okay boom over here so we have a few different functions and a few different variables so let's go firstly over the variables I have a few constants over here that are important so you can change them easily so in our case we have a resolution of this ADC of 12 bits the internal voltage reference around this number and there's the configuration register and the address of it so I said that the address of it is configured by one of those pins so it's not the same of the other sensors and these guys 49 and the configuration register has been configured for the first pin only so here we have multiple pins so we have eight channels and they could be differential or single ended so I just chose the first pin single ended relative to the common and the internal reference is turned on an ad converters turned on so this is how I comprise this command byte so this is the command byte and this is all the settings we also have an ADC data variable so this is gonna store the 12 bit ADC value this is gonna store the converted voltage so firstly we have an ADC read function I'm using this function to input the address of the device because it can be changed so that's why this is an external parameter the configuration register for it and the pointer to the data where this function will return the data also this function can return a status type death as we will see right now so I define this function to return the status type death but you don't need to if you don't want to it can just be avoid so firstly inside the function I'm using the hostage type def so I know if there was an error in any point of s critic communication that's why I use the return variable that is a hostage type death and if this function returns anything else but the how okay it will exit out the function and return this error so the first part is that we have to transmit the configuration register for this one so if you remember only the address and then the data of the register so this is what the master transmit function is for so into the address this is the 14 line left it by 1 and 0 because we're writing here's the pin configuration in this case I named it like that so this is the pointer to that one it's only 1 byte line and the time out of 50 millisecond we check it there was a problem if there wasn't let's continue I included the small for loop over here just a small delay it might be unnecessary but for this adc's you never know and the next time we just receive the data so this function will send the address of the device which in this case will be 1 & 1 at the begin at the end so the 49 is this number and it end one on the end so we know that we are receiving data and the data will go into this variable ad data which is the pointer to a 2 byte variable we know we're receiving to White with 50 milliseconds of time mode and if all goes well take those two numbers and glue them together so in this case the data is first byte and the second byte so this is the most significant bit of this data and this is the least one so we just glue the beginning of this one to here and just remove this few and force them to 0 if anything should happen so that's why I included this 0 F so the first four bytes or first four bits are forced to 0 so we're taking the first one in left shifting 8 by 8 bits and then gluing it on the end the second byte or transfer and sending it back with the pointer of the data and then to make it easier over here I have a voltage divider on this board because the maximum flow of this IDC is defined by its reference voltage and because the voltage going into it can be higher than that included by two voltage divider so we just multiply the number again by two to bring back the real value now to make the comparison if the results are true correct we have the ADC 2 volt function if you go to it it accepts argument of voltage reference the resolution the ADC value that it needs to convert to a voltage and then a pointer to the voltage floating variable and it converts it with the known formula for the ABCs and over here this 12 should be really the resolution so I found an fix and let's compile this one and this is really all there is to it and let's just launch it and to see if it works let's go to the cortex again if you have a normal board you just go in here and click debug but I have a drilling debugger that's why I'm gonna use this one I'm just gonna check if everything here is okay I don't need this and this is fine so if everyone just has to drilling these are the settings that you just have to use and then debug so my board is plugged into right now I'm gonna upload the code and let's start over here so let's put a breakpoint over here by double-clicking on the number I have 8 to run to here and let's just go into the code by f5 so we're in the function and let's f6 over it so let's see the return was Hal okay so this function worked no errors let's receive the data so this is gonna delay so that's why it's thing like crazy over here so let's stop it over here before it hurts itself let's go to the next one and let's have six over here and the howl okay hasn't been changed though no error was present now let's check the ad data register and we see that there is indeed some data in binary you can see that there is some data and if we glue it together and make it the ADC data we can see what the value of the pointer is in this case 1060 we will confirm this later when we multiply it by two so Knights 2120 and let's convert it to voltage it's one point two nine zero volts and I can confirm with a multimeter night now that it is one point two eight nine something vote so it's fairly accurate so a good voltage reference so we can see that it worked now let's do it parallel with the other sensor so I'm gonna plug in the code for the temperature sensor right now and this is all there is to it I included the only one function that does everything over here so let's go to the new variables for this max 302 l5 we have the address of it and the configuration register and the floating point variable for the temperature in this case the configuration is predetermined from the datasheet and in this case I'm just turning on and off the appropriate function that we need and don't need and in our case the address is the same from the datasheet I first wanted to put in the left shifted the pre left shifted values in this case this would be 48 before the left shift but decided for the ease of use and just copying data from the datasheet you have to know that this is the address that has been already left shifted and shouldn't left shift again so if you go into the function let's see what it does the arguments are the address the configuration register and the pointer to the float temperature and then inside I'm using the temperature data to byte variable because it will return two bytes of data because the temperature is in 16 bits and the first thing is well we have to tell it to which memory location water because this part now has multiple configuration registers or one configurations and three other one for temperature hysteresis and the output ping functionality so if you want to write anything at the configuration register we want to tell it to which memory address that's why I'm using the memory write function right now and with just the address and no zeros or ones because we're writing so there's only zero over here an address is already left shifted so you don't need to left it again otherwise there will be errors next is the address of the appropriate configuration register in this case is one the size is one and you're writing in the configurations passed by the pointer to the configurations function and then the size is only 8 bits or 1 byte 50 milliseconds of delay and that's it or the time out again the same delay and then we have the memory read function this memory read again has the address that is already left shifted but we add 0 1 because we want to read now so we have to have the last bit as 1 now the temperature register in this case is 0 so this is the first register that's why we put a 0 the size of the address is 1 and the temperature data is the name or the pointer to the temporarily array of data and we can expect 2 bytes as confirming with the data sheet 2 bytes over here and then we will check for any more errors and then we just calculate the temperature by gluing again these two bytes together into one sausage of 16 bit and then multiplying it by the lowest value of the temperature change that can be detected by the sensor and we get the temperature in floating in floating format so let's compile it no warnings and let's put a break over here so ready and another one over here and reupload this code so let's see how these two work one beside each other so these two are connected in parallel so important addresses were changed so here we are in the beginning of the functions so let's execute the first one and we get one point two nine volts correct and then the temperature one and we get twenty-three point five degrees so quite warm in my room so as we can see these functions work correctly so when we go through the read temperature function again let's run to this line and again the side of here firstly we write the configuration register and address one how okay we delay for a bit oh now this again now let's go to this one again now we read from the data register for the temperature which is to Bitesize and we have a wall over here because we're reading and then the temperature is by this formula and return it and we can see that the temperature is twenty three point five four degrees Celsius so everything works as it should so this is a kind of a long video but I wanted to show you in practical examples on two different kind of ICS that have different implementations and certain caches and hooks that you should be aware of like that address that was already left shifted and then you have multiple registers and it just cannot use the masterful function of the hull all the time because if you have multiple registers you have to know which one you want to address so this was kind of the idea for this video so I hope this video helped all these functions will be available as a pair of dot C n dot H for us in the github link down below so you can look at it again alongside with the video so you can have like a template it will be commented and I think it's pretty well commented right now so you can look at it how it's made so you also have this part of the main inside of it as well but you shouldn't just copy the whole main because it can be different depending on which processor you have so only should copy something like this part and this part and these functions will be included in the source files so again thank you for watching if you have another question or I did something wrong just please come down below again thank you for watching and I see in the next video bye
Info
Channel: Matej Blagšič
Views: 23,156
Rating: undefined out of 5
Keywords: stm32, stm32f407, programming, linux, gcc, data, dma controller, mint, linux mint, timers, st, delay, PWM, OC, stlink, gdb, debugging, systemworkbench, openstm, jlink, segger, stm32cubeide, ide, hal, tutorial, i2c, stm32 i2c, iic, serial interface, serial
Id: cvmQNTVJrzs
Channel Id: undefined
Length: 37min 50sec (2270 seconds)
Published: Sat Apr 04 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.