Monday, April 6, 2015

18 Bit ADC - MCP3421 - I2C Driver - ESP8266 CBDB

----------------------------------  UPDATE  --------------------------------------

For a ADC Input Frontend with Auto-range capabilities in the 0-40V Input range take a look also at the new ADC Input related article

---------------------------------  UPADTE  ----------------------------------------

    After testing the ESP8266 Internal ADC I think it's time to see also a higher resolution ADC at work. For this project we will use Microchip MCP3421 I2C ADC.

   The MCP3421 is a single channel, low-noise, high accuracy delta-sigma A/D converter with differential inputs and up to 18 bits of resolution in a small SOT-23-6 package. The on-board precision 2.048V reference voltage enables an input range of ±2.048V differentially. 
   The device uses a two-wire I2C compatible serial interface and operates from a single power supply ranging from 2.7V to 5.5V.  

    This device has an onboard programmable gain amplifier (PGA). User can select the PGA gain of x1, x2, x4, or x8 before the analog-to-digital conversion takes place.  This allows the MCP3421 device to convert a smaller input signal with high resolution. 

    The device has two possible to configure conversion modes:
  • Continuous mode
  • One-Shot mode. 
    In One-Shot mode, the device enters a low current standby mode automatically after one conversion. This reduces current consumption greatly during idle periods. Very goob for low power battery powered applications.

    • 18-bit resolution
    • Small 6-lead SOT-23 packaging
    • Differential input operation
    • On-board voltage reference with 5 ppm/°C drift
    • On-board PGA, gains of 1, 2, 4, 8
    • Programmable data rate options
      • 3.75 SPS (18 bits)
      • 15 SPS (16 bits)
      • 60 SPS (14 bits)
      • 240 SPS (12 bits)
    • INL 10 ppm of FSR max
    • Low current consumption, 145 µA at 3V
    • One-shot or continuous conversion options
    • Supports I2C™ serial interface
    • Extended temperature range: -40°C to +125°C

    For more details, please see MCP3421 Datasheet

    As been available in SOT-23-6 package, we will use again an DIP adaptor that will make it easy to integrate it on our CBDB Board expansion slots:

MCP3421 - SOT-23-6 To DIP Adapter

   Our CBDB Board has started to evolve and develop nice, with some interesting functions on board:

    Because of the high interest and the number of requests raised by the CBDB project in the next weeks we will run small batches of CBDB based devboard PCBs. The main purpose of the CBDB board was for local training and drivers development but  if any new one interested please express your wishes at: tech at

    It will be nothing fancy, just CBDB Board + some extra goodies on a standard 2 side factory made PCB that can help you to connect in minutes a new module and start programming. A nice I2C Dev Board, KISS concept at its plenitude :). 
A related Article will follow as soon as the first ones will hit the MailBox.

CBDB DevBoard v2.0b


    What we will need for our ADC project:

MCP3421 ADC I2C Driver implementation

    As MCP3421 has a I2C compatible compatible interface, driver building it following more or less the same  process  as before for I2C devices.
   Few important consideration about MCP3421: 

   The MCP3421 has an 8-bit wide configuration register to select for: PGA gain, conversion rate, and conversion mode. This register allows the user to change the operating condition of the device and check the status of the device operation. The user can rewrite the configuration byte any time during the device operation.

    The MCP3421 device accepts a fully differential analog input signal which is connected on the VIN+ and VINinput pins. The differential voltage that is converted is defined by VIN = (VIN+ - VIN-) where VIN+ is the voltage applied at the VIN+ pin and VIN- is the voltage applied at the VIN- pin. 
    The input signal level is amplified by the programmable gain amplifier (PGA) before the conversion.

    The digital output code produced by the MCP3421 is a function of PGA gain, input signal, and internal reference voltage. In a fixed setting, the digital output code is proportional to the voltage difference between the two analog inputs.

   The output data format is a binary two’s complement.

   With this code scheme, the MSB can be considered a sign indicator. When the MSB is a logic ‘0’, it indicates a positive value. When the MSB is a logic ‘1’, it
indicates a negative value. The following is an example of the output code: 
  •  for a negative full-scale input voltage: 100...000 
  • for a zero differential input voltage: 000...000
  • for a positive full-scale input voltage: 011...111.

   The MSB is always transmitted first through the serial port. The number of data bits for each conversion is 18, 16, 14, or 12 bits depending on the conversion mode selection.

   LSB size vs. conversion mode set :

   Bit Resolutions     LSB (V)
                 12 bits     1 mV
                 14 bits     250 μV
                 16 bits     62.5 μV
                 18 bits     15.625 μV

    For programming and uploading the driver and the software we will continue to use the LuaUploader as before.

  1. Init I2C bus/interface

          init = function (self, sda, scl)
                i2c.setup(0x0, sda, scl, i2c.SLOW)

   2. Write ADC Register Function

         write_ADC_config = function ( self, dev_addr, set) 
               i2c.address(0x0, dev_addr ,i2c.TRANSMITTER)

  3. READ ADC Function - 12, 14, or 16 bit-mode, 0-2.048V Range

         read_ADC_data = function (self,dev_addr)
              i2c.address(0x0, dev_addr,i2c.RECEIVER)
              c =,3)
              vadc = (bit.lshift(string.byte(c, 1), 8) + string.byte(c, 2))
              return vadc

For testing,  pack it together and save the code on ESP as 'mcp3421.lua', restart ESP and run:

        require('mcp3421')                                         -- call for new created MCP3421 Module Driver
        sda=2 --GPIO4
        scl=1 --GPIO5
        mcp3421:init(sda, scl)                                    -- init I2C
        mcp3421:write_ADC_config(0x68, 0x10)     -- Write Register config: 12Bit/CCV/PGA = 1V/V
        adc_val = mcp3421:read_ADC_data(0x68) -- Read ADC Data

        print("ADC Value : "..adc_val)

        lsb=1         -- 12 bit -> LSB = 1mA

        vts = (adc_val * l1)/1000*4.3043     --calibrate based on your power supply, Vref and divider

        print("\nValue = " ..adc_val.." \nVolts = "..string.format("%g",vts).." mV")
        print("\nValue = " ..adc_val.." \nVolts = "..string.format("%.4f",vts).." mV")

MCP3421 ADC - First test
First Test Video - Noisy environment - Live Bus voltage:

Filtered clean source voltage measurement :

 4. Read ADC and Print values on LCD 

       read_ADC_LCD1 = function()
            adc_val = mcp3421:read_ADC_data(0x68)
            l1=1         -- 12 bit
            --l1=0.0625    -- 16 bit
           val = (adc_val * l1)/1000*4.3043
           print("    ReadADC     : "..val)
           val = string.format("%g",val)

For testing,  pack it together and save the code on ESP as 'mcp3421.lua', restart ESP and run:

        require('mcp3421')                                         -- call for new created MCP3421 Module Driver
        sda=2 --GPIO4
        scl=1 --GPIO5
        mcp3421:init(sda, scl)                                    -- init I2C
        mcp3421:write_ADC_config(0x68, 0x10)     -- Write Register config: 12Bit/CCV/PGA = 1V/V


        st7032i:lcd_write("ADC_Val  Volts")

       tmr.alarm(0, 1000, 1, function() read_ADC_LCD1() end)  -- read ADC and Print on LCD

MCP3421 ADC - LCD Print test
MCP3421 ADC - LCD Print test

        1. Test done in filtered environment - highly stable voltage

        2. Test done in noisy environment - using real bus voltage - unfiltered 

       3. Test done in noisy environment - values are printed directly on CBDB DevBoard LCD Display

                      Thank you all for your continuous support and great feedback!


ferdo said...

I tested your code and it does not works. Can you please publish all the code to download?
Thank you.


Unknown said...

Hi Fero,

Are you sure that you are using the right I2C address for the ADC? It can be different than in the case above, please read datasheet about.

Full MCP3421 ADC I2C driver code:

ferdo said...


thank you for your response. Can you please write me which parameter is necessary to change ( I2C address ) ?
It's in the function write_ADC_config(0x68, 0x10)?
Thank you.


Unknown said...

you need to replace "dev_addr" that in my case is 0x68 with de I2C address of your ADC, look what version you have and choose address based on the datasheet.

I have used so far these variants: MCP3421A0T, MCP3421A1T, MCP3421A2T. Each one have a different I2C address.

Unknown said...


Post a Comment