tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/ds1307/ds1307.go (about) 1 // Package ds1307 provides a driver for the DS1307 RTC 2 // 3 // Datasheet: 4 // https://datasheets.maximintegrated.com/en/ds/DS1307.pdf 5 package ds1307 // import "tinygo.org/x/drivers/ds1307" 6 7 import ( 8 "errors" 9 "time" 10 11 "tinygo.org/x/drivers" 12 "tinygo.org/x/drivers/internal/legacy" 13 ) 14 15 // Device wraps an I2C connection to a DS1307 device. 16 type Device struct { 17 bus drivers.I2C 18 Address uint8 19 AddressSRAM uint8 20 } 21 22 // New creates a new DS1307 connection. I2C bus must be already configured. 23 func New(bus drivers.I2C) Device { 24 return Device{bus: bus, 25 Address: uint8(I2CAddress), 26 AddressSRAM: SRAMBeginAddres, 27 } 28 } 29 30 // SetTime sets the time and date 31 func (d *Device) SetTime(t time.Time) error { 32 data := make([]byte, 8) 33 data[0] = uint8(TimeDate) 34 data[1] = decToBcd(t.Second()) 35 data[2] = decToBcd(t.Minute()) 36 data[3] = decToBcd(t.Hour()) 37 data[4] = decToBcd(int(t.Weekday() + 1)) 38 data[5] = decToBcd(t.Day()) 39 data[6] = decToBcd(int(t.Month())) 40 data[7] = decToBcd(t.Year() - 2000) 41 err := d.bus.Tx(uint16(d.Address), data, nil) 42 return err 43 } 44 45 // ReadTime returns the date and time 46 func (d *Device) ReadTime() (time.Time, error) { 47 data := make([]byte, 8) 48 err := legacy.ReadRegister(d.bus, d.Address, uint8(TimeDate), data) 49 if err != nil { 50 return time.Time{}, err 51 } 52 seconds := bcdToDec(data[0] & 0x7F) 53 minute := bcdToDec(data[1]) 54 hour := hoursBCDToInt(data[2]) 55 day := bcdToDec(data[4]) 56 month := time.Month(bcdToDec(data[5])) 57 year := bcdToDec(data[6]) 58 year += 2000 59 60 t := time.Date(year, month, day, hour, minute, seconds, 0, time.UTC) 61 return t, nil 62 } 63 64 // Seek sets the offset for the next Read or Write on SRAM to offset, interpreted 65 // according to whence: 0 means relative to the origin of the SRAM, 1 means 66 // relative to the current offset, and 2 means relative to the end. 67 // returns new offset and error, if any 68 func (d *Device) Seek(offset int64, whence int) (int64, error) { 69 switch whence { 70 case 0: 71 whence = SRAMBeginAddres 72 case 1: 73 whence = int(d.AddressSRAM) 74 case 2: 75 whence = SRAMEndAddress 76 default: 77 return 0, errors.New("invalid starting point") 78 } 79 d.AddressSRAM = uint8(whence) + uint8(offset) 80 if d.AddressSRAM > SRAMEndAddress { 81 return 0, errors.New("EOF") 82 } 83 return int64(d.AddressSRAM), nil 84 } 85 86 // Write writes len(data) bytes to SRAM 87 // returns number of bytes written and error, if any 88 func (d *Device) Write(data []byte) (n int, err error) { 89 if int(d.AddressSRAM)+len(data)-1 > SRAMEndAddress { 90 return 0, errors.New("writing outside of SRAM") 91 } 92 buffer := make([]byte, len(data)+1) 93 buffer[0] = d.AddressSRAM 94 copy(buffer[1:], data) 95 err = d.bus.Tx(uint16(d.Address), buffer, nil) 96 if err != nil { 97 return 0, err 98 } 99 d.Seek(int64(len(data)), 1) 100 return len(data), nil 101 } 102 103 // Read reads len(data) from SRAM 104 // returns number of bytes written and error, if any 105 func (d *Device) Read(data []uint8) (n int, err error) { 106 if int(d.AddressSRAM)+len(data)-1 > SRAMEndAddress { 107 return 0, errors.New("EOF") 108 } 109 err = legacy.ReadRegister(d.bus, d.Address, d.AddressSRAM, data) 110 if err != nil { 111 return 0, err 112 } 113 d.Seek(int64(len(data)), 1) 114 return len(data), nil 115 } 116 117 // SetOscillatorFrequency sets output oscillator frequency 118 // Available modes: SQW_OFF, SQW_1HZ, SQW_4KHZ, SQW_8KHZ, SQW_32KHZ 119 func (d *Device) SetOscillatorFrequency(sqw uint8) error { 120 data := []byte{uint8(Control), sqw} 121 err := d.bus.Tx(uint16(d.Address), data, nil) 122 return err 123 } 124 125 // IsOscillatorRunning returns if the oscillator is running 126 func (d *Device) IsOscillatorRunning() bool { 127 data := []byte{0} 128 err := legacy.ReadRegister(d.bus, d.Address, uint8(TimeDate), data) 129 if err != nil { 130 return false 131 } 132 return (data[0] & (1 << CH)) == 0 133 } 134 135 // SetOscillatorRunning starts/stops internal oscillator by toggling halt bit 136 func (d *Device) SetOscillatorRunning(running bool) error { 137 data := make([]byte, 3) 138 err := legacy.ReadRegister(d.bus, d.Address, uint8(TimeDate), data) 139 if err != nil { 140 return err 141 } 142 if running { 143 data[0] &^= (1 << CH) 144 } else { 145 data[0] |= (1 << CH) 146 } 147 data[1], data[0] = data[0], uint8(TimeDate) 148 err = d.bus.Tx(uint16(d.Address), data[:2], nil) 149 return err 150 } 151 152 // decToBcd converts int to BCD 153 func decToBcd(dec int) uint8 { 154 return uint8(dec + 6*(dec/10)) 155 } 156 157 // bcdToDec converts BCD to int 158 func bcdToDec(bcd uint8) int { 159 return int(bcd - 6*(bcd>>4)) 160 } 161 162 // hoursBCDToInt converts the BCD hours to int 163 func hoursBCDToInt(value uint8) (hour int) { 164 if value&0x40 != 0x00 { 165 hour = bcdToDec(value & 0x1F) 166 if (value & 0x20) != 0x00 { 167 hour += 12 168 } 169 } else { 170 hour = bcdToDec(value) 171 } 172 return 173 }