SPI: The serial peripheral interface

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

Ben Eater is fucking awesome.

👍︎︎ 40 👤︎︎ u/Sinn_y 📅︎︎ Sep 04 2021 🗫︎ replies

Man, I want that oscilloscope.

👍︎︎ 14 👤︎︎ u/bless-you-mlud 📅︎︎ Sep 05 2021 🗫︎ replies

I wish these videos had existed back when I had free time

👍︎︎ 17 👤︎︎ u/sprashoo 📅︎︎ Sep 04 2021 🗫︎ replies

I now understand tenzen io a little better

👍︎︎ 2 👤︎︎ u/anhyzer_way 📅︎︎ Sep 05 2021 🗫︎ replies
Captions
there are a number of different interfaces that are used for communication within a computer system and you might be familiar with things like pci express or with sata and both of these are actually serial data interfaces but there's a lot of applications that don't require the speed and complexity of these types of interfaces like just communicating between different chips on a circuit board or communicating with you know an sd card through that interface um or interfacing with with other peripherals on a like a smartphone things like touch screen digitizers or sensors like accelerometers and things like that for example i've got a data sheet here for it's a temperature humidity and pressure sensor and it's it's really just this little tiny um device here this little silver thing and the way that it communicates with the rest of a computer system is through one of it actually supports two different protocols either spi or i squared c and both of these are very common protocols for communicating between chips the simpler of them is spi the serial peripheral interface and that's what i'm going to be talking about in this video an spi is is a fairly straightforward protocol which makes it quite flexible so it's used for communicating between a peripheral device of some sort hence the name serial peripheral interface or spi such as like this temperature sensor or this is actually a little accelerometer like you might find in a modern cell phone or you know sd cards displays and things like that um so sbi is used to communicate between any of these sorts of devices and some sort of microcontroller or microprocessor so you know whether it's esp8266 like this or an arduino or even just some low-cost microcontroller or you know a full-blown cpu-based system like the 6502 with all the associated i o hardware but whichever devices you're connecting to whichever controllers the spi interface is not symmetrical so the controller is always going to dictate everything about the communication with the device that it's connected to so sometimes you'll see the controller referred to as master and the device referred to as the slave and so the interface itself between them is typically a four wire interface you always have a clock and the clock signal is always generated by the controller and then you've got two data signals one going in each direction so one from the controller to the peripheral device and then one from the peripheral device back to the controller in the other direction and basically the way this interface works is that each time the controller or the master side toggles this clock signal one bit gets sent in each direction and that's roughly how this works finally there's a fourth wire which is a chip select and again that is going from the controller here over to the peripheral device that's a chip select and that's an active low signal so that needs to be pulled low before any communication will take place there's actually no official standard for spi so you may see some different naming conventions for these pins so for example if you look at the data sheet for that temperature sensor it talks about those four pins we've got csb chip select bar is what that stands for so that's you know basically this chip select with a bar over it so it's active low as they as they indicate here serial clock sck we've got and then for the data pins they refer to it as sdi and sdo serial data in serial data out so in this case you know that's the data sheet for the temperature sensor which is this peripheral device so this would be serial data in and this would be serial data out from the perspective of the peripheral so with that same naming convention we would actually have to flip that around because on the microcontroller this is serial data out and this is serial data in so serial data out on the controller goes to serial data in on the peripheral device and and vice versa another naming convention that you'll see quite commonly is to refer to this as mosi m-o-s-i and this signal as miso m-i-s-o and that actually refers to the the signal on both ends so on this end it would also be mosi and miso and that stands for master out slave in so that's indicating that it's output on the master side or this controller side and slave in meaning it's input on the peripheral side and then miso is master in slave out and so that's a common convention that you'll see because it has the advantage of being the same on both ends of the link so for example for this temperature sensor we saw in the data sheet that it's it uses the sdi sdo nomenclature to refer to its pins but it's on this um it's on the circuit board that does some level shifting and stuff so that we can communicate with it using 5 volt signals instead of 3.3 volt signals but you can see the pins are labeled you know chip select miso serial clock and mosi as well as of course power and ground here but regardless of what they're called for an spi interface those are the four signals that you're typically going to see although i guess i should mention that in some cases there might be a missing signal so in this case here we've got this led display and it has um of course there's power and ground there but then there's only three other pins so there's the clock as you would expect there's chip select and then there's data in which i guess is sort of the same as serial data in or mosi whatever you want to call that but there is no serial data out there is no miso and that just happens to be because this display you can send data to it for what you want to display but it doesn't actually have an ability to send any data back to you because that's just not necessary for what it's doing but anyhow once we've got those signals this is basically how it works so we've got the controller that master controlling the the chip select and serial clock as well as the the mosi master out data signal here and the first thing that happens is chip select goes low and then basically at each clock transition from low to high in this case the master is also able to send a bit and then when in this case the clock transitions from high to low again that bid on the data line might change so that the next time the clock goes high there's a different bit there and then you know when the clock goes low you change the bit again when the clock goes high we sample that bit and so on and that's how the the master side of this uh is able to transmit data by you know controlling this clock and then setting each bit that's uh that's being sent but simultaneously the device is able to send data back through the master in uh slave out or miso signal so basically every time the controller sends a bit by toggling this clock and setting a bit there the device also gets to send a bit that could be read by the controller so if all the microcontroller wants to do is send data then it can you know set ship select low toggle the clock and send its data out the mosi line and then it can just ignore the the miso line alternatively if the controller wants to receive data from a device then it can set chip select low toggle this clock you know not send anything just send all zeros or all ones or whatever doesn't matter uh out of mosi and and then just read on miso to get whatever data the device is sending to it so every clock pulse is is able to send a bit in both directions it just depending on the situation that bit might not mean anything if you only want to transmit data in one direction but in any case at the end of the transmission the chipset line is pulled high again to signal that it that it's done and like i said there is no spec for spi so some of this definition is a little bit loose for example there's no there's no single rule about how this clock is actually interpreted so here i'm showing the clock starting out low when when the line is idle and then using the positive going transition to indicate when to sample each bit and using the negative going transition is sort of the time where you flip from one bit to the next but there are actually sort of four different ways that this could work like i just showed you the clock could start out low and then on the negative going transitions it flips bits and on the positive going transmissions is where we sample what the what the bit is set to we could also flip that phase around so we still start out low but flip on the rising edge and then sample on the following edge or the clock could default to being high and just flip the whole polarity around so that we're you know sampling on the falling edge or the clock could start out high and we could sample on the rising edge and so which of these things we're doing is sort of defined by both the polarity of the clock whether it's you know starts out high or starts out low as well as the phase you know whether we're sampling on the rising or falling edge and in order to know which to use you'd have to look at the data sheet for the particular device that you're using so in this case for that temperature sensor it tells us right here it says the spi interface is compatible with spi mode 0 which is polarity and phase are 0. end mode 1 1 which would be three in in binary with uh polarity and phase equal to one and so basically to kind of read into what that's saying it's saying you know we can use either of these modes which which really is is just saying that it's gonna look it's gonna sample on the rising edge because these are actually the two scenarios where it samples on the rising edge and it's effectively saying like it doesn't really care what the clock is doing when the line is idle it could be either low or it could be high but either way we're going to sample on the rising edge so basically you just need to check the data sheet for your particular device to see what it wants the last thing i want to mention is about the chip select signal here why you know why does that exist and the reason is that we can actually connect lots of spi devices together on the same bus and so if we have multiple devices like this we can just connect all of the clocks together uh connect all of the the mosi signals together and and connect all of the miso signals together and so then all of these devices basically share the same three pins here there's the clock serial data in and out on our microcontroller and then you use this chip select to select which of the devices you're talking to so you do end up needing a separate chip select for each device so we might need a chip select for this device here that goes back to the microcontroller and a chip select for this device that goes back to the to the microcontroller and so we've got three chip select signals coming out of our microcontroller but then we're able to share the clock and the two data lines coming out of the microcontroller and of course these are inputs to these devices and if you really have a lot of devices you could use a decoder like this 74 ls 138 which has in this case three inputs and eight outputs and based on the value of the three inputs you're going to get one and only one output at a time that's that's set low and so that would actually work uh perfectly for this active low chip select where you want one and only one device selected at a time and you could use three pins over on your microcontroller to control potentially up to eight different devices and then of course share the clock and the two data lines and so that's basically the physical interface for spi now as for what data is actually sent that really totally depends on the particular device in question it's going to define its own protocol for for talking to it so to understand that we'll have to dig into the particular data sheet for that device so as an example let's take a look at the data sheet for this little temperature sensor thing and you know to understand how to use sbi to communicate with with this you really got to just kind of read through this whole data sheet to get an understanding of how it works overall but i'll spare you the details basically the way this device works is it defines a basic protocol for reading and writing a series of registers and so here are the different registers that it defines and some of them are pretty straightforward based on what the device does you've got these top two here so this is humidity least significant bite and then humidity most significant bite so those two together give you 16 bytes of correction 16 bits of humidity information and then that's followed by temperature so there's a temperature least significant bite and most significant bite and then there's also this temperature x lsb i don't know if it's extended or what that's supposed to mean extra but but basically you get 20 bits of temperature data and then these four bits here are always zeros uh and then same for pressure so there's 20 bits of pressure data so you know this device is it's a humidity temperature and pressure sensor and so here's how you read the humidity temperature and pressure out of it so there's 16 bits of humidity 20 bits of temperature 20 bits of pressure and each of these bytes has a particular address associated with it you'll see that the protocol that it uses over spi allows you to specify an address and then you'll be able to read whatever is in that particular register and get the values from the sensor there's also some configuration stuff and so these are registers that we can actually write to to you know control how often these registers are updated and there's some other settings for over sampling and filtering and averaging and things like that additionally there's some read-only registers in here for calibration data because it turns out when you read this humidity temperature pressure data you don't actually get the answer in a unit that you would be familiar with you need to do some math based on this calibration data which i guess during manufacturing they calibrated and then write some data into into some roms or something that you can then read from here but that's the basic interface is there's just a handful of registers that you can either read or write from and then when you get into the actual protocol for the spi interface they define you know how how to actually read or write from those registers and so here's a timing diagram that should look very familiar this is uh just spi uh but what it's showing is that it's showing that your chip slip goes low as we saw before and then the clock comes in and then on the rising edge we're reading in this data but what it's saying is that the first eight bits of data are going to come from the the microcontroller and the first bit is a read write bit so it's indicating whether we're reading or writing so if we're writing data that'll be a zero for reading data it'll be a one and then that's followed by seven bits of address and that address corresponds back with the uh wherever it went there it is corresponds back with the address associated with the register that you want to either read or write from so you send that and then once you send that you're either going to continue sending another eight bits of data that you want to write to that register or if this was a this first bit was a one you're reading then you're going to expect to get those uh those eight bits back which would be the value of whatever's in that register so this is basically defining how it's using that spi interface that we discussed to uh you know read and write from the registers and so it gives some examples here for writing a couple bytes into a couple different registers so those are showing chip select being set to zero and read write is zero so we're writing and then the address of the register is sent and then the data that we want to write to that register is sent and then if we want to write to another register we just follow it up with basically another copy of that command so it's you know we're writing in this case it's a different register and then we would follow that with whatever data and whenever we're done with all that writing the chip select would be set back to and then for reading it's basically the same deal or at least very similar where we start out by setting chip select to zero in this case we're reading so the read write bit is set to one and then whatever register value we want to read from so if we want to read the temperature we would just put the address of the of you know one of those temperature registers in there and then on subsequent clock pulses the device is going to send data back to the the controller with whatever data is in that register and the difference of what they're kind of calling out here is that there's this multiple byte read where it auto increments where if you send it an address and then you read eight bits you're going to get whatever date is in that address but if you read another eight bits you'll get what's in the next address and so that actually turns out to be kind of convenient for reading some of these uh temperature pressure or whatever because you can put in you know you want to read address f7 that's the pressure most significant bit we read those eight bits and if you just keep reading the next eight bits you'll get is the pressure least significant byte and then if you keep reading you'll get these additional bits here for this x lsb which overall will let you get all of the the bits for the pressure so that's just kind of a convenient shortcut that they give you so anyway let's hook this up and see it working so i've hooked this temperature sensor up to the 6502 computer and it's a pretty straightforward connection so we've got power and ground coming in here that's five volts and the the rest of these components on this board are actually there to convert from five volts to 3.3 volts and do level shifting for the control signals as well because this is a 3.3 volt sensor and we're connecting it to a 5 volt system so that's what all that other stuff is so we got our 5 volts going in and we've got our four connections for the spi interface and those are just going into i o pins on the versatile interface adapter that's hooked up to our 6502 bus that way we can just individually toggle these pins on and off or high and low as as we need to to communicate with this thing and then on the software side i've just defined some variables here for each of those four signals that map to the particular bit that they represent and we can just sort of ore these together and and send them out to toggle those pins high or low and there's a lot of different ways we could do this perhaps the best way would be to use a hardware shift register where we can actually use the hardware to generate the clock for us and do offload a lot of the work but i'm going to show a much more sort of brute force way something typically called bit banging where you're individually setting each individual line high and low to sort of bang out the bits one at a time and so what you'll see here is this code is basically just loading some value into the a register and then storing that value out port a and that'll have the effect of setting whatever bits high so in this case we're setting the mostly bit high out outport a in this case we're setting the clock bit and the most bit high out port a here we're setting the mostly bit high output a and so on and we basically just do this to send a whole sequence of different bit combinations but anyhow we start out with uh chip select high because that is in fact where we want to start out and then we're setting um this is basically setting the direction so we're saying that the chip select mosi and clock pins are our output pins miso is an input pin that all makes sense and we're setting that in the data direction register and then here we're getting into a sequence where we're starting to we're going to basically just bit bang out a a whole series of of bits and in this particular case what i'm sending is hex d0 so it's going to be this pattern of bits 1 1 0 1 0 0 0 0. and the reason i'm sending that particular sequence of bits is that if we look at the the registers register d0 is this what they call a chip id and basically the way that that works is the chip id is just always going to be hex 6 0. and so this is just you know a basic consistency check if you just want to verify that this device is is there it's operating this is kind of your simplest way of communicating with it is we read register d0 and we should get back 6-0 and that's just always what that chip id is set to as if we walk through this code you'll see how we send that so we're starting out by setting the mosi pin high and when we set the mostly pin high we're setting everything else low so we're we're setting chip select low we're setting the clock low but mostly is high so that the first bit's going to be a 1. then the next thing we do is we set clock and mostly high so that's basically at this point here so chip selects still low of course and it's going to continue to be low but now clock is high and mostly is remains high so that's that rising edge and that's actually the point where we're sending that first bit then the next thing we do is we said uh just mosey so that is going to keep mostly high but it's going to bring the clock low because we're not you know explicitly setting that high and of course chip select remains low and so that's kind of at this point here where mostly is high but everything else is low and the reason most is high is because the second bit we want to send is also going to be a one so we send that out and then the next thing is clock and mostly are both high and so that's going to give us this rising edge of the clock so now we're kind of at this point where the clock is high mostly is high chip select obviously still low we're not touching that and the next thing we do is we send a zero basically zero is going to say everything is low so chip selects low clock is low and mosey is also low and this time mostly is low because the bit we want to send is a zero right we're sending one one zero because the register we're trying to read from is d0 and that's what what that is in binary so we send that zero out then we just set clock high so that's going to be the rising edge of this clock and so now we're going to be in this point here where chip selects low clock is high mostly also still low because we're now sending that zero and basically it will continue on in this in this fashion so we've got mo c high and so we're setting another one and then we're sending a zero another zero another zero and another zero and so that's the eight bits that we're sending in order to send the the d0 right so it's one one zero one zero zero zero zero so we're sending that but then once we're done sending that we actually want to send eight more clocks because we want to receive something right because once we send those eight bits that indicate the the register we want to read from the controller has got to continue sending clock signals it's got to send another eight clock signals so that on the miso line we can actually read the the result or whatever's you know in this case we can read what's in that register so basically the next code here is just eight more clocks so we just kind of keep reading that and then at the very end the last thing we do is we set chip select high and put that out poor day and so that's this final thing where chip select is now high everything else is low and that finishes it up all right so let's see it in action i've got the code loaded up on the eprom here and of course got the sensor connected here and i've also got the an oscilloscope connected to the four signal lines so we can take a look at exactly what's going on there and if we look at the oscilloscope we can actually get it to decode the serial uh and there's a bunch of serial protocols it supports and spi is one of those so we've got spi set up there and then as for the signals we can configure the the four different signals so clock we've got set up on probe number one and you can set a threshold of two volts so again spi there really isn't a standard for it so the voltage levels aren't defined anywhere so it kind of depends on your circuit in this case we're using five volt logic so two volts is a good threshold for uh for a one here we can say the clock is rising edge mostly we've got set up on probe number two miso we've got set up on probe number three and chip select is on probe number four so with all that set up we've got our trigger set to trigger on actually we want to trigger on spi mosey data sure let's give that a try so now if i reset this there we go and at this point hopefully that looks pretty familiar to you so the bottom here of course is our chip select oops so that's showing you know the chipset goes low when we start transmitting data and of course this top one here is is obviously our clock so each bit we're seeing clocked out there and then our mostly our master out is is this signal here and so we can see we're sending the d0 here and it decodes that here for us as well so d0 and then simultaneously when we're sending that remember this is bi-directional and simultaneous so even though the the sensor you know isn't really trying to send us anything at this point in time it's still like that signal is going to be either high or low it's going to be something in this case it happens to be high and so we're effectively receiving ff we're receiving all ones and it just doesn't in this case have any particular meaning likewise once we're done sending the register we want to read from we do get the result and we can see the result is six zero which of course is exactly what the data sheet said it should be so that verifies that we're actually communicating properly but same thing here you know we're sending all those zeros and so i think it's just kind of interesting to realize that this is a bi-directional protocol so at the same time that we're sending the d0 we're receiving ff we just don't care and at the same time that we're receiving the six zero we're also sending zero zero it's just that the sensor doesn't care so in some sense even though the protocol is bidirectional in this particular application we're treating it as a request response type of thing so if we want to get fancy we can write better software so rather than you know banging each bit out one at a time like that we can do something where we create a loop this is still bit banging because we're still setting the individual bits one at a time but we're but you know in this case i'm doing it in a loop so i've got a routine that we can call here and it'll take the a register and basically loop through um all eight bits in the a register and then you know shift each bit into the carry flag test it and then either set mo c low or set it high depending on whether the next bit to send is is a zero or a one and then it'll toggle the clock and it'll also simultaneously take the the bit coming in on the miso signal and you know shift that into the the into a receive buffer basically and then you know we'll decrement our bit counter and go through a loop here and then once we've gone through eight clock cycles put the you know the data we received into the a register and return from the subroutine and so then the way that we can use that is something like this where we can we can start out by setting the the all the bits to zero so that's going to pull the chip select low to start transmitting uh and then we can just put the register value into the a register we want and call that transceive uh subroutine that we just looked at and so in this case it's gonna send the seven five and if we got anything back it would be in the a register but in this case we're just sending we're not we don't need to receive so the next thing we can do is just send something else in this case we're sending the actual parameter that goes along with this instruction because this particular instruction 75 that's writing to the config register so this is just whatever value we want to put in the config register so we send that and then 74 i think is the measurement control register and so we can send that as well as put the value that we want into that and send that and then we can bring the chip select high and send that out and so this very quickly you know we're able to send two different values to write to these two different registers to configure the uh the temperature sensor and then uh down here in the loop i've got you know some things that kind of runs a timer and you know just sort of sits in this loop until the timer expires but once that timer expires um same thing here we send a zero out to our port so that is going to have the effect of pulling chip select low and then we send the fa out and so this part here sending that fa is saying we want to read from the fa register and the fa register is the most significant byte of temperature and then we're going to do another transceive because each of these times we call transceive we're going to get eight clock pulses so this one was eight clock pulses to send the fa this one's going to be eight clock pulses to receive the result and once we receive that result it'll be in the a register so we can put that into our value variable or value plus one so it's going to be the second or the most significant byte of that and then we do another transceive to get another 8 bytes and this is going to read from instead of fa it'll be fb because it's just going to read the next register if we continue to send clock pulses and we can put that in value and then this will bring whoops this will bring the chip select line high again uh to end the the packet or end the transmission um at that point we've got you know the the least significant byte and most significant byte in value and value plus one so i've got this print num subroutine that i made in a previous video that you can check out that'll print a 16 byte number to the lcd so we clear the screen and do that and then go back up into our loop so basically we're gonna sit in this loop and uh read the temperature periodically and put it on the screen so let's give that a try so put that in there and reset and there we go so we're getting a value and you know again this value doesn't necessarily mean anything we have to do some conversions because there's a rom uh inside that chip that will uh that has some calibration data and we have to read that out of different registers and then there's some math that we can apply in order to convert this to an actual temperature but we should see it at least respond to temperature so let's check that out so it's what is it 34 300 if i put my hand on here to try to warm it up you see the numbers are getting bigger so that's a good sign i've got an ice cube here let's see if i put that on there yep the numbers uh are they getting smaller yeah i guess they're sort of getting smaller yeah there it goes those numbers are getting smaller i take that off they start going up again so it appears to be responding to temperature and then if we look at the oscilloscope we see it looks like there's some some stuff happening here but it's happening a lot slower and that of course is because you know we're not sending those bits as fast as we could because we're not doing that you know you know stupid simple bit banging we've actually got that loop in there we've got some logic so that's slowing things down but it doesn't matter you know the peripheral device here doesn't control the clock it doesn't get any say in the clock it has to just deal with whatever clock the the cpu is sending it so if this stuff takes longer than so be it in fact you see here between each of these bytes because we um you know we're getting that result and returning from a subroutine and then potentially saving that somewhere then calling the subroutine again there's actually a little bit of extra delay between each set of eight bytes because there's extra code running there and and that's totally fine you know that's that's a feature of spi where the controller is in complete control of the whole situation and so if you look at what's happening here so this is just the periodic reading of the temperature and so fa is the address of the um of the register that contains the temperature and so we're sending fa we're receiving ff at that time that's just because again that that miso just happens to be high doesn't really matter doesn't mean anything then you know we send another eight clocks in order to get the result and so the high order byte is eight six we happen to also be sending ff doesn't really matter because the temperature center isn't really going to pay any attention to that then we send another eight clocks to get the next register um in this case it's two eight two seven whatever it happens to be and for that it's kind of interesting to see you know we're sending eight six at the same time that we're receiving that second register and that hasn't doesn't have any meaning it doesn't really matter that we're sending that the only reason we happen to be sending that is that you know the way that the code that i have works is that when we're sending these eight clocks and receiving this eight six it just happens to wind up or it intentionally puts that in the a register and so then when we call that transceive subroutine again h6 is still in the a register it doesn't really matter and so it just happens to send it again doesn't matter we don't care that we're sending anything the reason we're sending those clocks is so that we can receive the next eight bits of register data and so anyway that's what allows us to read that register and we're putting that on the screen and appears to be measuring uh temperature now as i mentioned if we want to actually get the temperature in some sort of useful unit the data sheet gives us a c function that we can use to compensate and so this function would take in the 20-bit temperature and then it applies the the calibration constants and so we have to get those out of there's actually six registers that hold the calibration constants for for temperature so i won't go into all the gory details but i've extracted those calibration values and converted this compensation function over to 6502 assembly and got it running and so here it is and this is what it's outputting so it says it's 25.32 or 33 degrees which feels about right and just as a point of comparison i've got a multimeter here that has a temperature mode which you can use with a thermocouple probe so this is a thermocouple that you can plug in and thermocouple just generates a very small voltage and so the multimeter can read that and give you a temperature readout and there it is so 26.3 so it's close enough to the 25.37 one thing i've noticed is if i actually put this probe right on the same sensor they tend to get a little bit closer so there it is they're actually pretty close three four twenty five point well it was twenty five point point four there it is twenty five point four pretty close so obviously if i put my my hand over here and warm this up both of those start warming up so it seems like it's working another interesting thing i noticed is that for that compensation we needed to get all 20 bits of the temperature so you can see i'm getting uh now three bytes to get the 20 bits of data and it's interesting to see that that last byte is is flipping around so and even though the temperature is holding relatively constant at 25.66 or six five you can see there's uh maybe some more precision than we're actually getting so i'm not really sure what's up with that but just thought that was interesting anyway i hope you found this video interesting if you want more information about this particular temperature module i've got links in the description and of course if you want to build your own 6502 computer i've got kits and everything on my website links to that in the description as well and of course as always thanks to all my patrons who help make these videos possible you
Info
Channel: Ben Eater
Views: 209,037
Rating: 4.9823375 out of 5
Keywords:
Id: MCi7dCBhVpQ
Channel Id: undefined
Length: 32min 59sec (1979 seconds)
Published: Sat Sep 04 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.