Skip to content

Commit

Permalink
Merge pull request #30 from bablokb/4upstream
Browse files Browse the repository at this point in the history
timer-support
  • Loading branch information
tannewt authored Oct 10, 2023
2 parents d336221 + 4d3cf8b commit f0acff6
Show file tree
Hide file tree
Showing 11 changed files with 493 additions and 35 deletions.
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ Of course, you must import the library to use it:
.. code:: python3
import time
import adafruit_pcf8523
from adafruit_pcf8523.pcf8523 import PCF8523
All the Adafruit RTC libraries take an instantiated and active I2C object
(from the `board` library) as an argument to their constructor. The way to
Expand All @@ -101,7 +101,7 @@ the RTC object:

.. code:: python3
rtc = adafruit_pcf8523.PCF8523(i2c)
rtc = PCF8523(i2c)
Date and time
-------------
Expand Down
107 changes: 107 additions & 0 deletions adafruit_pcf8523/clock.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# SPDX-FileCopyrightText: 2016 Philip R. Moyer for Adafruit Industries
# SPDX-FileCopyrightText: 2016 Radomir Dopieralski for Adafruit Industries
# SPDX-FileCopyrightText: Copyright (c) 2023 Bernhard Bablok
#
# SPDX-License-Identifier: MIT

"""
`clock` - PCF8523 Clock module
==============================
This class supports the clkout-feature of the PCF8523-based RTC in CircuitPython.
Functions are included for reading and writing registers to configure
clklout frequency.
The class supports stand-alone usage. In this case, pass an i2-bus object
to the constructor. If used together with the PCF8523 class (rtc), instantiate
the rtc-object first and then pass the i2c_device attribute of the rtc
to the constructor of the clock.
Author(s): Bernhard Bablok
Date: September 2023
Implementation Notes
--------------------
**Hardware:**
* Adafruit `Adalogger FeatherWing - RTC + SD Add-on <https://www.adafruit.com/products/2922>`_
(Product ID: 2922)
* Adafruit `PCF8523 RTC breakout <https://www.adafruit.com/products/3295>`_ (Product ID: 3295)
**Software and Dependencies:**
* Adafruit CircuitPython firmware for the supported boards:
https://circuitpython.org/downloads
* Adafruit's Register library: https://github.com/adafruit/Adafruit_CircuitPython_Register
* Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
**Notes:**
#. Milliseconds are not supported by this RTC.
#. The alarm does not support seconds. It will always fire on full minutes.
#. Datasheet: http://cache.nxp.com/documents/data_sheet/PCF8523.pdf
"""

__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_PCF8523.git"

import time

from adafruit_bus_device.i2c_device import I2CDevice
from adafruit_register import i2c_bits
from micropython import const

try:
from typing import Union
from busio import I2C
except ImportError:
pass


class Clock: # pylint: disable=too-few-public-methods
"""Interface to the clkout of the PCF8523 RTC.
:param I2C i2c_bus: The I2C bus object
"""

clockout_frequency = i2c_bits.RWBits(3, 0x0F, 3) # COF[2:0]
"""Clock output frequencies generated. Default is 32.768kHz.
Possible values are as shown (selection value - frequency).
000 - 32.768khz
001 - 16.384khz
010 - 8.192kHz
011 - 4.096kHz
100 - 1.024kHz
101 - 0.032kHz (32Hz)
110 - 0.001kHz (1Hz)
111 - Disabled
"""

CLOCKOUT_FREQ_32KHZ = const(0b000)
"""Clock frequency of 32 KHz"""
CLOCKOUT_FREQ_16KHZ = const(0b001)
"""Clock frequency of 16 KHz"""
CLOCKOUT_FREQ_8KHZ = const(0b010)
"""Clock frequency of 8 KHz"""
CLOCKOUT_FREQ_4KHZ = const(0b011)
"""Clock frequency of 4 KHz"""
CLOCKOUT_FREQ_1KHZ = const(0b100)
"""Clock frequency of 4 KHz"""
CLOCKOUT_FREQ_32HZ = const(0b101)
"""Clock frequency of 32 Hz"""
CLOCKOUT_FREQ_1HZ = const(0b110)
"""Clock frequency of 1 Hz"""
CLOCKOUT_FREQ_DISABLED = const(0b111)
"""Clock output disabled"""

def __init__(self, i2c: Union[I2C, I2CDevice]) -> None:
if isinstance(i2c, I2CDevice):
self.i2c_device = i2c # reuse i2c_device (from PCF8563-instance)
else:
time.sleep(0.05)
self.i2c_device = I2CDevice(i2c, 0x68)
35 changes: 7 additions & 28 deletions adafruit_pcf8523.py → adafruit_pcf8523/pcf8523.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
# SPDX-License-Identifier: MIT

"""
`adafruit_pcf8523` - PCF8523 Real Time Clock module
====================================================
`pcf8523` - PCF8523 Real Time Clock module
==========================================
This library supports the use of the PCF8523-based RTC in CircuitPython. It
contains a base RTC class used by all Adafruit RTC libraries. This base
Expand Down Expand Up @@ -39,6 +39,7 @@ class is inherited by the chip-specific subclasses.
**Notes:**
#. Milliseconds are not supported by this RTC.
#. The alarm does not support seconds. It will always fire on full minutes.
#. Datasheet: http://cache.nxp.com/documents/data_sheet/PCF8523.pdf
"""
Expand Down Expand Up @@ -106,32 +107,21 @@ class PCF8523:

power_management = i2c_bits.RWBits(3, 0x02, 5)
"""Power management state that dictates battery switchover, power sources
and low battery detection. Defaults to BATTERY_SWITCHOVER_OFF (0b000)."""
and low battery detection. Defaults to BATTERY_SWITCHOVER_OFF (0b111)."""

# The False means that day comes before weekday in the registers. The 0 is
# that the first day of the week is value 0 and not 1.
datetime_register = i2c_bcd_datetime.BCDDateTimeRegister(0x03, False, 0)
"""Current date and time."""

clockout_frequency = i2c_bits.RWBits(3, 0x0F, 3)
"""Clock output frequencies generated. Default is 32.768kHz.
Possible values are as shown (selection value - frequency).
000 - 32.768khz
001 - 16.384khz
010 - 8.192kHz
011 - 4.096kHz
100 - 1.024kHz
101 - 0.032kHz (32Hz)
110 - 0.001kHz (1Hz)
111 - Disabled
"""

# The False means that day and weekday share a register. The 0 is that the
# first day of the week is value 0 and not 1.
alarm = i2c_bcd_alarm.BCDAlarmTimeRegister(
0x0A, has_seconds=False, weekday_shared=False, weekday_start=0
)
"""Alarm time for the first alarm."""
"""Alarm time for the first alarm. Note that the value of the seconds-fields
is ignored, i.e. alarms only fire at full minutes. For short-term
alarms, use a timer instead."""

alarm_interrupt = i2c_bit.RWBit(0x00, 1)
"""True if the interrupt pin will output when alarm is alarming."""
Expand Down Expand Up @@ -159,17 +149,6 @@ class PCF8523:
def __init__(self, i2c_bus: I2C):
self.i2c_device = I2CDevice(i2c_bus, 0x68)

# Try and verify this is the RTC we expect by checking the timer B
# frequency control bits which are 1 on reset and shouldn't ever be
# changed.
buf = bytearray(2)
buf[0] = 0x12
with self.i2c_device as i2c:
i2c.write_then_readinto(buf, buf, out_end=1, in_start=1)

if (buf[1] & 0b00000111) != 0b00000111:
raise ValueError("Unable to find PCF8523 at i2c address 0x68.")

@property
def datetime(self) -> struct_time:
"""Gets the current date and time or sets the current date and time then starts the
Expand Down
168 changes: 168 additions & 0 deletions adafruit_pcf8523/timer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
# SPDX-FileCopyrightText: 2016 Philip R. Moyer for Adafruit Industries
# SPDX-FileCopyrightText: 2016 Radomir Dopieralski for Adafruit Industries
# SPDX-FileCopyrightText: Copyright (c) 2023 Bernhard Bablok
#
# SPDX-License-Identifier: MIT

"""
`timer` - PCF8523 Timer module
==============================
This class supports the timer of the PCF8523-based RTC in CircuitPython.
Functions are included for reading and writing registers and manipulating
timer objects.
The PCF8523 support two timers named Tmr_A and Tmr_B in the datasheet.
For compatibility with the PCF8563, the Tmr_A is named timer while the
second timer is named timerB.
The class supports stand-alone usage. In this case, pass an i2-bus object
to the constructor. If used together with the PCF8523 class (rtc), instantiate
the rtc-object first and then pass the i2c_device attribute of the rtc
to the constructor of the timer.
Author(s): Bernhard Bablok
Date: September 2023
Implementation Notes
--------------------
**Hardware:**
* Adafruit `Adalogger FeatherWing - RTC + SD Add-on <https://www.adafruit.com/products/2922>`_
(Product ID: 2922)
* Adafruit `PCF8523 RTC breakout <https://www.adafruit.com/products/3295>`_ (Product ID: 3295)
**Software and Dependencies:**
* Adafruit CircuitPython firmware for the supported boards:
https://circuitpython.org/downloads
* Adafruit's Register library: https://github.com/adafruit/Adafruit_CircuitPython_Register
* Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
**Notes:**
#. Milliseconds are not supported by this RTC.
#. The alarm does not support seconds. It will always fire on full minutes.
#. Datasheet: http://cache.nxp.com/documents/data_sheet/PCF8523.pdf
"""

__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_PCF8523.git"

import time

from adafruit_bus_device.i2c_device import I2CDevice
from adafruit_register import i2c_bit
from adafruit_register import i2c_bits
from micropython import const

try:
from typing import Union
from busio import I2C
except ImportError:
pass


class Timer: # pylint: disable=too-few-public-methods
"""Interface to the timer of the PCF8563 RTC.
:param I2C i2c_bus: The I2C bus object
"""

timer_enabled = i2c_bits.RWBits(2, 0x0F, 1) # TAC[1:0]
"""Configures timer. Possible values:
00 - disabled
01 - enabled as countdown timer
10 - enabled as watchdog timer
11 - disabled
"""

timer_frequency = i2c_bits.RWBits(3, 0x10, 0) # TAQ[2:0]
"""TimerA clock frequency. Default is 1/3600Hz.
Possible values are as shown (selection value - frequency).
000 - 4.096kHz
001 - 64Hz
010 - 1Hz
011 - 1/60Hz
111 - 1/3600Hz
"""

TIMER_FREQ_4KHZ = const(0b000)
"""Timer frequency of 4 KHz"""
TIMER_FREQ_64HZ = const(0b001)
"""Timer frequency of 64 Hz"""
TIMER_FREQ_1HZ = const(0b010)
"""Timer frequency of 1 Hz"""
TIMER_FREQ_1_60HZ = const(0b011)
"""Timer frequency of 1/60 Hz"""
TIMER_FREQ_1_3600HZ = const(0b111)
"""Timer frequency of 1/3600 Hz"""

timer_value = i2c_bits.RWBits(8, 0x11, 0) # T_A[7:0]
""" TimerA value (0-255). The default is undefined.
The total countdown duration is calcuated by
timer_value/timer_frequency. For a higher precision, use higher values
and frequencies, e.g. for a one minute timer you could use
value=1, frequency=1/60Hz or value=60, frequency=1Hz. The
latter will give better results. See the PCF85x3 User's Manual
for details."""

timer_interrupt = i2c_bit.RWBit(0x01, 1) # CTAIE
"""True if the interrupt pin will assert when timer has elapsed.
Defaults to False."""

timer_watchdog = i2c_bit.RWBit(0x01, 2) # WTAIE
"""True if the interrupt pin will output when timer generates a
watchdog-alarm. Defaults to False."""

timer_status = i2c_bit.RWBit(0x01, 6) # CTAF
"""True if timer has elapsed. Set to False to reset."""

timer_pulsed = i2c_bit.RWBit(0x0F, 7) # TAM
"""True if timer asserts INT as a pulse. The default
value False asserts INT permanently."""

timerB_enabled = i2c_bit.RWBit(0x0F, 0) # TBC
"""True if the timerB is enabled. Default is False."""

timerB_frequency = i2c_bits.RWBits(3, 0x12, 0) # TBQ[2:0]
"""TimerB clock frequency. Default is 1/3600Hz.
Possible values are as shown (selection value - frequency).
000 - 4.096kHz
001 - 64Hz
010 - 1Hz
011 - 1/60Hz
111 - 1/3600Hz
"""

timerB_value = i2c_bits.RWBits(8, 0x13, 0) # T_B[7:0]
""" TimerB value (0-255). The default is undefined.
The total countdown duration is calcuated by
timerB_value/timerB_frequency. For a higher precision, use higher values
and frequencies, e.g. for a one minute timer you could use
value=1, frequency=1/60Hz or value=60, frequency=1Hz. The
latter will give better results. See the PCF85x3 User's Manual
for details."""

timerB_interrupt = i2c_bit.RWBit(0x01, 0) # CTBIE
"""True if the interrupt pin will assert when timerB has elapsed.
Defaults to False."""

timerB_status = i2c_bit.RWBit(0x01, 5) # CTBF
"""True if timerB has elapsed. Set to False to reset."""

timerB_pulsed = i2c_bit.RWBit(0x0F, 6) # TBM
"""True if timerB asserts INT as a pulse. The default
value False asserts INT permanently."""

def __init__(self, i2c: Union[I2C, I2CDevice]) -> None:
if isinstance(i2c, I2CDevice):
self.i2c_device = i2c # reuse i2c_device (from PCF8523-instance)
else:
time.sleep(0.05)
self.i2c_device = I2CDevice(i2c, 0x68)
8 changes: 7 additions & 1 deletion docs/api.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@

.. automodule:: adafruit_pcf8523
.. automodule:: adafruit_pcf8523.pcf8523
:members:

.. automodule:: adafruit_pcf8523.timer
:members:

.. automodule:: adafruit_pcf8523.clock
:members:
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
# Uncomment the below if you use native CircuitPython modules such as
# digitalio, micropython and busio. List the modules you use. Without it, the
# autodoc module docs will fail to generate with a warning.
# autodoc_mock_imports = ["adafruit_bus_device", "adafruit_register"]
autodoc_mock_imports = ["adafruit_bus_device", "adafruit_register"]

# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]
Expand Down
Loading

0 comments on commit f0acff6

Please sign in to comment.