driver/rtc_rx8010.c

561 lines
13 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file rtc_rx8010.c
* @author xxx
* @date 2023-08-30 08:58:43
* @brief 用于实现RTC芯片RX8010的应用功能
* @copyright Copyright (c) 2023 by xxx, All Rights Reserved.
*/
#include "rtc_rx8010.h"
#include "i2cs.h"
#include "delay.h"
#define RTC_RX8010_SDA_PORT RTC_SDA_GPIO_Port
#define RTC_RX8010_SDA_PIN RTC_SDA_Pin
#define RTC_RX8010_SCL_PORT RTC_SCL_GPIO_Port
#define RTC_RX8010_SCL_PIN RTC_SCL_Pin
static i2c_t *rtc;
static TIM_TypeDef *_timer_us;
static void _delay_us(uint32_t us)
{
if (_timer_us != NULL)
{
delay_hardware_us(_timer_us, us);
}
else
{
delay_us(us);
}
}
/* sec, min, hour, week, day, month, year */
// static uint8_t calendar[7] = {0, 0, 0, 1, 29, 2, 98};
/**
* @brief 从RTC芯片的指定地址读取一个字节数据
* @param {uint8_t} *read_buf
* @param {uint8_t} addr
* @return {*}
*/
static BOOL rtc_read_byte(uint8_t *read_buf, uint8_t addr)
{
uint8_t *p = read_buf;
/* 发送起始信号 */
rtc->interface.start(rtc);
/* 发送从机地址 + 读写方向 */
rtc->interface.write_byte(rtc, RTC_WR_ADDR); /* 此处是写方向,因为要发送读地址 */
if (rtc->interface.wait_ack(rtc) != TRUE)
{
rtc->interface.stop(rtc);
return FALSE;
}
/* 发送读地址 */
rtc->interface.write_byte(rtc, addr);
if (rtc->interface.wait_ack(rtc) != TRUE)
{
rtc->interface.stop(rtc);
return FALSE;
}
/* 重新发送起始信号。前面的代码的目的向RTC传送地址下面开始读取数据 */
rtc->interface.start(rtc);
/* 发送从机地址 + 读写方向 */
rtc->interface.write_byte(rtc, RTC_RD_ADDR); /* 此处是读方向,因为要开始读数据了 */
if (rtc->interface.wait_ack(rtc) != TRUE)
{
rtc->interface.stop(rtc);
return FALSE;
}
/* 读取数据 */
*p = rtc->interface.read_byte(rtc, FALSE); /* 读1个字节 */
/* 命令执行成功发送I2C总线停止信号 */
rtc->interface.stop(rtc);
return TRUE;
}
/**
* @brief 从RTC芯片的指定地址读取若干数据
* @param {uint8_t} *read_buf
* @param {uint8_t} addr
* @param {int} size
* @return {*}
*/
static BOOL rtc_read_bytes(uint8_t *read_buf, uint8_t addr, int size)
{
int i = 0;
/* 发送起始信号 */
rtc->interface.start(rtc);
/* 发送从机地址 + 读写方向 */
rtc->interface.write_byte(rtc, RTC_WR_ADDR); /* 此处是写方向,因为要发送读地址 */
if (rtc->interface.wait_ack(rtc) != TRUE)
{
rtc->interface.stop(rtc);
return FALSE;
}
/* 发送读地址 */
rtc->interface.write_byte(rtc, addr);
if (rtc->interface.wait_ack(rtc) != TRUE)
{
rtc->interface.stop(rtc);
return FALSE;
}
/* 重新发送起始信号。前面的代码的目的向RTC传送地址下面开始读取数据 */
rtc->interface.start(rtc);
/* 发送从机地址 + 读写方向 */
rtc->interface.write_byte(rtc, RTC_RD_ADDR); /* 此处是读方向,因为要开始读数据了 */
if (rtc->interface.wait_ack(rtc) != TRUE)
{
rtc->interface.stop(rtc);
return FALSE;
}
/* 循环读取数据RTC芯片地址自动自增 */
for (i = 0; i < size; i++)
{
/* 每读完1个字节后需要发送Ack 最后一个字节需要发Nack */
if (i != (size - 1))
{
read_buf[i] = rtc->interface.read_byte(rtc, TRUE); /* 读1个字节 */
}
else
{
read_buf[i] = rtc->interface.read_byte(rtc, FALSE); /* 读1个字节 */
}
}
/* 命令执行成功发送I2C总线停止信号 */
rtc->interface.stop(rtc);
return TRUE;
}
/**
* @brief 向RTC芯片的指定地址写入一个数据
* @param {uint8_t} data
* @param {uint8_t} addr
* @return {*}
* @note
*/
static BOOL rtc_write_byte(uint8_t data, uint8_t addr)
{
int retry = 0;
/* 尝试与RTC芯片建立I2C通讯 */
for (retry = 0; retry < 100; retry++)
{
rtc->interface.start(rtc); /* 发送起始信号 */
rtc->interface.write_byte(rtc, RTC_WR_ADDR); /* 发送从机地址 + 读写方向 */
if (rtc->interface.wait_ack(rtc) == TRUE)
{
break;
}
}
if (retry == 100)
{
rtc->interface.stop(rtc);
return FALSE;
}
/* 发送起始写地址 */
rtc->interface.write_byte(rtc, addr);
if (rtc->interface.wait_ack(rtc) != TRUE)
{
rtc->interface.stop(rtc);
return FALSE;
}
/* 写入数据 */
rtc->interface.write_byte(rtc, data);
if (rtc->interface.wait_ack(rtc) != TRUE)
{
rtc->interface.stop(rtc);
return FALSE;
}
/* 命令执行成功发送I2C总线停止信号 */
rtc->interface.stop(rtc);
return TRUE;
}
/**
* @brief 向RTC芯片的指定地址写入若干数据
* @param {uint8_t} *write_buf
* @param {uint8_t} addr
* @param {int} size
* @return {*}
* @note
*/
static BOOL rtc_write_bytes(uint8_t *write_buf, uint8_t addr, int size)
{
int i = 0;
int retry = 0;
for (i = 0; i < size; i++)
{
if (i == 0)
{
/* 尝试与RTC芯片建立I2C通讯 */
for (retry = 0; retry < 100; retry++)
{
rtc->interface.start(rtc); /* 发送起始信号 */
rtc->interface.write_byte(rtc, RTC_WR_ADDR); /* 发送从机地址 + 读写方向 */
if (rtc->interface.wait_ack(rtc) == TRUE)
{
break;
}
}
if (retry == 100)
{
rtc->interface.stop(rtc);
return FALSE;
}
/* 发送起始写地址 */
rtc->interface.write_byte(rtc, addr);
if (rtc->interface.wait_ack(rtc) != TRUE)
{
rtc->interface.stop(rtc);
return FALSE;
}
}
/* 循环写入数据RTC芯片地址自动自增 */
rtc->interface.write_byte(rtc, write_buf[i]);
if (rtc->interface.wait_ack(rtc) != TRUE)
{
rtc->interface.stop(rtc);
return FALSE;
}
}
/* 命令执行成功发送I2C总线停止信号 */
rtc->interface.stop(rtc);
return TRUE;
}
/**
* @brief 假读RTC芯片任意读地址不判断RTC响应
* @return {*}
* @note
*/
static void rtc_dummy_read(void)
{
rtc->interface.start(rtc);
rtc->interface.write_byte(rtc, RTC_WR_ADDR);
rtc->interface.write_byte(rtc, 0x20);
rtc->interface.start(rtc);
rtc->interface.write_byte(rtc, RTC_RD_ADDR);
rtc->interface.read_byte(rtc, FALSE);
rtc->interface.stop(rtc);
}
/**
* @brief 用于检查VLF寄存器地址0x1e bit[1]
* @return {uint8_t} 0 = VLF位为01 = VLF位为1
* @note
*/
static uint8_t rtc_check_vlf(void)
{
uint8_t flag_register = 1;
uint8_t vlf = 0;
rtc_read_byte(&flag_register, RTC_FLAG_ADDR);
vlf = (flag_register & 0x02);
if (vlf == 0)
{
return 0;
}
else
{
return 1;
}
}
/**
* @brief 等待VLF位清除寄存器地址0x1e bit[1]
* @return {uint8_t} 0 = 清零成功1 = 清零失败2 = 无需清零
*/
static uint8_t rtc_wait_vlf_clear(void)
{
uint8_t ret = 1;
uint8_t i = 0;
uint8_t vlf;
for (i = 0; i < 10; i++)
{
vlf = rtc_check_vlf();
if (vlf == 0)
{
ret = ((i > 0) ? 0 : 2);
return ret;
}
/* 清除VLF */
rtc_write_byte(0, RTC_FLAG_ADDR);
}
return ret;
}
/**
* @brief 复位
* @return {BOOL} FALSE = 复位成功TRUE = 复位失败
*/
static BOOL rtc_soft_reset(void)
{
BOOL ret = FALSE;
ret = rtc_write_byte(0x00, 0x1f);
ret = rtc_write_byte(0x80, 0x1f);
ret = rtc_write_byte(0xd3, 0x60);
ret = rtc_write_byte(0x03, 0x66);
ret = rtc_write_byte(0x02, 0x6b);
ret = rtc_write_byte(0x01, 0x6b);
if (ret == 0)
{
_delay_us(2000);
}
return ret;
}
/**
* @brief 时钟寄存器初始化函数
* @return {BOOL} TRUE = 初始化成功FALSE = 初始化失败
*/
static BOOL rtc_clock_reginit(void)
{
BOOL ret = FALSE;
/* set reserve register */
ret = rtc_write_byte(RTC_REG17_DATA, RTC_REG17_ADDR);
ret = rtc_write_byte(RTC_REG30_DATA, RTC_REG30_ADDR);
ret = rtc_write_byte(RTC_REG31_DATA, RTC_REG31_ADDR);
ret = rtc_write_byte(RTC_IRQ_DATA, RTC_IRQ_ADDR);
/* write 0x04 to reg_0x1d */
ret = rtc_write_byte(0x04, 0x1d);
/* write 0x00 to reg_0x1e */
ret = rtc_write_byte(0x00, 0x1e);
/* stop clock */
ret = rtc_write_byte(0x40, RTC_CONTROL_ADDR);
/* set the present time */
// ret = rtc_write_bytes(calendar, RTC_CLOCK_ADDR, sizeof(calendar));
/* start clock */
ret = rtc_write_byte(0x00, RTC_CONTROL_ADDR);
return ret;
}
/**
* @brief RTC芯片初始化
* @return {BOOL} TRUE = 成功FALSE = 失败
* @note
*/
BOOL rtc_init(TIM_TypeDef *timer_us)
{
if (timer_us != NULL)
{
_timer_us = timer_us;
ENABLE_TIM_COUNT(_timer_us);
}
i2c_gpio_group_t gpios;
int ret = 1;
gpios.scl = gpio_create(RTC_RX8010_SCL_PORT, RTC_RX8010_SCL_PIN);
gpios.sda = gpio_create(RTC_RX8010_SDA_PORT, RTC_RX8010_SDA_PIN);
rtc = i2c_create(gpios, 10);
rtc_dummy_read();
/* wait for VLF bit clear */
ret = rtc_wait_vlf_clear();
if (ret == 0)
{
/* software reset */
ret = rtc_soft_reset();
if (ret == FALSE)
{
return FALSE;
}
}
else if (ret == 1)
{
return FALSE;
}
/* register initialize */
return rtc_clock_reginit();
}
/**
* @brief RTC芯片反初始化
* @return {*}
* @note
*/
BOOL rtc_dinit(void)
{
GPIO_SET_ANALOG(RTC_RX8010_SCL_PORT, RTC_RX8010_SCL_PIN);
GPIO_SET_ANALOG(RTC_RX8010_SDA_PORT, RTC_RX8010_SDA_PIN);
return TRUE;
}
/**
* @brief 从RTC芯片读取时间
* @param {uint8_t} *read_buf - 接收缓存指针,用于接收读取到的数据
* @return {BOOL} TRUE = 成功FALSE = 失败
* @note
*/
BOOL rtc_get_clock_time(uint8_t *read_buf)
{
return rtc_read_bytes(read_buf, RTC_CLOCK_ADDR, 7);
}
/**
* @brief 向RTC芯片写入时间
* @param {rtc_date} *data - 发送缓存指针,用于存储要发送的数据
* @return {BOOL} TRUE = 成功FALSE = 失败
* @note
*/
BOOL rtc_set_clock_time(rtc_date *data)
{
BOOL ret = FALSE;
uint8_t tmp[7];
tmp[0] = data->second;
tmp[1] = data->minute;
tmp[2] = data->hour;
tmp[3] = data->weekday;
tmp[4] = data->day;
tmp[5] = data->month;
tmp[6] = data->year;
tmp[3] = (rtc_week_e)tmp[3]; // 改成星期几
/* stop clock */
ret = rtc_write_byte(0x40, RTC_CONTROL_ADDR);
/* set the present time */
ret = rtc_write_bytes(tmp, RTC_CLOCK_ADDR, sizeof(tmp));
/* start clock */
ret = rtc_write_byte(0x00, RTC_CONTROL_ADDR);
return ret;
}
/**
* 获取实时时钟RTC的时间戳
*
* 该函数从RTC设备中获取当前的日期和时间并将其转换为自1970年1月1日以来的秒数时间戳
* 如果无法从RTC设备中获取时间则返回0。
*
* @return 返回从1970年1月1日以来的秒数时间戳如果无法获取时间则返回0。
*/
uint32_t rtc_timestamp(void)
{
BOOL ret = FALSE;
uint8_t tmp[7];
rtc_date_t date;
rtc_time_t time;
ret = rtc_get_clock_time(tmp);
if (ret == FALSE)
{
return 0;
}
date.year = hex_format_dec(tmp[6]);
date.month = hex_format_dec(tmp[5]);
date.day = hex_format_dec(tmp[4]);
time.hour = hex_format_dec(tmp[2]);
time.minute = hex_format_dec(tmp[1]);
time.second = hex_format_dec(tmp[0]);
return time2stamp(&date, &time);
}
/**
* @brief 将星期转为星期码
* @param {uint8_t} *weekday 星期几
* @return {*}
* @note
*/
void rtc_weekday_convert(uint8_t *weekday)
{
switch (*weekday)
{
case 1:
*weekday = MON;
break;
case 2:
*weekday = TUE;
break;
case 3:
*weekday = WED;
break;
case 4:
*weekday = THUR;
break;
case 5:
*weekday = FRI;
break;
case 6:
*weekday = SAT;
break;
case 7:
*weekday = SUN;
break;
default:
*weekday = 0;
break;
}
}
/**
* @brief 将星期码转为星期
* @param {uint8_t} *weekday 星期码
* @return {*}
* @note
*/
void rtc_weekday_rconvert(uint8_t *weekday)
{
switch (*weekday)
{
case MON:
*weekday = 1;
break;
case TUE:
*weekday = 2;
break;
case WED:
*weekday = 3;
break;
case THUR:
*weekday = 4;
break;
case FRI:
*weekday = 5;
break;
case SAT:
*weekday = 6;
break;
case SUN:
*weekday = 7;
break;
default:
*weekday = 0;
break;
}
}