CS1237 24-bit ADC, a potential HX711 alternative!

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
welcome everyone in this video I'm going to show you a nice little ad converter so it is this circuit right here and the interesting part is this board here uh this is a cs12 37 24bit ad converter and why it is interesting is because it's a very cheap uh module and also very cheap ad converter but it's uh it's quite powerful so as I said it's a 24-bit resolution it has a built-in uh PGA which can go up to 128 and it also has quite a nice sampling rate so it is 1,280 so this chip or actually this board can be a very good uh alternative for the HX 711 board which is also a 24-bit ad converter uh used for load cells but it is much slower so this might be a better uh choice so here we can see that we have another chip next to the ad converter chip which is this here so the other chip here is actually a voltage reference chip and it has two purposes uh despite the fact that this ad converter has a builtin reference which is 2.5 volts uh we don't use that but we use this uh voltage reference right here which also happens to be 2.5 volts but it is not only feeding uh the reference input of this board but it is also feeding one of the pins here and this is because it can be used in a ratiometric uh measurement so both the reference and the device in use or device in test is is receiving the same reference voltage and also if there is a disturbance in the reference voltage then both uh the ad converter chip and the connected device feels the same so that kind of noise is cancelled out so then uh we have A+ and a minus pins which are the positive and negative inputs for this ADC chip because it has a differential input so actually the range uh provided by this 2.5 uh volt voltage reference is split into half so when not using the PGA so PGA equals 1 uh the range of this ad converter becomes plusus 1 and half volts so we can measure yeah negative signals as well and of course the AG and D is the analog ground so when we have these kind of four inputs we can use it with load cells uh uh but in this simple demonstration you can see that I just have a simple 10 kilohm potentiometer and then uh the device that will drive this is a simple Raspberry Pi 240 board this is a wave Share Board and you can see that uh it has a nice USBC port and it has a very tiny form factor this is a small uh breadboard I don't have a a banana for scale but I can show you I can show that this board is yeah quite tiny so you can see that the board is barely 3 cm long so it's it's really small and you can see that the there is only two wires go from the microcontroller to the ad converter because you can see here that there is only a d out and an sck uh pin here and why is that is because this has a uh B directional uh pin which is the D out or data ready so we can both read and write this pin and we have the sck which is the clock pin uh and by using only these two pins we are perfectly uh able to communicate with this uh ad converter and uh I developed the code for this uh from scratch so I will explain you how this thing works and then in future videos I will show you some nice applications for example load C and other cool stuff that can be used or utilized with this uh ad converter and before showing the code let me go back to this circuit board here so I earlier said this ad chip has an internal reference voltage but we are feeding it with an external one so actually you can modify the config uh register of this ad board and uh it can use its own internal uh reference but uh it is actually internally separated so there is nothing to switch let's say inside the chip package uh that can uh let's say route the internal reference voltage towards the input of the reference voltage pin but we have to do that manually and that is done in the following way so right here uh pin number one is the uh reference voltage pin if you look carefully you can see that that goes up to the pin here on the reference pin on the reference uh voltage source but then that can be also connected by this R5 part which is then pin number eight because that is the V ref out of the ad chip so what we can do is that uh if we don't have an external uh ad or if we don't have an external voltage source reference voltage source we can short this uh part here so the r R5 5 uh resistor either by using a Zer Ohm resistor like it is done here at R2 or we can just simply put a big solder blob here and then it's done and then that will make sure that the uh ad converter uses its own voltage reference uh which is the internal voltage reference and just for fun uh let's plug this thing in and let me do a quick measurement but of course it's nice if you see also so I'm just trying to show you the reference voltage uh value so this goes here and this goes here and of course I'm blocking it so 2.49 five volts is the voltage reference that can be also checked on pin number one here and then since I disabled the uh reference then I cannot measure anything on the other pin so that is disabled right now now then of course this is the digital voltage uh 3.3 volts once I can get the contact and then uh there's nothing else that I can measure because the rest is just the ground and and stuff so then we could see that the reference voltage is also relatively precise so now let's move to my computer and uh let me show you how the code works on this microcontroller that drives this ad converter and reads its uh values all right so we are in front of the computer and uh let's go through the code to understand how it works so in the beginning I would like to show you this uh small macro that I kind of defined here so if you look at the data sheet you will see that the operations or some of the operations require a delay uh which is below one microc namely it's 455 nond and that is not really possible by using the uh regular Arduino uh framework because the smallest amount of delay that you can use is 1 micros but this is half of it basically so what we can do here is that essentially we can run let's say empty uh cycles of the CPU or MCU in in this case and how it is done is that uh we have this uh line here uh where we have this n o which is no operation or or something like that and in the parentheses here I actually have 11 of that and that is 11 times uh the time which takes for the microcontroller to do one cycle now in this uh demonstration as you could see I use a raspberry uh 24t uh Z which has 133 mahz clock cycle so I wrote down the formula here so one clock cycle is 7.52 NCS and then uh this is somewhat uh experimental value that I came up with so in this part of the macro uh I have 11 of this n o uh which makes 8272 NS of delay and then in this uh function I call this macro uh 10 times so actually this is not 455 NS but uh it is more like 8 27.2 nond but after playing around with the microcontoller and the ad converter this is what I uh figured out to be good enough uh you will see the code you can check it on my GitHub uh so you will see the additional comments if you want but I scroll downwards now and show you the rest of the code so as I told you uh this uh chip has a kind of a simplified SPI so we have a clock pin which I defined to be the zero pin and we have a d out or data ready uh pin which I defined as the pin number one and as I wrote it here uh you have to be careful with certain microcontrollers because the pin zero and pin one is usually assigned to for example the serial communication especially with Arduino Uno or Nano uh but in this uh case I could uh use this but actually you can use any GPI op pins as long as you don't want to use them for another purpose but for these two arduinos uh you have to be a bit more careful uh because if you use uh pin number zero and pin number one on the microcontroller you won't be able to use the USB so be careful and then uh I just have two variables one is the ADC reading it's a 24bit uh ad converter and the long uh gives us uh 32 bits if I'm not wrong so we can store the 24bit in the 32-bit uh variable so it's uh the correct choice of type and int would be uh overflowed uh with with the ADC reading and then uh the PGA divider here is one actually I could uh use this 1.0 sometimes people like to define the floating point with the decimal point just to further indicate that it's a floating point and why I use an integer here uh still as a float because uh it's just more convenient for me to see that this will actually be used as a divider for a floating Point number so yeah it's just extra convenience but yeah it doesn't matter so then uh in the setup uh we start the serial communication this is the USB communication and then uh I just wait for the serial uh until it's available and after it became available I just wait three more seconds because that allows me to have an extra time to click to the top right corner and actually open the terminal so when I open the terminal I will see this uh vum message so then this moment we have have two pins so the D out uh that is an input pin and I pull it uh to low I know that it doesn't make sense or doesn't suggest too much sense for an input to write a value to it but uh trust me it works uh as I wanted to and then we have an output here uh which is also pulled to low this is just to follow the guidelines based in the data sheet and then we make sure that the the chip is awake so that is done in these two lines so basically we are waiting until this condition is true and then after this condition is true then we wait until this condition is true because in the data sheet you can see a graph uh which shows how the chips how the chip wakes up and then I wait one second just to be sure that uh yeah the chip is ready and then I set all the four parameters in the config uh regist according to my own arbitrary choice so the input there is only one input but it can uh be assigned with different values I choose uh ch0 which is the regular input where we uh really measured voltage and PGA is one so basically it's the default uh setting so we can use the full scale of the input and then uh the data rate is 10 Hertz this is also the default the lowest uh possible uh sampling rate and then uh I disabled the internal voltage uh reference and then that's all so now we can uh further proceed and first I show you how a acquisition is done because uh when we want to read and write the register it is based on this function it starts from this uh operation so uh this is a function which I wrote and it will will return with a long because it will return with the raow 24bit uh conversion value from the ad converter so we wait until the data ready Falls low and how we do that is that we have an empty V Loop here uh which stays in the loop until this is true so until the data or as long as the data ready pin or the out pin is one we are just running this empty cycle and then data ready was low so then we can proceed further so internally I just have a value which I call result uh we store the 24-bit uh data in this uh variable then we wait one microsc after after basically the data ready went low and this is equivalent or roughly equivalent to the T4 uh timing on the timing chart and then we can start uh shifting out the data and that is actually very simple because we can manually shift it out so we don't need to uh mess around with the SPI and its clock and whatever so here we basically manually toggle the scrk pin so set it to high and low with a certain time period And while we do this toggling uh we shift out the bits starting from the MSB most significant bit and then we just uh keep putting the incoming bits into the result variable so here we have uh this result and then we have this uh vertical line which is the logical or operation and then what we do is that with each clock cycle so we set it to high and then wait and then we read uh the status or read the the value of the D out uh pin and then that reading which can be either zero or one is shifted up uh to its corresponding place which is 23 minus I so in the first uh iteration of this four Loop uh this is zero so then uh the bit here here is shifted to the left uh to the 23rd bit in in this uh result variable and then we finish the clock by pulling thek low and wait again and then in the next iteration the I will be one so now the next bit which is bit number 22 uh that is shifted up and combined together with the result uh variable and so on and so on and in the last iteration when uh the four Loop is at the 23rd iteration then the parenthesis uh becomes zero so we don't shift basically so the last bit the LSB least significant bit is just combined together with the result value which already contains 23 bits and then the 2 uh fourth uh bit the last bit uh which comes in the last iteration of the for Loop is just simply combined together and then it's done and then if we continue looking at the timing chart we see that uh there are three more PES which we have to do and that is pulse number 25 26 and 27 and there we just simply toggle the clock pin uh with the uh corresponding uh clock or yeah PS cycles and then then we are done and after this is done we just return with the result which is the conversion result and that can be just displayed on the serial terminal so now we want to see how to get the value of a register so we Define a bite variable here one bite is 8 Bits and the register holds 8 Bits so this is perfect so here I perform an ADC reading as I said previously this will be necessary and actually I could only just call this function I would not need to store this uh in a variable uh actually you could get rid of this variable uh totally but for example if you want to reuse the reading even when you read the register then you can just uh refer to this uh variable and then the data sheet says that uh after reading out the ADC uh after the 27 PS we have to set the D out to Output uh this was input previously because it was reading the output of the ADC chip but now it will be an output because it will send data to the ADC chip so the shifting uh from input to Output is done then we emit two uh clock pulses so we advance uh with our uh progress and then we have to make seven more pulses so clock pulse number 30 to 36 and what this does is that it sends out a reading uh command which is this 0x uh 56 number and that is basically with each uh clock pulse it is shifted out by writing the corresponding bit on the the out pin so this is uh how it's done and after we shifted out the command we send one more pulse here I know the for Loop is uh totally unnecessary for one single pulse but I copy pasted all these kind of uh clock generation thingies so I just felt a bit lazy to clean this up but yeah uh one more pulse is uh shifted after we sent the read command so now we send the read command to the ADC chip and then the ADC chip will respond so what we have to do is that we have to set back the D out uh pin into an input pin because it will receive data so so then uh I set the register value to zero just because previously it could have been something else or uh whatever U maybe the value could have been uh yeah compromised by some way uh I might be paranoid but yeah let's set it to zero before we fill it up with data so then what we do here is that uh we just run eight pules because of the eight bits that we are going to read out and similarly to the strategy that we used to read out 24 bits we shift out only eight bits so we pause the clock so clock goes High wait a bit and then we read the status on the the out pin and then uh place the MSB to its MSB place so in the first or yeah first iteration I is zero so then and this becomes seven so the value that we read here either zero or one is shifted up uh to the bit number seven and then this is repeated until I becomes seven so then this becomes zero and that is when the LSB comes in so the value of this is just simply combined with the register value but there is no shifting done because the Bit Zero uh will be yeah put to its place and after this is done we send out just one more pul and then uh and then that's all I just set the pin uh to input once again just to be sure that uh everything is uh done and uh we are ready to return with the register value which is an 8bit uh number or a bite and that can be yeah displayed uh on the serial terminal later on and then we have to know how to set a register so I wrote a function which receiv two arguments one is the register to write and in this sense actually we have the same register all the time we so we are not choosing a register here it's just poor choice of uh name from my side uh this is the parameter to write and then uh this is the value to write so we update one of the parameters for example sampling speed and then this will be uh the value which will tell which sampling speed to choose so here uh yeah I just uh summarized uh the data sheet for myself and for you whoever uh uses this code so we can uh skip this and then uh what I have here is that first I read the register so I just uh stored the register value uh which is the most recent register value I want to see how it works uh and what was the most recent setting so I do this and then I also Define a so-called bite mask uh and that is yeah declared as totally zero and I will show you and tell you why I do this so uh based on this argument here uh I made a big switch case uh statement here so if the case is zero then I want to modify the input channels so what that means is that that uh first I create a bite mask here manually and I will use this as this so how my bite mask will work is the following as you can see uh these are all ones and these two which correspond to the uh Channel input uh selection uh are zero so you see in the next line that the register value will be the register value and the bite mask so this will actually make sure that since I use the logical end operation then whichever uh bits in the register value are in these two places they will be erased because uh when you use the logical end operation then both uh let's say bytes have to have uh ones at the at the same place to make their result uh to one as well so since the the masking bite is zero at the two places where we have the bits to select an input Channel then uh this operation will erase those uh bits whatever they were and why I do this is because I want to update them later on so then we have another deeper uh switch uh case statement and this accept the value to write uh as the argument let's say so then if that value is zero uh that means that we have the first uh option in the in the table where we can select uh inputs uh so what we have here is that this will be the channel a so we are using the proper voltage input channels on the board and uh that is actually done with this command so we read the zeroth uh or first in this case but we start numbering from zero uh zeroth parameter and it's zero possible option uh and and what we do is that uh the register value will become this so we combine the previously uh masked uh register value uh using the logical or operation with this operator so we keep everything as is and then we print to the serial Port that the channel is zero this is just for the user to to know what they did and then case number one so that's the second option in the table that is reserved we don't uh really have to do anything here so I don't do anything so I just let the user know that this is a reserved Channel invalid option blah blah blah so this this doesn't really matter and then the next is when the user sends this command to the serial Port so then uh this is what is in the table and this will be the temperature channel so then we let the user know that this is the temperature Channel and then the number three is when we send this command to the serial terminal and then uh that is when we want to have two ones or one one at these uh places and then that is when we internally short the chip and uh yeah it is what it is so then uh this is done so we can go to the next uh selection ction which is the PGA so then as you can see the masking zeros moved up two places towards the left because this is the these are the two uh bits which set the PGA so we keep everything unchanged except these two uh bits here how we do it is that uh the most recent uh reading of the register is logical anded together with the mask so then uh we can yeah work with the rest of the things so if the PGA is the first option then we read the first uh position in in this let's say bite and then uh the zeroth option so we keep everything unchanged because in the table that is 0 0 I set the PGA divider to one because uh later on this will be relevant and then we tell the user that they selected uh uh the PGA equals 1 and then the next PGA is when the PGA is set to two so that is done uh with this command here and now you can see that instead of 0 0 we set 01 to the PGA and then the PJ divider is is two simply uh two and then we let the user know and then following the same kind of uh logic then here we combine again and you can see that the two bits here is now one Z and that will be equivalent to the PGA uh 64 and then in the next uh step when both bits are one so the the two bits here are one one the PGA is 128 so then that's that and we can do the same with the D rate uh I speed up a bit here so you can see again that we have two bits that we can manipulate and again we erase the most recent register value by masking uh these two bits out from it and then we will update it according to our uh newest uh setting so as you can see we can have 10 Hertz so we have the W2 uh space zero command so again uh the two bits here are 0 0 so we keep everything as is and then 40 Hertz uh 01 640 htz it's 1 Z and then 1,280 Hertz 1 one and then each time we changed it we print print it on the serial that uh there is a new uh sampling speed uh value here and then here I implemented this one single bit here so if uh the value to write is zero so it's this one then I just simply use the bit write uh instead of masking because it's just one single bit and there is a function for it in the Arduino uh which is very simple so then the register values six uh bit become zero and then this means that the uh internal reference of the chip is enabled or we can send the number one then this is the basically the default value that we should that we should use uh is that the sixth uh bit is or bit number six is set to one and then VF is off and then if we would send another number then I just have an empty lse here so other values won't trigger anything so that's that's simple so this part only just updated the values locally in the microcontroller so now we have to do it with the with the ADC chip as well so we do an ADC reading similarly to the uh reading of a register and then we set the D out pin as an output because previously it was an input because we were reading from the ADC again two new pulses and then we have seven pulses and now we send first this value to the ad converter 0 x65 which is the right command and once the right command is shifted into the ad converters register then we do one more pulse here and then in the next eight pules here we shift out from the microcontroller to the register of the ad converter our new uh register value so the config register is updated so we have have the register value which is a bite 8 Bits and then uh bit by bit uh we shift it into the corresponding uh register and after that is done uh we do one more shift uh or one more pause uh if you like and uh set the D out as an input and that's done so now we know how to read data how to acquire data how to read register and how to right register so let's put this into a working system so I wrote a very simple Loop here uh we wait for the serial and then we are looking for a character sent from the serial port and then based on that character using this switch case uh statement we can do different things so if we send the capital r then uh we read the register so we simply run the get register function and put the value of it into this R values bite and then first I just print this and then I add the rest of the values uh to this line by uh shifting out or printing out uh the eight bits one by one uh to the serial Port so then we will see ones and zeros but it will be very easy to read because it is very easy to cross check uh with the uh settings uh in the data sheet then if we send a capital A that will be a continuous reading so what I do is that here is a while loop and while we don't send a small s to the serial Terminal S stands for stop then we acquire data and how it's done is that first we acquire the data then we check the sign of it and based on the bit number 23 which is the sign uh bit uh we can decide if we should or should not uh mirror the data because if if this becomes uh one so we can enter the if condition here then the the ADC value that we recently read has to be basically mirrored around the zero and this is how it's done so this is how you represent it as a negative number then what I do below here is that we have this voltage value which is 1,250 divided by the PGA divider so first of all the 1,250 comes from the formula in the data sheet because this is uh 0.5 times the voltage reference the voltage reference is 2 and half volts but I want to represent the data in Ms so 2,500 Ms and half of it is 1,2 50 and you could ask why half because the full range uh of the ad converter is divided into two you have the negative range and the positive range so then that uh 2 and half a volt which is basically described or defined by the reference voltage is split into half so the full range is between this uh half of the 2.5 volts basically and then we need to divide by the uh gain or PGA and then uh this is multiplied by the LSB basically least significant bit and uh that is then divided by this number which is simply this number which uh corresponds to the range of the ad converter and then uh once this uh uh thing is done I just print the row value and I print the voltage value with yeah not eight but 10 digits and then how we write the register uh as you could see we have to send basically three characters uh one letter and two numbers so first we parse uh obviously the W so we already pared it in the beginning of this switch case and then uh after the code detect that we received the W it comes to this part so first we parse the first number which comes after The W and that will select uh the the parameter in the register and uh then we have to parse the next number which is after the space and uh that will be the value that has to be updated in the register so then uh those two numbers are parsed so then we pass pass those two numbers to the to the register and that's all 400 lines of code maybe a little less if I write a bit more efficiently but uh it uh totally utilizes the uh CS 1237 0 converter so now what would be interesting is to see this in action so I just show you a few demonstration so now you can see that uh this is why I added uh three seconds of delay so I could catch up with the terminal and see these and you can see that here we have uh yeah different uh default values that I introduced you in the beginning of the code so the channel is the default channel uh PGA is One D rate is 10 Herz and VF is off so let's do a reading of the register right now and we can see that only this this value is one because of this the VF is off but everything is zero so let's change the PGA uh just for fun so that is on the parameter one and let's change it to PJ equals 2 so this is fine and I read the register again and we can see 01 here because that's uh for the PGA setting and then let's do some similar exercise with the sampling speed so sampling speed is 40 HZ now and if I read the register again then that becomes 01 again here obviously I don't want to change the channel here because uh I want to measure some voltage so then what we can do is uh we can do some sampling and let's do that by pressing a so now this is a good example because you can see that the value is unchanged and actually you can see that we have 625 here which is suspiciously half of the full range that we have and here we have this uh 8388 607 so 8,388 67 which is again half of the full range in the in bits so the problem here is that we we are feeding a higher voltage to the ADC that it can actually measure so let me tune this down so now we are reading 430 MTS and I will try to confirm this with a multimeter and my multimeter reads 435 uh Ms so it's close enough for me so I think we can accept this as a valid reading but yeah the main thing I want to show you that this uh thing works and you can see that it responds very quickly if you want we can stop this I can set the sampling rate to a slower uh value and I can even set the P or this was the PGA so let's change the sampling rate as well and now start the reading again so you can see that now the incoming data is more sluggish but for example I can go up to higher voltages and then of course I will hit the max range here again and now I'm I'm I'm below it so now we can read and you can see that uh actually where the microvolt starts so here that digit is also not too unstable so this is like 719 molts so then here starts obviously the the microvolt uh range and I'm not averaging anything or not filtering everything or anything so this could be improved uh so yeah this works I stop this I try this just to demonstrate now you can see that the terminal Goes Bananas because uh the incoming data is very fast and then with this uh I think I I can conclude that uh this is a very nice little ad converter so if you are interested in more resources please uh visit my website I also uploaded this code uh to GitHub so it's not on my uh patreon but if you feel uh you can donate me uh either by becoming my patreon or just uh leaving a donation but uh I think this could help so many people that uh it is worth to publish it on on GitHub it's not a library because I think it's too little code to struggle with all those things to make it into a library but uh yeah it's it can be used uh very easily and uh since the data sheet of this thing is in Chinese I hope that my uh translation and interpretation will help you if you want to go and uh dig deep with this uh ad converter and obviously I will not stop uh with this ad converter just uh here so I will show some applications with different devices connected to it and then we will see what are the uh capabilities this ad converter is supposed to be used with for example load cells so I will connect it to load cell in a future video and uh then we will see what it can do so once again visit my website and uh check the link in the description I left there all the usual links for useful resources and I hope that this video was useful to you I hope you learned something and see you in the next video
Info
Channel: Curious Scientist
Views: 1,935
Rating: undefined out of 5
Keywords: RP2040, microcontroller, CS1237, 24-bit AD converter, breadboard circuit, Arduino code, ADC tutorial, analog to digital converter, electronics tutorial, DIY electronics, embedded systems, microcontroller projects, electronic components, circuit design, breadboarding, programming tutorial, sensor interfacing, hardware tutorial, engineering, arduino programming, coding, load cell, bridge
Id: dSfWDSBnonM
Channel Id: undefined
Length: 44min 7sec (2647 seconds)
Published: Tue Feb 13 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.