/* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2009-04-26 yi.qiu first version * 2010-03-18 Gary Lee add functions such as GregorianDay * and rtc_time_to_tm * 2009-03-20 yi.qiu clean up */ #include #include #include #include // #define RTC_DEBUG #ifdef RT_USING_RTC #define RTC_ENABLE RTCCON |= 0x01; /*RTC read and write enable */ #define RTC_DISABLE RTCCON &= ~0x01; /* RTC read and write disable */ #define BCD2BIN(n) (((((n) >> 4) & 0x0F) * 10) + ((n) & 0x0F)) #define BIN2BCD(n) ((((n) / 10) << 4) | ((n) % 10)) /** * This function get rtc time */ void rt_hw_rtc_get(struct tm *ti) { rt_uint8_t sec, min, hour, mday, wday, mon, year; /* enable access to RTC registers */ RTCCON |= RTC_ENABLE; /* read RTC registers */ do { sec = BCDSEC; min = BCDMIN; hour = BCDHOUR; mday = BCDDATE; wday = BCDDAY; mon = BCDMON; year = BCDYEAR; } while (sec != BCDSEC); #ifdef RTC_DEBUG rt_kprintf("sec:%x min:%x hour:%x mday:%x wday:%x mon:%x year:%x\n", sec, min, hour, mday, wday, mon, year); #endif /* disable access to RTC registers */ RTC_DISABLE ti->tm_sec = BCD2BIN(sec & 0x7F); ti->tm_min = BCD2BIN(min & 0x7F); ti->tm_hour = BCD2BIN(hour & 0x3F); ti->tm_mday = BCD2BIN(mday & 0x3F); ti->tm_mon = BCD2BIN(mon & 0x1F); ti->tm_year = BCD2BIN(year); ti->tm_wday = BCD2BIN(wday & 0x07); ti->tm_yday = 0; ti->tm_isdst = 0; } /** * This function set rtc time */ void rt_hw_rtc_set(struct tm *ti) { rt_uint8_t sec, min, hour, mday, wday, mon, year; year = BIN2BCD(ti->tm_year); mon = BIN2BCD(ti->tm_mon); wday = BIN2BCD(ti->tm_wday); mday = BIN2BCD(ti->tm_mday); hour = BIN2BCD(ti->tm_hour); min = BIN2BCD(ti->tm_min); sec = BIN2BCD(ti->tm_sec); /* enable access to RTC registers */ RTC_ENABLE do{ /* write RTC registers */ BCDSEC = sec; BCDMIN = min; BCDHOUR = hour; BCDDATE = mday; BCDDAY = wday; BCDMON = mon; BCDYEAR = year; }while (sec != BCDSEC); /* disable access to RTC registers */ RTC_DISABLE } /** * This function reset rtc */ void rt_hw_rtc_reset (void) { RTCCON = (RTCCON & ~0x06) | 0x08; RTCCON &= ~(0x08|0x01); } static struct rt_device rtc; static rt_err_t rtc_open(rt_device_t dev, rt_uint16_t oflag) { RTC_ENABLE return RT_EOK; } static rt_err_t rtc_close(rt_device_t dev) { RTC_DISABLE return RT_EOK; } static rt_ssize_t rtc_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) { return RT_EOK; } static rt_err_t rtc_control(rt_device_t dev, int cmd, void *args) { struct tm tmp; time_t *time; RT_ASSERT(dev != RT_NULL); time = (time_t *)args; switch (cmd) { case RT_DEVICE_CTRL_RTC_GET_TIME: /* read device */ rt_hw_rtc_get(&tmp); *((rt_time_t *)args) = timegm(&tmp); break; case RT_DEVICE_CTRL_RTC_SET_TIME: /* write device */ gmtime_r(time, &tmp); rt_hw_rtc_set(&tmp); break; } return RT_EOK; } void rt_hw_rtc_init(void) { rtc.type = RT_Device_Class_RTC; /* register rtc device */ rtc.init = RT_NULL; rtc.open = rtc_open; rtc.close = rtc_close; rtc.read = rtc_read; rtc.write = RT_NULL; rtc.control = rtc_control; /* no private */ rtc.user_data = RT_NULL; rt_device_register(&rtc, "rtc", RT_DEVICE_FLAG_RDWR); } #ifdef RT_USING_FINSH #include void list_date() { time_t time; rt_device_t device; device = rt_device_find("rtc"); if (device != RT_NULL) { rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_TIME, &time); rt_kprintf("%d, %s\n", time, ctime(&time)); } } FINSH_FUNCTION_EXPORT(list_date, list date); #endif #endif