ADS1115 I2C A/D Convertor

Coming up next on HC2016 project –  the ADS1115 I2C 4-channel A/D convertor.

ads1115This item came from AliExpress – a very nice purple board – very clean – and importantly – very cheap at £1.89.

I started off looking at some Adafruit code for a similar chip and immediately spotted something wrong and noticed some of the code comments seemed incorrect – one of our readers offered a solution but ultimately – as I plan only to use this as a straight-forward 4-channel A/D convertor, to study the Texas data sheet.  Page 11 seemed pretty clear – I put ground to ground Vcc to 3v3, the “address” pin to ground (that pin can offer up to 4 addresses amazingly – grounded gives the base address of  0x48. Of course like other i2c 7-bit addresses this will be shifted left by one – but that’s already done in my routines.

As described on page 11, all you have to do is sent a 16-bit command (MSB first) to the config register, a zero to the pointer register then read 2 bytes (MSB first) from the read conversion register. What could be easier.

Having a need for a different number of parameters than before – in this case a receive where only the address is fired out – no parameters but just read 2 bytes back I made a new function which should make it easier to talk to devices in the future..

ic2_general(address,buffer,transmit_length,receive_length);

That way I get to need only one I2c function to do the lot – passing zero or more bytes – and receiving zero or more bytes.  I could see me back-fitting older code with this.

And (cutting out lots of experimenting) it works – I didn’t need a library for simple reading – it’s easy.

If you look at page 19 of the data sheet there are all manner of options for the config reg – I chose 4.096v as the full scale input – and using an argument I can setup which input (1,2,3,4) or read (0).

Initially {ads1115:1}  – that sets up input A0 and continuous conversion

then

{ads1115:0} – reads the value back.

Now an important point here – if you wire up the unit to 3v3 – you should NOT exceed that – so in my case I ended up with a reading around 26,385 when connecting the relevant input to 3v3 because of course this device can handle positive and negative inputs.

That value, given a top value of 32,767 for 4.096v full range indicates my supply voltage is 3.296.  My meter suggests Vcc is 3.28v so one of them is out just a TAD (mind you as the meter only had 2 digits after the decimal point the real value could have been very near 3.29 – so I’m not complaining – the readings were pretty consistent, not varying more than 3 digits and zero volts was showing at value 3 which seems reasonable given my shoddy wiring on this prototype.

Reading data - reasonably quickly

All in all – a nice addition for under £2 all in… so in one example I currently measure 12v battery voltage on my Pergola using the ESP built in A/D – now I can measure battery AND solar charger and figure out current and losses from there. That’ll make for some pretty graphs. I’m sure you can think of some much better uses.

28 thoughts on “ADS1115 I2C A/D Convertor

  1. Hi Peter, is your i2c function public? I’m trying to use this with an ESP32 but having stability problems that I think are related to the Adafruit library – I’m only wanting to pull off the A0 (single ended) value.

  2. MrShark – yes, they would be… right now we’re storing our web setup pages in FLASH arrays mainly so we end up with one ROM (+rboot). We could easily have put them into the top memory – but wanted to attempt to keep compatibility with smaller boards. In the future this extra memory could be used as storage for records but I’d want something more rebust than simply storing away in Flash (what happens if there is a power loss in the middle of writing) – I don’t think spiffs takes that into account – I may be wrong – and I KNOW that the Arduino-ESP doesn’t. I use the Espressif storage function calls for local variables. These are similar to the original MQTT code in that 3, 4k blocks are used. Two blocks contain data, the third block uses only a pointer to the first or second. The point of this – is that if you are updating info, it is updated to a new block along with the old data (takes the same time to write one byte as the whole block). When that is done, the 3rd block is updated. So if the update fails due to power loss, you only lose the last update. If the update succeeds but the power fails on writing to that third block – you still only lose the last update. I think I’d like to see that applied to ANY flash writing of data – hence you only get 1/3rd of the total available – but it is secure. Now you could make more efficient use of the third block – but that would involve more writing.

    Another way I thought of doing it which would only take 2 blocks – would be to read the last 32-bit value in one of two blocks and see which is the higher – and use that as the current block. When updating, the OTHER block would be updated – with a higher number. If that failed you continue to use the other block – etc. but I’ve not tried that in practice yet. If anyone steals that idea – it was mine 🙂

  3. The ADS1115 sounds good initially, but severely limited for its price. I bought one for my energy meter project, but later realized that the sampling rate is too low, and the ADC is multiplexed, similar to common MCUs (reducing sampling rate further). An Atmega328 (for 10-bit resolution) or STM32 (for 12-bit resolution) can do the job as an ADC and much more 🙂

    1. As it happens I already had the Atmega working – had not quite twigged that the ad convertor was 10 bit.. I’ll sort that now. Ta. STM32 on it’s way.

        1. Hi there MrShark – exciting on the surface of it – in fact a standard ESP with extra FLASH. Now -bear in mind that for example the ESP12 has 4 MEG of flash… 2 meg for programs (OTA), leaving 2 meg for…. erm… well, you could do some logging.

          Moving up to 16 Meg gives you… the same – but more logging. You won’t get bigger programs.

          I note that in the Arduino ESP they have a file system – but I also believe that neither their normal backup for system vars nor the file system has redundancy – and apparently adding this would cause compatibility issues – so personally I would not be using that. So really, not entirely sure why I’d want to pay more to get extra FLASH I can’t think of a use for.

          Did I miss something?
          🙂

          Pete.

          1. What I’d REALLY like – given my new I2c skills – is a board just like the ones we use now – with an Atmega328 and 16 meg Xtal on… and some connectors. By losing GPIO12 and 13 (one is used as an easily replaceable indicator, the other just for general purpose) – I would LOSE 2 outputs – but gain 4 ADCs, 13 digital IO lines, PWM, timers, beepers, etc etc etc… all for just a tiny bit of board optimisation. I could easily doctor my code to great {OUT0} all the way through to {OUT20} or so without a break – additional costs minimal – ok I can now do this with a tiny NANO board but having it all on one small cheap board would be lovely.

          2. You’re the boss, I just found that on Twitter and reported to talk about it 🙂
            In comments it’s reported about this memory, maybe the most interesting part is the ceramic antenna (some say better signal) and the external connector (via a resistor that needs to be rotated between 2 pads, as you did on some board in the past, if I remember well) 🙂

            1. Well, we are thinking about it – waiting to see what this new SAM32 board is like before taking the plunge – but it would convey two opportunities – one to get more IO and secondly to support stuff that won’t readily translate into the C environment on Eclipse etc.. Actually, I’d like to take the entire C code I have and make it work as C++ but that is proving to be a mental challenge. It would however make it a lot easier to get Arduino libraries working outside of Arduino.

  4. Turns out that the board mentions TWO chips – and when I looked at the purchase it was for the ADS1115… I guess that’s good because it sounds like a later chip. Almost got the basics working – but I need a good night’s sleep to go to the next step.

      1. Ah, right – thanks – saved me some reading. Well, I’m up early this morning – time to go look see what I’m doing wrong.

    1. Yes – actually you can OR or just add after shifting. Ok, looks like I need a new routine to receive 16 bits – that’s easy enough.

      Cheers.

    1. /**************************************************************************/
      static uint16_t readRegister(uint8_t i2cAddress, uint8_t reg) {
      Wire.beginTransmission(i2cAddress);
      // Possible bug here, seems hard coded to CONVERT register
      // i2cwrite(ADS1115_REG_POINTER_CONVERT);
      i2cwrite(reg);
      Wire.endTransmission();
      Wire.requestFrom(i2cAddress, (uint8_t)2);
      return ((i2cread() << 8) | i2cread());
      }

      /**************************************************************************/

      1. Oh… yes… thanks… what is “i2cread()” is that just pulling in the next item? In my case I’d have a loop based on the count and pull into an array..

Comments are closed.