mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-07-26 10:38:41 +00:00
pcf8563: add support for pcf8563 real time clock
This commit is contained in:
@@ -177,11 +177,20 @@ endif
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=arduino ./examples/keypad4x4/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=xiao ./examples/pcf8563/alarm/
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=xiao ./examples/pcf8563/clkout/
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=xiao ./examples/pcf8563/time/
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=xiao ./examples/pcf8563/timer/
|
||||
@md5sum ./build/test.hex
|
||||
|
||||
DRIVERS = $(wildcard */)
|
||||
NOTESTS = build examples flash semihosting pcd8544 shiftregister st7789 microphone mcp3008 gps microbitmatrix \
|
||||
hcsr04 ssd1331 ws2812 thermistor apa102 easystepper ssd1351 ili9341 wifinina shifter hub75 \
|
||||
hd44780 buzzer ssd1306 espat l9110x st7735 bmi160 l293x dht keypad4x4 max72xx p1am tone tm1637
|
||||
hd44780 buzzer ssd1306 espat l9110x st7735 bmi160 l293x dht keypad4x4 max72xx p1am tone tm1637 \
|
||||
pcf8563
|
||||
TESTS = $(filter-out $(addsuffix /%,$(NOTESTS)),$(DRIVERS))
|
||||
|
||||
unit-test:
|
||||
|
||||
@@ -52,7 +52,7 @@ func main() {
|
||||
|
||||
## Currently supported devices
|
||||
|
||||
The following 58 devices are supported.
|
||||
The following 60 devices are supported.
|
||||
|
||||
| Device Name | Interface Type |
|
||||
|----------|-------------|
|
||||
@@ -95,6 +95,7 @@ The following 58 devices are supported.
|
||||
| [MPU6050 accelerometer/gyroscope](https://store.invensense.com/datasheets/invensense/MPU-6050_DataSheet_V3%204.pdf) | I2C |
|
||||
| [P1AM-100 Base Controller](https://facts-engineering.github.io/modules/P1AM-100/P1AM-100.html) | SPI |
|
||||
| [PCD8544 display](http://eia.udg.edu/~forest/PCD8544_1.pdf) | SPI |
|
||||
| [PCF8563 real time clock](https://www.nxp.com/docs/en/data-sheet/PCF8563.pdf) | I2C |
|
||||
| [Resistive Touchscreen (4-wire)](http://ww1.microchip.com/downloads/en/Appnotes/doc8091.pdf) | GPIO |
|
||||
| [Semihosting](https://wiki.segger.com/Semihosting) | Debug |
|
||||
| [Shift register (PISO)](https://en.wikipedia.org/wiki/Shift_register#Parallel-in_serial-out_\(PISO\)) | GPIO |
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/pcf8563"
|
||||
)
|
||||
|
||||
var (
|
||||
i2c = machine.I2C0
|
||||
rtc = pcf8563.New(i2c)
|
||||
)
|
||||
|
||||
func main() {
|
||||
i2c.Configure(machine.I2CConfig{Frequency: machine.TWI_FREQ_400KHZ})
|
||||
rtc.Reset()
|
||||
|
||||
time.Sleep(3 * time.Second)
|
||||
rtc.SetTime(time.Date(2006, 1, 2, 15, 4, 50, 0, time.UTC))
|
||||
|
||||
rtc.SetAlarm(time.Date(2006, 1, 2, 15, 5, 0, 0, time.UTC))
|
||||
rtc.EnableAlarmInterrupt()
|
||||
|
||||
prev := -1
|
||||
|
||||
for {
|
||||
for {
|
||||
t, _ := rtc.ReadTime()
|
||||
if prev != t.Second() {
|
||||
fmt.Printf("%s\r\n", t.String())
|
||||
prev = t.Second()
|
||||
|
||||
if rtc.AlarmTriggered() {
|
||||
fmt.Printf("alarm triggered\r\n")
|
||||
rtc.ClearAlarm()
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/pcf8563"
|
||||
)
|
||||
|
||||
var (
|
||||
i2c = machine.I2C0
|
||||
rtc = pcf8563.New(i2c)
|
||||
)
|
||||
|
||||
func main() {
|
||||
i2c.Configure(machine.I2CConfig{Frequency: machine.TWI_FREQ_400KHZ})
|
||||
rtc.Reset()
|
||||
|
||||
for {
|
||||
rtc.SetOscillatorFrequency(pcf8563.RTC_COT_1HZ)
|
||||
time.Sleep(3 * time.Second)
|
||||
rtc.SetOscillatorFrequency(pcf8563.RTC_COT_32HZ)
|
||||
time.Sleep(3 * time.Second)
|
||||
rtc.SetOscillatorFrequency(pcf8563.RTC_COT_1KHZ)
|
||||
time.Sleep(3 * time.Second)
|
||||
rtc.SetOscillatorFrequency(pcf8563.RTC_COT_32KHZ)
|
||||
time.Sleep(3 * time.Second)
|
||||
rtc.SetOscillatorFrequency(pcf8563.RTC_COT_DISABLE)
|
||||
time.Sleep(3 * time.Second)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/pcf8563"
|
||||
)
|
||||
|
||||
var (
|
||||
i2c = machine.I2C0
|
||||
rtc = pcf8563.New(i2c)
|
||||
)
|
||||
|
||||
func main() {
|
||||
i2c.Configure(machine.I2CConfig{Frequency: machine.TWI_FREQ_400KHZ})
|
||||
rtc.Reset()
|
||||
|
||||
rtc.SetTime(time.Date(2006, 1, 2, 15, 4, 5, 0, time.UTC))
|
||||
|
||||
prev := -1
|
||||
|
||||
for {
|
||||
for {
|
||||
t, _ := rtc.ReadTime()
|
||||
if prev != t.Second() {
|
||||
fmt.Printf("%s\r\n", t.String())
|
||||
prev = t.Second()
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/pcf8563"
|
||||
)
|
||||
|
||||
var (
|
||||
i2c = machine.I2C0
|
||||
rtc = pcf8563.New(i2c)
|
||||
)
|
||||
|
||||
func main() {
|
||||
i2c.Configure(machine.I2CConfig{Frequency: machine.TWI_FREQ_400KHZ})
|
||||
rtc.Reset()
|
||||
|
||||
time.Sleep(3 * time.Second)
|
||||
rtc.SetTime(time.Date(2006, 1, 2, 15, 4, 5, 0, time.UTC))
|
||||
|
||||
rtc.SetTimer(15 * time.Second)
|
||||
rtc.EnableTimerInterrupt()
|
||||
|
||||
prev := -1
|
||||
|
||||
for {
|
||||
for {
|
||||
t, _ := rtc.ReadTime()
|
||||
if prev != t.Second() {
|
||||
fmt.Printf("%s\r\n", t.String())
|
||||
prev = t.Second()
|
||||
|
||||
if rtc.TimerTriggered() {
|
||||
fmt.Printf("timer triggered\r\n")
|
||||
rtc.ClearTimer()
|
||||
rtc.SetTimer(10 * time.Second)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
// Package pcf8563 implements a driver for the PCF8563 CMOS Real-Time Clock (RTC)
|
||||
//
|
||||
// Datasheet: https://www.nxp.com/docs/en/data-sheet/PCF8563.pdf
|
||||
//
|
||||
|
||||
package pcf8563
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
|
||||
// Device wraps an I2C connection to a PCF8563 device.
|
||||
type Device struct {
|
||||
bus drivers.I2C
|
||||
Address uint16
|
||||
}
|
||||
|
||||
// New creates a new PCF8563 connection. I2C bus must be already configured.
|
||||
func New(i2c drivers.I2C) Device {
|
||||
return Device{
|
||||
bus: i2c,
|
||||
Address: PCF8563_ADDR,
|
||||
}
|
||||
}
|
||||
|
||||
// Reset resets the `control and status registers`. When this method is
|
||||
// called, it writes `0x00` to the `control and status registers`. This will
|
||||
// cause `Alarm` and `Timer` to become Inactive. Please refer to the datasheet
|
||||
// for details.
|
||||
func (d *Device) Reset() (err error) {
|
||||
return d.bus.Tx(d.Address, []byte{0x00, 0x00, 0x00}, nil)
|
||||
}
|
||||
|
||||
// SetTime sets the time and date
|
||||
func (d *Device) SetTime(t time.Time) error {
|
||||
var buf [9]byte
|
||||
buf[0] = 0x02
|
||||
buf[1] = decToBcd(t.Second())
|
||||
buf[2] = decToBcd(t.Minute())
|
||||
buf[3] = decToBcd(t.Hour())
|
||||
buf[4] = decToBcd(t.Day())
|
||||
buf[5] = decToBcd(int(t.Weekday() + 1))
|
||||
buf[6] = decToBcd(int(t.Month()))
|
||||
buf[7] = decToBcd(t.Year() - 2000)
|
||||
err := d.bus.Tx(d.Address, buf[:], nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// ReadTime returns the date and time
|
||||
func (d *Device) ReadTime() (time.Time, error) {
|
||||
var buf [9]byte
|
||||
err := d.bus.Tx(d.Address, []byte{0x00}, buf[:])
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
seconds := bcdToDec(buf[2] & 0x7F)
|
||||
minute := bcdToDec(buf[3] % 0x7F)
|
||||
hour := bcdToDec(buf[4] & 0x3F)
|
||||
day := bcdToDec(buf[5] & 0x3F)
|
||||
month := time.Month(bcdToDec(buf[7] & 0x0F))
|
||||
year := int(bcdToDec(buf[8])) + 2000
|
||||
|
||||
t := time.Date(year, month, day, hour, minute, seconds, 0, time.UTC)
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// SetAlarm sets the alarm
|
||||
func (d *Device) SetAlarm(t time.Time) error {
|
||||
var buf [5]byte
|
||||
buf[0] = 0x09
|
||||
buf[1] = RTC_ALARM_ENABLE | decToBcd(t.Minute())
|
||||
buf[2] = RTC_ALARM_ENABLE | decToBcd(t.Hour())
|
||||
buf[3] = RTC_ALARM_ENABLE | decToBcd(t.Day())
|
||||
buf[4] = RTC_ALARM_DISABLE
|
||||
err := d.bus.Tx(d.Address, buf[:], nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// enable alarm
|
||||
buf[0] = 0x01
|
||||
err = d.bus.Tx(d.Address, buf[:1], buf[1:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf[1] |= RTC_CTRL_AF
|
||||
err = d.bus.Tx(d.Address, buf[:2], nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// ClearAlarm disables alarm.
|
||||
func (d *Device) ClearAlarm() error {
|
||||
var buf [2]byte
|
||||
buf[0] = 0x01
|
||||
err := d.bus.Tx(d.Address, buf[:1], buf[1:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf[1] &= ^uint8(RTC_CTRL_AF)
|
||||
err = d.bus.Tx(d.Address, buf[:], nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// EnableAlarmInterrupt enables alarm interrupt. When triggered, INT pin (3)
|
||||
// goes low.
|
||||
func (d *Device) EnableAlarmInterrupt() error {
|
||||
var buf [2]byte
|
||||
buf[0] = 0x01
|
||||
err := d.bus.Tx(d.Address, buf[:1], buf[1:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf[1] |= RTC_CTRL_AIE
|
||||
err = d.bus.Tx(d.Address, buf[:], nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// DisableAlarmInterrupt disable alarm interrupt.
|
||||
func (d *Device) DisableAlarmInterrupt() error {
|
||||
var buf [2]byte
|
||||
buf[0] = 0x01
|
||||
err := d.bus.Tx(d.Address, buf[:1], buf[1:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf[1] &= ^uint8(RTC_CTRL_AIE)
|
||||
err = d.bus.Tx(d.Address, buf[:], nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// AlarmTriggered returns whether or not an Alarm has been triggered.
|
||||
func (d *Device) AlarmTriggered() bool {
|
||||
var buf [1]byte
|
||||
buf[0] = 0x01
|
||||
err := d.bus.Tx(d.Address, buf[:], buf[:])
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return (buf[0] & RTC_CTRL_AF) != 0
|
||||
}
|
||||
|
||||
// SetTimer sets timer. The available durations are 1 to 127 seconds. If any
|
||||
// other value is specified, it will be truncated.
|
||||
func (d *Device) SetTimer(dur time.Duration) error {
|
||||
var buf [3]byte
|
||||
|
||||
sec := dur / time.Second
|
||||
if sec > 127 {
|
||||
sec = 127
|
||||
}
|
||||
|
||||
// Treat as sec timer.
|
||||
buf[0] = 0x0E
|
||||
buf[1] = RTC_TIMER_1S
|
||||
buf[2] = byte(sec)
|
||||
err := d.bus.Tx(d.Address, buf[:], nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// enable alarm
|
||||
buf[0] = 0x01
|
||||
err = d.bus.Tx(d.Address, buf[:1], buf[1:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf[1] |= RTC_CTRL_TF
|
||||
err = d.bus.Tx(d.Address, buf[:2], nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// ClearTimer disables timer.
|
||||
func (d *Device) ClearTimer() error {
|
||||
var buf [2]byte
|
||||
buf[0] = 0x01
|
||||
err := d.bus.Tx(d.Address, buf[:1], buf[1:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf[1] &= ^uint8(RTC_CTRL_TF)
|
||||
err = d.bus.Tx(d.Address, buf[:], nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// EnableTimerInterrupt enables timer interrupt. When triggered, INT pin (3)
|
||||
// goes low.
|
||||
func (d *Device) EnableTimerInterrupt() error {
|
||||
var buf [2]byte
|
||||
buf[0] = 0x01
|
||||
err := d.bus.Tx(d.Address, buf[:1], buf[1:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf[1] |= RTC_CTRL_TIE
|
||||
err = d.bus.Tx(d.Address, buf[:], nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// DisableTimerInterrupt disable timer interrupt.
|
||||
func (d *Device) DisableTimerInterrupt() error {
|
||||
var buf [2]byte
|
||||
buf[0] = 0x01
|
||||
err := d.bus.Tx(d.Address, buf[:1], buf[1:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf[1] &= ^uint8(RTC_CTRL_TIE)
|
||||
err = d.bus.Tx(d.Address, buf[:], nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// TimerTriggered returns whether or not an Alarm has been triggered.
|
||||
func (d *Device) TimerTriggered() bool {
|
||||
var buf [1]byte
|
||||
buf[0] = 0x01
|
||||
err := d.bus.Tx(d.Address, buf[:], buf[:])
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return (buf[0] & RTC_CTRL_TF) != 0
|
||||
}
|
||||
|
||||
// SetOscillatorFrequency sets output oscillator frequency
|
||||
// Available modes: RTC_COT_DISABLE, RTC_COT_32KHZ, RTC_COT_1KHZ,
|
||||
// RTC_COT_32Hz, RTC_COT_1HZ.
|
||||
func (d *Device) SetOscillatorFrequency(sqw uint8) error {
|
||||
var buf [2]byte
|
||||
buf[0] = 0x0D
|
||||
buf[1] = sqw
|
||||
return d.bus.Tx(d.Address, buf[:], nil)
|
||||
}
|
||||
|
||||
// decToBcd converts int to BCD
|
||||
func decToBcd(dec int) uint8 {
|
||||
return uint8(dec + 6*(dec/10))
|
||||
}
|
||||
|
||||
// bcdToDec converts BCD to int
|
||||
func bcdToDec(bcd uint8) int {
|
||||
return int(bcd - 6*(bcd>>4))
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package pcf8563
|
||||
|
||||
// Registers
|
||||
const (
|
||||
PCF8563_ADDR = 0x51 // R:A3 W:A2
|
||||
|
||||
I2C_SPEED_STANDARD = 100000
|
||||
I2C_SPEED_DOUBLE = 200000
|
||||
|
||||
RTC_CTRL_STOP = 0x20
|
||||
RTC_CTRL_TITP = 0x10
|
||||
RTC_CTRL_AF = 0x08
|
||||
RTC_CTRL_TF = 0x04
|
||||
RTC_CTRL_AIE = 0x02
|
||||
RTC_CTRL_TIE = 0x01
|
||||
|
||||
RTC_COT_DISABLE = 0x00
|
||||
RTC_COT_32KHZ = 0x80
|
||||
RTC_COT_1KHZ = 0x81
|
||||
RTC_COT_32HZ = 0x82
|
||||
RTC_COT_1HZ = 0x83
|
||||
|
||||
RTC_TIMER_DISABLE = 0x00
|
||||
RTC_TIMER_4KHZ = 0x80
|
||||
RTC_TIMER_64HZ = 0x81
|
||||
RTC_TIMER_1S = 0x82
|
||||
RTC_TIMER_60S = 0x83
|
||||
|
||||
RTC_ALARM_DISABLE = 0x80
|
||||
RTC_ALARM_ENABLE = 0x00
|
||||
)
|
||||
Reference in New Issue
Block a user