这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 【分享开发笔记,赚取电动螺丝刀】s32k146适配zephyr(四)使用I2C总

共1条 1/1 1 跳转至

【分享开发笔记,赚取电动螺丝刀】s32k146适配zephyr(四)使用I2C总线驱动RA8900CE芯片

高工
2025-04-11 23:17:25     打赏

【简介】

  在上一篇我们已经基于S32K146    完成了I2C总线设备的驱动。本地的LPI2C上挂载了四个I2C设备,我们使用I2C总线驱动 RA8900CE 芯片,RA8900CE 是一个RTC时钟芯片,对应框图的如下。

image.png

查看芯片的寄存器如下,OD/OF对应的控制寄存器,如果我们不需要实现中断输出及alarm 功能,我们不需要额外的配置,只需要配置00-06寄存器就会周期的更新计数,然后读取数据即可。

image.png

我们暂时只是驱动RA8900CE芯片能够读取配置RTC时间为基本任务,暂可以不关注上述框起来控制寄存器。

对应的时间寄存器描述如下

image.png

image.png

image.png

寄存器的数据格式采用BCD编码的数据格式,读取配置都需要进行格式转换。我们按照RTC芯片的寄存器layout 分别定义RTC BCD格式时间和便准时间的数据结构。

typedef struct {
/* [RA8900CE Register table */
	uint8_t second;	/**< second Register, offset: 0x0 */
	uint8_t minutes;	/**< minutes Register, offset: 0x1 */
	uint8_t hour;		/**< hour Register, offset: 0x2 */

	uint8_t week;		/**< week Register, offset: 0x3 */

	uint8_t day;		/**< day Register, offset: 0x4 */
	uint8_t month;	/**< month Register, offset: 0x5 */
	uint8_t year;		/**< year Register, offset: 0x6 */
}ExternRTCType;

typedef struct {

	uint8_t second;	/**< second Register, offset: 0x0 */
	uint8_t minutes;	/**< minutes Register, offset: 0x1 */
	uint8_t hour;		/**< hour Register, offset: 0x2 */

	uint8_t week;		/**< week Register, offset: 0x3 */

	uint8_t day;		/**< day Register, offset: 0x4 */
	uint8_t month;	/**< month Register, offset: 0x5 */
	uint8_t year;		/**< year Register, offset: 0x6 */

}ExternSTDType;

按照BCD 和标准的时间格式实现对应格式转换代码

/* external RTC data 2 std data */
static void ExtrRtc_RtcTime2StdTime(ExternRTCType *rtcData,ExternSTDType *stdData)
{
	uint8_t l_pos = 0 ,l_i = 0;
	ExternSTDType stdDataBuf={0} ;
	ExternRTCType rtcDataBuf = *rtcData;

	for(l_pos=0;l_pos<EX_RTC_TIME_LEN;l_pos++)
	{
		*(&stdDataBuf.second+l_pos) = 0 ;
		if(l_pos!=3)//sec min hour  day month year
		{
			for(l_i=0;l_i<8;l_i++)
			{
				if( ( *(&rtcDataBuf.second + l_pos) & (1<<(7-l_i)) ) != 0 )
				{
					*(&stdDataBuf.second+l_pos) += rtaDataMap[l_pos][l_i] ;
				}
			}
		}
		else//week
		{
			for(l_i=0;l_i<8;l_i++)
			{
				if( ( *(&rtcDataBuf.second + l_pos) & (1<<(7-l_i)) ) != 0 )
				{
					*(&stdDataBuf.second+l_pos) += rtaDataMap[l_pos][l_i];
					break;
				}
			}
		}
	}
	*stdData = stdDataBuf;
}

/* external std data 2 RTC data */
static void ExtrRtc_StdTime2RtcTime(ExternSTDType *stdData,ExternRTCType *rtcData)
{
	uint8_t l_pos = 0 ,l_i = 0;
	ExternSTDType stdDataBuf=*stdData ;
	ExternRTCType rtcDataBuf = {0};

	for(l_pos=0;l_pos<EX_RTC_TIME_LEN;l_pos++)
	{
		*(&rtcDataBuf.second+l_pos) = 0 ;
		if(l_pos!=3)//sec min hour  day month year
		{
			for(l_i=0;l_i<8;l_i++)
			{
				if(( rtaDataMap[l_pos][l_i] != 0 ) &&
					( *(&stdDataBuf.second + l_pos) >= rtaDataMap[l_pos][l_i] ) )
				{
					*(&rtcDataBuf.second+l_pos) |= (1<<(7-l_i));
					*(&stdDataBuf.second + l_pos) -= rtaDataMap[l_pos][l_i];
				}
			}
		}
		else//week
		{
			if( *(&stdDataBuf.second + l_pos) < 7 )// 0 1 2 3 4 5 6
			{
				*(&rtcDataBuf.second+l_pos) |= (1<<(*(&stdDataBuf.second + l_pos)));
			}
		}
	}
	*rtcData = rtcDataBuf;
}

使用zephyr的I2C 总线接口实现RTC芯片读写RTC寄存器代码。

/* external RTC write */
static uint8_t ExtrRtc_Write(uint8_t address,uint8_t *bufferPtr,uint32_t length)
{
	uint8_t l_returnValue = RET_EOK;
	static uint8_t l_databuf[EXTERN_RTC_DATA_MAX_LEN+1];
    static struct i2c_msg msg;

	/* RTC write atart address*/
	l_databuf[0] = address ;
	/* RTC write data copy to l_databuf */
	ExtrRtc_MemCpy(bufferPtr,&l_databuf[1],length);

    if(dev_lpi2c ==NULL)
    {
	    dev_lpi2c = device_get_binding("i2c@40066000");
        if(dev_lpi2c == NULL)
        {
            printf("i2c binding failed.\r\n");
        }

        l_returnValue = RET_ERROR;
    }

    if(dev_lpi2c)
    {
        msg.len = 1 + length;
        msg.buf = l_databuf;
        msg.flags = I2C_MSG_WRITE | I2C_MSG_STOP;

        if(i2c_transfer(dev_lpi2c,&msg,1,EX_RTC_ADDR))
        {
            l_returnValue = RET_ERROR;
        }
    }

	return l_returnValue;
}

/* external RTC read */
static uint8_t ExtrRtc_Read(uint8_t address,uint8_t *bufferPtr,uint32_t length)
{
	uint8_t l_returnValue = RET_EOK;
	static uint8_t l_databuf[EXTERN_RTC_DATA_MAX_LEN+1];
    static struct i2c_msg msg;

	/* RTC write atart address*/
	l_databuf[0] = address ;

    if(dev_lpi2c ==NULL)
    {
	    dev_lpi2c = device_get_binding("i2c@40066000");
        if(dev_lpi2c == NULL)
        {
            printf("i2c binding failed.\r\n");
        }

        l_returnValue = RET_ERROR;
    }

    if(dev_lpi2c)
    {
        msg.len = 1;
        msg.buf = l_databuf;
        msg.flags = I2C_MSG_WRITE | I2C_MSG_STOP;

        if(i2c_transfer(dev_lpi2c,&msg,1,EX_RTC_ADDR))
        {
            l_returnValue = RET_ERROR;
            goto out;
        }

        msg.len = length;
        msg.buf = bufferPtr;
        msg.flags = I2C_MSG_READ | I2C_MSG_STOP;

        if(i2c_transfer(dev_lpi2c,&msg,1,EX_RTC_ADDR))
        {
            l_returnValue = RET_ERROR;
            goto out;
        }

    }
out:
	return l_returnValue;
}

以上基本的格式转换和I2C读写访问接口实现完成后我们添加data 测试命令用于设置读取RTC时间来验证RTC功能。

static unsigned int date(char argc,char ** argv)
{
    ExternRTCType rtc_data;
    ExternSTDType std_data;
	const char * week[] = {"Sun","Mon","Tues","Wed","Thur","Fri","Sat"};
	if(argc == 1)
	{
		ExtrRtc_Read(0,(uint8_t *)&rtc_data,7);
        ExtrRtc_RtcTime2StdTime(&rtc_data,&std_data);
		printf("%d-%d-%d,%s,%d:%d:%d \r\n",std_data.year + 2000,std_data.month,std_data.day,week[std_data.week],
                                           std_data.hour,std_data.minutes,std_data.second);
	}

	if(argc == 7)
	{
		std_data.year = atoi(argv[1])-2000;
		std_data.month = atoi(argv[2]);
		std_data.day = atoi(argv[3]);
		std_data.week = inner_weekday(std_data.year,std_data.month,std_data.day);
		std_data.hour = atoi(argv[4]);
		std_data.minutes = atoi(argv[5]);
		std_data.second = atoi(argv[6]);

		ExtrRtc_StdTime2RtcTime(&std_data,&rtc_data);
		ExtrRtc_Write(0,(uint8_t *)&rtc_data,7);
	}
	return 0;
}

LTSH_FUNCTION_EXPORT(date,"get/set rtc time");

【功能验证】

将时间设置为2025-12-31 23:59:56 后连续读取RTC时间,RTC已经正常工作几秒后年月日 信息均发生更新,跟预期的保持一致。

image.png



共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]