165 lines
6.4 KiB
C
165 lines
6.4 KiB
C
/**
|
|
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "pico/stdlib.h"
|
|
#include "pico/binary_info.h"
|
|
#include "hardware/i2c.h"
|
|
|
|
/* Example code to talk to a PCF8520 Real Time Clock module
|
|
|
|
Connections on Raspberry Pi Pico board, other boards may vary.
|
|
|
|
GPIO PICO_DEFAULT_I2C_SDA_PIN (On Pico this is 4 (physical pin 6)) -> SDA on PCF8520 board
|
|
GPIO PICO_DEFAULT_I2C_SCK_PIN (On Pico this is 5 (physical pin 7)) -> SCL on PCF8520 board
|
|
5V (physical pin 40) -> VCC on PCF8520 board
|
|
GND (physical pin 38) -> GND on PCF8520 board
|
|
*/
|
|
|
|
#ifdef i2c_default
|
|
|
|
// By default these devices are on bus address 0x68
|
|
static int addr = 0x68;
|
|
|
|
static void pcf8520_reset() {
|
|
// Two byte reset. First byte register, second byte data
|
|
// There are a load more options to set up the device in different ways that could be added here
|
|
uint8_t buf[] = {0x00, 0x58};
|
|
i2c_write_blocking(i2c_default, addr, buf, 2, false);
|
|
}
|
|
|
|
static void pcf820_write_current_time() {
|
|
// buf[0] is the register to write to
|
|
// buf[1] is the value that will be written to the register
|
|
uint8_t buf[2];
|
|
|
|
//Write values for the current time in the array
|
|
//index 0 -> second: bits 4-6 are responsible for the ten's digit and bits 0-3 for the unit's digit
|
|
//index 1 -> minute: bits 4-6 are responsible for the ten's digit and bits 0-3 for the unit's digit
|
|
//index 2 -> hour: bits 4-5 are responsible for the ten's digit and bits 0-3 for the unit's digit
|
|
//index 3 -> day of the month: bits 4-5 are responsible for the ten's digit and bits 0-3 for the unit's digit
|
|
//index 4 -> day of the week: where Sunday = 0x00, Monday = 0x01, Tuesday... ...Saturday = 0x06
|
|
//index 5 -> month: bit 4 is responsible for the ten's digit and bits 0-3 for the unit's digit
|
|
//index 6 -> year: bits 4-7 are responsible for the ten's digit and bits 0-3 for the unit's digit
|
|
|
|
//NOTE: if the value in the year register is a multiple for 4, it will be considered a leap year and hence will include the 29th of February
|
|
|
|
uint8_t current_val[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
|
|
for (int i = 3; i < 10; ++i) {
|
|
buf[0] = i;
|
|
buf[1] = current_val[i - 3];
|
|
i2c_write_blocking(i2c_default, addr, buf, 2, false);
|
|
}
|
|
}
|
|
|
|
static void pcf8520_read_raw(uint8_t *buffer) {
|
|
// For this particular device, we send the device the register we want to read
|
|
// first, then subsequently read from the device. The register is auto incrementing
|
|
// so we don't need to keep sending the register we want, just the first.
|
|
|
|
// Start reading acceleration registers from register 0x3B for 6 bytes
|
|
uint8_t val = 0x03;
|
|
i2c_write_blocking(i2c_default, addr, &val, 1, true); // true to keep master control of bus
|
|
i2c_read_blocking(i2c_default, addr, buffer, 7, false);
|
|
}
|
|
|
|
|
|
void pcf8520_set_alarm() {
|
|
// buf[0] is the register to write to
|
|
// buf[1] is the value that will be written to the register
|
|
uint8_t buf[2];
|
|
|
|
// Default value of alarm register is 0x80
|
|
// Set bit 8 of values to 0 to activate that particular alarm
|
|
// Index 0 -> minute: bits 4-5 are responsible for the ten's digit and bits 0-3 for the unit's digit
|
|
// Index 1 -> hour: bits 4-6 are responsible for the ten's digit and bits 0-3 for the unit's digit
|
|
// Index 2 -> day of the month: bits 4-5 are responsible for the ten's digit and bits 0-3 for the unit's digit
|
|
// Index 3 -> day of the week: where Sunday = 0x00, Monday = 0x01, Tuesday... ...Saturday = 0x06
|
|
|
|
uint8_t alarm_val[4] = {0x01, 0x80, 0x80, 0x80};
|
|
// Write alarm values to registers
|
|
for (int i = 10; i < 14; ++i) {
|
|
buf[0] = (uint8_t) i;
|
|
buf[1] = alarm_val[i - 10];
|
|
i2c_write_blocking(i2c_default, addr, buf, 2, false);
|
|
}
|
|
}
|
|
|
|
void pcf8520_check_alarm() {
|
|
// Check bit 3 of control register 2 for alarm flags
|
|
uint8_t status[1];
|
|
uint8_t val = 0x01;
|
|
i2c_write_blocking(i2c_default, addr, &val, 1, true); // true to keep master control of bus
|
|
i2c_read_blocking(i2c_default, addr, status, 1, false);
|
|
|
|
if ((status[0] & 0x08) == 0x08) {
|
|
printf("ALARM RINGING");
|
|
} else {
|
|
printf("Alarm not triggered yet");
|
|
}
|
|
}
|
|
|
|
|
|
void pcf8520_convert_time(int conv_time[7], const uint8_t raw_time[7]) {
|
|
// Convert raw data into time
|
|
conv_time[0] = (10 * (int) ((raw_time[0] & 0x70) >> 4)) + ((int) (raw_time[0] & 0x0F));
|
|
conv_time[1] = (10 * (int) ((raw_time[1] & 0x70) >> 4)) + ((int) (raw_time[1] & 0x0F));
|
|
conv_time[2] = (10 * (int) ((raw_time[2] & 0x30) >> 4)) + ((int) (raw_time[2] & 0x0F));
|
|
conv_time[3] = (10 * (int) ((raw_time[3] & 0x30) >> 4)) + ((int) (raw_time[3] & 0x0F));
|
|
conv_time[4] = (int) (raw_time[4] & 0x07);
|
|
conv_time[5] = (10 * (int) ((raw_time[5] & 0x10) >> 4)) + ((int) (raw_time[5] & 0x0F));
|
|
conv_time[6] = (10 * (int) ((raw_time[6] & 0xF0) >> 4)) + ((int) (raw_time[6] & 0x0F));
|
|
}
|
|
#endif
|
|
|
|
int main() {
|
|
stdio_init_all();
|
|
#if !defined(i2c_default) || !defined(PICO_DEFAULT_I2C_SDA_PIN) || !defined(PICO_DEFAULT_I2C_SCL_PIN)
|
|
#warning i2c/pcf8520_i2c example requires a board with I2C pins
|
|
puts("Default I2C pins were not defined");
|
|
#else
|
|
printf("Hello, PCF8520! Reading raw data from registers...\n");
|
|
|
|
// This example will use I2C0 on the default SDA and SCL pins (4, 5 on a Pico)
|
|
i2c_init(i2c_default, 400 * 1000);
|
|
gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C);
|
|
gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C);
|
|
gpio_pull_up(PICO_DEFAULT_I2C_SDA_PIN);
|
|
gpio_pull_up(PICO_DEFAULT_I2C_SCL_PIN);
|
|
// Make the I2C pins available to picotool
|
|
bi_decl(bi_2pins_with_func(PICO_DEFAULT_I2C_SDA_PIN, PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C));
|
|
|
|
pcf8520_reset();
|
|
|
|
pcf820_write_current_time();
|
|
pcf8520_set_alarm();
|
|
pcf8520_check_alarm();
|
|
|
|
uint8_t raw_time[7];
|
|
int real_time[7];
|
|
char days_of_week[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
|
|
|
|
while (1) {
|
|
|
|
pcf8520_read_raw(raw_time);
|
|
pcf8520_convert_time(real_time, raw_time);
|
|
|
|
printf("Time: %02d : %02d : %02d\n", real_time[2], real_time[1], real_time[0]);
|
|
printf("Date: %s %02d / %02d / %02d\n", days_of_week[real_time[4]], real_time[3], real_time[5], real_time[6]);
|
|
pcf8520_check_alarm();
|
|
|
|
sleep_ms(500);
|
|
|
|
// Clear terminal
|
|
printf("\e[1;1H\e[2J");
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|