velxio/test/test_custom_chips/sdk/examples/ds3231.c

107 lines
3.0 KiB
C

/*
* ds3231.c — DS3231 high-precision I2C real-time clock.
*
* Pins: SDA, SCL, INT (alarm interrupt, open-drain), 32K (32 kHz output),
* RST (reset, active LOW).
*
* Address: 0x68 (fixed).
*
* Memory map (subset implemented):
* 0x00 seconds (BCD)
* 0x01 minutes (BCD)
* 0x02 hours (BCD, 24h)
* 0x03 day-of-week (1..7)
* 0x04 date (BCD, 1..31)
* 0x05 month (BCD, 1..12)
* 0x06 year (BCD, 0..99 = 2000..2099)
* 0x07-0x12 alarms / control (read-back as zero)
*
* Protocol: master writes 1 byte → register pointer.
* master writes more bytes → updates registers from pointer.
* master reads → returns from current pointer, auto-incrementing.
*/
#include "velxio-chip.h"
#include <stdlib.h>
#include <string.h>
#define RTC_ADDR 0x68
#define RTC_REG_COUNT 0x13
static uint8_t to_bcd(uint8_t n) { return (uint8_t)(((n / 10) << 4) | (n % 10)); }
static uint8_t from_bcd(uint8_t b) { return (uint8_t)(((b >> 4) & 0x0f) * 10 + (b & 0x0f)); }
typedef enum { ST_IDLE, ST_HAS_POINTER } rtc_state_t;
typedef struct {
vx_pin SDA, SCL, INT, RST_PIN, OUT32K;
uint8_t regs[RTC_REG_COUNT];
uint8_t pointer;
rtc_state_t state;
} chip_state_t;
static void seed_default_time(chip_state_t* s) {
/* Default: 2026-01-15 12:34:56, Thursday */
s->regs[0x00] = to_bcd(56);
s->regs[0x01] = to_bcd(34);
s->regs[0x02] = to_bcd(12);
s->regs[0x03] = 4; /* Thursday */
s->regs[0x04] = to_bcd(15);
s->regs[0x05] = to_bcd(1);
s->regs[0x06] = to_bcd(26);
}
static bool on_connect(void* ud, uint8_t addr, bool is_read) {
chip_state_t* s = (chip_state_t*)ud;
if (!is_read) s->state = ST_IDLE;
return true;
}
static bool on_write(void* ud, uint8_t byte) {
chip_state_t* s = (chip_state_t*)ud;
if (s->state == ST_IDLE) {
s->pointer = byte % RTC_REG_COUNT;
s->state = ST_HAS_POINTER;
} else {
s->regs[s->pointer] = byte;
s->pointer = (uint8_t)((s->pointer + 1) % RTC_REG_COUNT);
}
return true;
}
static uint8_t on_read(void* ud) {
chip_state_t* s = (chip_state_t*)ud;
uint8_t b = s->regs[s->pointer];
s->pointer = (uint8_t)((s->pointer + 1) % RTC_REG_COUNT);
return b;
}
static void on_stop(void* ud) {
chip_state_t* s = (chip_state_t*)ud;
s->state = ST_IDLE;
}
void chip_setup(void) {
chip_state_t* s = (chip_state_t*)calloc(1, sizeof(chip_state_t));
seed_default_time(s);
s->INT = vx_pin_register("INT", VX_OUTPUT_HIGH);
s->RST_PIN = vx_pin_register("RST", VX_INPUT_PULLUP);
s->OUT32K = vx_pin_register("32K", VX_OUTPUT_LOW);
vx_i2c_config cfg = {
.address = RTC_ADDR,
.scl = vx_pin_register("SCL", VX_INPUT),
.sda = vx_pin_register("SDA", VX_INPUT),
.on_connect = on_connect,
.on_read = on_read,
.on_write = on_write,
.on_stop = on_stop,
.user_data = s,
};
vx_i2c_attach(&cfg);
vx_log("DS3231 RTC ready (default 2026-01-15 12:34:56)");
/* Suppress unused warning */
(void)from_bcd;
}