Files
RingClock/Core/Src/ds1307.c
2026-03-26 11:27:17 +01:00

357 lines
8.2 KiB
C

/**
* @copyright (c) 2021 Noel Dom https://www.youtube.com/channel/UCINCDcQylATh2wS5BAYIBPg.
*
* @brief Device Driver for DS1307 Real-time clock (RTC)
* @file ds1307.c
* @version 0.1.0
* @date 2021
* @author Noel Dominguez.
*/
#include "ds1307.h"
#define DS1307_ADDRES 0x68
#define DS1307_SECONDS 0x00
#define DS1307_MINUTES 0x01
#define DS1307_HOURS 0x02
#define DS1307_DAY 0X03
#define DS1307_DATE 0x04
#define DS1307_MONTH 0x05
#define DS1307_YEAR 0x06
#define DS1307_CONTROL 0x07
#define DS1307_REG_UTC_HR 0x08
#define DS1307_REG_UTC_MIN 0x09
#define DS1307_REG_CENT 0x10
#define DS1307_REG_RAM 0x11
#define DS1307_TIMEOUT 1000
#define DS1307_HANDLER hi2c1
typedef enum{
DS1307_1HZ,
DS1307_4096HZ,
DS1307_8192HZ,
DS1307_32768HZ
}ds1307_rate_t;
static ds1307_err_t ds1307_write_byte(uint8_t ds1307_reg_addres, uint8_t data);
static uint8_t ds1307_read_byte(uint8_t ds1307_reg_addres);
static uint8_t ds1307_bcd_decode(uint8_t data);
static uint8_t ds1307_bcd_encode(uint8_t data);
/**
* @brief Write byte data from an specific address ds1307 RTC
*
* @param ds1307_reg_addres: REG Address you can see more in datasheet page 4 figure 2
* @param data
* @return ds1307_err_t: 0 if everything is ok
*/
static ds1307_err_t ds1307_write_byte(uint8_t ds1307_reg_addres, uint8_t data){
uint8_t buff[2] = {ds1307_reg_addres,data};
ds1307_err_t ret_val;
ret_val = HAL_I2C_Master_Transmit(&DS1307_HANDLER, DS1307_ADDRES << 1, buff, 2, DS1307_TIMEOUT);
return ret_val;
}
/**
* @brief Read byte data from an specific address ds1307 RTC
*
* @param ds1307_reg_addres: REG Address you can see more in datasheet page 4 figure 2
* @return data: data read from reg address
*/
static uint8_t ds1307_read_byte(uint8_t ds1307_reg_addres){
uint8_t data;
HAL_I2C_Master_Transmit(&DS1307_HANDLER, DS1307_ADDRES << 1, &ds1307_reg_addres, 1, DS1307_TIMEOUT);
HAL_I2C_Master_Receive(&DS1307_HANDLER, DS1307_ADDRES << 1, &data, 1, DS1307_TIMEOUT);
return data;
}
/**
* @brief BCD decode
*
* @param data: Value to convert
* @return uint8_t: data converted
*/
static uint8_t ds1307_bcd_decode(uint8_t data){
return (((data & 0xf0) >> 4) * 10) + (data & 0x0f);
}
/**
* @brief BCD Encode
*
* @param data: Value to convert
* @return uint8_t: data converted
*/
static uint8_t ds1307_bcd_encode(uint8_t data){
return (data % 10 + ((data / 10) << 4));
}
/**
* @brief Init ds1307
*
*/
void ds1307_init(void){
ds1307_set_clock_halt(0);
}
/**
* @brief To start the time and calendar, we must set the stop bit of the clock (CH) in 0, to stop, put the bit in 1
* more information see datasheet on page 4
*
* @param halt: 0 init, 1 stop
*/
void ds1307_set_clock_halt(uint8_t halt){
uint8_t ch = (halt ? 1 << 7 : 0);
ds1307_write_byte(DS1307_SECONDS, ch | (ds1307_read_byte(DS1307_SECONDS) & 0x7F));
}
/**
* @brief ds1307_get_clock_halt more info datasheet page 4
*
* @return uint8_t
*/
uint8_t ds1307_get_clock_halt(void){
return (ds1307_read_byte(DS1307_SECONDS) & 0x80) >> 7;
}
/**
* @brief ds1307_set_hour
*
* @param hour
* @return ds1307_err_t
*/
ds1307_err_t ds1307_set_hour(uint8_t hour){
return ds1307_write_byte(DS1307_HOURS,ds1307_bcd_encode(hour & 0x3F));
}
/**
* @brief ds1307_get_hour
*
* @return uint8_t
*/
uint8_t ds1307_get_hour(void){
return ds1307_bcd_decode(ds1307_read_byte(DS1307_HOURS) & 0x3F);
}
/**
* @brief ds1307_set_second
*
* @param second
*/
void ds1307_set_second(uint8_t second){
uint8_t val = ds1307_get_clock_halt();
ds1307_write_byte(DS1307_SECONDS, ds1307_bcd_encode(second | val));
}
/**
* @brief ds1307_get_second
*
* @return uint8_t
*/
uint8_t ds1307_get_second(void){
return ds1307_bcd_decode(ds1307_read_byte(DS1307_SECONDS) & 0x7F);
}
/**
* @brief ds1307_set_minutes
*
* @param minutes
*/
void ds1307_set_minutes(uint8_t minutes){
ds1307_write_byte(DS1307_MINUTES, ds1307_bcd_encode(minutes));
}
/**
* @brief ds1307_get_minutes
*
* @return uint8_t
*/
uint8_t ds1307_get_minutes(void){
return ds1307_bcd_decode(ds1307_read_byte(DS1307_MINUTES));
}
/**
* @brief ds1307_set_day
*
* @param day
*/
void ds1307_set_day(uint8_t day){
ds1307_write_byte(DS1307_DAY, ds1307_bcd_encode(day));
}
/**
* @brief ds1307_get_day
*
* @return ds1307_days_t
*/
ds1307_days_t ds1307_get_day(void){
return ds1307_read_byte(ds1307_bcd_decode(DS1307_DAY));
}
/**
* @brief ds1307_set_date
*
* @param date
*/
void ds1307_set_date(uint8_t date){
ds1307_write_byte(DS1307_DATE, ds1307_bcd_encode(date));
}
/**
* @brief
*
* @return uint8_t
*/
uint8_t ds1307_get_date(void){
return ds1307_bcd_decode(ds1307_read_byte(DS1307_DATE));
}
/**
* @brief ds1307_set_month
*
* @param month
*/
void ds1307_set_month(ds1307_months_t month){
ds1307_write_byte(DS1307_MONTH, ds1307_bcd_encode(month));
}
/**
* @brief ds1307_get_month
*
* @return ds1307_months_t
*/
ds1307_months_t ds1307_get_month(void){
return ds1307_read_byte(ds1307_bcd_decode(DS1307_MONTH));
}
/**
* @brief ds1307_set_year
*
* @param year setup year
*/
void ds1307_set_year(uint16_t year){
ds1307_write_byte(DS1307_REG_CENT, year / 100);
ds1307_write_byte(DS1307_YEAR, ds1307_bcd_encode(year % 100));
}
/**
* @brief ds1307_get_year
*
* @return uint16_t: current year
*/
uint16_t ds1307_get_year(void){
uint16_t cent = ds1307_read_byte(DS1307_REG_CENT) * 100;
return ds1307_bcd_decode(ds1307_read_byte(DS1307_YEAR)) + cent;
}
/**
* @brief Set your time zone more info at https://everytimezone.com/
*
* @param hr: current hour
* @param min: current min
*/
void ds1307_set_time_zone(int8_t hr, uint8_t min){
ds1307_write_byte(DS1307_REG_UTC_HR, hr);
ds1307_write_byte(DS1307_REG_UTC_MIN, min);
}
/**
* @brief Get the actual timezone-hour configured in the rtc
*
* @return int8_t actual time zone
*/
int8_t ds1307_get_time_zone_hour(void){
return ds1307_read_byte(DS1307_REG_UTC_HR);
}
/**
* @brief Get the actual timezone-min configured in the rtc
*
* @return int8_t: actual time zone
*/
int8_t ds1307_get_time_zone_min(void){
return ds1307_read_byte(DS1307_REG_UTC_MIN);
}
/**
* @brief Update ds1307 data
*
* @param dev: ds1307 pointer
*/
void ds1307_update(ds1307_dev_t *ds1307_dev){
ds1307_dev->seconds = ds1307_get_second();
ds1307_dev->minutes = ds1307_get_minutes();
ds1307_dev->hours = ds1307_get_hour();
ds1307_dev->day = ds1307_get_day();
ds1307_dev->date = ds1307_get_date();
ds1307_dev->month = ds1307_get_month();
ds1307_dev->year = ds1307_get_year();
ds1307_dev->t_zone_hour = ds1307_get_time_zone_hour();
ds1307_dev->t_zone_min = ds1307_get_time_zone_min();
}
/**
* @brief Use this function to configure the DS1307, you only need to call this function once on the the first run of your RTC.
*
* @param seconds
* @param minutes
* @param hours
* @param day
* @param date
* @param month
* @param year
* @param t_zone_hour
* @param t_zone_min
*/
void ds1307_config(uint8_t seconds, uint8_t minutes, uint8_t hours,ds1307_days_t day, uint8_t date,
ds1307_months_t month, uint16_t year, int8_t t_zone_hour, int8_t t_zone_min)
{
ds1307_set_second(seconds);
ds1307_set_minutes(minutes);
ds1307_set_hour(hours);
ds1307_set_day(day);
ds1307_set_date(date);
ds1307_set_month(month);
ds1307_set_year(year);
ds1307_set_time_zone(t_zone_hour, t_zone_min);
}
/**
* @brief: Display ds1307 info by UART, @todo you need to implement your printf function!
*
* @param: ds1307_dev ds1307 struct pointer
*/
void ds1307_log_uart(ds1307_dev_t *ds1307_dev){
DBG_print("%d:%d:%d %d/%d/%d\n",ds1307_dev->hours,ds1307_dev->minutes,ds1307_dev->seconds,
ds1307_dev->date,ds1307_dev->month,ds1307_dev->year);
}
/**
* @brief This function helps to scan all connected devices on our I2C peripheral
*
* @param I2Chnd: I2C Handles
* @param delay_: Delay between scanning
*/
void start_i2c_scan(I2C_HandleTypeDef *I2Chnd, uint32_t delay_){
HAL_StatusTypeDef status;
uint8_t no_devices = 0;
DBG_print("\n\r [ I2C Scanner v0.1 ]");
for (uint8_t i = 0; i < 128; i++){
status = HAL_I2C_IsDeviceReady(I2Chnd , (uint16_t)(i<<1), 2, 2);
if ( status != HAL_OK){
//DBG_print(".\n\r");
} else {
DBG_print("\n\rDevice found! Address: 0x%X",i);
++no_devices;
}
HAL_Delay(delay_);
}
if (!no_devices){
DBG_print("\n\r No Devices found!");
} else {
DBG_print("\n\r Total Devices found: %d",no_devices);
}
}