IIC(inter-integrated Circuit集成电路总线)总线支持设备之间的短距离通信,用于处理器和一些外围设备之间的接口,它需要两根信号线来完成信息交换,它是由数据线SDA和时钟线SCL构成的串行总线,可发送和接收数据。常见的外围设备如温湿度传感器,RTC模块、RFID等。IIC是半双工通信方式。
所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。I2C总线上的每个设备都自己一个唯一的地址,来确保不同设备之间访问的准确性。
每发送一个字节(8个bit)**在一个字节传输的8个时钟后的第九个时钟期间,接收器接收数据后必须回一个ACK应答信号给发送器,这样才能进行数据传输
SDA线上的数据在SCL时钟“高”期间必须是稳定的,只有当SCL线上的时钟信号为低时,数据线上的“高”或“低”状态才可以改变。输出到SDA线上的每个字节必须是8位,数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)。
当一个字节按数据位从高位到低位的顺序传输完后,紧接着从设备将拉低SDA线,回传给主设备一个应答位ACK, 此时才认为一个字节真正的被传输完成 ,如果一段时间内没有收到从机的应答信号,则自动认为从机已正确接收到数据。
IIC通信原理参考
#ifndef _T_SD2405_H_
#define _T_SD2405_H_
#include "common.h"
//时间计数器
#define SD2405_ADDR_YEAR 0x6 /*year:0-99*/
#define SD2405_ADDR_MONTH 0x5 /*month:1-12*/
#define SD2405_ADDR_DAY 0x4 /*day:1-31*/
#define SD2405_ADDR_WEEK 0x3 /*week:0-6*/
#define SD2405_ADDR_HOUR 0x2 /*hour:0-23*/
#define SD2405_ADDR_MINUTE 0x1 /*minute:0-59*/
#define SD2405_ADDR_SECOND 0x0 /*second:0-59*/
//闹钟计数器
#define SD2405_ADDR_ALARM_YEAR 0xd /*year:0-99*/
#define SD2405_ADDR_ALARM_MONTH 0xc /*month:1-12*/
#define SD2405_ADDR_ALARM_DAY 0xb /*day:1-31*/
#define SD2405_ADDR_ALARM_WEEK 0xa /*week:0-6*/
#define SD2405_ADDR_ALARM_HOUR 0x9 /*hour:0-23*/
#define SD2405_ADDR_ALARM_MINUTE 0x8 /*minute:0-59*/
#define SD2405_ADDR_ALARM_SECOND 0x7 /*second:0-59*/
//闹钟使能
#define SD2405_ADDR_ALARM_ENABLE 0xe /*alarm enable reg*/
//RTC 控制寄存器
#define SD2405_ADDR_CTR1 0X0F /*ctr1 reg*/
#define SD2405_ADDR_CTR2 0X10 /*ctr2 reg*/
#define SD2405_ADDR_CTR3 0X11 /*ctr3 reg*/
//时间调整
#define SD2405_ADDR_ADJ 0x12 /*timer adjustment*/
//倒计时定时器 count down
#define SD2405_ADDR_CT 0x13 /*Count down*/
//通用RAM 14-1F 12bytes
#define SD2405_ADDR_RAM 0x14 /*general ram*/
typedef enum{
ALARM_YEAR_DISABLE =0 , /*disable*/
ALARM_YEAR_ENABLE = (0x1<<0) ,
ALARM_MONTH_ENABLE = (0x1<<1) ,
ALARM_DAY_ENABLE = (0x1<<2) ,
ALARM_WEEK_ENABLE = (0x1<<3) ,
ALARM_HOUR_ENABLE = (0x1<<4) ,
ALARM_MINUTE_ENABLE = (0x1<<5) ,
ALARM_SECOND_ENABLE = (0x1<<6) , /*enable:-*/
ALARM_ALL_ENABLE = 0b0111111 /*enable:all*/
}ENUM_ALARM_ENABLE_TYPE;
typedef enum{
CTRREG_INT_EN = 0, /*中断使能位*/
CTRREG_INTAF, /*报警中断标志位*/
CTRREG_INTDF, /*倒计时中断标志位*/
CTRREG_INTS, /*中断类型*/
CTRREG_FS, /*频率中断*/
CTRREG_TDS0,
CTRREG_TDS1,
CTRREG_WRTC1,
CTRREG_WRTC2,
CTRREG_WRTC3,
CTRREG_ARST,
CTRREG_FOBAT,
CTRREG_RTCF,
CTRREG_IM,
}ENUM_CTRREG_CMD;
typedef enum{ /*中断允许位*/
DISABLE_ALL = 0,
INTFE = (0x1<<0), /*frequency int*/
INTAE = (0x1<<1), /*alarm int*/
INTDE = (0x1<<2), /*count down int*/
ENANLE_ALL = 0b111
}ENUM_INT_ENABLE;
typedef enum{
NONE_INT = 0, //禁止输出,高阻态
AlARM_INT = 1, //报警中断
FREQ_INT = 2, //频率中断
CD_INT = 3 //倒计时中断
}ENUM_INT_TYPE;
typedef enum{
INTDF_FLAG = 0x1,
INTAF_FLAG = 0x2
}ENUM_INT_FLAG;
#pragma pack(1)
typedef struct
{
unsigned short year;
unsigned char month;
unsigned char day;
unsigned char hour;
unsigned char minute;
unsigned char second;
unsigned char week;
}SD2405_DateTypedef;
#pragma pack()
void sd2405_init(void);
void sd2405_write_time(SD2405_DateTypedef* date);
void sd2405_read_time(SD2405_DateTypedef* date);
void sd2405_test(void);
#endif
#include "t-sd2405.h"
#include "snps-i2c.h"
#include "board-snps-i2c.h"
//#define _SD2405_DBG_
/******************FUNCTION******************/
unsigned int _sd2405_read(unsigned int addr);
void _sd2405_write(unsigned int addr,unsigned char val);
void sd2405_print_curtime(void);
/*******************DEFINE*******************/
/*
BIT7 BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0
0 1 1 0 0 1 0 R/W
R:1
W:0
注意: IIC 地址支持7位
*/
#define SD2405_RTC_ADDRESS 0x32
#define SD2405_IIC_ID 0
#define sd2405_pr(format, args...) vsi_printf("[sd2405]: "format, ##args)
#ifdef _SD2405_DBG_
#define sd2405_dbg(format, args...) vsi_printf("[sd2405]: "format, ##args)
#else
#define sd2405_dbg(format, args...) do {} while (0)
#endif
#define WRTC1_ENABLE (0x1<<7)
#define WRTC2_ENABLE (0x1<<2)
#define WRTC3_ENABLE (0x1<<7)
#define ARST_ENABLE (0x1<<7)
//BCD码 十进制 互转
#define UChar2BCD(chr) ((((chr) / 10) << 4) | ((chr) % 10))
#define BCD2UChar(bcd) ((((bcd) >> 4) * 10) + ((bcd) & 0X0F))
const char *Week[] = {"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saterday"};
void _sd2405_reg_dump(void)
{
#ifdef _SD2405_DBG_
unsigned char val = 0;
val = _sd2405_read(SD2405_ADDR_CTR1);
sd2405_dbg("CTR1[%x]: 0x%x\n",SD2405_ADDR_CTR1,val);
val = _sd2405_read(SD2405_ADDR_CTR2);
sd2405_dbg("CTR3[%x]: 0x%x\n",SD2405_ADDR_CTR2,val);
val = _sd2405_read(SD2405_ADDR_CTR3);
sd2405_dbg("CTR3[%x]: 0x%x\n",SD2405_ADDR_CTR3,val);
sd2405_dbg("\n");
unsigned char year,month,day,week,hour,minute,second;
year = _sd2405_read(SD2405_ADDR_YEAR);
month = _sd2405_read(SD2405_ADDR_MONTH);
day = _sd2405_read(SD2405_ADDR_DAY);
hour = _sd2405_read(SD2405_ADDR_HOUR);
minute = _sd2405_read(SD2405_ADDR_MINUTE);
second = _sd2405_read(SD2405_ADDR_SECOND);
week = _sd2405_read(SD2405_ADDR_WEEK);
sd2405_dbg("Date Hex[0x%x-0x%x]: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n ",SD2405_ADDR_YEAR,SD2405_ADDR_SECOND,year,month,day,hour,minute,second,week);
#endif
}
void _sd2405_reset(void)
{
unsigned char val = 0;
val = _sd2405_read(SD2405_ADDR_CTR3);
val = val | ARST_ENABLE;
_sd2405_write(SD2405_ADDR_CTR3,val);
}
/*官方文档:
WRTC1、WRTC2、WRTC3 位: 寄存器(00H~1FH)写允许位。
即 WRTC1=1、WRTC2=1、WRTC3=1 时 写允许.注意置位有先后顺序,先置 WRTC1 为 1,后置 WRTC2、WRTC3 为 1;;
当 WRTC1=0、WRTC2=0、WRTC3=0 时则写禁止,同样置位有先后顺序,先置 WRTC2、WRTC3 为 0,后置 WRTC1 为 0。
当写禁止时,除了以上三位可以写以外,从 00H 到 1FH 所有的寄存器均不可以写。写禁止并不影响读操作。
*/
void _sd2405_ctr_wr_en(bool enable)
{
unsigned char val = 0;
if(enable)
{
val = _sd2405_read(SD2405_ADDR_CTR2) | WRTC1_ENABLE;
_sd2405_write(SD2405_ADDR_CTR2,val);
mdelay(3);
val = _sd2405_read(SD2405_ADDR_CTR1) | WRTC2_ENABLE | WRTC3_ENABLE ;
_sd2405_write(SD2405_ADDR_CTR1,val);
}
else
{
val = _sd2405_read(SD2405_ADDR_CTR1);
val = val & (~(WRTC2_ENABLE | WRTC3_ENABLE));
_sd2405_write(SD2405_ADDR_CTR1,val);
mdelay(3);
val = _sd2405_read(SD2405_ADDR_CTR2);
val = val & (~WRTC1_ENABLE);
_sd2405_write(SD2405_ADDR_CTR2,val);
}
return;
}
unsigned char _sd2405_read_ctr(ENUM_CTRREG_CMD ctr_cmd)
{
unsigned char val = 0;
switch(ctr_cmd)
{
case CTRREG_INT_EN:
//todo:
val = _sd2405_read(SD2405_ADDR_CTR2);
val = val & 0x7;
break;
case CTRREG_INTAF:
case CTRREG_INTDF:
//todo:
val = _sd2405_read(SD2405_ADDR_CTR1);
val = (val>>4) & 0x3;
break;
case CTRREG_FS:
val = _sd2405_read(SD2405_ADDR_CTR3);
val = val | 0xF;
break;
case CTRREG_INTS:
val = _sd2405_read(SD2405_ADDR_CTR2);
val = (val>>4) & 0x3;
break;
case CTRREG_TDS0:
case CTRREG_TDS1:
val = _sd2405_read(SD2405_ADDR_CTR3);
val = (val>>4) & 0x3;
break;
case CTRREG_WRTC1:
case CTRREG_WRTC2:
case CTRREG_WRTC3:
//nothing now
break;
case CTRREG_ARST:
val = _sd2405_read(SD2405_ADDR_CTR3);
val = (val>>7) & 0x1;
break;
case CTRREG_FOBAT:
val = _sd2405_read(SD2405_ADDR_CTR2);
val = (val>>3) & 0x1;
break;
case CTRREG_RTCF:
val = _sd2405_read(SD2405_ADDR_CTR1);
val = val & 0x1;
break;
case CTRREG_IM:
break;
default:
break;
}
return val;
}
unsigned int _sd2405_read(unsigned int addr)
{
unsigned char val = 0;
snps_i2c_read(SD2405_IIC_ID, addr, &val, 1, SD2405_RTC_ADDRESS, 1);
return val;
}
void _sd2405_write(unsigned int addr,unsigned char val)
{
unsigned char tmp = val;
snps_i2c_write(SD2405_IIC_ID, addr, &tmp, 1, SD2405_RTC_ADDRESS, 1);
}
SD2405_DateTypedef _sd2405_build_time(u32 year, u32 mon, u32 day,
u32 hour, u32 min, u32 sec, u32 week)
{
SD2405_DateTypedef rtc_time = {0};
if(year>99)
{
sd2405_pr("Warning:The year shoud be in 2000-2099\n");
rtc_time.year = year%100;
}else{
rtc_time.year = year;
}
rtc_time.month = mon;
rtc_time.day = day;
rtc_time.hour = hour;
rtc_time.minute = min;
rtc_time.second = sec;
rtc_time.week = week;
return rtc_time;
}
void _sd2405_rtc_irq_handler()
{
char int_type = _sd2405_read_ctr(CTRREG_INTS);
if(AlARM_INT == int_type ){
//to do something
}
else if(FREQ_INT == int_type){
//to do something
}
else if(CD_INT == int_type){
//to do something
}else{
//no interrupt
}
return;
}
void sd2405_init(void)
{
sd2405_pr(" %s\n", __func__);
snps_i2c_pin_init(SD2405_IIC_ID);
snps_i2c_init(SD2405_IIC_ID, 100000, 0, 0);
sd2405_pr("sd2405_init down\n");
//reset
_sd2405_reset();
//init a time struct
SD2405_DateTypedef load_time = _sd2405_build_time(2022, 2, 2, 2, 30, 0, 2);
sd2405_write_time(&load_time);
//test
sd2405_print_curtime();
}
void sd2405_write_time(SD2405_DateTypedef* date)
{
_sd2405_ctr_wr_en(1);
_sd2405_write(SD2405_ADDR_YEAR,UChar2BCD(date->year));
_sd2405_write(SD2405_ADDR_MONTH,UChar2BCD(date->month));
_sd2405_write(SD2405_ADDR_DAY,UChar2BCD(date->day));
_sd2405_write(SD2405_ADDR_HOUR,UChar2BCD(date->hour));
_sd2405_write(SD2405_ADDR_MINUTE,UChar2BCD(date->minute));
_sd2405_write(SD2405_ADDR_SECOND,UChar2BCD(date->second));
_sd2405_write(SD2405_ADDR_WEEK,UChar2BCD(date->week));
_sd2405_ctr_wr_en(0);
return;
}
void sd2405_read_time(SD2405_DateTypedef* date)
{
//SD2405_DateTypedef read_time = {0};
date->year = BCD2UChar(_sd2405_read(SD2405_ADDR_YEAR));
date->month = BCD2UChar(_sd2405_read(SD2405_ADDR_MONTH));
date->day = BCD2UChar(_sd2405_read(SD2405_ADDR_DAY));
date->hour = BCD2UChar(_sd2405_read(SD2405_ADDR_HOUR));
date->minute = BCD2UChar(_sd2405_read(SD2405_ADDR_MINUTE));
date->second = BCD2UChar(_sd2405_read(SD2405_ADDR_SECOND));
date->week = BCD2UChar(_sd2405_read(SD2405_ADDR_WEEK));
sd2405_dbg(" time: %d-%d-%d %d:%d:%d %s\n", date->year,
date->month, date->day, date->hour,
date->minute, date->second,Week[date->week]);
return ;//read_time;
}
void sd2405_print_curtime(void)
{
//SD2405_DateTypedef *curr_time = (SD2405_DateTypedef *)malloc(sizeof(SD2405_DateTypedef)); //当前gcc 不支持malloc
SD2405_DateTypedef curr_time = {0};
sd2405_read_time(&curr_time);
vsi_printf(" time: %d-%d-%d %d:%d:%d %s\n", curr_time.year,
curr_time.month, curr_time.day, curr_time.hour,
curr_time.minute, curr_time.second, Week[curr_time.week]);
}
/*建议只使用一种闹钟,TODO:组合闹钟*/ //测试建议用s、m、h
//void as2405_set_alarm_enable(unsigned int int_type)
void as2405_set_alarm_enable(ENUM_ALARM_ENABLE_TYPE int_type)
{
unsigned char val = 0;
val = _sd2405_read(SD2405_ADDR_CTR2);
val = val | INTAE;
_sd2405_write(SD2405_ADDR_CTR2,val);
_sd2405_write(SD2405_ADDR_ALARM_ENABLE,int_type);
}
void sd2405_set_alarm(SD2405_DateTypedef* date)
{
//todo : 中断控制
_sd2405_ctr_wr_en(1);
_sd2405_write(SD2405_ADDR_ALARM_YEAR,UChar2BCD(date->year));
_sd2405_write(SD2405_ADDR_ALARM_MONTH,UChar2BCD(date->month));
_sd2405_write(SD2405_ADDR_ALARM_DAY,UChar2BCD(date->day));
//年月日
/*
_sd2405_write(SD2405_ADDR_ALARM_YEAR,_sd2405_read(SD2405_ADDR_YEAR));
_sd2405_write(SD2405_ADDR_ALARM_MONTH,_sd2405_read(SD2405_ADDR_MONTH));
_sd2405_write(SD2405_ADDR_ALARM_DAY,_sd2405_read(SD2405_ADDR_DAY));
*/
_sd2405_write(SD2405_ADDR_ALARM_HOUR,UChar2BCD(date->hour));
_sd2405_write(SD2405_ADDR_ALARM_MINUTE,UChar2BCD(date->minute));
_sd2405_write(SD2405_ADDR_ALARM_SECOND,UChar2BCD(date->second));
_sd2405_write(SD2405_ADDR_ALARM_WEEK,UChar2BCD(date->week));
_sd2405_ctr_wr_en(0);
return;
}
void sd2405_test(void)
{
vsi_printf("Testing sd2405 iic rtc.\n");
vsi_printf("TODO: interrupt function\\Alarm function \n");
vsi_printf("input \n ");
vsi_printf("0:init 1: get time 2: set time 3: Test\n ");
u8 c = vsi_getc();
if('0' == c){
vsi_printf("sd2405 init...\n");
sd2405_init();
_sd2405_reg_dump();
}
else if('1' == c){
vsi_printf("sd2405 print time.\n");
sd2405_print_curtime();
}
else if('2' == c){
SD2405_DateTypedef load_time = _sd2405_build_time(2055, 5, 5, 5, 30, 0, 5);
sd2405_write_time(&load_time);
sd2405_print_curtime();
}
else if('3' == c)
{
unsigned int counter = 0;
while(1)
{
vsi_printf("[%d]: ",counter);
sd2405_print_curtime();
delay(60);
counter++;
}
}
else
{
vsi_printf("errors\n");
}
}
2.日期的存储是以BCD码的形式存储的,不能以16进制或者2进制换算日期。
3.读取的字节数为1.
2. YEAR 寄存器为8个字节,并且是以BCD存储,所以最大只能是99。 所以要注意时间的开始是2000年,2000要自己加上。
3. 代码是硬件IIC 电路, 有特定的IIC 驱动接口可以调用, 并不是软件模拟的GPIO控制。
BUGFIX: 新增12hour 24hour 进制转换、
#include "t-sd2405.h"
#include "snps-i2c.h"
#include "board-snps-i2c.h"
//#define _SD2405_DBG_
/******************FUNCTION******************/
unsigned int _sd2405_read(unsigned int addr);
void _sd2405_write(unsigned int addr,unsigned char val);
void sd2405_print_curtime(void);
/*******************DEFINE*******************/
/*
BIT7 BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0
0 1 1 0 0 1 0 R/W
R:1
W:0
注意: IIC 地址支持7位
*/
#define SD2405_RTC_ADDRESS 0x32
#define SD2405_IIC_ID 0
#define sd2405_pr(format, args...) vsi_printf("[sd2405]: "format, ##args)
#ifdef _SD2405_DBG_
#define sd2405_dbg(format, args...) vsi_printf("[sd2405]: "format, ##args)
#else
#define sd2405_dbg(format, args...) do {} while (0)
#endif
#define WRTC1_ENABLE (0x1<<7)
#define WRTC2_ENABLE (0x1<<2)
#define WRTC3_ENABLE (0x1<<7)
#define ARST_ENABLE (0x1<<7)
#define AM_PM_BIT 5
#define H24_12_BIT 7
//BCD码 十进制 互转
#define UChar2BCD(chr) ((((chr) / 10) << 4) | ((chr) % 10))
#define BCD2UChar(bcd) ((((bcd) >> 4) * 10) + ((bcd) & 0X0F))
/*AM: 0 PM: 1*/
unsigned int AM_PM_flag = 0;
unsigned int hour_24_flag = 0;
const char *Week[] = {"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saterday"};
const char *AMPM[] = {"AM","PM"};
void _sd2405_reg_dump(void)
{
#ifdef _SD2405_DBG_
unsigned char val = 0;
val = _sd2405_read(SD2405_ADDR_CTR1);
sd2405_dbg("CTR1[%x]: 0x%x\n",SD2405_ADDR_CTR1,val);
val = _sd2405_read(SD2405_ADDR_CTR2);
sd2405_dbg("CTR3[%x]: 0x%x\n",SD2405_ADDR_CTR2,val);
val = _sd2405_read(SD2405_ADDR_CTR3);
sd2405_dbg("CTR3[%x]: 0x%x\n",SD2405_ADDR_CTR3,val);
sd2405_dbg("\n");
unsigned char year,month,day,week,hour,minute,second;
year = _sd2405_read(SD2405_ADDR_YEAR);
month = _sd2405_read(SD2405_ADDR_MONTH);
day = _sd2405_read(SD2405_ADDR_DAY);
hour = _sd2405_read(SD2405_ADDR_HOUR);
minute = _sd2405_read(SD2405_ADDR_MINUTE);
second = _sd2405_read(SD2405_ADDR_SECOND);
week = _sd2405_read(SD2405_ADDR_WEEK);
sd2405_dbg("Date Hex[0x%x-0x%x]: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n ",SD2405_ADDR_YEAR,SD2405_ADDR_SECOND,year,month,day,hour,minute,second,week);
#endif
}
void _sd2405_reset(void)
{
unsigned char val = 0;
val = _sd2405_read(SD2405_ADDR_CTR3);
val = val | ARST_ENABLE;
_sd2405_write(SD2405_ADDR_CTR3,val);
}
/*官方文档:
WRTC1、WRTC2、WRTC3 位: 寄存器(00H~1FH)写允许位。
即 WRTC1=1、WRTC2=1、WRTC3=1 时 写允许.注意置位有先后顺序,先置 WRTC1 为 1,后置 WRTC2、WRTC3 为 1;;
当 WRTC1=0、WRTC2=0、WRTC3=0 时则写禁止,同样置位有先后顺序,先置 WRTC2、WRTC3 为 0,后置 WRTC1 为 0。
当写禁止时,除了以上三位可以写以外,从 00H 到 1FH 所有的寄存器均不可以写。写禁止并不影响读操作。
*/
void _sd2405_ctr_wr_en(bool enable)
{
unsigned char val = 0;
if(enable)
{
val = _sd2405_read(SD2405_ADDR_CTR2) | WRTC1_ENABLE;
_sd2405_write(SD2405_ADDR_CTR2,val);
mdelay(3);
val = _sd2405_read(SD2405_ADDR_CTR1) | WRTC2_ENABLE | WRTC3_ENABLE ;
_sd2405_write(SD2405_ADDR_CTR1,val);
}
else
{
val = _sd2405_read(SD2405_ADDR_CTR1);
val = val & (~(WRTC2_ENABLE | WRTC3_ENABLE));
_sd2405_write(SD2405_ADDR_CTR1,val);
mdelay(3);
val = _sd2405_read(SD2405_ADDR_CTR2);
val = val & (~WRTC1_ENABLE);
_sd2405_write(SD2405_ADDR_CTR2,val);
}
return;
}
void _sd2405_clear_time_adj(void)
{
_sd2405_write(SD2405_ADDR_ADJ,0);
}
unsigned char _sd2405_read_ctr(ENUM_CTRREG_CMD ctr_cmd)
{
unsigned char val = 0;
switch(ctr_cmd)
{
case CTRREG_INT_EN:
//todo:
val = _sd2405_read(SD2405_ADDR_CTR2);
val = val & 0x7;
break;
case CTRREG_INTAF:
case CTRREG_INTDF:
//todo:
val = _sd2405_read(SD2405_ADDR_CTR1);
val = (val>>4) & 0x3;
break;
case CTRREG_FS:
val = _sd2405_read(SD2405_ADDR_CTR3);
val = val | 0xF;
break;
case CTRREG_INTS:
val = _sd2405_read(SD2405_ADDR_CTR2);
val = (val>>4) & 0x3;
break;
case CTRREG_TDS0:
case CTRREG_TDS1:
val = _sd2405_read(SD2405_ADDR_CTR3);
val = (val>>4) & 0x3;
break;
case CTRREG_WRTC1:
case CTRREG_WRTC2:
case CTRREG_WRTC3:
//nothing now
break;
case CTRREG_ARST:
val = _sd2405_read(SD2405_ADDR_CTR3);
val = (val>>7) & 0x1;
break;
case CTRREG_FOBAT:
val = _sd2405_read(SD2405_ADDR_CTR2);
val = (val>>3) & 0x1;
break;
case CTRREG_RTCF:
val = _sd2405_read(SD2405_ADDR_CTR1);
val = val & 0x1;
break;
case CTRREG_IM:
break;
default:
break;
}
return val;
}
void _sd2405_set_24h(bool en)
{
if(en)
hour_24_flag = 1;
else
hour_24_flag = 0;
}
unsigned int _sd2405_read(unsigned int addr)
{
unsigned char val = 0;
snps_i2c_read(SD2405_IIC_ID, addr, &val, 1, SD2405_RTC_ADDRESS, 1);
//BUGFIX: 小时的最高位 12_/24 是 12 或 24 小时制选择位。
//当 12_/24=1 时,24 小时制; 当 12_/24=0 时, 12 小时制。
//12 小时制时,H20 为 AM/PM 指示位,H20=0 为 AM,H20=1 为 PM,
//date->hour = BCD2UChar(_sd2405_read(SD2405_ADDR_HOUR));
if(SD2405_ADDR_HOUR == addr)
{
sd2405_dbg("read addr: %x\n",val);
if(val>>H24_12_BIT)
{
val &= 0x3F;
}
else
{
if(val>>AM_PM_BIT)
{
AM_PM_flag = 1;
}
else
{
AM_PM_flag = 0;
}
val &= 0x1F;
}
sd2405_dbg("return val: %x\n",val);
}
return val;
}
void _sd2405_write(unsigned int addr,unsigned char bcd_char)
{
unsigned char tmp = 0;
//hour 特殊处理
if(SD2405_ADDR_HOUR == addr)
{
if(hour_24_flag)
{
tmp = bcd_char | (1<<H24_12_BIT);
}
else{
if(AM_PM_flag)
tmp = bcd_char | (1<<AM_PM_BIT);
else
tmp = bcd_char;
}
sd2405_dbg("write val: %x\n",bcd_char);
}
else
{
tmp = bcd_char;
}
snps_i2c_write(SD2405_IIC_ID, addr, &tmp, 1, SD2405_RTC_ADDRESS, 1);
}
SD2405_DateTypedef _sd2405_build_time(u32 year, u32 mon, u32 day,
u32 hour, u32 min, u32 sec, u32 week)
{
SD2405_DateTypedef rtc_time = {0};
if(year>99)
{
//sd2405_pr("Warning:The year shoud be in 2000-2099\n");
rtc_time.year = year%100;
}else{
rtc_time.year = year;
}
rtc_time.month = mon;
rtc_time.day = day;
rtc_time.hour = hour;
rtc_time.minute = min;
rtc_time.second = sec;
rtc_time.week = week;
return rtc_time;
}
void _sd2405_rtc_irq_handler()
{
char int_type = _sd2405_read_ctr(CTRREG_INTS);
if(AlARM_INT == int_type ){
//to do something
}
else if(FREQ_INT == int_type){
//to do something
}
else if(CD_INT == int_type){
//to do something
}else{
//no interrupt
}
return;
}
void sd2405_init(void)
{
sd2405_pr(" %s\n", __func__);
snps_i2c_pin_init(SD2405_IIC_ID);
snps_i2c_init(SD2405_IIC_ID, 100000, 0, 0);
sd2405_pr("sd2405_init down\n");
//reset
_sd2405_reset();
_sd2405_set_24h(1);
//init a time struct
SD2405_DateTypedef load_time = _sd2405_build_time(2022, 2, 2, 2, 30, 0, 0);
sd2405_write_time(&load_time);
//test
sd2405_print_curtime();
}
void sd2405_write_time(SD2405_DateTypedef* date)
{
_sd2405_clear_time_adj();
_sd2405_ctr_wr_en(1);
if(hour_24_flag){
sd2405_dbg("Write: %d-%d-%d %d:%d:%d %s\n", date->year,
date->month, date->day, date->hour,
date->minute, date->second,Week[date->week]);
}else{
sd2405_dbg("Write: %d-%d-%d %d:%d:%d %s %s\n", date->year,
date->month, date->day, date->hour,
date->minute, date->second,AMPM[AM_PM_flag],Week[date->week]);
}
_sd2405_write(SD2405_ADDR_YEAR,UChar2BCD(date->year));
_sd2405_write(SD2405_ADDR_MONTH,UChar2BCD(date->month));
_sd2405_write(SD2405_ADDR_DAY,UChar2BCD(date->day));
if( 0 == hour_24_flag )
{
if(date->hour >= 12){
AM_PM_flag = 1;
date->hour -= 12 ;
}
}
_sd2405_write(SD2405_ADDR_HOUR,UChar2BCD(date->hour));
_sd2405_write(SD2405_ADDR_MINUTE,UChar2BCD(date->minute));
_sd2405_write(SD2405_ADDR_SECOND,UChar2BCD(date->second));
_sd2405_write(SD2405_ADDR_WEEK,UChar2BCD(date->week));
_sd2405_ctr_wr_en(0);
return;
}
void sd2405_read_time(SD2405_DateTypedef* date)
{
//SD2405_DateTypedef read_time = {0};
date->year = BCD2UChar(_sd2405_read(SD2405_ADDR_YEAR));
date->month = BCD2UChar(_sd2405_read(SD2405_ADDR_MONTH));
date->day = BCD2UChar(_sd2405_read(SD2405_ADDR_DAY));
date->hour = BCD2UChar(_sd2405_read(SD2405_ADDR_HOUR));
date->minute = BCD2UChar(_sd2405_read(SD2405_ADDR_MINUTE));
date->second = BCD2UChar(_sd2405_read(SD2405_ADDR_SECOND));
date->week = BCD2UChar(_sd2405_read(SD2405_ADDR_WEEK));
if(hour_24_flag){
sd2405_dbg("Read: %d-%d-%d %d:%d:%d %s\n", date->year,
date->month, date->day, date->hour,
date->minute, date->second,Week[date->week]);
}else{
sd2405_dbg("Read: %d-%d-%d %d:%d:%d %s %s\n", date->year,
date->month, date->day, date->hour,
date->minute, date->second,AMPM[AM_PM_flag],Week[date->week]);
}
return ;//read_time;
}
void sd2405_print_curtime(void)
{
//SD2405_DateTypedef *curr_time = (SD2405_DateTypedef *)malloc(sizeof(SD2405_DateTypedef)); //当前gcc 不支持malloc
SD2405_DateTypedef curr_time = {0};
sd2405_read_time(&curr_time);
if(hour_24_flag)
{
vsi_printf("Time: %d-%d-%d %d:%d:%d %s\n", curr_time.year,
curr_time.month, curr_time.day, curr_time.hour,
curr_time.minute, curr_time.second, Week[curr_time.week]);
}else{
vsi_printf("Time: %d-%d-%d %d:%d:%d %s %s\n", curr_time.year,
curr_time.month, curr_time.day, curr_time.hour,
curr_time.minute, curr_time.second,AMPM[AM_PM_flag],Week[curr_time.week]);
}
}
/*建议只使用一种闹钟,TODO:组合闹钟*/ //测试建议用s、m、h
//void as2405_set_alarm_enable(unsigned int int_type)
void as2405_set_alarm_enable(ENUM_ALARM_ENABLE_TYPE int_type)
{
unsigned char val = 0;
val = _sd2405_read(SD2405_ADDR_CTR2);
val = val | INTAE;
_sd2405_write(SD2405_ADDR_CTR2,val);
_sd2405_write(SD2405_ADDR_ALARM_ENABLE,int_type);
}
void sd2405_set_alarm(SD2405_DateTypedef* date)
{
//todo : 中断控制
_sd2405_ctr_wr_en(1);
_sd2405_write(SD2405_ADDR_ALARM_YEAR,UChar2BCD(date->year));
_sd2405_write(SD2405_ADDR_ALARM_MONTH,UChar2BCD(date->month));
_sd2405_write(SD2405_ADDR_ALARM_DAY,UChar2BCD(date->day));
//年月日
/*
_sd2405_write(SD2405_ADDR_ALARM_YEAR,_sd2405_read(SD2405_ADDR_YEAR));
_sd2405_write(SD2405_ADDR_ALARM_MONTH,_sd2405_read(SD2405_ADDR_MONTH));
_sd2405_write(SD2405_ADDR_ALARM_DAY,_sd2405_read(SD2405_ADDR_DAY));
*/
_sd2405_write(SD2405_ADDR_ALARM_HOUR,UChar2BCD(date->hour));
_sd2405_write(SD2405_ADDR_ALARM_MINUTE,UChar2BCD(date->minute));
_sd2405_write(SD2405_ADDR_ALARM_SECOND,UChar2BCD(date->second));
_sd2405_write(SD2405_ADDR_ALARM_WEEK,UChar2BCD(date->week));
_sd2405_ctr_wr_en(0);
return;
}
void sd2405_test(void)
{
vsi_printf("Testing sd2405 iic rtc.\n");
vsi_printf("TODO: interrupt function\\Alarm function \n");
vsi_printf("input \n ");
vsi_printf("0:init 1: get time 2: set time 3: Test\n ");
u8 c = vsi_getc();
if('0' == c){
vsi_printf("sd2405 init...\n");
sd2405_init();
_sd2405_reg_dump();
}
else if('1' == c){
vsi_printf("sd2405 print time.\n");
sd2405_print_curtime();
}
else if('2' == c){
SD2405_DateTypedef load_time ={0};
_sd2405_set_24h(1);
load_time = _sd2405_build_time(2025, 5, 5, 23, 30, 0, 0);
sd2405_write_time(&load_time);
sd2405_print_curtime();
_sd2405_set_24h(0);
load_time = _sd2405_build_time(2025, 5, 5, 23, 30, 0, 0);
sd2405_write_time(&load_time);
sd2405_print_curtime();
//warning : 12小时进制转24进制, 天数会+1
_sd2405_set_24h(1);
load_time = _sd2405_build_time(2025, 5, 5, 5, 30, 0, 0);
sd2405_write_time(&load_time);
sd2405_print_curtime();
_sd2405_set_24h(1);
load_time = _sd2405_build_time(2025, 5, 5, 2, 30, 0, 0);
sd2405_write_time(&load_time);
sd2405_print_curtime();
}
else if('3' == c)
{
unsigned int counter = 0;
while(1)
{
vsi_printf("[%d]: ",counter);
sd2405_print_curtime();
delay(60);
counter++;
}
}
else
{
vsi_printf("errors\n");
}
}