Explorar el Código

Added full support for DS3231

Vittorio Giovanelli hace 8 años
padre
commit
ca104a96ce
Se han modificado 2 ficheros con 436 adiciones y 6 borrados
  1. 242 2
      lua_modules/ds3231/ds3231.EN.md
  2. 194 4
      lua_modules/ds3231/ds3231.lua

+ 242 - 2
lua_modules/ds3231/ds3231.EN.md

@@ -39,10 +39,11 @@ package.loaded["ds3231"]=nil
 <a id="ds3231_settime"></a>
 ## setTime()
 ####Description
-Sets the current date and time.
+Sets the current date and time.  
+if _disableOscillator_ is set to 1 the oscillator will **stops** on battery.
 
 ####Syntax
-setTime(second, minute, hour, day, date, month, year)
+setTime(second, minute, hour, day, date, month, year, disableOscillator)
 
 ####Parameters
 second: 00-59  
@@ -52,6 +53,7 @@ day: 1-7 (Sunday = 1, Saturday = 7)
 date: 01-31  
 month: 01-12  
 year: 00-99
+disableOscillator: (optional) 0-1
 
 ####Returns
 nil
@@ -110,5 +112,243 @@ ds3231 = nil
 package.loaded["ds3231"]=nil
 
 ```
+####See also
+**-**   []()
+
+<a id="ds3231_setAlarm"></a>
+## setAlarm()
+####Description
+Set an alarm to be triggered on SQW pin:
+_alarm1_ has a precision of **seconds**; _alarm2_ has a precision of **minutes** (`second` parameter will be ignored).  
+
+Alarms sets gpio.LOW over the SQW pin and let it unchanged until reloaded. When reloaded sets gpio.HIGH.
+Alarms trigger **only once**, after that, if you want them to trigger again, you need to call `reloadAlarms()` or `setAlarm(...)` again.
+
+Alarm type set the alarm match conditions:  
+- `ds3231.EVERYSECOND` works only with _alarm1_ and triggers every second;  
+- `ds3231.EVERYMINUTE` works only with _alarm2_ and triggers every minute (at 00 seconds);  
+- `ds3231.SECOND` triggers when time match given `seconds` parameter;  
+- `ds3231.MINUTE` triggers when time match given `seconds` and `minutes` parameters;  
+- `ds3231.HOUR` triggers when time match given `seconds`, `minutes`, and `hours` parameters;  
+- `ds3231.DAY` triggers when time match given `seconds`, `minutes`, and `hours` on week day `date/day` parameters;  
+- `ds3231.DATE` triggers when time match given `seconds`, `minutes`, and `hours` on date (day of the month) `date/day` parameters;  
+
+####Syntax
+setAlarm(alarmId, alarmType, seconds, minutes, hours, date/day)
+
+####Parameters
+alarmId: 1-2  
+alarmType: 1-7  
+seconds: 00-59  
+minutes: 00-59  
+hours: 00-23  
+date/day: 01-31 or 1-7 (Sunday = 1, Saturday = 7)
+
+####Returns
+nil
+
+####Example
+```lua
+ds3231=require("ds3231")
+ds3231.init(3, 4)
+
+-- Setting PIN1 to triggers on interrupt when alarm triggers
+gpio.mode(1,gpio.INT)
+gpio.trig(1,'down',function(level)
+  print('Time is passing')
+  -- If not reloaded it will be triggered only once
+  ds3231.reloadAlarms()
+end)
+
+ds3231.setAlarm(2,ds3231.EVERYMINUTE)
+
+-- Don't forget to release it after use
+ds3231 = nil
+package.loaded["ds3231"]=nil
+```
+
+####See also
+**-**   []()
+
+<a id="ds3231_reloadAlarms"></a>
+## reloadAlarms()
+####Description
+Reload an already triggered alarm. Otherwise it will never be triggered again.
+Alarms have to be reloaded both to let them triggers.
+
+####Syntax
+reloadAlarms()
+
+####Parameters
+nil
+
+####Returns
+nil
+
+####Example
+```lua
+ds3231=require("ds3231")
+ds3231.init(3, 4)
+
+-- Setting PIN1 to triggers on interrupt when alarm triggers
+gpio.mode(1,gpio.INT)
+gpio.trig(1,'down',function(level)
+  print('Time is passing')
+  -- If not reloaded it will be triggered only once
+  ds3231.reloadAlarms()
+end)
+
+ds3231.setAlarm(2,ds3231.EVERYMINUTE)
+
+-- Don't forget to release it after use
+ds3231 = nil
+package.loaded["ds3231"]=nil
+```
+
+####See also
+**-**   []()
+
+<a id="ds3231_enableAlarm"></a>
+## enableAlarm()
+####Description
+Enable an already setted alarm with the previous matching conditions. It reload alarms internally.
+
+####Syntax
+enableAlarm(alarmId)
+
+####Parameters
+alarmId: 1-2
+
+####Returns
+nil
+
+####Example
+```lua
+ds3231=require("ds3231")
+ds3231.init(3, 4)
+
+-- Trigger on x:20:15
+ds3231.setAlarm(1,ds3231.MINUTE,15,20)
+
+if badThing == 1 then
+  ds3231.disableAlarm(1)
+end
+
+if goodThing == 1 then
+  ds3231.enableAlarm(1)
+end
+
+-- Don't forget to release it after use
+ds3231 = nil
+package.loaded["ds3231"]=nil
+```
+
+####See also
+**-**   []()
+
+<a id="ds3231_disableAlarm"></a>
+## disableAlarm()
+####Description
+Disable an already setted alarm with the previous matching conditions.  
+if _alarmId_ is not 1 or 2 it disables both alarms.  
+**Warning**: `disableAlarm()` prevent alarms to trigger interrupt over SQW pin but alarm itself will triggers at the matching conditions as it could be seen on _status byte_.
+
+####Syntax
+disableAlarm(alarmId)
+
+####Parameters
+alarmId: 0-2
+
+####Returns
+nil
+
+####Example
+```lua
+ds3231=require("ds3231")
+ds3231.init(3, 4)
+
+-- Trigger on x:20:15
+ds3231.setAlarm(1,ds3231.MINUTE,15,20)
+
+if badThing == 1 then
+  ds3231.disableAlarm(1)
+end
+
+if goodThing == 1 then
+  ds3231.enableAlarm(1)
+end
+
+-- Don't forget to release it after use
+ds3231 = nil
+package.loaded["ds3231"]=nil
+```
+
+####See also
+**-**   []()
+
+<a id="ds3231_getBytes"></a>
+## getBytes()
+####Description
+Get bytes of control, for debug purpose, and status of DS3231. To see what they means check the [Datasheet](http://datasheets.maximintegrated.com/en/ds/DS3231.pdf)
+
+####Syntax
+getBytes()
+
+####Parameters
+nil
+
+####Returns
+control: integer. Control 0-255
+status: integer. Status 0-143 (bit 6-5-4 unused)
+
+####Example
+```lua
+ds3231=require("ds3231")
+ds3231.init(3, 4)
+
+control,status = ds3231.getBytes()
+print('Control byte: '..control)
+print('Status byte: '..status)
+
+-- Don't forget to release it after use
+ds3231 = nil
+package.loaded["ds3231"]=nil
+```
+
+####See also
+**-**   []()
+
+<a id="ds3231_resetStopFlag"></a>
+## resetStopFlag()
+####Description
+Stop flag on status byte means that the oscillator either is stopped or was stopped for some period and may be used to judge the validity of the timekeeping data.
+When setted to 1 this flag keeps that values until changed to 0.  
+Call `resetStopFlag()` if you need to check validity of time data after that.
+
+####Syntax
+resetStopFlag()
+
+####Parameters
+nil
+
+####Returns
+nil
+
+####Example
+```lua
+ds3231=require("ds3231")
+ds3231.init(3, 4)
+
+control,status = ds3231.getBytes()
+if bit.band(bit.rshift(status, 7),1) == 1 then
+  print('[WARNING] RTC has stopped')
+  ds3231.resetStopFlag()
+end
+
+-- Don't forget to release it after use
+ds3231 = nil
+package.loaded["ds3231"]=nil
+```
+
 ####See also
 **-**   []()

+ 194 - 4
lua_modules/ds3231/ds3231.lua

@@ -9,6 +9,16 @@ local moduleName = ...
 local M = {}
 _G[moduleName] = M
 
+-- Constants:
+M.EVERYSECOND = 6
+M.EVERYMINUTE = 7
+M.SECOND = 1
+M.MINUTE = 2
+M.HOUR = 3
+M.DAY = 4
+M.DATE = 5
+M.DISABLE = 0
+
 -- Default value for i2c communication
 local id = 0
 
@@ -16,6 +26,7 @@ local id = 0
 local dev_addr = 0x68
 
 local function decToBcd(val)
+  if val == nil then return 0 end
   return((((val/10) - ((val/10)%1)) *16) + (val%10))
 end
 
@@ -23,6 +34,11 @@ local function bcdToDec(val)
   return((((val/16) - ((val/16)%1)) *10) + (val%16))
 end
 
+local function addAlarmBit(val,day)
+  if day == 1 then return bit.bor(val,64) end
+  return bit.bor(val,128)
+end
+
 -- initialize i2c
 --parameters:
 --d: sda
@@ -32,10 +48,10 @@ function M.init(d, l)
     sda = d
     scl = l
   else
-    print("iic config failed!") return nil
+    print("[ERROR] i2c config failed!") return nil
   end
-    print("init done")
-    i2c.setup(id, sda, scl, i2c.SLOW)
+  print("[LOG] DS3231 init done")
+  i2c.setup(id, sda, scl, i2c.SLOW)
 end
 
 --get time from DS3231
@@ -58,7 +74,8 @@ function M.getTime()
 end
 
 --set time for DS3231
-function M.setTime(second, minute, hour, day, date, month, year)
+-- enosc setted to 1 disables oscilation on battery, stopping time
+function M.setTime(second, minute, hour, day, date, month, year, disOsc)
   i2c.start(id)
   i2c.address(id, dev_addr, i2c.TRANSMITTER)
   i2c.write(id, 0x00)
@@ -70,6 +87,179 @@ function M.setTime(second, minute, hour, day, date, month, year)
   i2c.write(id, decToBcd(month))
   i2c.write(id, decToBcd(year))
   i2c.stop(id)
+
+  i2c.start(id)
+  i2c.address(id, dev_addr, i2c.TRANSMITTER)
+  i2c.write(id, 0x0E)
+  i2c.stop(id)
+  i2c.start(id)
+  i2c.address(id, dev_addr, i2c.RECEIVER)
+  local c = string.byte(i2c.read(id, 1), 1)
+  i2c.stop(id)
+  if disOsc == 1 then c = bit.bor(c,128)
+  else c = bit.band(c,127) end
+  i2c.start(id)
+  i2c.address(id, dev_addr, i2c.TRANSMITTER)
+  i2c.write(id, 0x0E)
+  i2c.write(id, c)
+  i2c.stop(id)
+end
+
+-- Reset alarmId flag to let alarm to be triggered again
+function M.reloadAlarms ()
+  if bit == nil or bit.band == nil or bit.bor == nil then
+    print("[ERROR] Module bit is required to use alarm function")
+    return nil
+  end
+  i2c.start(id)
+  i2c.address(id, dev_addr, i2c.TRANSMITTER)
+  i2c.write(id, 0x0F)
+  i2c.stop(id)
+  i2c.start(id)
+  i2c.address(id, dev_addr, i2c.RECEIVER)
+  local d = string.byte(i2c.read(id, 1), 1)
+  i2c.stop(id)
+  -- Both flag needs to be 0 to let alarms trigger
+  d = bit.band(d,252)
+  i2c.start(id)
+  i2c.address(id, dev_addr, i2c.TRANSMITTER)
+  i2c.write(id, 0x0F)
+  i2c.write(id, d)
+  i2c.stop(id)
+  print('[LOG] Alarm '..almId..' reloaded')
+end
+
+-- Enable alarmId bit. Let it to be triggered
+function M.enableAlarm (almId)
+  if bit == nil or bit.band == nil or bit.bor == nil then
+    print("[ERROR] Module bit is required to use alarm function")
+    return nil
+  end
+  if almId ~= 1 and almId ~= 2 then print('[ERROR] Wrong alarm id (1 or 2): '..almId) return end
+  i2c.start(id)
+  i2c.address(id, dev_addr, i2c.TRANSMITTER)
+  i2c.write(id, 0x0E)
+  i2c.stop(id)
+  i2c.start(id)
+  i2c.address(id, dev_addr, i2c.RECEIVER)
+  local c = string.byte(i2c.read(id, 1), 1)
+  i2c.stop(id)
+  c = bit.bor(c,4)
+  if almId == 1 then c = bit.bor(c,1)
+  else c = bit.bor(c,2) end
+  i2c.start(id)
+  i2c.address(id, dev_addr, i2c.TRANSMITTER)
+  i2c.write(id, 0x0E)
+  i2c.write(id, c)
+  i2c.stop(id)
+  M.reloadAlarms()
+  print('[LOG] Alarm '..almId..' enabled')
+end
+-- If almID equals 1 or 2 disable that alarm, otherwise disables both.
+function M.disableAlarm (almId)
+  if bit == nil or bit.band == nil or bit.bor == nil then
+    print("[ERROR] Module bit is required to use alarm function")
+    return nil
+  end
+  i2c.start(id)
+  i2c.address(id, dev_addr, i2c.TRANSMITTER)
+  i2c.write(id, 0x0E)
+  i2c.stop(id)
+  i2c.start(id)
+  i2c.address(id, dev_addr, i2c.RECEIVER)
+  local c = string.byte(i2c.read(id, 1), 1)
+  i2c.stop(id)
+  if almId == 1 then c = bit.band(c, 254)
+  elseif almId == 2 then c = bit.band(c, 253)
+  else
+    almId = '1 and 2'
+    c = bit.band(c, 252)
+  end
+  i2c.start(id)
+  i2c.address(id, dev_addr, i2c.TRANSMITTER)
+  i2c.write(id, 0x0E)
+  i2c.write(id, c)
+  i2c.stop(id)
+  print('[LOG] Alarm '..almId..' disabled')
+end
+
+-- almId can be 1 or 2;
+-- almType should be taken from constants
+function M.setAlarm (almId, almType, second, minute, hour, date)
+  if bit == nil or bit.band == nil or bit.bor == nil then
+    print("[ERROR] Module bit is required to use alarm function")
+    return nil
+  end
+  if almId ~= 1 and almId ~= 2 then print('[ERROR] Wrong alarm id (1 or 2): '..almId) return end
+  M.enableAlarm(almId)
+  second = decToBcd(second)
+  minute = decToBcd(minute)
+  hour = decToBcd(hour)
+  date = decToBcd(date)
+  if almType == M.EVERYSECOND or almType == M.EVERYMINUTE then
+    second = addAlarmBit(second)
+    minute = addAlarmBit(minute)
+    hour = addAlarmBit(hour)
+    date = addAlarmBit(date)
+  elseif almType == M.SECOND then
+    minute = addAlarmBit(minute)
+    hour = addAlarmBit(hour)
+    date = addAlarmBit(date)
+  elseif almType == M.MINUTE then
+    hour = addAlarmBit(hour)
+    date = addAlarmBit(date)
+  elseif almType == M.HOUR then
+    date = addAlarmBit(date)
+  elseif almType == M.DAY then
+    date = addAlarmBit(date,1)
+  end
+  local almStart = 0x07
+  if almId == 2 then almStart = 0x0B end
+  i2c.start(id)
+  i2c.address(id, dev_addr, i2c.TRANSMITTER)
+  i2c.write(id, almStart)
+  if almId == 1 then i2c.write(id, second) end
+  i2c.write(id, minute)
+  i2c.write(id, hour)
+  i2c.write(id, date)
+  i2c.stop(id)
+  print('[LOG] Alarm '..almId..' setted')
+end
+
+-- Get Control and Status bytes
+function M.getBytes ()
+  i2c.start(id)
+  i2c.address(id, dev_addr, i2c.TRANSMITTER)
+  i2c.write(id, 0x0E)
+  i2c.stop(id)
+  i2c.start(id)
+  i2c.address(id, dev_addr, i2c.RECEIVER)
+  local c = i2c.read(id, 2)
+  i2c.stop(id)
+  return tonumber(string.byte(c, 1)), tonumber(string.byte(c, 2))
+end
+
+-- Resetting RTC Stop Flag
+function M.resetStopFlag ()
+  if bit == nil or bit.band == nil or bit.bor == nil then
+    print("[ERROR] Module bit is required to reset stop flag")
+    return nil
+  end
+  i2c.start(id)
+  i2c.address(id, dev_addr, i2c.TRANSMITTER)
+  i2c.write(id, 0x0F)
+  i2c.stop(id)
+  i2c.start(id)
+  i2c.address(id, dev_addr, i2c.RECEIVER)
+  local s = string.byte(i2c.read(id, 1))
+  i2c.stop(id)
+  s = bit.band(s,127)
+  i2c.start(id)
+  i2c.address(id, dev_addr, i2c.TRANSMITTER)
+  i2c.write(id, 0x0F)
+  i2c.write(id, s)
+  i2c.stop(id)
+  print('[LOG] RTC stop flag resetted')
 end
 
 return M