ADS1118 - SPI - K Type Confusion

I tried to breadboard this and the readings seamed strange, so I had a pcb made and I am getting the same issue.

ADS1118 Datasheet

When reading the ADS1118 in Temp mode (Internal reading) I get the proper readings.

However when reading the ADS1118 in ADC mode with a K type thermocouple, It returns 0. If I grab ahold of the thermocouple the value will increase slowly in my hand I can get it to go up to about 12 or 13. If I put a flame on it I can get it to up to around 125 or so. I have read over the data sheet several times. I am wondering if the result I am getting is the difference between the internal temp and the temp reading of the external k type thermocouple. I can post the code if needed, but since I get the proper reading from the internal temp sensor I am not suspecting my code.

On a second note, I cant seem to capture the SPI comms on a propscope, is it just to fast for the propscope ? It cant even catch the cs line going up and down.


  • Can you post your code, or just the config params? Are you using a second type K for your cold junction reference or are you using the built-in reference? I’m no expert, but I’ve got a whole morning to kill and this does sound like fun.
  • Greg LaPollaGreg LaPolla Posts: 196
    edited 2020-05-17 - 16:00:09
    I am just trying to get a reading from the sensor. not using the reference.

    I also have a spin version of the code.
    #include "simpletools.h"                      // Include simple tools
    const int DIN = 20;
    const int DOUT = 21;
    const int CS = 22;
    const int CLK = 23;
    const int ADC_CFG = 0b1000101010001011;
    int adc;
    float volts;
    int main()                                    // Main function
      high(CS); // cs line high
      low(CLK);  // clk line low
      low(CS);  // cs line low
      high(CS); // cs line high
        low(CS); // cs line low
        adc = shift_in(DOUT,CLK,MSBPRE,16);
        high(CS); // cs line high
        adc >>= 2;
        if (adc >=0x8000) {
          adc =((~adc)+1);
          volts =((float)(adc*256/32768)*-1);
        } else {
          volts =(float)(adc*256/32768);
        volts = volts * 1000;
        // volts = adc * 0.0078125;
        print("%c adc reading = %d%c", HOME, adc, CLREOL);    // Display test message
        //print("%c adc reading = %d%c", HOME, adc, CLREOL);    // Display test message
        //print("%c Millivolts = %f%c", HOME, volts, CLREOL);    // Display test message    
  • You're running in continuous conversion mode instead of doing one-shots, so just for giggles, what happens if you change bits 7:5 ("data rate") in ADC_CFG to 8 SPS instead of the current 128?
    const int ADC_CFG = 0b1000101010001011;  'old setting
    const int ADC_CFG = 0b1000101000001011;  'new setting
  • Same result. I am using continuous mode because haven't been able to get one shot mode to work.

  • Does changing the scale factor register change the values being returned? It might be worth it to make a voltage divider that outputs 1/2 of full scale and see if this value is correctly returned in a non-differential/non-compensated input.

    FWIW, I have used this chip before and had no trouble. Looking at your code it all seems fine, so like you I’m really scratching my head. (My design used 10 meg bias resistors, but the design you are using is basically straight out of the App Note you linked, so I doubt this is a factor).
  • can you break down the one shot mode ? I cant seem to get it to work. I always get a 0 or a 8192.
  • I've been using the max31855 myself. And had no problem using 8 ea. Modules at one time K type. Don't know if you've used that one before.
  • Tracy AllenTracy Allen Posts: 6,494
    edited 2020-05-18 - 17:33:39
    I use the ADS1115 for thermocouples. It has an i2c interface rather than the spi interface of the ADS1118, but the command structures are basically the same. I think the main issue is your PGA gain setting. As is, %101, you have +/- 2.048 volts full scale. You need to push that down to +/-0.256 volts full scale, pga:=%111. That will give you around 7 microvolts per bit, which is what you need for best resolution with the thermocouple.

    Do you have the thermocouple connected between adc0 and adc1, differential? That is what the mux:=%000 calls out.

    Single conversion: Once the mode bit is set to single conversion, start a conversion by setting bit 15 of the config register high. Then wait, either for the ready line to go back high, or for the full conversion time, which should be slightly longer than clkfreq/(samplesPerSecond). Then read the conversion register. The ADC then drops back to its sleep mode until you initiate another conversion.

  • @Tracy Allen

    The thermocouple is connected to AIN0 and AIN1. I have tried with all options and I get the same result. Both of my thermocouples are kinda old like 10 + years and the insolation is fiberglass. I have ordered a new thermocouple type J from amazon that should be here today. If I don't get a better reading with that then I am at a complete loss.

    Reading the internal temp sensor gets 421 reading the external gets 0.
  • Greg: Any way you can whip-up a voltage divider with a variable resistor and apply a known potential to the inputs and see what happens?
  • Tracy AllenTracy Allen Posts: 6,494
    edited 2020-05-18 - 21:01:03
    Instead of the thermocouple, for test purposes, can you try a source of voltage from a battery or potentiometer to one or more inputs; read that? Also, you should indeed be able to see something from the spi lines on your propscope.

    The adc channels return the voltage, not temperature directly. The temperature channel is there for your program to use as a cold junction reference, but that has to be combined in firmware with the thermocouple voltage. the calculation procedure is outlined in section 10 of the data sheet. The calculation also has to know the type of thermocouple you are using. Type K and type J have different responses. An advantage of the ADS1118 is that it allows you to use any type of thermocouple.

    I might be able to help more if you post your program in Spin. I'm far from fluent in C, and I'm puzzled by the code you posted above. The config is set for reading the adc, but the returned value is shifted right by two as if it is reading the temperature channel. A 14-bit value of 421 returned from the temperature channel corresponds to about 13 °C. (421 * 0.03125 °C per bit.). Is that reasonable? In your first post, you reported a value of 125 when the K thermocouple was in a flame. Your PGA setting %101 is fine for the full scale of 256mV, 7.8125 µV per bit. But 125*7.8125/40 = ~24 °C. (The factor 40µV/°C is the typical output of the K thermocouple)
  • Here is the spin version. It's messy as I have ben tweaking it.
  • I got the new thermocouple. running it on AIN2 and AIN3 at room temperature it reads a 7. Alternating back and forth between old sensor and new sensor, old sensor always reads 0 unless you warm it up. I think it's safe to say the old thermocouples are toast.
  • You can always repair a thermocouple by cutting the damaged part off and joining the two fresh wire ends. Just has to to be a clean electrical join is all.

    The join is not where the magic happens. The naming "couple" is misleading. It's the wire itself that is doing the work. Or more specifically, along the temperature gradient of the wire.

  • You can connect you thermocouple to an ordinary 3.5 digit voltmeter on its 200mV full scale range, just to test the thermocouple for operation. Each 1 degC temperature change should give around 40 microvolts.

    You can connect a known source of voltage to the ADC inputs to test the circuit and the firmware. Basic troubleshooting.
  • Greg: K-type thermos mostly fail either because of a mechanical break (hydrogen embrittlement), contamination (sulfur), or extreme overheating that changes the characteristics of the wire. Try Tracy Allens suggestion with a multimeter. Take a torch to the tip and you should definitely see a response. See the published K-type tables for expected voltages vs temperature.
  • Please also share your "spi.spin"
        adc : "SPI" 

    The configuration word itself looks okay. One thing though,
    data := data >> 2
    That statement should only be applied to the temperature measurement. The ADC readings on the other hand use all 16 bits.
  • Here is spi.spin. I got it from the OBEX
  • This is my 8 module TC board. I posted some good thermocouple info. But it looks like it was deleted by mistake.
    1536 x 2048 - 770K
  • Tracy AllenTracy Allen Posts: 6,494
    edited 2020-05-20 - 22:31:38
    Attached is a shot from a Saleae Logic analyzer. This shows the correct transmission of the config word. There should be no problem seeing that yourself on your propscope. The spi.spin object is all spin, no pasm, so it is relatively slow and easy to capture.

    There is a possible bug in spi.spin, especially as it relates to single shot mode. Here is the Shiftout method, and you can see that it returns before it executes the instruction that is supposed to deselect the chip. So, the pin sticks low. That puzzled me when I first ran the code, but it started to work and show the proper decoding when I rewrote it with result := instead of the RETURN.
    PUB ShiftOut(Data, PINcs)      'A write method. Receives data anyway, but this is normally not use
       RETURN Transfer(dummy)           'Returns data just for the sake of it
    PUB ShiftOut(Data, PINcs)      'A write method. Receives data anyway, but this is normally not use
       result := Transfer(dummy)           '  <----- rewrote so that it will execute the next line, to deselect.
  • @DigitalBob, Thats a nice setup with the MAX31855K and the connectors.

    I'm attaching a photo of my "kSUMS" board that uses two ADS1115 chips. It can take 3 thermocouples in differential mode or 6 in single ended mode. The SIP resistor pack on the board sets the common mode voltage so that the couples have best emi resistance. There is a separate reference temperature sensor in contact with the terminal block.

    I was hopeful when the ADS1118 came out that it would be a drop-in replacement for the ADS1115, nice to have a built-in reference sensor. But for some reason, they went with SPI for the ADS1118, whereas everything else in that family is i2c. Go figure.
    720 x 540 - 97K
  • Tracey thanks for the nice comment. I used the sparkfun boards because they where quick to put together. But I'm going to make my own to keep the cost down. I'm going to pickup one of those ADS boards and see how well they work for me.
  • @Tracy Allen

    Thanks for the info on the bug. I actually got Beau's SPI spin and I found your ADS115 code in the forum and I started from scratch and I actually got the one shot to work. After that I started suspecting the code I was using had an issue.

    I will make the changes you showed there and see if I can get it to work. Doesn't RETURN cause an exit ?


    Check out JLPCB. 2 bucks for 5 boards but 17 bucks to ship. Pretty fast turn around.
  • Playing With Fusion 4ch max31856

    This is the board I have used. PWF used to make a
    Propeller based accessory control board for a FRC

    The DR0 - DR3 wires are not required, but it may
    require two 3.3v supplies (mine did).

    Bill M.
    640 x 480 - 172K
  • I am now convinced the spi in obex not the one Beaux wrote is buggy. I think there is issues with the chip select. I have switched to the spi_spin from OBEX.

    One shot is working perfectly using 2 channels.

    I can even see the communication in the Propscope. I have attached the new working code.
  • @Tracy Allen

    Using the math from your ads1115 code when you output to pst term you divide by 1000. When I do this I always get 0. I don't think thats normal.

    Is there something wrong in my code posted in previous post.

  • There is no division by 1000. Where did you see that? It may have been in a demo program I wrote for the ADS1115 when the result is displayed in whole millivolts.

    In my object for the ADS1115, I convert from the raw count into microvolts, as you have also...
    volts0 := data0 * 8 - data0  * 3 / 16
        volts1 := data1 * 8 - data1  * 3 / 16
    That serves the same purpose as the floating point operation that you have commented out
    'vlts := f.FMul(vlts,0.0078125)
    That is, 8 - 3/16 = 7 + 13/16 = 7.8125, which is the scale factor of 7.8125 microvolts per bit, on the highest programmable gain setting. To go from that to the thermocouple temperature, turn the crank on the microvolts and the reference temperature.

    You might find it expedient to extract the routines that you need from the spin object and put them as dedicated methods in your project. You only need to deal with one mode, and with 16 bit words, and with setting up the pins. There is not much to it when it is stripped down.
    Other gain settings use different scale factors:
      case ipga   ' this is the pga setting, determines scale factor, always return result in microvolts
        constant(PGA_2_3>>9) : result := result * 187 + result / 2     ' units of 187.5 microvolts per bit
        constant(PGA_1>>9) : result := result * 125                   ' units of 125 microvolts per bit
        constant(PGA_2>>9) : result := result * 62 + result / 2       ' units of 62.5 microvolts
        constant(PGA_4>>9) : result := result * 32 - result * 3 / 4   ' units of 31.25 microvolts
        constant(PGA_8>>9) : result := result * 16 - result * 3 / 8   ' units of 15.625 microvolts
        constant(PGA_16>>9) : result := result * 8 - result * 3 / 16  ' units of 7.8125 microvolts, 7_13/16 
  • I have put my drivers up on gitlab

    Spin object has been derived from Beau's SPI Spin object and Tracy's ADS1115 object. It still has a little weirdness with timing when reading thermocouple and cold junction alternately. Feedback is welcome on that.

    C driver was based on an Arduino driver I found. Seems to work pretty good. Feedback welcome on that as well.

    @Tracy Allen The divide by 1000 was in the demo program. It always is 0.

    Still trying to figure out how to get actual millivolts from the thermocouple reading. Thermocouple always reads 0 at room temp and cold junction reading is around 21C. Applying heat to thermocouple will cause it to increase from 0.

  • It sounds like it is working as it should, nicely done. Your ADS1118 demo is returning readings on the order of 10s or 100s of microvolts, as it must for a thermocouple. My ADS1115 demo divided the microvolt reading by 1000 for reading battery voltage in millivolts. You might want to do that with one of the other two channels of the ADS1118. Of course you could simplify the object a lot if you are only going to use it for thermocouples.

    There is no mystery to the actual millivolts from the thermocouple being zero at room temperature. That is, zero when the thermocouple temperature equals the reference temperature, whatever it may be. Thermocouples always produce a voltage as a function of differential temperature.

    Your next steps involve a calculation, or more likely a lookup table that has the K voltage vs temperature referred to an ice point temperature of zero °C.
    1) lookup the voltage a type k thermocouple would produce at your measured reference temperature (wrt to an ice bath).
    2) add that to your measured thermocouple differential voltage.
    3) use that to lookdown your actual thermocouple temperature.

    I'll attach my object for type K couples that takes the above steps and include DAT for type K in 10 degree intervals from -200 °C to +1370 °C. The code uses linear interpolation within those intervals.

Sign In or Register to comment.