Friday, March 13, 2015

PCF8563 - Real Time Clock - I2C Driver - ESP8266 CBDB



   It's time for TIME!

   I was delaying this article about RTC's despite de fact that was higly requested with the hope that the ordered DS3231 modules will arrive in time. Didn't happen, so, until they will hit my MailBox I am presenting you an alternate solution, an RTC chip used before in many projects without any problems: PCF8563 from NXP.

PCF8563 - Real-Time Clock (RTC) and calendar

    The PCF8563 is a CMOS Real-Time Clock (RTC) and Calendar optimized for low power
consumption. A programmable clock output, interrupt output and voltage-low detector are also provided. All addresses and data are transferred serially via a two-line bidirectional I2C-bus with a maximum bus speed of 400 kbit/s. 

   It is maybe not so fancy as DS3231 but can do the job very well and is way more cheaper that DS3231. Like 1.21$ versus 7-8$ on Digikey. I know they are cheaper DS3231 modules on Ebay but if you want to integrate a RTC on your own projects it's something mayber to consider.

    Features: 

     •  Provides year, month, day, weekday, hours, minutes, and seconds based on a
        32.768 kHz quartz crystal
     •  Century flag
     •  Clock operating voltage: 1.0 V to 5.5 V at room temperature
     •  Low backup current; typical 0.25uA at Vdd =3.0V and Tamb=25C
     •   400 kHz two-wire I2C-bus interface (at VDD= 1.8 V to 5.5 V)
     •   Programmable clock output for peripheral devices (32.768 kHz, 1.024 kHz, 32 Hz, and 1Hz)
     •   Alarm and timer functions
     •   Integrated oscillator capacitor
     •   Internal Power-On Reset (POR)
     •   I2C-bus slave address: read A3h and write A2h
     •   Open-drain interrupt pin

 For more details, please see PCF8563 Datasheet

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

PCF8563 RTC Module

    Yes, that's it the entire RTC Module: PCF8563, 32.768khz Quarts cristal oscillator and a decoupling cap. Not bad at all, on a tiny DIP8 size board!

     And on the CBDB Board :




     You can see now better the difference between the MSOP8 MCP9808 Temperature sensor, the SO8 PCF8563 RTC and the SOT23 12BIT DAC, MCP4726:

CBDB Board with EXT modules installed

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

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

Driver implementation

    As PCF8563 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 PCF8563:

    The PCF8563 contains sixteen 8-bit registers with an auto-incrementing register address,
an on-chip 32.768 kHz oscillator with one integrated capacitor, a frequency divider which
provides the source clock for the Real-Time Clock (RTC) and calender, a programmable
clock output, a timer, an alarm, a voltage-low detector, and a 400 kHz I2C-bus interface.

    All 16 registers are designed as addressable 8-bit parallel registers although not all bits
are implemented. The first two registers (memory address 00h and 01h) are used as
control and/or status registers. The memory addresses 02h through 08h are used as
counters for the clock function (seconds up to years counters). Address locations 09h
through 0Ch contain alarm registers which define the conditions for an alarm.

     Address 0Dh controls the CLKOUT output frequency. 0Eh and 0Fh are the Timer_control
and Timer registers, respectively.

    When one of the RTC registers is written or read, the contents of all time counters are
frozen. Therefore, faulty writing or reading of the clock and calendar during a carry
condition is prevented.

    The Seconds, Minutes, Hours, Days, Months, Years as well as the Minute_alarm,
Hour_alarm, and Day_alarm registers are all coded in Binary Coded Decimal (BCD)
format so we need some BCD to DEC and DEC to BCD functions.


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, 0x02)
       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(bit.band(string.byte(c,1),0x7f)),
               bcdToDec(bit.band(string.byte(c,2),0x7f)),
               bcdToDec(bit.band(string.byte(c,3),0x3f)),
               bcdToDec(bit.band(string.byte(c,4),0x3f)),
               wkd[tonumber(bcdToDec(bit.band(string.byte(c,5),0x7)))],
               bcdToDec(bit.band(string.byte(c,6),0x1f)),
               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, 0x02)
       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 'pcf8563.lua', restart ESP and run:

-- Set Initial Time and Date
require('pcf8563')                                -- call for new created PCF8563 Module Driver
sda, scl = 2, 1                                      --  declare your I2C interface PIN's
pcf8563:init(sda, scl)                          
-- initialize I2C Bus

 pcf8563:setTime(0,34,13,12,4,3,15)   -- setTime(s,min,hour,day,weekday,month, year)
-- get Time and Date
require('pcf8563')
sda, scl = 2, 1
pcf8563:init(sda, scl)


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





      As you have seen above, the RTC can be initialized from the input prompt without problems.
 If you want a more automated process to syncronize your Time and Date then you need to look for other options like a NTP Client or to sync it with the Google page help for example. As implementing NTP protocol is a different story itself, let'e see how hard is to pick timestamps from Google page header.


  Time sync with Google page

   How  we will do it:  Connect to Google server, fetch the page header that contain the Timestamp and do some string manipulation to obtain the Date & Time information in the format that we need to be able to update our Real Time Clock:

 getTime = function()
     conn=net.createConnection(net.TCP, 0)
     conn:on("connection",function(conn, payload)
            conn:send("HEAD / HTTP/1.1\r\n"..
                      "Host: google.com\r\n"..
                      "Accept: */*\r\n"..
                      "User-Agent: Mozilla/4.0 (compatible; esp8266 Lua;)"..
                      "\r\n\r\n")
            end)           
     conn:on("receive", function(conn, payload)
          tstamp = string.sub(payload,string.find(payload,"Date: ")+6,string.find(payload,"Date: ")+35)
          --print('Timestamp : '..tstamp)
          conn:close()
     end)
    conn:connect(80,'google.com')
    conn = nil

    t = {}
    i=0
    for token in string.gmatch(tstamp, "[^%s]+") do
       t[i] = token
       --print(t[i])
       i=i+1
    end

    wkd = {["Sun"]=1, ["Mon"]=2, ["Tue"]=3, ["Wed"]=4, ["Thu"]=5, ["Fri"]=6, ["Sat"]=7 }
    mnt = {["Jan"]=1, ["Feb"]=2, ["Mar"]=3, ["Apr"]=4, ["May"]=5, ["Jun"]=6, ["Jul"]=7, ["Aug"]=8, ["Sep"]=9, ["Oct"]=10, ["Nov"]=11,["Dec"]=12}
    wk1=string.sub(t[0],0,3)
    dtd=wkd[wk1]
    d1=t[1]
    mn1=t[2]
    mnl=mnt[mn1]
    y1=string.sub(t[3],3,4)
    h1=2+string.sub(t[4],0,2)
    m1=string.sub(t[4],4,5)
    s1=string.sub(t[4],7,8)

    --print("Date : "..wk1..", "..d1.."/"..mn1.."/"..t[3])
    --print("Time : "..h1..":"..m1..":"..s1)

    return s1,m1,h1,d1,dtd,mnl,y1
end



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

 --GetTime from Google Server and set RTC Time
require('gettime')
s2,m2,h2,d2,dtd2,l2,y2=getTime()
    print("Date : "..dtd..", "..d1.."/"..mn1.."/"..y1)
    print("Time : "..h1..":"..m1..":"..s1)


-- Set Time and Date
require('pcf8563')
sda, scl = 2, 1
pcf8563:init(sda, scl)
pcf8563:setTime(s1,m1,h1,d1,dtd,mnl,y1)




If you run in trouble because of lack of memory, before running, just compile the programs, it will help a lot:

      node.compile("gettime.lua")
      node.compile("pcf8563.lua")


And the Youtube demo:



Tuesday, March 10, 2015

Mailbag arrival! New ESP Modules in Town :)


 Just a quick one about new goodies found in the MailBox :

External protective envelope

   Envelope in Bulgarian language:)

   Have you ever heard about Bulgaria? Is a country in southeastern Europe, member of the European Union, NATO, and the Council of Europe.

   And why are we interested about?

   It's a lovely Country, nice seaside, nice and friendly people and I can give you another MAJOR reason:

Plovdiv - the second largest city in Bulgaria, is home of OLIMEX LTD, a leading provider for development tools and programmers for embedded market, a well knows company with over 20 years experience in designing, prototyping and manufacturing printed circuit boards, sub-assemblies, and complete electronic products.

   Ok, ok, enough with geography lessons let's see what's inside :)

Products individual cardboard packaging boxes


Inside the boxes - 1

   YES, indeed, they are ESP8266 Modules :). They look promising and first of all they are Open Source Hardware! You can find all the related documents, schematics and software examples on OLIMEX website.


1. MOD-WIFI-ESP8266 Module

MOD-WIFI-ESP8266 - TOP

MOD-WIFI-ESP8266 - Bottom

2. MOD-WIFI-ESP8266-DEV Module

MOD-WIFI-ESP8266-DEV - TOP
MOD-WIFI-ESP8266-DEV - Bottom

   If you are interested how it looks compared with the corresponding cheap Chinese Module sold on Ebay and arround, take a look below:

TOP

BOTTOM


     I don't know how much can be seen in the pictures above but is quite a big difference in the quality of the products. And if you remember the ESP-07 Module DOA story  might worth to think about spending a few bucks more on a proper tested product from a trustable source. Chinese NO-NAME one is around 4$ on Ebay, Olimex one about 5.50.

     I, personally, think that is good to have also other options and sources than the Far-East Factories. And not only for ESP Modules. Putting all the Global eggs in one basket might become a nasty story sometime...


3. ESP8266-EVB Board

    ESP8266-EVB is the companion Evaluation board for MOD-WIFI-ESP8266-DEV with relay, button, UEXT, all GPIOs available on standard 0.1" header. Breadboard friendly! 


ESP8266-EVB - TOP


ESP8266-EVB - Bottom

   
                That's all for Mailbag today and be sure we will put them at work soon !!