Showing posts with label I2C Driver. Show all posts
Showing posts with label I2C Driver. Show all posts

Saturday, July 30, 2016

AC PWM Dimmer with Light Sensor



//YOUTUBE VIDEO HERE//

You can see this article as a continuation of the previous BH1750FVI - I2C Light Sensor Driver one.

    The main goal of the project is to create a AC Mains Light dimmer that can automatically control the level of light and keep in in the desired set interval without any external intervention.

   Why would you be intrested in such a setup? Well, if you have any interest in hydroponics, photography, or anywhere where you need some sort of constant flood light lamps with precise light intensitity level setup then might be a good idea to take a look :)


What we will need:

 

     Connection with the ESP8266 nEXT EVO Board is very easy, as MPU6050 GY-521 Module connector is fully compatible with the nEXT Bus connector. Depending on how to you choose you socket type, you can install it on TOP or Bottom of the ESP8266 nEXT EVO Board :



BH1750FVI Module directly connected to the ESP8266 nEXT EVO Board


And the whole project setup, with MPDVv4 AC Dimmer connected on ESP8266 GPIO13 (pin 7):

 
MPDM v4 + nEXT EVO + BH1750FVI



Closer look, MPDMv4 connected at ESP8266 GPIO13 (Pin7) for PWM control



Software implementation

You will need also the code from the previous BH1750FVI article. Please take also a look there for more details.




1. Ligth level auto-adjust function

 function set_light()
    read_input(dev_addr)
    ll = light - hst    --lower level
    lh = light + hst    --upper level
    if (lux < ll) then
       p=0
       i = i - step
       if (i<0) then i = 0
       end
       pwm.setduty(7, i)    
    end
    if (lux >lh) then
       p=0
       i = i + step
       if (i>880) then i = 880
       end
       pwm.setduty(7, i)    
    end
    --print("Auto Level Adjust : "..i)
    --print(ll)
    --print(lh)
    if (ll< lux and lux < lh) then
      if (p<1) then p=1
      end
      if (p<2) then
         print(string.format("\nLight Level: %0.2f lux",lux))
         print("Auto Level Adjust : "..i)
         p=2
      end
    end
end



Main Program
 
--PWM testing for MPDMv4 AC Dimmer Board
 

pwm.setup(7, 500, 850)    --MPDMv4 control pin
i=10                                  --initial Light Level

pwm.setduty(7, i)             --set initial ligfht level

light = 250                       --light level
hst = 40                            --histeresis coef for desired light interval
step = 1                            --light step
p=0         
 

--read light intensity value every 50 and autoadjust Light Dimmer Driver accordingly
tmr.alarm( 1, 50, 1, function()
  set_light()
end)



Wednesday, July 27, 2016

Mailbag - BH1750FVI - I2C Light Sensor Driver




//YOUTUBE VIDEO WILL FOLLOW HERE //

   In the process of choosing of some Light Sensors for one of the new projects that will involve the nEXT EVO Board and also the MPDMv4 Mains Dimmer  somebody suggested to give a try also to the ROHM BH1750FVI Sensor.

Just received some BH1750FVI modules in my mail yesterday and must say that it's a pretty impressive little board for only about 2.5USD, even less in a pack of 10!

This is how are looking the received modules:

BH1750FVI Module - TOP

   As you can see on the picture above, on the tiny board, you have the BH1750FVI Sensor, a LDO regulator some filtering caps and pull-up resistors and that's it!



 
BH1750FVI Module - Bottom
     The bottom side is bringing us more good news, the Module interface connector is fully compatible with the nEXT EVO  Bus!



BH1750FVI Overview

  BH1750FVI is an digital Ambient Light Sensor IC for I2C bus interface. This IC is the mostly used to obtain the ambient light data for adjusting LCD and Keypad backlight power of Mobile phone. 
 This is great as we are looking forward to use it for Automatic light adjustment using the MPDMv4 AC Dimmer board :)





Features

  • I2C bus Interface ( f / s Mode Support )
  • Spectral responsibility is approximately human eye response
  • Illuminance to Digital Converter
  • Wide range and High resolution. ( 1 - 65535 lx )
  • Low Current by power down function
  • 50Hz / 60Hz Light noise reject-function
  • 1.8V Logic input interface
  • Native 3.3V Device
  • No need any external parts
  • Light source dependency is little. ( ex. Incandescent Lamp. Fluorescent Lamp. Halogen Lamp. White LED. Sun Light )
  • It is possible to select 2 type of I2C slave-address.
  • Adjustable measurement result for influence of optical window ( It is possible to detect min. 0.11 lx, max. 100000 lx by using this function. )
  • Small measurement variation (+/- 20%)
  • The influence of infrared is very small.


Internal Diagram
BH1750FVI - Internal Diagram

  • PD - Photo diode with approximately human eye response.
  • AMP - Integration-OPAMP for converting from PD current to Voltage.
  • ADC - AD converter for obtainment Digital 16bit data.
  • Logic + I2C Interface :
                 - Ambient Light Calculation and I2C BUS Interface. It is including below register.
                 - Data Register - This is for registration of Ambient Light Data. Initial Value is
                       "0000_0000_0000_0000".
                 - Measurement Time Register - This is for registration of measurement time. Initial Value
                          is  "0100_0101".
  • OSC - Internal Oscillator ( typ. 320kHz ). It is CLK for internal logic.

For more details please take a look at the BH1750FVI Datasheet.



What we will need:

    Connection with the ESP8266 nEXT EVO Board is very easy, as MPU6050 GY-521 Module connector is fully compatible with the nEXT Bus connector. Depending on how to you choose you socket type, you can install it on TOP or Bottom of the ESP8266 nEXT EVO Board :


BH1750FVI Module directly connected to the ESP8266 nEXT EVO Board







BH1750FVI Driver implementation


1. Init I2C bus/interface


 Standard I2C Bus Initialisation function:

function init_I2C()
    i2c.setup(bus, sda, scl, i2c.SLOW)
end



2. WRITE Function - Set BH1750FVI Register config

      From BH1750FVI Datasheet :
   

  • No active state : pwr_down 0x00 
  • Wating for measurment command : pwr_on=0x01 
  • Reset data register value - not accepted in POWER_DOWN mode : reset=0x07

    Continuous modes, no pwr down:
  •  Start measurement at 1lx resolution. Measurement time is approx 120ms:
            hi_res_m1=0x10 
  • Start measurement at 0.5lx resolution. Measurement time is approx 120ms. 
           hi_res_m2=0x11
  • Start measurement at 4lx resolution. Measurement time is approx 16ms.
           lo_res_m1=0x13


    Device is automatically set to Power Down after measurement:
  • Start measurement at 1lx resolution. Measurement time is approx 120ms.
          hi_res_m3=0x20
  • Start measurement at 0.5lx resolution. Measurement time is approx 120ms.
           hi_res_m4=0x21
  • Start measurement at 1lx resolution. Measurement time is approx 120ms.
          lo_res_m2=0x23
 

function setcfg(cfg) 
    i2c.start(id)
    i2c.address(id, dev_addr ,i2c.TRANSMITTER)
    i2c.write(id,cfg)
    i2c.stop(id)
end


3. READ Sensor Input Function


Measurement Procedure

function read_input(dev_addr)
      i2c.start(id)
      i2c.address(id, dev_addr,i2c.RECEIVER)
      c = i2c.read(id,2)
      i2c.stop(id)
      --print("RAW H: "..string.byte(c,1))
      --print("RAW L: "..string.byte(c,2))
      rawl = (bit.lshift(string.byte(c, 1), 8) + string.byte(c, 2))
      lux = rawl/1.2
      print(string.format("\nLight Level: %0.2f lux",lux))
      --print(string.format("             %d raw",rawl))
      return rawl
end


4. MAIN PROGRAM


id = 0                    --I2C Bus ID
sda=2                     --GPIO4
scl=1                      --GPIO5
dev_addr = 0x23   --BH1750FVI I2C Address
i2c_init()                          --init I2C Bus
setcfg(hi_res_m1)            --SET config register
read_input(dev_addr)     --Read sensor data and compute LUX Light level value





Thursday, March 31, 2016

Mailbag - Si7021 / SHT21 Temperature/Humidity sensor








And the story behind: 

Somebody sent to me a nice & tiny temperature/humidity sensor breakout board based on the Si7021 IC:

Si7021 Module - Top View

On the Top side we have Si7021 Sensor only.


Si7021 Module - Bottom View

Bottom Side, a 3.3V LDO and a Voltage level shifting circuit that probably makes it 5V tolerant on I2C bus. We will use it at 3.3V so nothing to worry about.



DESCRIPTION

    The  Si7021  I2C  Humidity  and  Temperature  Sensor  is  a  monolithic  CMOS  IC integrating   humidity   and   temperature   sensor   elements,   an   analog-to-digital converter, signal processing, calibration data, and an I2C Interface.

    The patented use of industry-standard, low-K polymeric dielectrics for sensing humidity enables the  construction  of  low-power,  monolithic  CMOS  Sensor  ICs  with  low  drift  and hysteresis, and excellent long term stability.

   The  humidity  and  temperature  sensors  are  factory-calibrated  and  the  calibration data is stored in the on-chip non-volatile memory.  This ensures that the sensors are fully interchangeable, with no recalibration or software changes required.

   The Si7021 offers an accurate, low-power, factory-calibrated digital solution ideal for measuring humidity, dew-point, and temperature, in applications ranging from HVAC/R and asset tracking to industrial and consumer platforms.


Si7021 - Block Diagram


Nice. Looks more or less like SHT21 from Sensirion. And we will see that it is quite compatible (at least on the temp/humidity reading procedure side) with small differences for the rest of registers.




FEATURES
  • Precision Relative Humidity Sensor - ± 3% RH (max), 0–80% RH
  • High Accuracy Temperature Sensor - ±0.4 °C (max), –10 to 85 °C
  • 0 to 100% RH operating range
  • Up to –40 to +125 °C operating range
  • Wide operating voltage (1.9 to 3.6 V) (SHT21 - 2.1V min !)
  • Low Power Consumption:
         - 150 μA active current
         - 60 nA standby current
  • Factory-calibrated 
  • I2C Interface
  • Integrated on-chip heater
  • 3x3 mm DFN Package
  • Excellent long term stability
  • Optional factory-installed cover
        - Low-profile
        - Protection during reflow
        - Excludes liquids and particulates



Si7021 - Pinout Diagram



Typical Application Circuit for Relative Humidity and Temperature Measurements




For more details please take a look at the Si7021 Datasheet.



What we will need:

  • ESP8266 nEXT EVO Board
  • Si7021 Module as the one from above
  • For programming and uploading the driver and the software we will continue to use the LuaUploader as before.  
Connection with ESP8266 nEXT EVO Board is pretty straight-forward as the module is fully pin-to-pin compatible with the availavble nEXT Bus connector.

 
Si7021 Board connected with ESP8266 nEXT EVO DevBoard - TOP view




Si7021 Board connected with ESP8266 nEXT EVO DevBoard - 45 deg view





Software implementation

 The Si7021 communicates with the host controller over a digital I2C interface. The 7-bit base slave address is 0x40

 Master I2C devices communicate with the Si7021 using a command structure. The commands are listed below in the I2C command  table.  
 Commands  other  than  those  documented  below  are  undefined  and  should  not  be  sent  to  the device.


 
I2C Command Table



Issuing a Measurement Command
 
   The measurement commands instruct the Si7021 to perform one of two possible measurements: Relative Humidity or  Temperature. 

   The  procedure  to  issue  any  one  of  these  commands  is  identical.  While  the  measurement  is  in progress, the option of either clock stretching (Hold Master Mode) or Not Acknowledging read requests (No Hold Master  Mode)  is  available  to  indicate  to  the  master  that  the  measurement  is  in  progress. The  chosen  command code determines which mode is used.

   Optionally,  a  checksum  byte  can  be  returned  from  the  slave  for  use  in  checking  for  transmission  errors.  The checksum  byte  will  follow  the  least  significant  measurement  byte  if  it  is  acknowledged  by  the  master.  


   The checksum  byte  is  not  returned  if  the  master  “not  acknowledges”  the  least  significant  measurement  byte.  The checksum byte is calculated using a CRC generator polynomial of x^8+ x^5 + x^4 + 1, with an initialization of 0x00.

   The  checksum  byte  is  optional  after  initiating  an  RH  or  temperature  measurement  with  commands  0xE5,  0xF5,0xE3, and 0xF3. It is required for reading the electronic ID with commands 0xFA 0x0F and 0xFC 0xC9. 


  For all other commands, the checksum byte is not supported.









1. Init I2C bus/interface

 Standard I2C Bus Initialisation function:

function init_I2C()
    i2c.setup(bus, sda, scl, i2c.SLOW)
end

2.  Write Si7021 Register Function


    write_Si_Reg = function (dev_addr, set) 
          i2c.start(0x0)
          i2c.address(0x0, dev_addr ,i2c.TRANSMITTER)
          i2c.write(0x0,set)
          i2c.stop(0x0)
          tmr.delay(5000)
     end

 3.  Read Si7021 Register Function 


     read_Si_Reg = function (dev_addr)          
          i2c.start(0x0)
          i2c.address(0x0, dev_addr,i2c.RECEIVER)
          tmr.delay(5000)
          c = i2c.read(0x0,2)
          i2c.stop(0x0)

          rval = (bit.lshift(string.byte(c, 1), 8) + string.byte(c, 2))
          status = bit.band(rval,3)    --save status bits
          rval = bit.band(rval,65532)  --clear status bits
          return rval, status
     end

 4. Measuring Relative Humidity
 

         Once  a  relative  humidity  measurement  has  been  made,  the  results  of  the  measurement  
     may  be  converted  to percent relative humidity by using the following expression:

             hum = -6.0+125.0/65536.0*rval

       A humidity measurement will always return XXXXXX10 in the LSB field -> Status bit = 1 -> 

     marking a Humidity measurement data.

function read_hum()
   write_Si_Reg(dev_addr, RHumidityHoldCmd)
   tmr.delay(10000)
   read_Si_Reg(dev_addr)       
   hum = -6.0+125.0/65536.0*rval
   print("\nStatus : "..status)
   print("Humidity : "..string.format("%.2f",hum).."%")
end

 

5. Measuring Temperature

   Each time a relative humidity measurement is made a temperature measurement is also made for the purposes of temperature  compensation  of  the  relative  humidity  measurement.  If  the  temperature  value  is  required,  it  can  be read  using  command  0xE0;  this  avoids  having  to  perform  a  second  temperature  measurement.  


   The  measure temperature  commands  0xE3  and  0xF3  will  perform  a  temperature  measurement  and  return  the  measurement value, command 0xE0 does not perform a measurement but returns the temperature value measured during the relative humidity measurement.
The checksum output is not available with the 0xE0 command.

The results of the temperature measurement may be converted to temperature in degrees Celsius (°C) using the following expression:


     temp = -46.85+175.72/65536.0*rval

  A temperature measurement will always return XXXXXX00 in the LSB field - Status bit = 0 -> marking a Temperature measurement data.


 function read_temp()
   write_Si_Reg(dev_addr, TempHoldCmd)
   read_Si_Reg(dev_addr)      
   temp = -46.85+175.72/65536.0*rval
   print("Status : "..status)
   print("Temperature : "..string.format("%.2f",temp).."C")
end


6. Main Program
init_I2C()

tmr.alarm( 0, 5000, 1, function()
    read_hum()
    read_temp()
end)




Thursday, April 9, 2015

Mailbag Arrival !! DS3231 - I2C Real Time Clock Module





     If  you remember my article about PCF8563 Real Time Clock  this one was a looong avaited MailBox hit. Actually I didn't expect it to show anymore after so much time but miracles happening sometime :)

     The DS3231 is a extremely accurate I2C real-time clock (RTC) with an integrated temperature-compensated crystal oscillator (TCXO) and crystal.

     The device incorporates a battery input, and maintains accurate timekeeping when main power to the device is interrupted. The integration of the crystal resonator enhances the long-term accuracy of the device as well as reduces the piece-part count in a manufacturing line.

     The RTC maintains seconds, minutes, hours, day, date,month, and year information. The date at the end of the month is automatically adjusted for months with fewer than 31 days, including corrections for leap year. The clock operates in either the 24-hour or 12-hour format with an AM/PM indicator. 


      Two programmable time-of-day alarms and a programmable square-wave output are provided. Address and data are transferred serially through an I2C bidirectional bus.
 

      A precision temperature-compensated voltage reference and comparator circuit monitors the status of VCC to detect power failures, to provide a reset output, and to automatically switch to the backup supply when necessary. Additionally, the RST pin is monitored as a pushbutton input for generating a μP reset.

 
DS3231 Typical Operating Circuit


FEATURES :
  •  Highly Accurate RTC Completely Manages All Timekeeping Functions
            •   Real-Time Clock Counts Seconds, Minutes, Hours, Date of the Month, Month, Day of 
                   the   Week, and Year, with Leap-Year Compensation Valid Up to 2100
            •  Accuracy ±2ppm from 0°C to +40°C
            •  Accuracy ±3.5ppm from -40°C to +85°C
            •  Digital Temp Sensor Output: ±3°C Accuracy
            •  Register for Aging Trim
            •  Active-Low RST Output/Pushbutton Reset Debounce Input
            •  Two Time-of-Day Alarms
            •  Programmable Square-Wave Output Signal

  • Simple Serial Interface Connects to Most Microcontrollers
            •  Fast (400kHz) I2C Interface
  • Battery-Backup Input for Continuous Timekeeping
            •  Low Power Operation Extends Battery-Backup Run Time
            •  3.3V Operation

  • Operating Temperature Ranges: Commercial (0°C to +70°C) and Industrial (-40°C to +85°C)
  • Underwriters Laboratories® (UL) Recognized
     
 For more details, please see  DS3231 Datasheet



DS3231 Module:

 
Top


Bottom

Close-up

    As you can see from the pictures above, a nice compact module, with backup battery holder on the back (CR2032). Also you can find on the same module sharing the I2C bus a 24C32N EEPROM ( 32k - 4096 x 8) , totally independent from the RTC circuit. A nice addon for a possible WIFI Datalogger system, what do you think about? :)

  32k might sound a small amount of data storage but depending on your application requests might be more than enough for collecting 6 moths or a year data, even more. As I know already from your requests that this subject is of big interest, we will elaborate more about this one in the next article, for now let's go back to our fancy RTC :)


Clock and Calendar - Theory of operation

   The time and calendar information is obtained by reading the appropriate register bytes. The time and calendar data are set or initialized by writing the appropriate register bytes. The contents of the time and calendar registers are in the binary-coded decimal (BCD) format.
 

    The DS3231 can be run in either 12-hour or 24-hour mode. Bit 6 of the hours register is defined as the 12- or 24-hour mode select bit. When high, the 12-hour mode is selected. In the 12-hour mode, bit 5 is the AM/PM bit with logic-high being PM. In the 24-hour mode, bit 5 is the 20-hour bit (20–23 hours).
 

The century bit (bit 7 of the month register) is toggled when the years register overflows from 99 to 00.
 

   The day-of-week register increments at midnight. Values that correspond to the day of week are user-defined but must be sequential (i.e., if 1 equals Sunday, then 2 equals Monday, and so on). Illogical time and date entries result in undefined operation.
 

   When reading or writing the time and date registers, secondary (user) buffers are used to prevent errors when the internal registers update. When reading the time and date registers, the user buffers are synchronized to the internal registers on any START and when the register pointer rolls over to zero. The time information is read from these secondary registers, while the clock continues to run. This eliminates the need to reread the registers in case the main registers update during a read.
 

   The countdown chain is reset whenever the seconds register is written. Write transfers occur on the acknowledge from the DS3231. Once the countdown chain is reset, to avoid rollover issues the remaining time and date registers must be written within 1 second.

   The 1Hz square-wave output, if enabled, transitions high 500ms after the seconds data transfer, provided the oscillator is already running. 



   What we will need:
  • CBDB Board
  • USB adapter (take a look on Part 1 for details how to connect them together)
  • DS3231 Module from above

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



Driver implementation

    As DS3231 has a I2C compatible compatible interface, driver building it following more or less the same  process  as before for I2C devices.



1. Data conversion functions:

  1.1 Decimal to BCD:

        function decToBcd(val)
             local d = string.format("%d",tonumber(val / 10))
             local d1 = tonumber(d*10)
             local d2 = val - d1
            return tonumber(d*16+d2)
         end

  

1.2  BCD to Decimal:

      function bcdToDec(val)
           local hl=bit.rshift(val, 4)
           local hh=bit.band(val,0xf)
          local hr = string.format("%d%d", hl, hh)
          return string.format("%d%d", hl, hh)
     end


 
2. Init I2C bus/interface:

        address = 0x51, -- A2, A1, A0 = 0
        id = 0


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

 

3. ReadTime function:

      readTime = function (self)
       wkd = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }
       i2c.start(self.id)
       i2c.address(self.id, self.address, i2c.TRANSMITTER)
       i2c.write(self.id, 0x00)
       i2c.stop(self.id)
       i2c.start(self.id)
       i2c.address(self.id, self.address, i2c.RECEIVER)
       c=i2c.read(self.id, 7)
       i2c.stop(self.id)
       return  bcdToDec(string.byte(c,1)),
               bcdToDec(string.byte(c,2)),
               bcdToDec(string.byte(c,3)),
               wkd[tonumber(bcdToDec(string.byte(c,4)))],
               bcdToDec(string.byte(c,5)),
               bcdToDec(string.byte(c,6)),
               bcdToDec(string.byte(c,7))
   end



4. SetTime function:

   setTime = function (self, second, minute, hour, day, date, month, year)
       i2c.start(self.id)
       i2c.address(self.id, self.address, i2c.TRANSMITTER)
       i2c.write(self.id, 0x00)
       i2c.write(self.id, decToBcd(second))
       i2c.write(self.id, decToBcd(minute))
       i2c.write(self.id, decToBcd(hour))
       i2c.write(self.id, decToBcd(day))
       i2c.write(self.id, decToBcd(date))
       i2c.write(self.id, decToBcd(month))
       i2c.write(self.id, decToBcd(year))
       i2c.stop(self.id)
   end



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

-- Set Initial Time and Date
require('ds3231')                                -- call for new created DS3231 Module Driver
sda, scl = 2, 1                                      --  declare your I2C interface PIN's
ds3231:init(sda, scl)                           -- initialize I2C Bus
 ds3231:setTime(5,08,12,3,6,04,15)   -- setTime(s,min,hour,weekday,day,month, year)
-- get Time and Date
require('ds3231')
sda, scl = 2, 1
ds3231:init(sda, scl)

s, m, h, d, dt, mn, y = ds3231:readTime()
=string.format("%s - %s/%s/20%s",d, dt, mn, y)
=string.format(" %s:%s:%s", h, m, s)


 
First run test



 5.  Read Time & Date - Print on LCD


   require('st7032i')
   sda, scl = 2, 1
   st7032i:init_i2c(sda, scl)
   st7032i:init_LCD()

   Time_LCD = function()
       s, m, h, d, dt, mn, y = ds3231:readTime()
       date = string.format("%s",dt).."/"..string.format("%s",mn).."/"..string.format("20%s",y)
       st7032i:lcd_print(3,1,date)
       time = string.format("%s",h)..":"..string.format("%s",m)..":"..string.format("%s",s)
       st7032i:lcd_print(4,2,time)
   end

   tmr.alarm(0, 1000, 1, function() Time_LCD() end)  -- set call Time_LCD function Timer





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.

FEATURES: 
    • 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 esp8266-projects.com.

    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)
          end



   2. Write ADC Register Function

         write_ADC_config = function ( self, dev_addr, set) 
               i2c.start(0x0)
               i2c.address(0x0, dev_addr ,i2c.TRANSMITTER)
               i2c.write(0x0,set)
               i2c.stop(0x0)
          end


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


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


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)
           st7032i:lcd_print(0,2,adc_val)
           st7032i:lcd_print(9,2,val)
       end


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

        require('st7032i')
        st7032i:init_LCD()


        st7032i:lcd_setCursor(0,1)
        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!