From 8ded673ec3d168b9bda1a353ace20ce02b18fcae Mon Sep 17 00:00:00 2001 From: UncleRus Date: Sun, 9 Oct 2016 14:14:17 +0500 Subject: [PATCH] DS1307 RTC driver + example --- examples/ds1307/Makefile | 3 + examples/ds1307/main.c | 45 ++++++++++ extras/ds1307/component.mk | 9 ++ extras/ds1307/ds1307.c | 164 +++++++++++++++++++++++++++++++++++++ extras/ds1307/ds1307.h | 114 ++++++++++++++++++++++++++ 5 files changed, 335 insertions(+) create mode 100644 examples/ds1307/Makefile create mode 100644 examples/ds1307/main.c create mode 100644 extras/ds1307/component.mk create mode 100644 extras/ds1307/ds1307.c create mode 100644 extras/ds1307/ds1307.h diff --git a/examples/ds1307/Makefile b/examples/ds1307/Makefile new file mode 100644 index 0000000..319d007 --- /dev/null +++ b/examples/ds1307/Makefile @@ -0,0 +1,3 @@ +PROGRAM = ds1307 +EXTRA_COMPONENTS = extras/i2c extras/ds1307 +include ../../common.mk diff --git a/examples/ds1307/main.c b/examples/ds1307/main.c new file mode 100644 index 0000000..2f22447 --- /dev/null +++ b/examples/ds1307/main.c @@ -0,0 +1,45 @@ +/* + * Example of using DS1307 RTC driver + * + * Part of esp-open-rtos + * Copyright (C) 2016 Ruslan V. Uss + * BSD Licensed as described in the file LICENSE + */ +#include +#include +#include +#include +#include + +#define SCL_PIN 5 +#define SDA_PIN 4 + +void user_init (void) +{ + uart_set_baud (0, 115200); + printf ("SDK version:%s\n", sdk_system_get_sdk_version ()); + + i2c_init (SCL_PIN, SDA_PIN); + ds1307_start (true); + + // setup datetime: 2016-10-09 13:50:10 + struct tm time = { + .tm_year = 2016, + .tm_mon = 10, + .tm_mday = 9, + .tm_hour = 13, + .tm_min = 50, + .tm_sec = 10 + }; + ds1307_set_time (&time); + + while (true) + { + ds1307_get_time (&time); + + printf ("%04d-%02d-%02d %02d:%02d:%02d\n", time.tm_year, time.tm_mon, time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec); + + for (uint32_t i = 0; i < 1000; i ++) + sdk_os_delay_us (500); + } +} diff --git a/extras/ds1307/component.mk b/extras/ds1307/component.mk new file mode 100644 index 0000000..217716e --- /dev/null +++ b/extras/ds1307/component.mk @@ -0,0 +1,9 @@ +# Component makefile for extras/ds1307 + +# expected anyone using RTC driver includes it as 'ds1307/ds1307.h' +INC_DIRS += $(ds1307_ROOT).. + +# args for passing into compile rule generation +ds1307_SRC_DIR = $(ds1307_ROOT) + +$(eval $(call component_compile_rules,ds1307)) diff --git a/extras/ds1307/ds1307.c b/extras/ds1307/ds1307.c new file mode 100644 index 0000000..cd4472f --- /dev/null +++ b/extras/ds1307/ds1307.c @@ -0,0 +1,164 @@ +/* + * Driver for DS1307 RTC + * + * Part of esp-open-rtos + * Copyright (C) 2016 Ruslan V. Uss + * BSD Licensed as described in the file LICENSE + */ +#include "ds1307.h" +#include +#include + +#define ADDR 0x68 +#define RAM_SIZE 56 + +#define TIME_REG 0 +#define CONTROL_REG 7 +#define RAM_REG 8 + +#define CH_BIT (1 << 7) +#define HOUR12_BIT (1 << 6) +#define PM_BIT (1 << 5) +#define SQWE_BIT (1 << 4) +#define OUT_BIT (1 << 7) + +#define CH_MASK 0x7f +#define SECONDS_MASK 0x7f +#define HOUR12_MASK 0x1f +#define HOUR24_MASK 0x3f +#define SQWEF_MASK 0x03 +#define SQWE_MASK 0xef +#define OUT_MASK 0x7f + +static uint8_t bcd2dec(uint8_t val) +{ + return (val >> 4) * 10 + (val & 0x0f); +} + +static uint8_t dec2bcd(uint8_t val) +{ + return ((val / 10) << 4) + (val % 10); +} + +static uint8_t read_register(uint8_t reg) +{ + uint8_t val; + i2c_slave_read(ADDR, reg, &val, 1); + return val; +} + +static void update_register(uint8_t reg, uint8_t mask, uint8_t val) +{ + uint8_t buf[2]; + + buf[0] = reg; + buf[1] = (read_register(reg) & mask) | val; + + i2c_slave_write(ADDR, buf, 2); +} + +void ds1307_start(bool start) +{ + update_register(TIME_REG, CH_MASK, start ? 0 : CH_BIT); +} + +bool ds1307_is_running() +{ + return !(read_register(TIME_REG) & CH_BIT); +} + +void ds1307_get_time(struct tm *time) +{ + uint8_t buf[7]; + + i2c_slave_read(ADDR, TIME_REG, buf, 7); + + time->tm_sec = bcd2dec(buf[0] & SECONDS_MASK); + time->tm_min = bcd2dec(buf[1]); + if (buf[2] & HOUR12_BIT) + { + // RTC in 12-hour mode + time->tm_hour = bcd2dec(buf[2] & HOUR12_MASK); + if (buf[2] & PM_BIT) + time->tm_hour += 12; + } + else time->tm_hour = bcd2dec(buf[2] & HOUR24_MASK); + time->tm_wday = bcd2dec(buf[3]) - 1; + time->tm_mday = bcd2dec(buf[4]); + time->tm_mon = bcd2dec(buf[5]); + time->tm_year = bcd2dec(buf[6]) + 2000; +} + +void ds1307_set_time(const struct tm *time) +{ + uint8_t buf[8]; + buf[0] = TIME_REG; + buf[1] = dec2bcd(time->tm_sec); + buf[2] = dec2bcd(time->tm_min); + buf[3] = dec2bcd(time->tm_hour); + buf[4] = dec2bcd(time->tm_wday); + buf[5] = dec2bcd(time->tm_mday); + buf[6] = dec2bcd(time->tm_mon); + buf[7] = dec2bcd(time->tm_year - 2000); + + i2c_slave_write(ADDR, buf, 8); +} + +void ds1307_enable_squarewave(bool enable) +{ + update_register(CONTROL_REG, SQWE_MASK, enable ? SQWE_BIT : 0); +} + +bool ds1307_is_squarewave_enabled() +{ + return read_register(CONTROL_REG) & SQWE_BIT; +} + +void ds1307_set_squarewave_freq(ds1307_squarewave_freq_t freq) +{ + update_register(CONTROL_REG, SQWEF_MASK, (uint8_t)freq); +} + +ds1307_squarewave_freq_t ds1307_get_squarewave_freq() +{ + return (ds1307_squarewave_freq_t)(read_register(CONTROL_REG) & SQWEF_MASK); +} + +bool ds1307_get_output() +{ + return read_register(CONTROL_REG) & OUT_BIT; +} + +void ds1307_set_output(bool value) +{ + update_register(CONTROL_REG, OUT_MASK, value ? OUT_BIT : 0); +} + +bool ds1307_read_ram(uint8_t offset, uint8_t *buf, uint8_t len) +{ + if (offset + len > RAM_SIZE) return false; + + return i2c_slave_read(ADDR, RAM_REG + offset, buf, len); +} + +bool ds1307_write_ram(uint8_t offset, uint8_t *buf, uint8_t len) +{ + if (offset + len > RAM_SIZE) return false; + + // temporary buffer on the stack is not good so copy-paste :( + bool success = false; + do { + i2c_start(); + if (!i2c_write(ADDR << 1)) + break; + if (!i2c_write(RAM_REG + offset)) + break; + while (len--) { + if (!i2c_write(*buf++)) + break; + } + i2c_stop(); + success = true; + } while(0); + return success; +} diff --git a/extras/ds1307/ds1307.h b/extras/ds1307/ds1307.h new file mode 100644 index 0000000..d2daeee --- /dev/null +++ b/extras/ds1307/ds1307.h @@ -0,0 +1,114 @@ +/* + * Driver for DS1307 RTC + * + * Part of esp-open-rtos + * Copyright (C) 2016 Ruslan V. Uss + * BSD Licensed as described in the file LICENSE + */ +#ifndef EXTRAS_DS1307_H_ +#define EXTRAS_DS1307_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Squarewave frequency + */ +typedef enum _ds1307_squarewave_freq_t +{ + DS1307_1HZ = 0, //!< 1 Hz + DS1307_4096HZ, //!< 4096 Hz + DS1307_8192HZ, //!< 8192 Hz + DS1307_32768HZ //!< 32768 Hz +} ds1307_squarewave_freq_t; + +/** + * \brief Start/stop clock + * \param start Start clock if true + */ +void ds1307_start(bool start); + +/** + * \brief Get current clock state + * \return true if clock running + */ +bool ds1307_is_running(); + +/** + * \brief Get current time + * \param time Pointer to the time struct to fill + */ +void ds1307_get_time(struct tm *time); + +/** + * \brief Set time to RTC + * \param time Pointer to the time struct + */ +void ds1307_set_time(const struct tm *time); + +/** + * \brief Enable or disable square-wave oscillator output + * \param enable Enable oscillator if true + */ +void ds1307_enable_squarewave(bool enable); + +/** + * \brief Get square-wave oscillator output + * \return true if square-wave oscillator enabled + */ +bool ds1307_is_squarewave_enabled(); + +/** + * \brief Set square-wave oscillator frequency + * \param freq Frequency + */ +void ds1307_set_squarewave_freq(ds1307_squarewave_freq_t freq); + +/** + * \brief Get current square-wave oscillator frequency + * \return Frequency + */ +ds1307_squarewave_freq_t ds1307_get_squarewave_freq(); + +/** + * \brief Get current output level of the SQW/OUT pin + * \return true if high + */ +bool ds1307_get_output(); + +/** + * \brief Set output level of the SQW/OUT pin + * Set output level if square-wave output is disabled + * \param value High level if true + */ +void ds1307_set_output(bool value); + +/** + * \brief Read RAM contents into the buffer + * \param offset Start byte, 0..55 + * \param buf Buffer + * \param len Bytes to read, 1..56 + * \return false if error occured + */ +bool ds1307_read_ram(uint8_t offset, uint8_t *buf, uint8_t len); + +/** + * \brief Write buffer to RTC RAM + * \param offset Start byte, 0..55 + * \param buf Buffer + * \param len Bytes to write, 1..56 + * \return false if error occured + */ +bool ds1307_write_ram(uint8_t offset, uint8_t *buf, uint8_t len); + + +#ifdef __cplusplus +} +#endif + +#endif /* EXTRAS_DS1307_H_ */