【RT-Thread】高精度RTC rx8900 驅動軟件包

1 介紹

  rx8900 軟件包是針對RT-Thread驅動框架實現的實時時鐘驅動,遵循RT-Thread RTC框架,可以從芯片內置RTC無縫切換使用外置高精度rx8900 RTC。rx8900是愛普生公司一款i2c接口的高精度RTC芯片,集成32768Hz晶振和溫度傳感器,並能根據環境溫度調整頻率,具有供電範圍靈活、待機電流低、走時精度高等優點。

在這裏插入圖片描述

1.1 支持功能

  • 實時時鐘
  • 鬧鐘
  • 片內溫度讀取

1.2 目錄結構

名稱 說明
docs 文檔目錄
inc 頭文件目錄
src 源代碼目錄
LICENSE 許可證文件
SConscript RT-Thread默認構建腳本

1.3 許可證

rx8900 軟件包遵循 Apache license v2.0 許可,詳見 LICENSE 文件。


1.4 依賴

  • RT-Thread 3.0+
  • RT-Thread I2C設備驅動框架
  • RT-Thread RTC設備驅動框架

2 實現功能

  實現rx8900驅動層的函數接口。

在這裏插入圖片描述


2.1 rx8900驅動描述

  RT-Thread rtc驅動設備繼承其標準設備驅動,使用struct rt_device描述rx8900設備。rx8900訪問接口是i2c,依賴於RT-Thread i2c總線框架,我們使用struct rt_device的私有數據user_data保存rx8900的i2c設備總線信息。後面過程則是實現struct rt_device函數指針實體。

/**
 * Device structure
 */
struct rt_device
{
    struct rt_object          parent;                   /**< inherit from rt_object */

    enum rt_device_class_type type;                     /**< device type */
    rt_uint16_t               flag;                     /**< device flag */
    rt_uint16_t               open_flag;                /**< device open flag */

    rt_uint8_t                ref_count;                /**< reference count */
    rt_uint8_t                device_id;                /**< 0 - 255 */

    /* device call back */
    rt_err_t (*rx_indicate)(rt_device_t dev, rt_size_t size);
    rt_err_t (*tx_complete)(rt_device_t dev, void *buffer);

#ifdef RT_USING_DEVICE_OPS
    const struct rt_device_ops *ops;
#else
    /* common device interface */
    rt_err_t  (*init)   (rt_device_t dev);
    rt_err_t  (*open)   (rt_device_t dev, rt_uint16_t oflag);
    rt_err_t  (*close)  (rt_device_t dev);
    rt_size_t (*read)   (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
    rt_size_t (*write)  (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
    rt_err_t  (*control)(rt_device_t dev, int cmd, void *args);
#endif

#if defined(RT_USING_POSIX)
    const struct dfs_file_ops *fops;
    struct rt_wqueue wait_queue;
#endif

    void                     *user_data;                /**< device private data */
};
static struct rt_device rx8900_dev;		/* rx8900 device */

2.2 rx8900讀寄存器接口

static rt_err_t  rx8900_write_reg(rt_device_t dev, rt_uint8_t reg, rt_uint8_t *data, rt_uint8_t data_size)
  • dev,rx8900設備描述地址
  • reg,寄存器地址
  • data,返回數據地址(緩存)
  • data_size,讀取數據長度
  • 返回值,成功返回RT_EOK

2.3 rx8900寫寄存器接口

static rt_err_t  rx8900_write_reg(rt_device_t dev, rt_uint8_t reg, rt_uint8_t *data, rt_uint8_t data_size)
  • dev,rx8900設備描述地址
  • reg,寄存器地址
  • data,待寫數據地址
  • data_size,待寫數據長度
  • 返回值,成功返回RT_EOK

2.4 RT-Thread設備虛擬文件接口

  RT-Thread設備虛擬文件接口,常用有open/read/write/control/close,RT-Thread rtc設備框架中,關於時間和鬧鐘的設置,使用的是control接口,實現該接口具體功能內容。

  • 獲取實時時間
/* get time */
        case RT_DEVICE_CTRL_RTC_GET_TIME:
	        time = (time_t *)args;
	        ret = rx8900_read_reg(dev, REG_SEC, buff, 7);
			if(ret == RT_EOK)
			{
				time_temp.tm_year  = bcd_to_hex(buff[6]) + 2000 - 1900;
				time_temp.tm_mon   = bcd_to_hex(buff[5]&0x1f) - 1;
				time_temp.tm_mday  = bcd_to_hex(buff[4]&0x3f);
				time_temp.tm_hour  = bcd_to_hex(buff[2]&0x3f);
				time_temp.tm_min   = bcd_to_hex(buff[1]&0x7f);
				time_temp.tm_sec   = bcd_to_hex(buff[0]&0x7f);
	        	*time = mktime(&time_temp);
			}
        break;
  • 設置實時時間
/* set time */
        case RT_DEVICE_CTRL_RTC_SET_TIME:
        {
        	struct tm *time_new;
					
            time = (time_t *)args;
            time_new = localtime(time);
            buff[6] = hex_to_bcd(time_new->tm_year + 1900 - 2000);
            buff[5] = hex_to_bcd(time_new->tm_mon + 1);
            buff[4] = hex_to_bcd(time_new->tm_mday);
            buff[3] = hex_to_bcd(time_new->tm_wday+1);
            buff[2] = hex_to_bcd(time_new->tm_hour);
            buff[1] = hex_to_bcd(time_new->tm_min);
            buff[0] = hex_to_bcd(time_new->tm_sec);
            ret = rx8900_write_reg(dev, REG_SEC, buff, 7);
        }
        break;
  • 獲取鬧鐘時間

  rx8900鬧鐘模式支持的最小精度是1分鐘,因此鬧鐘秒數值(tm_sec)應設置爲0。rx8900支持天數和星期鬧鐘,RT-Thread目前鬧鐘框架暫時支持時分秒匹配,天數和星期由軟件實現。

/* get alarm time */
		case RT_DEVICE_CTRL_RTC_GET_ALARM:
		{ 	
		  	struct rt_rtc_wkalarm *alm_time;
			rt_uint8_t state[3] = {0x00};		
			
		  	ret = rx8900_read_reg(dev, REG_ALM_MIN, buff, 2);
			if(ret != RT_EOK)
			{
				return -RT_ERROR;
			}
			alm_time = (struct rt_rtc_wkalarm *)args;
			alm_time->tm_hour  = bcd_to_hex(buff[1]&0x7f);	
			alm_time->tm_min   = bcd_to_hex(buff[0]&0x7f);
			alm_time->tm_sec   = 0;	/* hardware alarm precision is 1 minute */
			
			ret = rx8900_read_reg(dev, RGE_EXT, state, 3);
			if(ret != RT_EOK)
			{
				return -RT_ERROR;
			}
			if (state[0] & VALUE_EXT_WADA)
			{/* day alarm */
				/* todo, RTT not supported temporarily */	
			}
			else
			{/* week day alarm */
				/* todo, RTT not supported temporarily */
			}
		}
  • 設置鬧鐘時間

  針對RT-Thread鬧鐘框架,rx8900鬧鐘禁止天數(tm_day)和星期(tm_wday)匹配功能,只設置小時(tm_hour)和分鐘(tm_minute),同時將秒數(tm_sec)設爲0。

/* set alarm time */
		case RT_DEVICE_CTRL_RTC_SET_ALARM:
		{
			struct rt_rtc_wkalarm *alm_time;
			rt_uint8_t ctrl[2] = {0x00};
			
            alm_time = (struct rt_rtc_wkalarm *)args;
            buff[2] = ALM_DISABLE(0x00);	/* week and day alarm disable */	
            buff[1] = hex_to_bcd(ALM_ENABLE(alm_time->tm_hour));/* enable, alarm when hours and minutes match */
            buff[0] = hex_to_bcd(ALM_ENABLE(alm_time->tm_min));
			
			ret = rx8900_read_reg(dev, REG_FLAG, ctrl, 2);
			if (ret != RT_EOK)
			{
				return -RT_ERROR;
			}
			if (ctrl[0]&VALUE_EXT_WADA)
			{/* day alarm */
			  	/* todo, RTT not supported temporarily */
			}
			else
			{/* week day alarm */
				/* todo, RTT not supported temporarily */
			}
	
			/* write to hardware */
			ret = rx8900_write_reg(dev, REG_ALM_MIN, buff, 3);
			if (ret != RT_EOK)
			{
				return -RT_ERROR;
			}
			
			/* clear alarm flag */
			ctrl[1] &= ~VALUE_FLAG_AF;
			ret = rx8900_write_reg(dev, REG_FLAG, &ctrl[1], 1);
		}
		break;

2.5 片內溫度獲取接口

  rx8900內部集成一個溫度傳感器和溫度校準係數,讀取溫度寄存器值通過一定的換算公式計算出實際溫度。rx8900芯片手冊提供攝氏度(℃)與寄存器值轉換公式如下。

在這裏插入圖片描述

寄存器值與溫度轉換

  獲取溫度接口

/*
 *  @brief  Read temperature from rx8900
 *  @return Celsius temperature,-55~+125C,0.1C     
 */
float rx8900_get_temperature(void)
{
 	rt_uint8_t value = 0;
	float temp = 0.0f;
	
	rx8900_read_reg(&rx8900_dev, REG_TEMP, (rt_uint8_t*)&value, 1);
	temp = (value*2-187.19)/3.218;
	
	return temp;
}

  我們把溫度讀取接口註冊到RT-Thread的調試終端(msh/finsh),方便測試。

#ifdef RT_USING_FINSH
#include <finsh.h>

void list_rx89_temp(void)
{
	float temp = 0.0f;
	
	temp = rx8900_get_temperature();
	
	rt_kprintf("rx8900 temperature: [%d.%dC] \n", (int)temp, (int)(temp * 10) % 10);
}
FINSH_FUNCTION_EXPORT(list_rx89_temp, list rx8900 temperature.)
#endif /* RT_USING_FINSH */

#if defined(RT_USING_FINSH) && defined(FINSH_USING_MSH)
MSH_CMD_EXPORT(list_rx89_temp, list rx8900 temperature.);
#endif /* RT_USING_FINSH & FINSH_USING_MSH */

2.6 rtc設備註冊

rx8900設備註冊

  • rx8900使用的是系統“i2c1”,i2c1驅動請自行初始化註冊;否則rx8900設備註冊失敗
  • rx8900設備中user_data保存i2c1總線信息,用於後續訪問rx8900
  • rx8900設備名稱保持與rtc設備框架的rtc名稱一致,統一爲“rtc”
int rt_hw_rx8900_init(void)
{	
    struct rt_i2c_bus_device *i2c_bus =RT_NULL;
    rt_uint8_t flags = 0;
	rt_bool_t  need_clear = RT_FALSE;
	rt_bool_t  need_reset = RT_FALSE;
	
    i2c_bus = rt_i2c_bus_device_find(RX8900_I2C_BUS);
    if (i2c_bus == RT_NULL)
    {
        LOG_E("i2c bus device %s not found!\r\n", RX8900_I2C_BUS);
        return -RT_ERROR;
    }				 	
	
    /* register rtc device */
    rx8900_dev.type   	= RT_Device_Class_RTC;
    rx8900_dev.init    	= RT_NULL;
    rx8900_dev.open    	= rt_rx8900_open;
    rx8900_dev.close   	= RT_NULL;
    rx8900_dev.read   	= rt_rx8900_read;
    rx8900_dev.write  	= RT_NULL;
    rx8900_dev.control 	= rt_rx8900_control;
    rx8900_dev.user_data= (void*)i2c_bus;	/* save i2cbus */
    rt_device_register(&rx8900_dev, RX8900_DEVICE_NAME, RT_DEVICE_FLAG_RDWR);
	......
}

rx8900私有信息初始化

  rx8900私有信息初始化主要包括:

  • 獲取rx8900狀態寄存器值
  • 根據狀態寄存器值每一bit的含義執行復位、初始化操作或者清除狀態寄存器操作
	if (flags & VALUE_FLAG_VDET)
	{
	  	LOG_D("Temperature compensation stop detected.\n");
		need_clear = RT_TRUE;
	}
	
	/* alarm */
	if (flags & VALUE_FLAG_AF) 
	{ 
		LOG_D("Alarm was detected.\n");
		need_clear = RT_TRUE;
	}
	
	/* timer */
	if (flags & VALUE_FLAG_TF) 
	{  
		LOG_D("Timer was detected.\n");
		need_clear = RT_TRUE;
	}
	......

3 獲取 rx8900 軟件包

  使用 rx8900 package, 需要在 RT-Thread 的包管理器中選擇它,具體路徑如下:

RT-Thread online packages --->
    peripheral libraries and drivers --->
        [*] extren rtc drivers  --->
            [*] rx8900:Extern RTC drivers fo rx8900 
                 Version (latest)  --->

在這裏插入圖片描述
  然後讓 RT-Thread 的包管理器自動更新,或者執行 pkgs --update 命令更新包到 BSP 中。


4 使用 rx8900 軟件包

4.1 初始化

  首先需初始化rx8900 驅動,可以手動在初始化線程合適的地方調用rt_hw_rx8900 _init()初始化,也可以直接使用INIT_DEVICE_EXPORT通過RT-Thread的自動初始化機制來初始化註冊。初始化成功後,會註冊名稱爲“rtc”的驅動設備。

INIT_DEVICE_EXPORT(rt_hw_rx8900_init);	/* 通過RTT的自動初始化機制初始化rx8900 */

注:

如果開啓了芯片內部RTC,需先禁止內部RTC


4.2 使用方式

  查看設備是否註冊成功。

在這裏插入圖片描述

  對於時間和鬧鐘的訪問,使用RT-Thread標準RTC和鬧鐘接口訪問。片內溫度讀取,則由軟件包提供一個函數接口。

  • 獲取當前時間
time_t time(time_t *t)
time_t now;      
now = time(RT_NULL);
  • 設置時間
 #define RT_DEVICE_CTRL_RTC_SET_TIME     0x11        /**< set time */
 rt_err_t rt_device_control(rt_device_t dev, int cmd, void *arg)
  • 獲取鬧鐘時間
 #define RT_DEVICE_CTRL_RTC_GET_ALARM    0x12        /**< get alarm */
 rt_err_t rt_device_control(rt_device_t dev, int cmd, void *arg)
  • 設置鬧鐘時間
 #define RT_DEVICE_CTRL_RTC_SET_ALARM    0x13      /**< set alarm */
 rt_err_t rt_device_control(rt_device_t dev, int cmd, void *arg)

注:

詳細用法可以參考“/components/drivers/rtc.c”和“/components/drivers/alarm.c”源碼。


  • 提供一個獲取片內溫度接口
float rx8900_get_temperature(void)

4.3 msh/finsh測試

  • msh獲取時間
msh >date
Sat Jan  1 00:00:04 2000
  • msh設置時間
msh date 2020 04 10 17 41 10  
msh >date
Fri Apr 10 17:41:15 2020
  • finsh獲取時間
finsh >list_date()
Fri Apr 10 17:41:49 2020
  • finsh設置時間
finsh >set_date(2020,5,1)
        0, 0x00000000
finsh >set_time(12,0,0)  
        0, 0x00000000
finsh >list_date()
Fri May  1 12:00:04 2020
  • msh打印溫度
msh >list_rx89_temp
rx8900 temperature: [27.5C] 
  • finsh打印溫度
finsh >list_rx89_temp()
rx8900 temperature: [27.5C]

5 注意事項

使用RT-Thread的RTC框架,RTC設備註冊名稱爲“rtc”,注意需先屏蔽芯片內置RTC驅動。


6 聯繫方式


7 相關文章

【1】pcf8563匹配RT-Thread驅動
【2】RT-Thread DS3231驅動軟件包

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章