How to write SPI Interface code in Verilog HDL for a 12-bit ADC (using the DE0-Nano)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
the de0 nano is a very low cost board with a cyclone 4 fpga but it's also got some other interest in hardware on board including a 12 bit a to d converter and this gives us a chance to practice writing spi interface code using the fpga using verilog hardware description language to interface to this a to d converter and once you've got the hang of this one i'm fairly sure that you'll be able to write spi interface code for any a to d converter so let's give this a go and see how far we get before we get to the specifics of our device let's look at the big picture now the role of an hd converter is to convert a sampled analog waveform into a digital equivalent and you can see here this device uses 12 bits now the more bits you have the finer the resolution in which you can represent an analog sample but there are actually two types of atd converter one of them sends out these 12 bits in parallel so they all come out at the same time the second type sends out the bits in series so you get one bit at a time and your interface code has to work out a way of picking out these bits at the right time to form your 12-bit word the big advantage of this serial type of a to d converter is that you don't need so many pins in fact to read out each conversion you need just a single pin now typically you'll also need to program the 80d converter so there's normally a pin dedicated to this and again you write bits in in series you also have a chip select or start conversion pin and importantly you also have a clock and that clock kind of coordinates everything and the key thing to remember with this kind of device is that timing is really important so you have to pick out the 12 bits at exactly the right time to form your conversion word and similarly to program the device you know let's say to choose the the channel or the acquisition mode you need to write in those bits at exactly the right time so the clock the s clock is important because it allows you to coordinate this activity now hopefully this will make a bit more sense when we go to the timing diagram for the device that we'll be using okay so here we are with the part of the data sheet for the adc-128s022 this is the atd converter that's on the de0 nano board it's an eight channel 50 kilo sample per second to 200 kilo sample per second 12 bit 80d converter we've got the pin map uh here so this might become important when we do some probing later on with the oscilloscope but the important page for us at the moment if we want to write interface code for this chip is the timing diagram so typically this is where you would go first you know this basically tells you everything you need to know to write the interface code and you can see we have those four pins that we talked about earlier we have the chip select pin so that will go down and on the falling edge that will initiate the start of the conversions then we have the s clock so the s clock frequency you have to be careful here because there are limitations on the maximum frequency that you can have for the s clock so i think for this chip it's a 3.2 kilo megahertz sorry upper limit on the s clock frequency then we have the d in so this is the programming pin for this chip and you can see it's actually quite limited on this chip what you can actually program so you know all you can do here is actually choose which channel currently taken a sample from based on the value of of these bits at this time in the s clock then we have the d out so this is where the uh the 12-bit conversion word for the current sample is read out and and this comes out one bit at a time so we have to be really careful in the interface code that we pick these bits off one by one and we have to know exactly when they're coming and you know the way that you know is you look at where you are in the s clock so we can expect uh bit 11 we can expect that to come out well it will it will start on the falling edge of uh the fifth s clock but really we should be reading this on the positive edge of the fifth s clock so that's when we look at what the value of this bit is and then we uh basically register that value into our 12-bit word then we do the same for db 10 that's on the sixth cycle of s clock and then so on and we build up our 12-bit word one by one now for the programming bits as i said before this this determines which channel we're looking at on the chip you can see we have eight channels here so you can put you know you can put analog signals into all eight of these channels if you want but the 80d converter needs to know which one you you you're looking at basically and from the the table in this data sheet if we're just looking at channel 0 we can set these to 0 0 0 and then i think zero zero one is channel one and so on but that that's basically it that that that's all there is to this so i think we're ready now actually to make a start with our interface code let's just remind ourselves of the sequence of events that we need to cater for in the interface code and i've made an animation for this so this is the analog waveform we sampled this at 200 kilo samples per second now let's say we zoom in to this blue box so we're within the time scale of just a single sample and now we can see things happening at a much faster rate the sequence of events is as follows we have the chip select pin go low which initiates the start of the conversion then we have the track time for the adc and then we have to make sure in our code that we write the appropriate values to the input d in pin and read out the bits one by one as they come out of the d out pin you can see i've numbered here the s clock cycles we have to make sure in our code that we keep track of where we are in the s clock cycle you can see we get 16 counts counts of s clock and what we can do actually is just have a 16 count that's that's a four bit free running counter which just repeats itself so it goes from 1 to 16 and then it goes back to one and that will be appropriate for us because we can just keep the conversions going so this is what we plan to do so we want to write a verilog module for the interface code we want to write a test bench and simulate the interface code then we'll create a bdf import our working interface module and apply a clock of course we need to assign the correct pins program the de0 nano board and then we can check whether it's working by using a signal tap and then we'll rewrite the code to accommodate multiple channels not just a single channel here i am in quartus i've started a new project and you can see in my device settings i've made sure i've selected the correct code for the fpga on the de0 nano board but now it's time to start writing the interface code and as i said before my workflow will be to first of all write a basic version of the interface code then i'll simulate using model sim and then i'll slowly progress this to implementation on the board with the help of signal tap which is a really nice debugging tool because you have to work out if the fpga is actually doing what what it should be doing so signal tap allows you to basically see the signals in real time inside the fpga so first thing i'll do here is go to file new verilog hdl file and i'll start a new module and i'll call this module spi interface and initially i'll just make sure my input signals i have a clock coming in i know i'll have d in coming in and i know i'll have d out coming out of this interface module they're the basic signals that we need and there's actually one i forgot we also need the ship select pin so i'll go ahead now and just define these as inputs and outputs so dn is an input from the hdd converter we have an output d out which is just a one bit output and then we also have an output chip select which again is a one bit output now if we take a look at the timing diagram we note that the the way things happen is kind of in a a 16 count cycle so the first thing i would do here is make sure that i had a counter a four bit counter which will help basically to regulate all the activity and the good thing is because it's a 16 count cycle we can have a free running counter so we can just set it up as a 4 bit counter 1 to 16 and then it'll roll back to the beginning again or 0 to 15 actually then it'll roll back to the beginning and just repeat with a cycle of 16 so that's gonna be the first thing i do and to do this i'll just make sure i have a a four bit register called count i will initialize this register to starting value of we might as well start it as zero and then in verilog d it's really easy to do a free running counter so we just do always a positive edge of clock and we just make sure that the count using a non-blocking assignment will increment by one at the positive edge of each clock so that will give us a a four bit counter which will go from zero to fifteen and then just roll back down to zero so that's fundamentally that that's a key part of this interface code now let's take a look at this timing diagram now the first thing i'll do is look at this chip select and you can see that chip select starts off at one so what i'll do is in the initial i will initialize chip select to one because we know that's where it will start but note how chip select initiates the start of the conversions on the falling edge so what we need to do is find a way to make chip select go to zero but we want this to be controlled and we also want it to uh sort of correlate with when the s clock starts going okay because the s clock also starts at one and my plan here is actually to you know we know that the clock is coming in that clock is going to be at 3.2 megahertz if if that's the s clock frequency that that we're going for and what i want to do is make the value of s clock take on the value of clock in a controlled way okay so what i'm going to do is make chip select go low and at the same time as chip select going low i want s clock to begin taking on whatever the clock is in some ways what we need is something similar to an if statement for s clock and we say if chip select is one then s clock is one or if chip select is zero then s clock is equal to clock but first of all let's deal with chip select so what i'm gonna do is to start off chip select as one and then i'm going to have another always block and i'm gonna say if count is equal to one then i will make cs go low like this this is controlled by the value of count now you can also make this controllable via a push button or another verilog module but we'll we'll keep it simple for now okay so i've just added an s-clock here as an output register that's one that i forgot to put on the list here so i think we're just about ready to finish the first step of this development and what i'm going to do next is actually simulate what we have at the moment and the reason i'm simulating so early because we're nowhere near finished with this interface code but the reason i like simulate early is twofold really the first reason is it gets your test bench ready and the second reason it allows us now to take an incremental approach to the rest of the development and believe me with with something like this it might not be the most complicated piece of code there are some headaches that we have to solve in terms of the relative timing between signals so we will have to reiterate our code and go back into model sim an element of it is trial and error sometimes you can't get away from that but this is what we have so far so what i've done is i've made a test bench so just to avoid some nasty numbers here i'm going to go with a one megahertz clock you know this is going to be a 500 nanoseconds so every 1000 nanoseconds that will be one period of the clock we can always change that later but we've instantiated the spi interface module that we've built here so dot clock that's taking the clock dot s clock so we've defined that as a wire nothing is actually happening here i've just realized if we run this we wouldn't get any signals out but the thing we're interested in is actually the value of count at the moment anyway i mean this is just uh the start so what i'm going to do is just make count an output register okay so i'll make count an output register and that will make it easy for us to monitor the value of count within modelsim so i'll just go ahead and add count into the list here and just make sure that we generate a three bit wire called count we can actually call it anything we want within the test bench but um tell you what just just to make it same as all the other test bench signals i'll call it this so that's basically our test bench for now so i'm going to go ahead and run this code i'm going to set the test bench as the top level entity i'm gonna go into assignments settings okay this is one of the hoops that quartus makes you jump through to get a simulation going so go to simulation compile test bench test benches new test bench our test bench is is called testbench and then we have to select the dot v add add and now that's nicely set up in the native link settings which will allow us to open model sim straight from quartus let's just make sure we set the test bench as the top level and then we'll go to analysis and elaboration so as always we get a few errors so the first one i was missing a semicolon okay just ignore that um so next error so cannot connect instance port so i think i've that should be a dot this is the common kind of error that you get sometimes with with quarters so i'll try again so this time we've had a bit more luck so i think we can now go to tools run simulation tool rtl simulation and now model sim should open so this is the simulation results in model sim so what we're looking for is just the value of count so what i'll do is just right click this change the radix to decimal and there we can see well if we make it unsigned decimal that would be even better and we can see that count is incrementing from 0 to 15 on the positive edge of the clock so first step is good we can also check on the chip select and that goes low at the right time so we can move on to the next stage now now i mentioned before that i want the s clock to start off as one so s clock should start out at one and then i want it to take on the value of the input clock when the chip select pin goes low okay remember the input clock is just going to look like a clock at all times but we want the s clock to start off at one and then only when the chip select goes low do we want the s clock to basically mimic what the clock is doing and one way we can do this is to have the the clock coming in and we can have a kind of an if statement looking at the value of chip select if it's if it's one then make s clock one if it's zero then we wire the input clock to s clock and i'm actually going to change s clock to a wire here just to make our life easier and then i'm going to use this assign statement okay so i'm going to say assign s clock is equal to chip select question mark and that's saying basically what's the value of chip select if chip select is one s clock is assigned the value of one otherwise s clock is assigned clock okay so this is a shortcut way of doing a sort of an if statement so this is kind of a one-line trick a very concise way of writing this expression and hopefully this should give us exactly what we want in terms of the s clock taking on the value of the input clock when this chip select goes low so let's give this a go we'll run the test bench again and we'll see if this works so this is the model sim result and you can see it's kind of working because we have the s clock here uh now when the chip select goes low we can see that the s clock begins to take on the value of clock but it doesn't quite look like the timing diagram in the data sheet because what you'll notice is it's not instantaneous so what we really want is for chip select to go low and we want s clock to go low straight away because the chip select is being updated on the positive edge of the clock now if we change this to happen on the negative edge of the clock so when count becomes one the chip select should go low on the negative edge of the clock and that should give us the behavior that we're looking for here so let's try this one and then we'll re-simulate in uh model sim and here's the updated model sim results and you can see now this is the behavior we're looking for because the s clock will begin to take on the value of clock on the negative edge of the clock when the chip select goes down that's exactly what we want so we can push on with the design so where do we go next with this i think it's time now to start looking at what we do with the d out and the d in pins remember with d out this is the information which is coming from the a to d converter into the fpga into our interface code basically gets a series of of bits so it starts off with the most significant bits of the 12-bit word now that comes out you know that the image diagram tells you exactly when this comes out okay so it's on well we look for it on the rising edge of the fifth s clock and they come out one by one and our interface code has to pick these out at the right time then construct this 12-bit word now d in that's the uh the programming bit which is coming from our interface code into the a to d converter and remember the value of those bits will determine which channel the a2d converter is sampling from and remember channel zero is zero zero zero for for add two add one add zero and there's a table which tells you what these bits should be to give you the uh appropriate channel but again we have to get the timing right on this okay so those bits have to change at the right time okay so we've got two potentially tricky challenges here now we'll simulate we'll we'll do we'll have a shot at this code and simulate but i will warn you once we get to the fpga and implementation on the fpga it doesn't always work as as you see it in simulation and there is an element of trial and error but this is why a tool like signal tap is so important but anyway let's adapt this code and let's see how we can tackle this problem now if we take a look at the timing diagram again we can see that we need to take action on the positive edge of s clock okay so if we start with a d out so remember this is the the 12 bit word coming into us from the a to d converter we'll see here that we need to register these input bits on the positive edge of the s clock that's something to bear in mind but we also look at d in d in is defined as the programming bit to the a to d converter so this is signals that we need to make in our interface code and then send out to the a to d converter and we can see that we need to change these values on the positive edge of the clock of the s clock both things need to happen on the positive edge of the s clock that's hinting to me that we need an always block with the positive edge of the clock and then we can take care of both of these things maybe potentially in the same always block i've made a bit of a mistake here because dn should actually be an output okay and i'm going to define this as an output register similarly d out should actually be an input okay so that's coming in to us from the a to d converter but let's start here with what we do for d in okay i'm going to paste some code in and what i've got here is an always block so always that positive edge of clock we're looking at the value of count and as a first guess what i'm gonna say is if count is equal to three so positive edge of clock count is equal to three what i'm going to do is i'm going to make d in take the value from add two then when we get to four we'll take on the value of add1 and then when we get to 5 we'll take on the value of add0 to make this work these values here are registers they're kind of variables and what we need to do is just define these signals in our code and then we can initialize these to whatever whatever we want okay so i'm going to start them off at zero in fact i'm going to make the middle one one just so when we simulate it we can kind of work out where we are and if we got the timing right but doing it this way just makes it a bit easier for us to change these values later on if we need to okay so again i'm going to take an incremental approach so what i'll do now before i even think about doing a d out i'm just going to make sure that this is working and then we can make another step forward so i'll just move to model c and i'll run analysis elaboration again and then go to modelsim so just very quickly i've made a well i will make a modification to the test bench now we've made d in an output reg because it's an output of a module in our test bench we need to make it a wire and the input to the module which is in fact d out is a reg this is what will change a bit later to be the input to this module but for now i'm going to go to save and i'm just going to do analysis and elaboration again and then we can open this test bench so here's the model sim results and you can see d in remember we've set the middle of the three address bits to one to check its alignment with where it should be relative to the count and you can see it goes high on between the fourth and the fifth s clock that's roughly where we want it to be okay so i think we can now go ahead and move to the d out pins but it's actually difficult now because d out is what's produced by the 80d converter so we've kind of hit a roadblock now we can't really make much more progress until we actually program the device apply a signal and then check to see what we have in signal tab so at this point i'm going to say that's probably enough for the simulation and i think we can now move forward and actually do the move the development towards implementation on the actual device so let's go ahead with that so i'm going to go to file new and i'm going to do a new block diagram schematic file a bdf file the good thing about doing a test bench and at least partially testing it is that we know we have a a semi working module here which we can drag into our bdf file so to do this i'm going to right click on the dot v and i'm going to select create symbol file for current file that will produce a block and we can double click somewhere in our bdf and our block should be in project so that's our block what we need to do now is generate an input clock so we're going to have our clock coming in here we have d out here so that's an input into our interface code and that's going to carry with it the adc 12 bit result coming in series and then we have the outputs of the interface module which of course s clock dn chip select they are the signals which need to go out into the a to d converter so we've got some pins to put in but first of all i'm going to make the clock i'm going to go to utility windows i'm going to go to ipcatalog and i'm going to look for a phase locked loop uh this facelock loop alt pll give it a name and i'm going to configure this phase lock loop for uh an input signal of 50 megahertz that's the the crystal clock frequency on the de0 nano board of course that's coming into the phase lock loop but we can configure the output of the pll to a custom frequency now we don't need any asynchronous reset or any locked output but what we do need is an output clock the output clock that we want is 32 megahertz so let's see if we sorry 3.2 megahertz let's see how close we can get and that's fine we're going to get 3.2 megahertz so next finish finish and i think i should have selected that to make a block for us but um it doesn't matter i can just right click and i can create symbol file from the dot v to give us our our clock but let's save the bdf first i'm going to save it as block and now it will make a block for our bdf so i'm going to go back to the bdf sorry trying to work in a small space here now if i double click you'll see that the pll is there i'm going to drop that into my design i'm going to wire the output of the pll to the input of my spi interface and now i'm going to put some pins in so we know we need an input pin for the input clock and we need an input pin to d out we also need some output pins so i'm going to do one two three output pins for s clock d in and chip select so now it's just a case of uh wiring these up so let me wire these up and i'll come back when that's done so here's the bdf now with the input pins and the output pins so what i can do now is set the block as the top level and then i will go to analysis and elaboration and once that's finished with the bdf as the top level we've basically transitioned our workflow to programming the actual fpga so just as a quick recap if we want to simulate we put test benches the top level if we want to program the board we put the block or the bdf as the top level so once analysis and elaboration has been completed we can then do the pin assignments so we go to uh assignments pin planner and then now it's a case of going to the user manual for the de0 nano board and just making sure we put the right assignments in here so i'll just go and check what those pin assignments are and then come back so if you are following this at home here are the pin assignments so we've got the input clock is r8 and then we have the other pins assigned here so this information is available in the user manual for the de0 nanoboard so i'll just close that one go back to our design and now it's time to do compilation so i have compiled that was successful so what i'm gonna do next is see if we can program the board using signal tap and the reason signal tap is so useful in this kind of scenario is because it gives us visibility inside the fpga so for something like an a to d converter this is invaluable because we get to actually plot the the signal in real time now without signal tap this is very tricky you have to do some you have to do some custom logic to um you know and send the signals out it's just trickier so let's see if we can open signal tap so if i go to tools and then i open signal tap logic analyzer now let me just bring the window in the moment there's nothing here so what we need to do is you know first of all find the uh the device i've currently got the device plugged in i've got the usb blaster so it finds our device straight away but what i need to do now is first of all select a clock so the clock is important in signal tap because that's what triggers the event so when we see the waveforms it needs to be triggered by something so what i'm going to do is select the clock and i'm going to select signal tap pre-synthesis as the first attempt now if i hit list we get a list of our signals and the one i'm going to select is this one the 3.2 megahertz clock that's what everything else will at the moment trigger off now for the sample depth we want maybe 4k now there is a trade-off with the amount of memory that you have in the device but at the moment we're not using anything in terms of the built-in memory of this fpga so 4000 sample depth that's probably safe and now we select the signals so again i'm going to select pre-synthesis and it does a search for all the available signals that we can look at so i'm going to go into the spi interface i'm going to look at count i'm going to put that one in definitely going to look at s clock i'll look at uh d out now look at d in and look at chip select there's no point looking at clock because that's going to be same as the trigger and i think that's okay for now so i'm going to insert this these signals in they should go into the window that's that's it so sorry you probably couldn't see that but they're the signals that i selected from signal tap close and now we have to recompile that's one of the disadvantages of signal tab every time you make a change you need to recompile so let's hit recompile and i'll come back when this has finished so time to go full screen i think so when you've finished the compilation with signal tap you just need to select the output file here so if you go here select the output file it might be in output files but you get the dot sof and that will have the signal tap enabled once you have that you can just hit program device that will program the device and then you can auto run analysis by hitting that button and you can see this gives us a really good insight into what's going on so this is actually real-time signals within the fpga which we we have visibility of because of signal tap and you can see we have i'll just pause it here we definitely have the count so what i might do is just change the display format to unsigned decimal and we can see that's definitely going from 0 to 15 and then back to zero d in well that looks very much like our test bench doesn't it so that's encouraging but we also have d out here and what i'm doing is i'm applying a six kilohertz signal at one volt peak to peak with an offset of 1.6 volts so we should see d out vary so but i'm not actually sure i've got this in the right channel let me just check what channel i'm i'm actually applying the signal to because actually the channel that this is um sampling is going to be affected by the fact that we have the add one set to one so it might not be the channel that i've currently got got it connected to let me just double check okay so this is interesting i've actually changed the input channel now to channel 0 and it seems to be that the input channel that it's sampling is actually channel 0 okay and i know this because i've changed my input signal to a dc and i currently have it as an offset of zero volts so we should see absolutely nothing at the moment and that's exactly what we see on d out but watch what happens when i start increasing the dc value on this a to d converter you can see now we have a signal coming out of d out that's a hundred millivolts this is 200 millivolts 300 400 500 and you can see that signal changing so let's just recap back in the verilog code what we've just observed is when add1 is one and add0 and add2 are zero we're seeing channel 2 is being sampled so what this is telling us is this is lined up correctly so what we can start thinking about now is reading out the bits from the a to d converter and forming in our 12-bit word okay because at the moment if we look at signal tap the bits from the atd converter are coming out in series so we need to work out where the first bit is where the second bit is and we need to one by one construct a 12-bit word okay so that's the next challenge okay so i'm going to paste some code in to our fpi interface module here you can see it's another always block okay so we have always at positive edge of clock okay because we know that the d out should be registered at the positive edge of the clock that's what the time in diagram is telling us so that's exactly what we do in this always block uh now you'll note i also have a something else going on in here okay so we've got a clock out signal which goes to one approximately halfway through the cycle and the reason for that might become more clear when we go back to the signal tap okay well just to give you a preview of why this is necessary what we would like to do later on is basically sample this signal not at the spi clock rate but at the same rate as the samples are coming out of the interface code and basically we get one sample every 16 s clocks so if we create a clock and we make that clock uh transition basically go to one halfway through the cycle like this we can use this to trigger signal tap to basically tell us what the value of data route is at that time okay so that's something we'll do later but uh just to look at this again is a case statement and we're looking at you know when the value of count is six that's when we will register d out into this array so data temp is the array so the most significant bit is being registered the value of d out when the count is six and we just keep on going until we filled up all 12 bits of data temp when all 12 bits are registered into data temp we take that value of data temp and we register into that into a different 12-bit variable called data out and data out is the one that we will be looking at in signal tap and that's the one that we can basically plot our signal from registered on on clock out okay so i hope that makes sense so i just need to create these variables and just make sure everything is correct so basically data out is another register okay so it's an 11 bit register and we also need temporary register called data temp so it's the same thing still a register but this one is called data temp and we also need a new register called clock out and this is just a one bit register okay and let's just make sure we initialize these to a starting value so data route will be 12 decimal 0 and data 10 will be 12 decimal 0. and we need to make sure actually that data out is an output because we want to view this as an output of the interface code so i need to make data out and output register so i think that's basically it for now so let's save and we can then recompile okay so that's finished compilation and we're back in signal tap i'm applying a a 1.7 volt dc signal here and you can see there's something not quite right because what we would expect is you know for you know if the reference voltage on on on the hdd converter is 3.2 volts so 1.6 volts would be half range so we would expect the most significant bit here to be uh one but what we can see here is we're not quite uh getting that so if i pause this again now we know that d in you know this is for channel two so we can kind of guess that that's not quite aligned as it should be and i think if we go back to the timing diagram add1 would be there and you can see we already have some signal there and i'm just wondering if that is the most significant bit that's likely to be where it would be so there's a problem with reading these signals in so let's just go back to the code and see if we can align this a bit better now i've got it going in at count six here now maybe that should be going in at count or so i'm gonna change the first one to count four uh update the rest and then see if that makes a difference so that's the updated statement case statement here with the new numbers so i'll recompile so this is the updated signal tap results and we can see we're almost there now because you can almost map out because that's zero one zero zero one so you can see the pattern here so it must be picking out this point this bit here first when it should be picking out this bit but you can see the pattern it's one zero zero one zero zero one one one zero zero now the only reason i know what this should be is because i know that this is over halfway in the in the range so i know that this must be the most significant bit now there there is you know you could do this more scientifically if you go to the timing diagram and you compare it with what we have for d in because we know that's channel 2 so we know that must align with add1 but um trial and error it is another way to do it so i'm going to go back and just make this adjustment and then we'll come back and see if that works and the adjustment i made was just to increase the count by one so it picks up that bit just one clock cycle later so i'm back in signal tap here i'm applying a 2.2 volt dc signal and if i just pause it here you can see that i think data out is the correct value now so you can see the pattern this is d out one zero one zero one zero one one zero one and that is approximately what we're getting now if i just move the dc input to below 1.6 so this is below v ref divided by two we should see the most significant bit go to zero because now we're halfway below the range and if i pause it here you can see that's approximately correct now what i'm going to do next is just uh just grab my camera and i'll just change the wave shape to a sinusoidal wave shape but what i need to do is set the offset to 1.6 so that's v ref divided by two and then i can set my if we just choose a 200 millivolt rms sinusoidal wave and the frequency one kilohertz so let's see what effect that's had if i just play again and now what we can do is if i right click data out and i go to bus display format unsigned line chart you can see we are seeing some kind of wave shape if i increase the frequency you can see we're seeing a sinusoidal wave which is exactly what we want to see let me quickly change this to a square wave yeah that looks a bit like a square wave but now the problem we run into now is we don't have enough samples to really see this wave properly okay and the reason for that is because signal tap is being triggered by the s-clock which is much much faster than our sample rate so if i just zoom out you can see we're taking 16 samples per output sample from the 80d converter so what we need to do is go back to the code and make signal tap trigger of a signal which is much slower and in fact if i go back to signal tap we look at our spi interface you can see we've already got this signal clock out and i talked about this uh earlier the reason i put that in is because it now gives us an option if we look at the rising edge of clock out and then sample data out that will sample that will trigger at a much slower rate and and the rate will actually be the same as the output samples from the 80d converter so we should see much more of the waveform so let's recompile signal tap but this time we'll put clock out as our trigger okay so i've now added clock out as the trigger in signal tap and just to make this clear what i needed to do was to make clock out an output from the module because signal tap in pre synthesis mode wasn't finding clock out it was being synthesized away so if you put it as an output clock sorry an output signal from the module we don't intend it to go anywhere but it just makes it easier for signal tap to basically find it so let's go back into signal tap so now we have clock out as the trigger and now that is going high at the same rate the same frequency as our samples are coming out of the 80d converter okay so now we get to see much more of the waveform so you can see here i'm applying a 12 kilohertz uh signal note that uh d out and d in these are meaningless now because we're sampling at a much slower rate than the s clock d out and d in uh uh coming out so that's meaningless at the moment so don't bother looking at these signals that's just uh meaningless but what we can see is the output waveform well much more of the signal okay so that's 12 kilohertz i can decrease the frequency that's five kilohertz i can increase the amplitude so now we can go up to five six 800 volts rms peak to peak i can change it to a square wave okay that's good ramp pulse and so on so i'm fairly happy with this now this is sampling on channel two okay but i'm satisfied now that this is doing what it should be doing and i'm satisfied that the interface code that we wrote might have taken a while it might have taken some trial and error it might have taken some repeated attempts but we got there in the end and you can see this is sampling on channel two this is exactly what we would expect for zero one zero on these add pins pin sorry on the um dn pin however if we wanted to change the channel and well i guess the common situation would be if you wanted to sample on more than one channel simultaneously that's the next challenge and that's what i'm going to do next so if we go back to the interface code and we look at the timing diagram again we recall that the channel that is being sampled by the atd converter depends on the value of these add01 and two values at the appropriate time in the timing diagram so at the moment we have it set so we have zero one zero and we've made sure that that's the case by using this always statement on an account and we verified that 0 1 0 here does indeed give us an input on channel 2 and all the other channels give no output from the hdd converter so if we want to change which channel the 80d converter is currently looking at we need to change these values and it does get a bit complicated because if we want to look at more than one channel at at once so let's say we wanted to sample channel 0 and channel 2 at the same time we would have to dynamically change these values between cycles okay so for one cycle so 16 uh cycles of the s clock would would give you one cycle so for that cycle you would look at channel zero but for the next one you would have to dynamically change the value of of these bits to change which channel the hd converter is looking at so that makes it a bit complicated one way that we can do this is by changing the value of add1 on each cycle so basically inverting this bit so if we start off at one that will look at channel two and then we can have somewhere within our code we could have maybe a command which inverts this bit so it turns it from a one to a zero so for the next cycle it will revert to channel zero so that's one way that we can have the a to d converter looking at channel two for one cycle and then channel zero for the next cycle now it's important to note here that we can't look at two channels of more than one channel simultaneously but we have to do it by cycle and what we're effectively doing here is cut in the maximum sampling rate that we can have for the 80d converter so currently we only have one channel so we can have the maximum 200 kilosamples per second but if we have two channels it cuts down to 100 kilo samples per second for each channel because effectively now we're only taking one sample every 32 s clocks rather than every 16 s clocks let's see if we can adapt this code so we can look at more than one channel now at the moment we have this variable data out and what i'm going to do is make a second variable called data out 2 and that will hold the value of the second channel okay and i'm going to use an if statement which looks at the value of add1 so if add1 is one then we will put data temp into data out if it's zero we will put data temp into data route two so let me take take a second to adjust this code and then we'll come back and have a look at it right so i've made some modifications to the code so first modification i've made is now added a statement here which inverts the value of add1 on count five so that's after add1 has been registered for that cycle we change it so it's inverted so the next cycle the other channel will be sampled so that's the first big change that's been made the next change is in the main always block here which is um registering the inputs from the hd converter into the 12-bit word what i've done on count 4 is i've looked at what the value of add 1 is for that cycle if it's one we register the temporary word which has been picked off bit by bit from the from the bits coming in and we put that into data out otherwise it goes into data out too so data out will carry one channel and data route two will carry the other channel so we should be able to see the output from both channels in signal tap and this code should be reading both channels at a reduced sampling rate so let's go over to signal tap i've already programmed it here and you can see i've um i'm applying a if i just get the the camera i'm applying to uh channel one 3.6 kilohertz so that's one of the channels and the other channel is a six kilohertz uh sine wave so we can see roughly that's what we're getting so if i decrease the frequency of the first one there we go three let's go to the other one 3.6 make them the same and if i change the amplitude that one then they look roughly the same so in terms of the the board you can see i've got um both channels of the signal generator being used and they're going into both channels into the a to d converter at the same time and we can make one of them a square wave one of them a ramp so i'm pleased with the progress so far there might be some bugs to um to iron out but hopefully you enjoyed that video so we walked through step-by-step how to write spi interface code for the a to d converter on the de0 nano board seems to work fine as you recall we started off simulating that's a good habit to get into but we very quickly transitioned to the use of signal tap and i think i've demonstrated here the usefulness of a tool like signal tap because without signal tap well well what could we do i mean one one solution would be to output these waveforms on a on a dac but i don't have a dac so signal tap is an amazing debugging tool if you're not already using it i would highly recommend you develop some expertise in it because it will expedite your fpga development so thank you very much for watching and i'll see you in the next video you
Info
Channel: Visual Electric
Views: 8,936
Rating: 4.9658117 out of 5
Keywords: SPI, SPI Interface, adc, ADC, Verilog, signaltap, FPGA, DEO-NANO, DE0, NANO, HDL, adc128s022
Id: 7gQxw3FUchY
Channel Id: undefined
Length: 53min 42sec (3222 seconds)
Published: Tue Sep 22 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.