/*
|
* sht20.c
|
*
|
* Created on: Jan 19, 2023
|
* Author: Wenxue
|
*/
|
|
#include <stdio.h>
|
#include <string.h>
|
#include "isl1208.h"
|
|
/*+--------------------------------------+
|
*| RTC Chipset ISL1208 Register |
|
*+--------------------------------------+*/
|
/* rtc section */
|
#define ISL1208_REG_SC 0x00
|
#define ISL1208_REG_MN 0x01
|
#define ISL1208_REG_HR 0x02
|
#define ISL1208_REG_HR_MIL (1<<7) /* 24h/12h mode */
|
#define ISL1208_REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */
|
#define ISL1208_REG_DT 0x03
|
#define ISL1208_REG_MO 0x04
|
#define ISL1208_REG_YR 0x05
|
#define ISL1208_REG_DW 0x06
|
#define ISL1208_RTC_SECTION_LEN 7 /* RTC Section register */
|
#define REGS_RTC_SR_LEN 8 /* RTC Section and status register */
|
|
/* control/status section */
|
#define ISL1208_REG_SR 0x07
|
#define ISL1208_REG_SR_ARST (1<<7) /* auto reset */
|
#define ISL1208_REG_SR_XTOSCB (1<<6) /* crystal oscillator */
|
#define ISL1208_REG_SR_WRTC (1<<4) /* write rtc */
|
#define ISL1208_REG_SR_EVT (1<<3) /* event */
|
#define ISL1208_REG_SR_ALM (1<<2) /* alarm */
|
#define ISL1208_REG_SR_BAT (1<<1) /* battery */
|
#define ISL1208_REG_SR_RTCF (1<<0) /* rtc fail */
|
#define ISL1208_REG_INT 0x08
|
#define ISL1208_REG_INT_ALME (1<<6) /* alarm enable */
|
#define ISL1208_REG_INT_IM (1<<7) /* interrupt/alarm mode */
|
#define ISL1219_REG_EV 0x09
|
#define ISL1219_REG_EV_EVEN (1<<4) /* event detection enable */
|
#define ISL1219_REG_EV_EVIENB (1<<7) /* event in pull-up disable */
|
#define ISL1208_REG_ATR 0x0a
|
#define ISL1208_REG_DTR 0x0b
|
|
/* alarm section */
|
#define ISL1208_REG_SCA 0x0c
|
#define ISL1208_REG_MNA 0x0d
|
#define ISL1208_REG_HRA 0x0e
|
#define ISL1208_REG_DTA 0x0f
|
#define ISL1208_REG_MOA 0x10
|
#define ISL1208_REG_DWA 0x11
|
#define ISL1208_ALARM_SECTION_LEN 6
|
|
/* user section */
|
#define ISL1208_REG_USR1 0x12
|
#define ISL1208_REG_USR2 0x13
|
#define ISL1208_USR_SECTION_LEN 2
|
|
#define ISL1208_REGS_MAX 0x13
|
|
const char *weekday[7]={"Sun.","Mon.","Tue.","Wed.","Thu.","Fri.","Sat." };
|
|
#define CONFIG_RTC_DEBUG
|
|
#ifdef CONFIG_RTC_DEBUG
|
#define rtc_print(format,args...) printf(format, ##args)
|
#else
|
#define rtc_print(format,args...) do{} while(0)
|
#endif
|
|
#ifdef CONFIG_RTC_DEBUG
|
__attribute__((unused)) static void dump_buf(const char *prompt, uint8_t *buf, uint32_t size)
|
{
|
int i;
|
|
if(!buf)
|
return ;
|
|
if(prompt)
|
printf("%s\r\n", prompt);
|
|
for(i=0; i<size; i++)
|
printf("%02x ", buf[i]);
|
|
printf("\r\n");
|
}
|
#endif
|
|
|
/*
|
*+----------------------------------+
|
*| ISL1208 Low level API |
|
*+----------------------------------+
|
*/
|
|
static int isl1208_i2c_read_regs(uint8_t regaddr, uint8_t *regs, uint8_t len)
|
{
|
uint8_t i;
|
int rv = 0;
|
uint8_t byte;
|
uint8_t ack;
|
|
if( !regs || len<=0 )
|
{
|
rtc_print("ISL1208: Invalid input arguments\r\n");
|
return -PARM_ERROR;
|
}
|
|
I2C_StartCondition(ISL1208_I2CBUS);
|
|
if( NO_ERROR != (rv=I2C_SendAddress(ISL1208_I2CBUS, I2C_WR)) )
|
{
|
rtc_print("ISL1208: Send chipset address[W] failure: rv=0x%02x\r\n", rv);
|
rv = -rv;
|
goto OUT;
|
}
|
|
if( NO_ERROR != (rv=I2C_WriteByte(ISL1208_I2CBUS, regaddr) ) )
|
{
|
rtc_print("ISL1208: Set register[0x%02x] failure: rv=0x%02x\r\n", regaddr, rv);
|
rv = -rv;
|
goto OUT;
|
}
|
|
I2C_StartCondition(ISL1208_I2CBUS);
|
|
if( NO_ERROR != (rv=I2C_SendAddress( ISL1208_I2CBUS, I2C_RD ) ) )
|
{
|
rtc_print("ISL1208: Send chipset address[W] failure: rv=0x%02x\r\n", rv);
|
rv = -rv;
|
goto OUT;
|
}
|
|
for (i=0; i<len; i++)
|
{
|
if( i == (len-1) )
|
ack = ACK_NONE;
|
else
|
ack = ACK;
|
|
rv = I2C_ReadByte(ISL1208_I2CBUS, &byte, ack, I2C_CLK_STRETCH_TIMEOUT);
|
if( NO_ERROR != rv )
|
{
|
rtc_print("ISL1208: Read register data failure: rv=0x%02x\r\n", rv);
|
rv = -rv;
|
goto OUT;
|
}
|
|
regs[i] = byte;
|
}
|
|
OUT:
|
I2C_StopCondition(ISL1208_I2CBUS);
|
return rv;
|
}
|
|
static int isl1208_i2c_write_regs(uint8_t regaddr, uint8_t *regs, uint8_t len)
|
{
|
uint8_t i;
|
int rv = 0;
|
|
I2C_StartCondition(ISL1208_I2CBUS);
|
|
if( NO_ERROR != (rv=I2C_SendAddress(ISL1208_I2CBUS, I2C_WR ) ) )
|
{
|
rtc_print("ISL1208: Send chipset address[W] failure: rv=0x%02x\r\n", rv);
|
rv = -rv;
|
goto OUT;
|
}
|
|
if( NO_ERROR != (rv=I2C_WriteByte(ISL1208_I2CBUS, regaddr) ) )
|
{
|
rtc_print("ISL1208: Set register[0x%02x] failure: rv=0x%02x\r\n", regaddr, rv);
|
rv = -rv;
|
goto OUT;
|
}
|
|
for (i=0; i<len; i++)
|
{
|
rv = I2C_WriteByte(ISL1208_I2CBUS, regs[i]);
|
if( NO_ERROR != rv )
|
{
|
rtc_print("ISL1208: Write register data failure: rv=0x%02x\r\n", rv);
|
rv = -rv;
|
goto OUT;
|
}
|
}
|
|
rv = 0;
|
|
OUT:
|
I2C_StopCondition(ISL1208_I2CBUS);
|
return rv;
|
}
|
|
|
#define bcd2bin(x) (((x) & 0x0f) + ((x) >> 4) * 10)
|
#define bin2bcd(x) ((((x) / 10) << 4) + (x) % 10)
|
|
int set_rtc_time(rtc_time_t tm)
|
{
|
int rv;
|
uint8_t regs[ISL1208_RTC_SECTION_LEN] = { 0, };
|
uint8_t sr;
|
|
regs[ISL1208_REG_SC] = bin2bcd(tm.tm_sec);
|
regs[ISL1208_REG_MN] = bin2bcd(tm.tm_min);
|
regs[ISL1208_REG_HR] = bin2bcd(tm.tm_hour) | ISL1208_REG_HR_MIL;
|
|
regs[ISL1208_REG_DT] = bin2bcd(tm.tm_mday);
|
regs[ISL1208_REG_MO] = bin2bcd(tm.tm_mon);
|
regs[ISL1208_REG_YR] = bin2bcd(tm.tm_year - 2000);
|
//regs[ISL1208_REG_DW] = bin2bcd(tm.tm_wday & 7);
|
|
if( i2c_init(ISL1208_I2CBUS, ISL1208_CHIPADDR) )
|
{
|
rtc_print("ISL1208: Initial I2C bus failure!\r\n");
|
return -2;
|
}
|
|
rv = isl1208_i2c_read_regs(ISL1208_REG_SR, &sr, 1);
|
if( rv < 0 )
|
{
|
rtc_print("ISL1208: read Status Register failure, rv=%d!\r\n", rv);
|
rv = -3;
|
goto OUT;
|
}
|
sr |= ISL1208_REG_SR_WRTC;
|
rv = isl1208_i2c_write_regs(ISL1208_REG_SR, &sr, 1);
|
if( rv < 0 )
|
{
|
rtc_print("ISL1208: Set Status Register WRTC failure, rv=%d!\r\n", rv);
|
rv = -4;
|
goto OUT;
|
}
|
|
rv=isl1208_i2c_write_regs(ISL1208_REG_SC, regs, ISL1208_RTC_SECTION_LEN);
|
if(rv < 0 )
|
{
|
rtc_print("ISL1208: Set RTC section registeres failure, rv=%d!\r\n", rv);
|
rv = -5;
|
goto OUT;
|
}
|
|
sr &= (~ISL1208_REG_SR_WRTC);
|
rv = isl1208_i2c_write_regs(ISL1208_REG_SR, &sr, 1);
|
if( rv < 0 )
|
{
|
rtc_print("ISL1208: Clear Status Register WRTC failure, rv=%d!\r\n", rv);
|
rv = -6;
|
goto OUT;
|
}
|
|
OUT:
|
i2c_term(ISL1208_I2CBUS);
|
return rv;
|
}
|
|
int get_rtc_time(rtc_time_t *tm)
|
{
|
int rv = 0;
|
uint8_t regs[REGS_RTC_SR_LEN] = { 0, };
|
|
if( !tm )
|
{
|
rtc_print("ISL1208: Invalid input arugments!\r\n");
|
return -1;
|
}
|
|
if( i2c_init(ISL1208_I2CBUS, ISL1208_CHIPADDR) )
|
{
|
rtc_print("ISL1208: Initial I2C bus failure!\r\n");
|
return -2;
|
}
|
|
rv = isl1208_i2c_read_regs(ISL1208_REG_SC, regs, REGS_RTC_SR_LEN);
|
if (rv < 0)
|
{
|
rtc_print("ISL1208: read RTC_SECTION and SR registeres failure, rv=%d!\r\n", rv);
|
rv = -3;
|
goto OUT;
|
}
|
|
if( regs[ISL1208_REG_SR] & ISL1208_REG_SR_RTCF )
|
{
|
rtc_print("ISL1208: Initialize RTC time after power failure!\r\n");
|
rv = -4;
|
goto OUT;
|
}
|
|
tm->tm_sec = bcd2bin(regs[ISL1208_REG_SC]);
|
tm->tm_min = bcd2bin(regs[ISL1208_REG_MN]);
|
|
{
|
const uint8_t _hr = regs[ISL1208_REG_HR];
|
|
if (_hr & ISL1208_REG_HR_MIL) /* 24H */
|
{
|
tm->tm_hour = bcd2bin(_hr & 0x3f);
|
}
|
else /* 12H */
|
{
|
tm->tm_hour = bcd2bin(_hr & 0x1f);
|
if (_hr & ISL1208_REG_HR_PM)
|
tm->tm_hour += 12;
|
}
|
}
|
|
tm->tm_mday = bcd2bin(regs[ISL1208_REG_DT]);
|
tm->tm_mon = bcd2bin(regs[ISL1208_REG_MO]);
|
tm->tm_year = bcd2bin(regs[ISL1208_REG_YR]) + 2000;
|
tm->tm_wday = bcd2bin(regs[ISL1208_REG_DW]);
|
|
OUT:
|
i2c_term(ISL1208_I2CBUS);
|
return rv;
|
}
|
|
void print_rtc_time(void)
|
{
|
rtc_time_t tm;
|
|
if( get_rtc_time(&tm) < 0 )
|
return ;
|
|
printf("%04d-%02d-%02d %02d:%02d:%02d %s\r\n", tm.tm_year, tm.tm_mon, tm.tm_mday,
|
tm.tm_hour, tm.tm_min, tm.tm_sec, weekday[tm.tm_wday]);
|
}
|