/** * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #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; }