kopia lustrzana https://github.com/pimoroni/pimoroni-pico
initial rtc driver and example
rodzic
7db6d62515
commit
48c502c3a1
|
@ -33,3 +33,4 @@ add_subdirectory(servo)
|
|||
add_subdirectory(encoder)
|
||||
add_subdirectory(motor)
|
||||
add_subdirectory(vl53l5cx)
|
||||
add_subdirectory(pcf85063a)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
include(pcf85063a.cmake)
|
|
@ -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)
|
|
@ -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, ®_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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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})
|
|
@ -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;
|
||||
}
|
Ładowanie…
Reference in New Issue