Skip to content

Added alarm features for DS3231 #758

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
241 changes: 241 additions & 0 deletions ds3231/ds3231.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package ds3231 // import "tinygo.org/x/drivers/ds3231"

import (
"errors"
"time"

"tinygo.org/x/drivers"
Expand Down Expand Up @@ -148,6 +149,105 @@ func (d *Device) ReadTime() (dt time.Time, err error) {
return
}

func (d *Device) GetSqwPinMode() SqwPinMode {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exported functions need documentation

data := []uint8{0}
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_CONTROL, data)
if err != nil {
return SQW_OFF
}

data[0] &= 0x1C // turn off INTCON
if data[0]&0x04 != 0 {
return SQW_OFF
}

return SqwPinMode(data[0])
}

func (d *Device) SetSqwPinMode(mode SqwPinMode) error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This too, exported functions need documentation

data := []uint8{0}
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_CONTROL, data)
if err != nil {
return err
}

data[0] &^= 0x04 // turn off INTCON
data[0] &^= 0x18 // set freq bits to 0

data[0] |= uint8(mode)

err = legacy.WriteRegister(d.bus, uint8(d.Address), REG_CONTROL, data)
if err != nil {
return err
}

return nil
}

// SetAlarm1 set the alarm1 time
func (d *Device) SetAlarm1(dt time.Time, mode Alarm1Mode) error {
dataCtrl := []uint8{0}
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_CONTROL, dataCtrl)
if err != nil {
return err
}
if dataCtrl[0]&(1<<INTCN) == 0x00 {
return errors.New("INTCN has to be disabled")
}

A1M1 := uint8((mode & 0x01) << 7)
A1M2 := uint8((mode & 0x02) << 6)
A1M3 := uint8((mode & 0x04) << 5)
A1M4 := uint8((mode & 0x08) << 4)
DY_DT := uint8((mode & 0x10) << 2)

day := dt.Day()
if DY_DT > 0 {
day = dowToDS3231(int(dt.Weekday()))
}

data := make([]uint8, 4)
data[0] = uint8ToBCD(uint8(dt.Second())) | A1M1
data[1] = uint8ToBCD(uint8(dt.Minute())) | A1M2
data[2] = uint8ToBCD(uint8(dt.Hour())) | A1M3
data[3] = uint8ToBCD(uint8(day)) | A1M4 | DY_DT

err = legacy.WriteRegister(d.bus, uint8(d.Address), REG_ALARMONE, data)
if err != nil {
return err
}
dataCtrl[0] |= AlarmFlag_Alarm1
err = legacy.WriteRegister(d.bus, uint8(d.Address), REG_CONTROL, dataCtrl)
if err != nil {
return err
}

return nil
}

// ReadAlarm1 returns the alarm1 time
func (d *Device) ReadAlarm1() (dt time.Time, err error) {
data := make([]uint8, 5)
err = legacy.ReadRegister(d.bus, uint8(d.Address), REG_ALARMONE, data)
if err != nil {
return
}
second := bcdToInt(data[0] & 0x7F)
minute := bcdToInt(data[1] & 0x7F)
hour := hoursBCDToInt(data[2] & 0x3F)

isDayOfWeek := (data[3] & 0x40) >> 6
var day int
if isDayOfWeek > 0 {
day = bcdToInt(data[3] & 0x0F)
} else {
day = bcdToInt(data[3] & 0x3F)
}

dt = time.Date(2000, 5, day, hour, minute, second, 0, time.UTC)
return
}

// ReadTemperature returns the temperature in millicelsius (mC)
func (d *Device) ReadTemperature() (int32, error) {
data := make([]uint8, 2)
Expand All @@ -158,6 +258,139 @@ func (d *Device) ReadTemperature() (int32, error) {
return milliCelsius(data[0], data[1]), nil
}

// disableAlarm disable alarm
func (d *Device) disableAlarm(alarm_num uint8) error {
data := []byte{0}
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_CONTROL, data)
if err != nil {
return err
}
data[0] &^= (1 << (alarm_num - 1))
err = legacy.WriteRegister(d.bus, uint8(d.Address), REG_CONTROL, data)
if err != nil {
return err
}
return nil
}

// enableAlarm enable alarm
func (d *Device) enableAlarm(alarm_num uint8) error {
data := []byte{0}
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_CONTROL, data)
if err != nil {
return err
}
data[0] |= (1 << (alarm_num - 1))
err = legacy.WriteRegister(d.bus, uint8(d.Address), REG_CONTROL, data)
if err != nil {
return err
}
return nil
}

// isEnabledAlarm check if alarm is enabled for interrupt
func (d *Device) isEnabledAlarm(alarm_num uint8) bool {
data := []byte{0}
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_CONTROL, data)
if err != nil {
return false
}
return (data[0] & (1 << (alarm_num - 1))) != 0x00
}

// IsEnabledAlarm1 checks if alarm1 is enabled
func (d *Device) IsEnabledAlarm1() bool {
return d.isEnabledAlarm(1)
}

// DisableAlarm1 disable alarm1
func (d *Device) DisableAlarm1() error {
return d.disableAlarm(1)
}

// EnableAlarm1 enable alarm1
func (d *Device) EnableAlarm1() error {
return d.enableAlarm(1)
}

// clearAlarm clear status of alarm
func (d *Device) clearAlarm(alarm_num uint8) error {
data := []byte{0}
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_STATUS, data)
if err != nil {
return err
}
data[0] &^= (1 << (alarm_num - 1))
err = legacy.WriteRegister(d.bus, uint8(d.Address), REG_STATUS, data)
if err != nil {
return err
}
return nil
}

// ClearAlarm1 clear status of alarm1
func (d *Device) ClearAlarm1() error {
return d.clearAlarm(1)
}

// IsAlarmFired get status of alarm
func (d *Device) isAlarmFired(alarm_num uint8) bool {
dataCtrl := []byte{0}
legacy.ReadRegister(d.bus, uint8(d.Address), REG_CONTROL, dataCtrl)
dataCtrl[0] &^= (1 << (alarm_num - 1))
data := []byte{0}
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_STATUS, data)
if err != nil {
return false
}
return (data[0] & (1 << (alarm_num - 1))) != 0x00
}

// IsAlarm1Fired get status of alarm1
func (d *Device) IsAlarm1Fired() bool {
return d.isAlarmFired(1)
}

// Enable32K enables the 32KHz output
func (d *Device) Enable32K() error {
data := []byte{0}
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_STATUS, data)
if err != nil {
return err
}
data[0] |= 1 << EN32KHZ
err = legacy.WriteRegister(d.bus, uint8(d.Address), REG_STATUS, data)
if err != nil {
return err
}
return nil
}

// Disable32K disables the 32KHz output
func (d *Device) Disable32K() error {
data := []byte{0}
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_STATUS, data)
if err != nil {
return err
}
data[0] &^= 1 << EN32KHZ
err = legacy.WriteRegister(d.bus, uint8(d.Address), REG_STATUS, data)
if err != nil {
return err
}
return nil
}

// IsEnabled32K get status of 32KHz output
func (d *Device) IsEnabled32K() bool {
data := []byte{0}
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_STATUS, data)
if err != nil {
return false
}
return (data[0] & (1 << EN32KHZ)) != 0x00
}

// milliCelsius converts the raw temperature bytes (msb and lsb) from the DS3231
// into a 32-bit signed integer in units of milli Celsius (1/1000 deg C).
//
Expand Down Expand Up @@ -200,3 +433,11 @@ func hoursBCDToInt(value uint8) (hour int) {
}
return
}

// dowToDS3231 converts the day of the week to internal DS3231 format
func dowToDS3231(d int) int {
if d == 0 {
return 7
}
return d
}
23 changes: 23 additions & 0 deletions ds3231/registers.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,26 @@ const (
AlarmTwo Mode = 4
ModeAlarmBoth Mode = 5
)

// SQW Pin Modes
type SqwPinMode uint8

const (
SQW_OFF SqwPinMode = 0x1C
SQW_1HZ SqwPinMode = 0x00
SQW_1KHZ SqwPinMode = 0x08
SQW_4KHZ SqwPinMode = 0x10
SQW_8KHZ SqwPinMode = 0x18
)

// ALarm1 Modes
type Alarm1Mode uint8

const (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't be add Alarm2 too?

A1_PER_SECOND Alarm1Mode = 0x0F
A1_SECOND Alarm1Mode = 0x0E
A1_MINUTE Alarm1Mode = 0x0C
A1_HOUR Alarm1Mode = 0x08
A1_DATE Alarm1Mode = 0x00
A1_DAY Alarm1Mode = 0x10
)