163 lines
3.9 KiB
C
163 lines
3.9 KiB
C
#include "ds1302.h"
|
|
|
|
void _prepare_read(uint8_t address);
|
|
void _prepare_write(uint8_t address);
|
|
uint8_t _read_byte();
|
|
void _write_byte(uint8_t value);
|
|
void _make_clock_cycle();
|
|
|
|
void _end_transfer();
|
|
|
|
#define REG_SECONDS 0x80 // SEC
|
|
#define REG_MINUTES 0x82 // MIN
|
|
#define REG_HOUR 0x84 // HR
|
|
#define REG_DATE 0x86 // DATE
|
|
#define REG_MONTH 0x88 // MONTH
|
|
#define REG_DAY 0x8A // DAY
|
|
#define REG_YEAR 0x8C // YEAR
|
|
#define REG_WP 0x8E // CONTROL
|
|
// TRICKLE CHARGER 1001000_ 0x90
|
|
#define REG_BURST 0xBE // CLOCK BURST
|
|
|
|
#define REG_RAM00 0xC0
|
|
#define REG_RAM_BURST 0xFE
|
|
|
|
void ds1302_init() {
|
|
gpio_init(PIN_RTC_RESET);
|
|
gpio_set_dir(PIN_RTC_RESET, GPIO_OUT);
|
|
gpio_put(PIN_RTC_RESET, LOW);
|
|
|
|
gpio_init(PIN_RTC_CLOCK);
|
|
gpio_set_dir(PIN_RTC_CLOCK, GPIO_OUT);
|
|
gpio_put(PIN_RTC_CLOCK, LOW);
|
|
|
|
gpio_init(PIN_RTC_IO);
|
|
gpio_set_dir(PIN_RTC_IO, GPIO_IN);
|
|
}
|
|
|
|
int ds1302_is_clock_halted() {
|
|
_prepare_read(REG_SECONDS);
|
|
uint8_t seconds = _read_byte();
|
|
_end_transfer();
|
|
return (seconds & 0b10000000);
|
|
}
|
|
|
|
void ds1302_get_datetime(DateTime *dt) {
|
|
_prepare_read(REG_BURST);
|
|
dt->second = ds1302_decode_bcd(_read_byte() & 0b01111111);
|
|
dt->minute = ds1302_decode_bcd(_read_byte() & 0b01111111);
|
|
dt->hour = ds1302_decode_bcd(_read_byte() & 0b00111111);
|
|
dt->day = ds1302_decode_bcd(_read_byte() & 0b00111111);
|
|
dt->month = ds1302_decode_bcd(_read_byte() & 0b00011111);
|
|
dt->dow = ds1302_decode_bcd(_read_byte() & 0b00000111);
|
|
dt->year = ds1302_decode_bcd(_read_byte() & 0b01111111);
|
|
_end_transfer();
|
|
}
|
|
|
|
void ds1302_set_datetime(DateTime *dt) {
|
|
// disable write protection
|
|
_prepare_write(REG_WP);
|
|
_write_byte(0b00000000); // 0, false
|
|
_end_transfer();
|
|
// OR call writeProtect(0)
|
|
|
|
_prepare_write(REG_BURST);
|
|
_write_byte(ds1302_encode_bcd(dt->second % 60));
|
|
_write_byte(ds1302_encode_bcd(dt->minute % 60));
|
|
_write_byte(ds1302_encode_bcd(dt->hour % 24));
|
|
_write_byte(ds1302_encode_bcd(dt->day % 32));
|
|
_write_byte(ds1302_encode_bcd(dt->month % 13));
|
|
_write_byte(ds1302_encode_bcd(dt->dow % 8));
|
|
_write_byte(ds1302_encode_bcd(dt->year % 100));
|
|
_write_byte(0b10000000);
|
|
_end_transfer();
|
|
}
|
|
|
|
void ds1302_halt() {
|
|
_prepare_write(REG_SECONDS);
|
|
_write_byte(0b10000000);
|
|
_end_transfer();
|
|
}
|
|
|
|
void _prepare_read(uint8_t address) {
|
|
gpio_set_dir(PIN_RTC_IO, GPIO_OUT);
|
|
gpio_put(PIN_RTC_RESET, HIGH);
|
|
uint8_t command = 0b10000001 | address;
|
|
_write_byte(command);
|
|
gpio_set_dir(PIN_RTC_IO, GPIO_IN);
|
|
}
|
|
|
|
void _prepare_write(uint8_t address) {
|
|
gpio_set_dir(PIN_RTC_IO, GPIO_OUT);
|
|
gpio_put(PIN_RTC_RESET, HIGH);
|
|
uint8_t command = 0b10000000 | address;
|
|
_write_byte(command);
|
|
}
|
|
|
|
void _end_transfer() { gpio_put(PIN_RTC_RESET, LOW); }
|
|
|
|
uint8_t _read_byte() {
|
|
uint8_t byte = 0;
|
|
for (uint8_t b = 0; b < 8; b++) {
|
|
if (gpio_get(PIN_RTC_IO) == HIGH)
|
|
byte |= 0x01 << b;
|
|
_make_clock_cycle();
|
|
}
|
|
return byte;
|
|
}
|
|
|
|
void _write_byte(uint8_t value) {
|
|
for (uint8_t b = 0; b < 8; b++) {
|
|
gpio_put(PIN_RTC_IO, (value & 0x01) ? HIGH : LOW);
|
|
_make_clock_cycle();
|
|
value >>= 1;
|
|
}
|
|
}
|
|
|
|
void _make_clock_cycle() {
|
|
gpio_put(PIN_RTC_CLOCK, HIGH);
|
|
sleep_us(1);
|
|
gpio_put(PIN_RTC_CLOCK, LOW);
|
|
sleep_us(1);
|
|
}
|
|
|
|
void ds1302_get_ram_byte(uint8_t addr, uint8_t *data) {
|
|
_prepare_read(addr);
|
|
*data = _read_byte();
|
|
_end_transfer();
|
|
}
|
|
|
|
void ds1302_set_ram_byte(uint8_t addr, uint8_t *data) {
|
|
_prepare_write(addr);
|
|
_write_byte(*data);
|
|
_end_transfer();
|
|
}
|
|
|
|
void ds1302_set_write_protection(int enable) {
|
|
_prepare_write(REG_WP);
|
|
_write_byte(enable);
|
|
_end_transfer();
|
|
}
|
|
|
|
void ds1302_write_ram_bulk(const uint8_t *data, int len) {
|
|
if (len <= 0 || len > 31) {
|
|
return;
|
|
}
|
|
_prepare_write(REG_RAM_BURST);
|
|
for (int i = 0; i < len; i++) {
|
|
_write_byte(data[i]);
|
|
}
|
|
_end_transfer();
|
|
}
|
|
|
|
void ds1302_read_ram_bulk(uint8_t *data, int len) {
|
|
if (len <= 0 || len > 31) {
|
|
return;
|
|
}
|
|
_prepare_read(REG_RAM_BURST);
|
|
for (int i = 0; i < len; i++) {
|
|
data[i] = _read_byte();
|
|
}
|
|
_end_transfer();
|
|
}
|