Showing posts with label Development board. Show all posts
Showing posts with label Development board. Show all posts

Wednesday, May 3, 2017

ESP8266 USB Programmer USBProg


USBPrg v8.4 -  a fully isolated SAFE USB to Serial adapter for communcation and programming devices protecting your USB ports and devices.


The perfect companion for a complete Development platform for your projects!

Now available on TINDIE Store: https://www.tindie.com/products/nEXT_EVO1/usbprgv84-isolated-usb-serial-programmer-adapter/

You can buy it a special price in the MPRSx8 Home Automation Development pack - MPRSx8 Dev Board + USPPrgv8.4  programmer: https://www.tindie.com/products/nEXT_EVO1/wifi-8x-mains-relays-board-for-home-automation/


------------------------------------------------------------------------------------------------------------------

What is it?

 

  A fully isolated USB to Serial adapter for communication and also programming devices protecting your USB ports and connected devices.
  Integrated hardware Autoreset function makes it suitable for direct programming ESP8266, ESP32 and other MCU's that require it.
  If you use Arduino IDE/Platformio/etc for example with ESP8266, you will love it, as it doesn't need to press anymore RST/Prog buttons for new sketch upload! The autoreset function takes care of that, putting automatically the ESP8266 module in the right boot mode.


Youtube Video step-by-step Tutorial on how to use it to program a ESP8266 Module:



 In the case above ESP8266 is embedded on a MPRSx8 Home Automation board but in the same easy way can be used for programming standalone ESP8266 modules.


Pinout



      Capabilities

    • Fully isolated interface
    • High speed (can work OK also at 115200 and up - used it with Arduino IDE/Platfromio at 921600)
    • DTR/RTS/autoreset function
    • 2.5 kV RMS integrated digital isolator from Silicon Labs
    • High electromagnetic immunity
    • Ultra low power
    • Schmitt trigger inputs
    • Transient Immunity 50 kV/μs

     

    Schematics

    USB interface



    Digital isolator



    Auto-reset circuit


    Below you can find also the wiring for the MPRSx8 Home Automation Board Programming:







    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)




    Wednesday, March 30, 2016

    ESP8266 - ADC Input frontend



    Autorange Analog frontend


    For a deeper Hardware description please take a look at the ESP8266 Analog Extension Board





    What we will need:
     


    ADC Frontend description

     Selection of the input voltage divider is done using an analog switch driven by PCF8574 PORT P0 and P1 bits:

    0 - 1:20 Divider
    1 - 1:10 Divider
    2 - 1:5 Divider
    3 - Full Voltage Range


    As the ADC Input is programmed to be used in the 0-2V range that will give us the followings available ranges:

    0 -> 0 - 40V
    1 -> 0 - 20V
    2 -> 0 - 10V
    3 -> 0 - 2V

    In the case of using the MCP3421 ADC at 12 Bit resolution, we will have the following corresponding LSB values:

    - 1:20 Divider  -  0.02V
    - 1:10 Divider  -  0.01V
    - 1:5 Divider    -  0.005V
    - Full Range    -  0.001V




    Software implementation

    1. Init I2C bus/interface

     Standard I2C Bus Initialisation function:

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

     2. Set PCF8574 PORT Register Function
    function setPort( port, stat) 
        i2c.start(id)
        i2c.address(id, dev_addr ,i2c.TRANSMITTER)
        i2c.write(id,stat)
        i2c.stop(id)
    end

     3. Set Port function 

     Just a nicer way to write data to PCF8574 Register. Remember that we need to write a "ZERO" to the corresponding bit. We are sinking not sourcing !!

    function setPortdata(p)
        pp = 255-p
        setPort(0x20,pp)
    end


    4. Set Voltage Divider function

      Select the desired Voltage divider ratio based on the choosen ratio value and calibrated LSB data.

    --calibration data
    x20 = 0.020056
    x10 = 0.01014
    x5  = 0.005014
    xfl = 0.0010075
    xrt = x20 --by default start with highest VDIV!
    function SetVDivider(rtio)
        if (rtio==0) then xrt=x20 end
        if (rtio==1) then xrt=x10 end
        if (rtio==2) then xrt=x5 end
        if (rtio==3) then xrt=xfl end
        print("XRT = "..xrt)
        setPortdata(rtio)    -- select desired voltage divider
        return xrt
    end



           -- Set/Change Voltage Divider ratio:
    SetVDivider(0)  -- 1:20 Divider
    SetVDivider(1)  -- 1:10 Divider
    SetVDivider(2)  -- 1:5  Divider
    SetVDivider(3)  -- 1:1  Full Voltage in!!


    5. MAIN Program


    -- Main Program
    id = 0
    sda=2 --GPIO4
    scl=1 --GPIO5
    dev_addr = 0x20
    --calibration data
    x20 = 0.020056
    x10 = 0.01014
    x5  = 0.005014
    xfl = 0.0010075
    xrt = x20 --by default start with highest VDIV!
    --init I2C Bus
    init_I2C()

    --Init Volatage divider
    setPortdata(0) -- --by default start with highest VDIV!
    SetVDivider(0)  -- 1:20 Divider

    ----MCP3421 ADC
    require('mcp3421')
    sda=2 --GPIO4
    scl=1 --GPIO5
    mcp3421:init(sda, scl)
    mcp3421:write_ADC_config(0x68, 0x10)

    tmr.alarm( 0, 1000, 1, function()
        adc_val = mcp3421:read_ADC_data(0x68)
        print("\nADC Value : "..adc_val.." \n Voltage  : " ..adc_val*xrt)
        return adc_val
    end)





    Tuesday, February 23, 2016

    MCP4728 - 12 Bit I2C DAC Driver - AN1



     MCP4726 - 12 Bit I2C DAC Driver for ESP8266 nEXT EVO AN-1


    Youtube Video here


        From today we will move on the Analog interface part of the nEXT EVO Board AN-1 and we will start talking about the Digital to Analog conversion, Analog Autoscaling input and Analog to Digital conversion .

     For the Digital to Analog conversion part the choosen one is the Microchip MCP4728 I2C DAC IC.

     The MCP4728 device is a quad, 12-bit voltage output Digital-to-Analog Convertor (DAC) with non-volatile memory (EEPROM).

    As it has a on-board precision output amplifier with rail-to-rail analog output swing capabilities that means first of all that we don't need any other Output Buffer as mandatory needed for non-buffered DAC's.

     The MCP4728 device has also a high precision internal voltage reference (VREF = 2.048V). The user can select the internal reference or external reference (VDD) for each channel individually.


    Features

    • 12-Bit Voltage Output DAC with 4 Buffered Voltage Outputs

            - Each output is driven by its own output buffer with a gain of 1 or 2 depending on the gain and
           VREF selection bit settings.
            - In normal mode, the DC impedance of the output pin is about 1Ω. In Power-Down mode,
           the output pin is internally connected to 1 kΩ, 100 kΩ, or 500 kΩ, depending on the
           Power-Down selection bit settings.
            - The VOUT pin can drive up to 1000 pF of capacitive load. It is recommended to use a load
           with RL greater than 5 kΩ.

    • On-Board Non-Volatile Memory (EEPROM) for DAC Codes and I2CTM Address Bits
    • Internal or External Voltage Reference Selection
    • Output Voltage Range:
         - Using Internal VREF (2.048V):
                0.000V to 2.048V with Gain Setting = 1
               0.000V to 4.096V with Gain Setting = 2
         - Using External VREF (VDD): 0.000V to VDD
    • ±0.2 LSB DNL (typical)
    • Fast Settling Time: 6 μs (typical)
    • Normal or Power-Down Mode
    • Low Power Consumption
    • Single-Supply Operation: 2.7V to 5.5V
    • I2C Interface:
          - Address bits: User Programmable to EEPROM
          - Standard (100 kbps), Fast (400 kbps) and High Speed (3.4 Mbps) Modes
    • 10-Lead MSOP Package
    • Extended Temperature Range: -40°C to +125°C

    If you want you can consider it the 4 channels big brother of the MCP4726 1 Channel 12 Bit DAC  

    For more details, please see MCP4728 Datasheet



    What we will need:
     
    ESP8266 nEXT Evo + AN1 Board



    Driver implementation
     
     
    As MCP4728 has a I2C compatible compatible interface, building a driver for it it's a pretty straigh forward process:

     
    1 . I2C Bus initialisation function
    function  init_i2c(sda, scl)
              i2c.setup(id, sda, scl, i2c.SLOW)
         end

    2. DAC Register Data load

     Each channel has its own volatile DAC input register and EEPROM. The details of the input registers and EEPROM are shown in the tables below:



      

    2.1 Simple version using the Power supply Voltage as External 
          Voltage reference, Vref=Vcc

            -- single Write command version
     function dac(ch_reg,voltage)
              volt=(voltage*4096)/vcal -- calibrate!
              print("Voltage Steps:" .. string.format("%d",volt))

              msb = bit.rshift(volt, 8)
              print("MSB:" .. string.format("%d",msb))      
              lsb = volt-bit.lshift(msb,8)
              print("LSB:" .. string.format("%d",lsb))      

              i2c.start(id)
              i2c.address(id, dac_addr ,i2c.TRANSMITTER)
              i2c.write(id,ch_reg)
        
              i2c.write(id,msb)
              i2c.write(id,lsb)
              i2c.stop(id)
    end


    2.2 Using the internal Voltage Reference, Vref=2.048V
              - Gain settings also enabled, 1x,  2x
     function dac_vref(ch_reg,vref,g,voltage)
              volt=(voltage*4096)/vcal -- calibrate!
              print("Voltage Steps:" .. string.format("%d",volt))

              msb = bit.rshift(volt, 8)
              print("MSB:" .. string.format("%d",msb))      
              lsb = volt-bit.lshift(msb,8)
              print("LSB:" .. string.format("%d",lsb))      
              if (vref==1) then
                    msb = msb + 128
                    if (g==2) then msb = msb + 16 end
              end
              i2c.start(id)
              i2c.address(id, dac_addr ,i2c.TRANSMITTER)
              i2c.write(id,ch_reg)
        
              i2c.write(id,msb)
              i2c.write(id,lsb)
              i2c.stop(id)
    end


     3. TEST program

    3.1 Vref = External, Vref=Vcc


    init_i2c(sda,scl)
    --SINGLE WRITE COMMAND: WRITE A SINGLE DAC INPUT REGISTER AND EEPROM

    ch_reg=0x58         -- CH A - VRef Vcc
    dac(ch_reg,0.5)
    ch_reg=0x5A        -- CH B - VRef Vcc
    dac(ch_reg,1)
    ch_reg=0x5C        -- CH C - VRef Vcc
    dac(ch_reg,2)
    ch_reg=0x5E        -- CH D - VRef Vcc
    dac(ch_reg,3)

    3.2 Vref = Internal, Vref=2.048V

     -- SET PG to x1 or x2 - valid only when Vref = Vref Internal !!
    ch_reg = 0x58
    vref= 1    --set internal Vref = 2.048 !!
    vcal=2.048

    gain=2
    voltage = 1
    voltage= voltage/2
    dac_vref(ch_reg,vref,gain,voltage)
    voltage=0.5
    dac_vref(ch_reg,vref,gain,voltage)


     3.3 Vref = Vcc

    -- EXTERNAL Vref = Vcc
    voltage = 2
    gain=1
    ch_reg = 0x58
    vref= 0 -- set EXTERNAL Vref = Vcc = 3.265 - MEASURE & Calibrate!!
    vcal=3.265
    dac_vref(ch_reg,vref,gain,voltage)

    --autoupdate DAC every sec
    tmr.alarm( 0, 1000, 1, function()
      print("\nUpdate DAC data")
      dac_vref(ch_reg,vref,gain,voltage)
    end)


    Tuesday, February 9, 2016

    Mailbag - 4x4 Matrix Keyboard for ESP8266 nEXT EVO Board



    This Mailbag can also be seen as Part 4 of the ESP8266 nEXT EVO Analog Extension Board (AN1)


      In this part we will continue talking about the ESP8266 nEXT Evo 8 Bit I/O Expansion  Port based on the PCF8574 chip from NXP, testing procedures and software programming for the AN1 Board.

      After testing the Output of the 8Bit I/O Port it's now time to test also the Input function.
      So, what can be easier to use for such a processs than some pushbuttons for interaction?  I was thinking about some sort of buttons interface and because I just have arround a small 4x4 Matrix Keyboard why not directly a keyboard interface, especially that I'm waiting to receive some very thin membrane ones to be used for some projects.





    Previous related Articles:



    --------------------------------------------------------------------------------------------------------------------------
    For any new CBDB orders/requests please feel free to use as usual:
         tech at esp8266-projects.com.


    ESP8266 nEXT Evo bare PCB has also been made available directly at Dirty PCBs, our preferred PCB House for experimenting (**):
     http://dirtypcbs.com/view.php?share=9699&accesskey=91d782fd4a10943fd36ecc371c7ff2cd


    (**) - Actually you have there 2 Boards for the price of one, a ESP8266 nEXT Evo together with a AN1 nEXT Analog Extension Board that brings you a 18Bit ADC (autoscale 0-40V input!), 4x12Bit DAC, Precison Temperature measurement, 8bit I/O port, etc.  
    -------------------------------------------------------------------------------------------------------------------------






    What we will need:





        Connection with the ESP8266 nEXT EVO Board is very easy, as Analog Extension Board - AN1 connector is fully compatible with the nEXT connector. Matrix Keyboard can be connected directly to the Analog Extension Board - AN1 8Bit I/O Port :

    4x4 Matrix Keyboard connected to the ESP8266 nEXT Evo Board 8Bit I/O Expansion Port

     For more details and explanations please take a look at the Youtube Video from above: https://youtu.be/cVv7GCHmZ_o





    Software implementation

    For a better understanding of the way how the PCF8574 8Bit quasi-bidirectional I/O Port is working it might be a good idea to look at the prevoius related article and the PCF8574 Datasheet



    1. Init I2C bus/interface

             -- init I2C nEXT BUS
           function i2c_init()
                i2c.setup(id, sda, scl, i2c.SLOW)
          end



    2. Set PCF8574 PORT Register Function
    function setPort( port, stat) 
        i2c.start(id)
        i2c.address(id, dev_addr ,i2c.TRANSMITTER)
        i2c.write(id,stat)
        i2c.stop(id)
    end

    3. Set Port function 

     Just a nicer way to write data to PCF8574 Register. Remember that we need to write a "ZERO" to the corresponding bit. We are sinking not sourcing !!
    function setPortdata(p)
        pp = 255-p
        setPort(0x20,pp)
    end

    4. I/O Port READ Input
    function read_input(dev_addr)
          i2c.start(id)
          i2c.address(id, dev_addr,i2c.RECEIVER)
          c = i2c.read(id,1)
          d = 255-string.byte(c)
          i2c.stop(id)
          --print("Read Value : "..d)
          return c,d
    end



     5. OLED DISPLAY Related Functions

        5.1 Init OLED Display
     function init_OLED(sda,scl) --Set up the u8glib lib
         sla = 0x3C
         i2c.setup(0, sda, scl, i2c.SLOW)
         disp = u8g.ssd1306_128x64_i2c(sla)
         disp:setFont(u8g.font_6x10)
         disp:setFontRefHeightExtendedText()
         disp:setDefaultForegroundColor()
         disp:setFontPosTop()
         disp:setRot180()
    end

     

         5.2 Print TEXT on Display
    function PrintText()
      disp:drawStr(10, 25, str1)
      disp:drawStr(105, 25, str2)
    end


     

         5.3 Print_LCD Function
    function print_LCD()
       disp:firstPage()
       repeat
         PrintText()
         disp:drawFrame(2,2,126,62)
       until disp:nextPage() == false
    end

    6. Main Program
    str1="Keyboard Input:"
    str2="KEY"
    id = 0
    sda=2                           -- GPIO4
    scl=1                            -- GPIO5
    dev_addr = 0x20          -- PCF8574 Address

    port={1,2,4,8}              -- COLS definition
    row={128,64,32,16}     -- ROWS definition
    key={'1','4','7','*','2','5','8','0','3','6','9','#','A','B','C','D'}   -- keys translation table

    i=1
    j=1
    k=1
    init_OLED(2,1)
    print_LCD()
    tmr.alarm( 0, 100, 1, function()
      setPortdata(port[i])                        -- activate COL[i]
      read_input(dev_addr)                     -- read active ROW

      while j<5 do
          if d==port[i]+row[j] then
                print("Col[i] = "..port[i])         -- for debug only
                print("Row[j] = "..row[j])        -- for debug only
                print("Read Value : "..d)           --for debug only
                print("Read Key   : "..k)            -- for debug only
                print("Pressed KEY Value : "..key[k].."\n")    -- print pressed KEY value
                str2=key[k]
                print_LCD()                              -- print also on Display
          end
          j=j+1
          k=k+1
          tmr.wdclr()
       end
      j=1

      i=i+1
      if i>4 then i=1
      end
      if k>16 then k=1
      end
    end)

           


    Sunday, January 31, 2016

    ESP8266 nEXT EVO - Analog extension Board - P3



    This is Part 3 of the ESP8266 nEXT EVO Analog Extension Board (AN1)


    In this part we will talk about the ESP8266 nEXT Evo 8 Bit I/O Expansion  Port based on the PCF8574 chip from NXP, testing procedures and software programming for the AN1 Board






    Previous related Articles:



    --------------------------------------------------------------------------------------------------------------------------
    For any new CBDB orders/requests please feel free to use as usual:
         tech at esp8266-projects.com.


    ESP8266 nEXT Evo bare PCB has also been made available directly at Dirty PCBs, our preferred PCB House for experimenting (**):
     http://dirtypcbs.com/view.php?share=9699&accesskey=91d782fd4a10943fd36ecc371c7ff2cd


    (**) - Actually you have there 2 Boards for the price of one, a ESP8266 nEXT Evo together with a AN1 nEXT Analog Extension Board that brings you a 18Bit ADC (autoscale 0-40V input!), 4x12Bit DAC, Precison Temperature measurement, 8bit I/O port, etc.  
    -------------------------------------------------------------------------------------------------------------------------



    PCF8574 General Description

      The PCF8574/74A provides general-purpose remote I/O expansion via the two-wire
    bidirectional I2C-bus (serial clock (SCL), serial data (SDA)).
      

       The devices consist of eight quasi-bidirectional ports, 100 kHz I2C-bus interface, three
    hardware address inputs and interrupt output operating between 2.5 V and 6 V. The
    quasi-bidirectional port can be independently assigned as an input to monitor interrupt
    status or keypads, or as an output to activate indicator devices such as LEDs. System
    master can read from the input port or write to the output port through a single register.


      The active LOW open-drain interrupt output (INT) can be connected to the interrupt logic
    of the microcontroller and is activated when any input state differs from its corresponding
    input port register state. It is used to indicate to the microcontroller that an input state has
    changed and the device needs to be interrogated without the microcontroller continuously
    polling the input register via the I2C-bus.


     
    Features : 
    • I2C-bus to parallel port expander 
    • 100 kHz I2C-bus interface (Standard-mode I2C-bus)
    • Operating supply voltage 2.5 V to 6 V with non-overvoltage tolerant I/O held to VDD with 100uA current source
    • 8-bit remote I/O pins that default to inputs at power-up
    • Latched outputs directly drive LEDs
    • Total package sink capability of 80 mA
    • Active LOW open-drain interrupt output
    • Eight programmable slave addresses using three address pins
    • Low standby current (2.5 uA typical)
    • -40C to +85C operation 
    • ESD protection exceeds 2000 V HBM per JESD22-A114 and 1000 V CDM per JESD22-C101
    • Latch-up testing is done to JEDEC standard JESD78 which exceeds 100 mA
    • Packages offered: DIP16, SO16, SSOP20

    Bidirectional I/O Expander Example

    Something to remember: 
    • PCF8574 can SINK but NOT SOURCE much current - 100uA only (it cannot output high, if you want). Look at the above example how is connected the LED for SINKING current.
    • Each of the 8 GPIOs have a minimum guaranteed sinking current of 10 mA per bit at 5 V.
    • Each pin needs its own limiting resistor to prevent damage to the device!! keep under 25mA/pin.
    • Maximum device limit sink current in about 80mA. If you need more, look after PCA8574 (200mA max sink current!)

    For more details please take a look at the PCF8574 Datasheet



    For easy testing the PCF8574 8Bit Port Output Pins we will use a very simple "Ghetto-Tester" based on 8 LED's and corresponding current limiting resitors:




    What we will need:



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






        By default, on the AN-1 Board you should have the following available devices:
    • PCF8574 8Bit I/O Extension port  - at address 0x20
    • LM75 Temperature sensor             - at address 0x48
    • MCP4728 - 4x12Bit DAC             - at address 0x60
    • MCP3421 - 18Bit ADC                 - at address 0x68
       When also connected, the SSD1306 OLED Display will be available at 0x3C


       A first step in testing the AN-1 available functions and devices will be to scan the nEXT I²C Bus and see if all the existing ones are alive and responding to the I²C Master requests. Also will list any new added devices, if alive.

    Using the SCANBUS program described in the Part 2 of the AN-1 Series, you can find very easy if your PCF8574 8Bit I/O Extension port  is available on the nEXT Bus :








     Software implementation


    PCF8574 8Bit I/O port is a quasi-bidirectional I/O Port, same as Port 1,2,3 on the 8051 MCU, if you like.

        A quasi-bidirectional I/O is an input or output port without using a direction control register.
    Whenever the master reads the register, the value returned to master depends on the
    actual voltage or status of the pin. At power on, all the ports are HIGH with a weak 100 uA
    internal pull-up to VDD, but can be driven LOW by an internal transistor, or an external
    signal. The I/O ports are entirely independent of each other, but each I/O octal is controlled by the same read or write data byte.

    Advantages of the quasi-bidirectional I/O over totem pole I/O include:

    • Better for driving LEDs since the p-channel (transistor to VDD) is small, which saves die size and therefore cost. LED drive only requires an internal transistor to ground, while the LED is connected to VDD through a current-limiting resistor. Totem pole I/O have both n-channel and p-channel transistors, which allow solid HIGH and LOW output levels without a pull-up resistor — good for logic levels.
    • Simpler architecture — only a single register and the I/O can be both input and output at the same time. Totem pole I/O have a direction register that specifies the port pin direction and it is always in that configuration unless the direction is explicitlychanged.

    • Does not require a command byte. The simplicity of one register (no need for the pointer register or, technically, the command byte) is an advantage in some embedded systems where every byte counts because of memory or bandwidth limitations.


    Testing I/O Port Output

    There is only one register to control four possibilities of the port pin: Input HIGH, input
    LOW, output HIGH, or output LOW.

    • Input HIGH: The master needs to write 1 to the register to set the port as an input mode if the device is not in the default power-on condition. The master reads the register to check the input status. If the external source pulls the port pin up to VDD or drives logic 1, then the master will read the value of 1.

    • Input LOW: The master needs to write 1 to the register to set the port to input mode if the device is not in the default power-on condition. The master reads the register to check the input status. If the external source pulls the port pin down to VSS or drives logic 0, which sinks the weak 100uA current source, then the master will read the value of 0.

    • Output HIGH: The master writes 1 to the register. There is an additional ‘accelerator’ or strong pull-up current when the master sets the port HIGH. The additional strong pull-up is only active during the HIGH time of the acknowledge clock cycle. This accelerator current helps the port’s 100uA current source make a faster rising edge into a heavily loaded output, but only at the start of the acknowledge clock cycle to avoid bus contention if an external signal is pulling the port LOW to VSS/driving the port with logic 0 at the same time. After the half clock cycle there is only the 100uA current source to hold the port HIGH.
    • Output LOW: The master writes 0 to the register. There is a strong current sink transistor that holds the port pin LOW. A large current may flow into the port, which could potentially damage the part if the master writes a 0 to the register and an external source is pulling the port HIGH at the same time.

    Simple quasi-bidirectional I/O example


        In our case, to light-up our LED's we will use the last option, Output LOW!


      1. Init I2C bus/interface

             -- init I2C nEXT BUS
           function i2c_init()
                i2c.setup(id, sda, scl, i2c.SLOW)
          end



    2. Set PCF8574 PORT Register Function
    function setPort( port, stat) 
        i2c.start(id)
        i2c.address(id, dev_addr ,i2c.TRANSMITTER)
        i2c.write(id,stat)
        i2c.stop(id)
    end

    3. Set Port function 

     Just a nicer way to write data to PCF8574 Register. Remember that we need to write a "ZERO" to the corresponding bit. We are sinking not sourcing !!
    function setPortdata(p)
        pp = 255-p
        setPort(0x20,pp)
    end

    4. Main Program

    i2c_init()

    -- Direct port bit by bit set
    setPortdata(0)   -- All OFF  
    setPortdata(1)   -- P0 - ON     
    setPortdata(2)   -- P1 - ON     
    setPortdata(4)   -- P2 - ON
    setPortdata(8)   -- P3 - ON
    setPortdata(16)  -- P4 - ON  
    setPortdata(32)  -- P5 - ON
    setPortdata(64)  -- P6 - ON
    setPortdata(128) -- P7 - ON 

    -- mixed bit set - set 2 or more bits at the same time. Do not exceed max sink current!
    setPortdata(3) -- P0 & P1 - ON 


    -- test autoincrement bit
    i=1
    tmr.alarm( 0, 200, 1, function()
      print(i)
      setPortdata(i)
      i=i+i
      if i>128 then i=1
      end
    end)

    tmr.stop(0)


    -- cycle visual step-by-step, from left-to-right
    port={1,2,4,8,128,64,32,16}
    i=1
    tmr.alarm( 0, 100, 1, function()
      print(port[i])
      setPortdata(port[i])
      i=i+1
      if i>8 then i=1
      end
    end)


    -- Knight Rider style test - anybody remember about Knight Rider  KITT car?:)
    port={1,2,4,8,128,64,32,16}
    i=1
    c=1
    tmr.alarm( 0, 75, 1, function()
      --print(port[i])
      setPortdata(port[i])
      if c<8 then i=i+1
      else
          if c>14 then
                       c=1
                       i=2
           else
                i=i-1
           end
      end
      --print(port[i].."  i="..i.."  c="..c)
      c=c+1
    end)


    That's all for today, next time, PCF8574 Input, and a nice 4x4 Matrix Keyboard example :)