initial rtc driver and example

pcf85063a
Jonathan Williamson 2022-05-27 15:44:58 +01:00 zatwierdzone przez Phil Howard
rodzic 7db6d62515
commit 48c502c3a1
8 zmienionych plików z 332 dodań i 0 usunięć

Wyświetl plik

@ -33,3 +33,4 @@ add_subdirectory(servo)
add_subdirectory(encoder)
add_subdirectory(motor)
add_subdirectory(vl53l5cx)
add_subdirectory(pcf85063a)

Wyświetl plik

@ -0,0 +1 @@
include(pcf85063a.cmake)

Wyświetl plik

@ -0,0 +1,10 @@
set(DRIVER_NAME pcf85063a)
add_library(${DRIVER_NAME} INTERFACE)
target_sources(${DRIVER_NAME} INTERFACE
${CMAKE_CURRENT_LIST_DIR}/${DRIVER_NAME}.cpp)
target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
# Pull in pico libraries that we need
target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib hardware_i2c hardware_rtc)

Wyświetl plik

@ -0,0 +1,146 @@
#include "pcf85063a.hpp"
#include <chrono>
#include "hardware/i2c.h"
#include "hardware/rtc.h"
namespace pimoroni {
const uint8_t REG_CONTROL_1 = 0x00;
const uint8_t REG_CONTROL_2 = 0x01;
const uint8_t REG_OFFSET = 0x02;
const uint8_t REG_RAM_BYTE = 0x03;
const uint8_t REG_SECONDS = 0x04;
const uint8_t REG_MINUTES = 0x05;
const uint8_t REG_HOURS = 0x06;
const uint8_t REG_DAYS = 0x07;
const uint8_t REG_WEEKDAYS = 0x08;
const uint8_t REG_MONTHS = 0x09;
const uint8_t REG_YEARS = 0x0a;
const uint8_t REG_SECOND_ALARM = 0x0b;
const uint8_t REG_MINUTE_ALARM = 0x0c;
const uint8_t REG_HOUR_ALARM = 0x0d;
const uint8_t REG_DAY_ALARM = 0x0e;
const uint8_t REG_WEEKDAY_ALARM = 0x0f;
const uint8_t REG_TIMER_VALUE = 0x10;
const uint8_t REG_TIMER_MODE = 0x11;
void PCF85063A::init() {
// configure i2c interface and pins
i2c_init(i2c, i2c_baud);
gpio_set_function(sda, GPIO_FUNC_I2C);
gpio_set_function(scl, GPIO_FUNC_I2C);
if(interrupt != PIN_UNUSED) {
gpio_set_function(interrupt, GPIO_FUNC_SIO);
gpio_set_dir(interrupt, GPIO_IN);
gpio_set_pulls(interrupt, false, true);
}
}
void PCF85063A::configure(uint8_t flags) {
static uint8_t command[2] = {REG_CONTROL_2, flags};
i2c_write_blocking(i2c, I2C_ADDRESS, command, 2, false);
}
void PCF85063A::reset() {
static uint8_t command[2] = {REG_CONTROL_1, COMMAND_RESET};
i2c_write_blocking(i2c, I2C_ADDRESS, command, 2, false);
}
uint8_t bcd_encode(uint v) {
uint v10 = v / 10;
uint v1 = v - (v10 * 10);
return v1 | (v10 << 4);
}
int8_t bcd_decode(uint v) {
uint v10 = (v >> 4) & 0x0f;
uint v1 = v & 0x0f;
return v1 + (v10 * 10);
}
bool PCF85063A::set_datetime(datetime_t *t) {
/*if (!valid_datetime(t)) {
return false;
} */
static uint8_t command[8] = {0};
command[0] = REG_SECONDS;
command[1] = bcd_encode((uint)t->sec);
command[2] = bcd_encode((uint)t->min);
command[3] = bcd_encode((uint)t->hour);
command[4] = bcd_encode((uint)t->dotw);
command[5] = bcd_encode((uint)t->day);
command[6] = bcd_encode((uint)t->month);
command[7] = bcd_encode((uint)t->year - 2000);
i2c_write_blocking(i2c, I2C_ADDRESS, command, 8, false);
return true;
}
datetime_t PCF85063A::get_datetime() {
static uint8_t result[7] = {0};
i2c_write_blocking(i2c, I2C_ADDRESS, &REG_SECONDS, 1, false);
i2c_read_blocking(i2c, I2C_ADDRESS, result, 7, false);
datetime_t dt = {
.year = (int16_t)(bcd_decode(result[6]) + 2000),
.month = (int8_t)bcd_decode(result[5]),
.day = (int8_t)bcd_decode(result[4]),
.dotw = (int8_t)bcd_decode(result[3]),
.hour = (int8_t)bcd_decode(result[2]),
.min = (int8_t)bcd_decode(result[1]),
.sec = (int8_t)bcd_decode(result[0] & 0x7f)
};
return dt;
}
void PCF85063A::set_second_alarm(uint sec) {
uint8_t se = bcd_encode((uint)sec);
se |= 0x80; // enable alarm bit
static uint8_t command[2] = {REG_SECOND_ALARM, se};
i2c_write_blocking(i2c, I2C_ADDRESS, command, 2, false);
}
void PCF85063A::reset_timer() {
static uint8_t command[2] = {REG_TIMER_MODE, 0b00000000};
i2c_write_blocking(i2c, I2C_ADDRESS, command, 2, false);
}
void PCF85063A::set_seconds_timer(uint8_t sec) {
reset_timer();
static uint8_t command1[2] = {REG_TIMER_VALUE, sec};
i2c_write_blocking(i2c, I2C_ADDRESS, command1, 2, false);
static uint8_t command2[2] = {REG_TIMER_MODE, 0b00010110};
i2c_write_blocking(i2c, I2C_ADDRESS, command2, 2, false);
}
i2c_inst_t* PCF85063A::get_i2c() const {
return i2c;
}
int PCF85063A::get_sda() const {
return sda;
}
int PCF85063A::get_scl() const {
return scl;
}
int PCF85063A::get_interrupt() const {
return interrupt;
}
}

Wyświetl plik

@ -0,0 +1,90 @@
#pragma once
#include "hardware/i2c.h"
#include "../../common/pimoroni_common.hpp"
namespace pimoroni {
class PCF85063A {
//--------------------------------------------------
// Constants
//--------------------------------------------------
public:
static const uint DEFAULT_SDA_PIN = 4;
static const uint DEFAULT_SCL_PIN = 5;
static const uint8_t I2C_ADDRESS = 0x51;
static const uint8_t COMMAND_RESET = 0b01011000;
static const uint8_t ALARM_INTERRUPT = 0b10000000;
static const uint8_t CLEAR_ALARM_FLAG = 0b01000000;
static const uint8_t MINUTE_INTERRUPT = 0b00100000;
static const uint8_t HALF_MINUTE_INTERRUPT = 0b00010000;
static const uint8_t TIMER_FLAG = 0b00001000;
static const uint8_t CLOCK_OUT_32768HZ = 0b00000000;
static const uint8_t CLOCK_OUT_16384HZ = 0b00000001;
static const uint8_t CLOCK_OUT_8192HZ = 0b00000010;
static const uint8_t CLOCK_OUT_4096HZ = 0b00000011;
static const uint8_t CLOCK_OUT_2048HZ = 0b00000100;
static const uint8_t CLOCK_OUT_1024HZ = 0b00000101;
static const uint8_t CLOCK_OUT_1HZ = 0b00000110;
static const uint8_t CLOCK_OUT_OFF = 0b00000111;
static const uint8_t RTC_STOP = 0b00100000;
static const uint8_t MODE_12_HOUR = 0b00000010;
static const uint8_t MODE_24_HOUR = 0b00000000;
static const uint8_t CAP_7PF = 0b00000000;
static const uint8_t CAP_12_5PF = 0b00000001;
//--------------------------------------------------
// Variables
//--------------------------------------------------
private:
// ????
public:
// ????
private:
i2c_inst_t *i2c = i2c0;
// interface pins with our standard defaults where appropriate
uint sda = DEFAULT_SDA_PIN;
uint scl = DEFAULT_SCL_PIN;
uint interrupt = PIN_UNUSED;
uint32_t i2c_baud = 400000;
//--------------------------------------------------
// Constructors/Destructor
//--------------------------------------------------
public:
PCF85063A() {}
PCF85063A(i2c_inst_t *i2c, uint sda, uint scl, uint interrupt = PIN_UNUSED) :
i2c(i2c), sda(sda), scl(scl), interrupt(interrupt) {}
//--------------------------------------------------
// Methods
//--------------------------------------------------
public:
void init();
void reset();
bool set_datetime(datetime_t *t);
datetime_t get_datetime();
void set_second_alarm(uint sec);
void configure(uint8_t flags);
void reset_timer();
void set_seconds_timer(uint8_t sec);
i2c_inst_t* get_i2c() const;
int get_sda() const;
int get_scl() const;
int get_interrupt() const;
};
}

Wyświetl plik

@ -35,6 +35,7 @@ add_subdirectory(pico_explorer_encoder)
add_subdirectory(pico_motor_shim)
add_subdirectory(pico_rgb_keypad)
add_subdirectory(pico_rtc_display)
add_subdirectory(pico_rtc)
add_subdirectory(pico_tof_display)
add_subdirectory(pico_trackball_display)
add_subdirectory(pico_audio)

Wyświetl plik

@ -0,0 +1,14 @@
set(OUTPUT_NAME rtc)
add_executable(
${OUTPUT_NAME}
demo.cpp
)
# Pull in pico libraries that we need
target_link_libraries(${OUTPUT_NAME} pico_stdlib pcf85063a)
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
# create map/bin/hex file etc.
pico_add_extra_outputs(${OUTPUT_NAME})

Wyświetl plik

@ -0,0 +1,69 @@
#include <cstdio>
#include <stdio.h>
#include "pico/stdlib.h"
#include "pcf85063a.hpp"
using namespace pimoroni;
PCF85063A rtc;
int main() {
// keep the pico awake by holding vsys_en high
gpio_set_function(2, GPIO_FUNC_SIO);
gpio_set_dir(2, GPIO_OUT);
gpio_put(2, true);
stdio_init_all();
printf("woken up!\n");
// turn on led to show we're awake
gpio_set_function(6, GPIO_FUNC_SIO);
gpio_set_dir(6, GPIO_OUT);
gpio_put(6, true);
rtc.init();
rtc.configure(PCF85063A::CLEAR_ALARM_FLAG);
// rtc.setup(false);
// Make sure we have 24-hour time (smaller display!)
// if(rtc.is_12_hour())
//rtc.set_24_hour();
datetime_t now = {
.year = 2022, .month = 5, .day = 27,
.hour = 12, .min = 29, .sec = 14
};
rtc.set_datetime(&now);
// stay awake for 1 second
sleep_ms(1000);
// shuold wake up 4 seconds after going to sleep
rtc.set_seconds_timer(3);
// printf("going to sleep!\n");
// go to sleep by driving vsys_en low
//gpio_put(2, false);
gpio_set_dir(2, GPIO_IN);
/*
while(true) {
datetime_t dt = rtc.get_datetime();
printf(
"%04d-%02d-%02d %02d:%02d:%02d\n",
dt.year, dt.month, dt.day,
dt.hour, dt.min, dt.sec
);
sleep_ms(1000);
}
*/
return 0;
}