|
1 | | -/* |
2 | | - * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD |
3 | | - * |
4 | | - * SPDX-License-Identifier: MIT |
5 | | - */ |
6 | | -#include "rx8130.h" |
7 | | - |
8 | | -// RX-8130 Register definitions |
9 | | -#define RX8130_REG_SEC 0x10 |
10 | | -#define RX8130_REG_MIN 0x11 |
11 | | -#define RX8130_REG_HOUR 0x12 |
12 | | -#define RX8130_REG_WDAY 0x13 |
13 | | -#define RX8130_REG_MDAY 0x14 |
14 | | -#define RX8130_REG_MONTH 0x15 |
15 | | -#define RX8130_REG_YEAR 0x16 |
16 | | - |
17 | | -#define RX8130_REG_ALMIN 0x17 |
18 | | -#define RX8130_REG_ALHOUR 0x18 |
19 | | -#define RX8130_REG_ALWDAY 0x19 |
20 | | -#define RX8130_REG_TCOUNT0 0x1A |
21 | | -#define RX8130_REG_TCOUNT1 0x1B |
22 | | -#define RX8130_REG_EXT 0x1C |
23 | | -#define RX8130_REG_FLAG 0x1D |
24 | | -#define RX8130_REG_CTRL0 0x1E |
25 | | -#define RX8130_REG_CTRL1 0x1F |
26 | | - |
27 | | -#define RX8130_REG_END 0x23 |
28 | | - |
29 | | -// Extension Register (1Ch) bit positions |
30 | | -#define RX8130_BIT_EXT_TSEL (7 << 0) |
31 | | -#define RX8130_BIT_EXT_WADA (1 << 3) |
32 | | -#define RX8130_BIT_EXT_TE (1 << 4) |
33 | | -#define RX8130_BIT_EXT_USEL (1 << 5) |
34 | | -#define RX8130_BIT_EXT_FSEL (3 << 6) |
35 | | - |
36 | | -// Flag Register (1Dh) bit positions |
37 | | -#define RX8130_BIT_FLAG_VLF (1 << 1) |
38 | | -#define RX8130_BIT_FLAG_AF (1 << 3) |
39 | | -#define RX8130_BIT_FLAG_TF (1 << 4) |
40 | | -#define RX8130_BIT_FLAG_UF (1 << 5) |
41 | | - |
42 | | -// Control 0 Register (1Еh) bit positions |
43 | | -#define RX8130_BIT_CTRL_TSTP (1 << 2) |
44 | | -#define RX8130_BIT_CTRL_AIE (1 << 3) |
45 | | -#define RX8130_BIT_CTRL_TIE (1 << 4) |
46 | | -#define RX8130_BIT_CTRL_UIE (1 << 5) |
47 | | -#define RX8130_BIT_CTRL_STOP (1 << 6) |
48 | | -#define RX8130_BIT_CTRL_TEST (1 << 7) |
49 | | - |
50 | | -static uint8_t bcd2dec(uint8_t val) |
51 | | -{ |
52 | | - return (val >> 4) * 10 + (val & 0x0f); |
53 | | -} |
54 | | - |
55 | | -static uint8_t dec2bcd(uint8_t val) |
56 | | -{ |
57 | | - return ((val / 10) << 4) + (val % 10); |
58 | | -} |
59 | | - |
60 | | -bool RX8130_Class::begin() |
61 | | -{ |
62 | | - bool result = _i2c->start(_addr, false, _freq) && _i2c->stop(); |
63 | | - return result; |
64 | | -} |
65 | | - |
66 | | -void RX8130_Class::setTime(struct tm *time) |
67 | | -{ |
68 | | - uint8_t rbuf = 0; |
69 | | - |
70 | | - time->tm_year -= 100; |
71 | | - |
72 | | - // set STOP bit before changing clock/calendar |
73 | | - rbuf = readRegister8(RX8130_REG_CTRL0); |
74 | | - rbuf = rbuf | RX8130_BIT_CTRL_STOP; |
75 | | - writeRegister8(RX8130_REG_CTRL0, rbuf); |
76 | | - |
77 | | - uint8_t date[7] = {dec2bcd(time->tm_sec), dec2bcd(time->tm_min), dec2bcd(time->tm_hour), |
78 | | - dec2bcd(time->tm_wday), dec2bcd(time->tm_mday), dec2bcd(time->tm_mon), |
79 | | - dec2bcd(time->tm_year % 100)}; |
80 | | - |
81 | | - writeRegister(RX8130_REG_SEC, date, 7); |
82 | | - |
83 | | - // clear STOP bit after changing clock/calendar |
84 | | - rbuf = readRegister8(RX8130_REG_CTRL0); |
85 | | - rbuf = rbuf & ~RX8130_BIT_CTRL_STOP; |
86 | | - writeRegister8(RX8130_REG_CTRL0, rbuf); |
87 | | -} |
88 | | - |
89 | | -void RX8130_Class::getTime(struct tm *time) |
90 | | -{ |
91 | | - uint8_t date[7]; |
92 | | - readRegister(RX8130_REG_SEC, date, 7); |
93 | | - |
94 | | - time->tm_sec = bcd2dec(date[RX8130_REG_SEC - 0x10] & 0x7f); |
95 | | - time->tm_min = bcd2dec(date[RX8130_REG_MIN - 0x10] & 0x7f); |
96 | | - time->tm_hour = bcd2dec(date[RX8130_REG_HOUR - 0x10] & 0x3f); // only 24-hour clock |
97 | | - time->tm_mday = bcd2dec(date[RX8130_REG_MDAY - 0x10] & 0x3f); |
98 | | - time->tm_mon = bcd2dec(date[RX8130_REG_MONTH - 0x10] & 0x1f); |
99 | | - time->tm_year = bcd2dec(date[RX8130_REG_YEAR - 0x10]); |
100 | | - time->tm_wday = bcd2dec(date[RX8130_REG_WDAY - 0x10] & 0x7f); |
101 | | - |
102 | | - time->tm_year += 100; |
103 | | -} |
104 | | - |
105 | | -void RX8130_Class::clearIrqFlags() |
106 | | -{ |
107 | | - writeRegister8(RX8130_REG_FLAG, 0); |
108 | | -} |
109 | | - |
110 | | -void RX8130_Class::disableIrq() |
111 | | -{ |
112 | | - writeRegister8(RX8130_REG_CTRL0, 0); |
113 | | -} |
| 1 | +/* |
| 2 | + * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: MIT |
| 5 | + */ |
| 6 | +#include "rx8130.h" |
| 7 | + |
| 8 | +// RX-8130 Register definitions |
| 9 | +#define RX8130_REG_SEC 0x10 |
| 10 | +#define RX8130_REG_MIN 0x11 |
| 11 | +#define RX8130_REG_HOUR 0x12 |
| 12 | +#define RX8130_REG_WDAY 0x13 |
| 13 | +#define RX8130_REG_MDAY 0x14 |
| 14 | +#define RX8130_REG_MONTH 0x15 |
| 15 | +#define RX8130_REG_YEAR 0x16 |
| 16 | + |
| 17 | +#define RX8130_REG_ALMIN 0x17 |
| 18 | +#define RX8130_REG_ALHOUR 0x18 |
| 19 | +#define RX8130_REG_ALWDAY 0x19 |
| 20 | +#define RX8130_REG_TCOUNT0 0x1A |
| 21 | +#define RX8130_REG_TCOUNT1 0x1B |
| 22 | +#define RX8130_REG_EXT 0x1C |
| 23 | +#define RX8130_REG_FLAG 0x1D |
| 24 | +#define RX8130_REG_CTRL0 0x1E |
| 25 | +#define RX8130_REG_CTRL1 0x1F |
| 26 | + |
| 27 | +#define RX8130_REG_END 0x23 |
| 28 | + |
| 29 | +// Extension Register (1Ch) bit positions |
| 30 | +#define RX8130_BIT_EXT_TSEL (7 << 0) |
| 31 | +#define RX8130_BIT_EXT_WADA (1 << 3) |
| 32 | +#define RX8130_BIT_EXT_TE (1 << 4) |
| 33 | +#define RX8130_BIT_EXT_USEL (1 << 5) |
| 34 | +#define RX8130_BIT_EXT_FSEL (3 << 6) |
| 35 | + |
| 36 | +// Flag Register (1Dh) bit positions |
| 37 | +#define RX8130_BIT_FLAG_VLF (1 << 1) |
| 38 | +#define RX8130_BIT_FLAG_AF (1 << 3) |
| 39 | +#define RX8130_BIT_FLAG_TF (1 << 4) |
| 40 | +#define RX8130_BIT_FLAG_UF (1 << 5) |
| 41 | + |
| 42 | +// Control 0 Register (1Еh) bit positions |
| 43 | +#define RX8130_BIT_CTRL_TSTP (1 << 2) |
| 44 | +#define RX8130_BIT_CTRL_AIE (1 << 3) |
| 45 | +#define RX8130_BIT_CTRL_TIE (1 << 4) |
| 46 | +#define RX8130_BIT_CTRL_UIE (1 << 5) |
| 47 | +#define RX8130_BIT_CTRL_STOP (1 << 6) |
| 48 | +#define RX8130_BIT_CTRL_TEST (1 << 7) |
| 49 | + |
| 50 | +static uint8_t bcd2dec(uint8_t val) |
| 51 | +{ |
| 52 | + return (val >> 4) * 10 + (val & 0x0f); |
| 53 | +} |
| 54 | + |
| 55 | +static uint8_t dec2bcd(uint8_t val) |
| 56 | +{ |
| 57 | + return ((val / 10) << 4) + (val % 10); |
| 58 | +} |
| 59 | + |
| 60 | +// Helper function to check if a year is a leap year |
| 61 | +static bool isLeapYear(int year) |
| 62 | +{ |
| 63 | + return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); |
| 64 | +} |
| 65 | + |
| 66 | +// Helper function to get the number of days in a given month |
| 67 | +// Note: month is 1-12 for this function |
| 68 | +static int getDaysInMonth(int month, int year) |
| 69 | +{ |
| 70 | + static const int daysInMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; |
| 71 | + |
| 72 | + if (month == 2 && isLeapYear(year)) { |
| 73 | + return 29; |
| 74 | + } |
| 75 | + return daysInMonth[month - 1]; |
| 76 | +} |
| 77 | + |
| 78 | +bool RX8130_Class::begin() |
| 79 | +{ |
| 80 | + bool result = _i2c->start(_addr, false, _freq) && _i2c->stop(); |
| 81 | + return result; |
| 82 | +} |
| 83 | + |
| 84 | +void RX8130_Class::setTime(struct tm *time) |
| 85 | +{ |
| 86 | + uint8_t rbuf = 0; |
| 87 | + |
| 88 | + time->tm_year -= 100; |
| 89 | + |
| 90 | + // set STOP bit before changing clock/calendar |
| 91 | + rbuf = readRegister8(RX8130_REG_CTRL0); |
| 92 | + rbuf = rbuf | RX8130_BIT_CTRL_STOP; |
| 93 | + writeRegister8(RX8130_REG_CTRL0, rbuf); |
| 94 | + |
| 95 | + uint8_t date[7] = {dec2bcd(time->tm_sec), dec2bcd(time->tm_min), dec2bcd(time->tm_hour), |
| 96 | + dec2bcd(time->tm_wday), dec2bcd(time->tm_mday), dec2bcd(time->tm_mon + 1), |
| 97 | + dec2bcd(time->tm_year % 100)}; |
| 98 | + |
| 99 | + writeRegister(RX8130_REG_SEC, date, 7); |
| 100 | + |
| 101 | + // clear STOP bit after changing clock/calendar |
| 102 | + rbuf = readRegister8(RX8130_REG_CTRL0); |
| 103 | + rbuf = rbuf & ~RX8130_BIT_CTRL_STOP; |
| 104 | + writeRegister8(RX8130_REG_CTRL0, rbuf); |
| 105 | +} |
| 106 | + |
| 107 | +void RX8130_Class::getTime(struct tm *time) |
| 108 | +{ |
| 109 | + uint8_t date[7]; |
| 110 | + readRegister(RX8130_REG_SEC, date, 7); |
| 111 | + |
| 112 | + time->tm_sec = bcd2dec(date[RX8130_REG_SEC - 0x10] & 0x7f); |
| 113 | + time->tm_min = bcd2dec(date[RX8130_REG_MIN - 0x10] & 0x7f); |
| 114 | + time->tm_hour = bcd2dec(date[RX8130_REG_HOUR - 0x10] & 0x3f); // only 24-hour clock |
| 115 | + time->tm_mday = bcd2dec(date[RX8130_REG_MDAY - 0x10] & 0x3f); |
| 116 | + time->tm_year = bcd2dec(date[RX8130_REG_YEAR - 0x10]); |
| 117 | + time->tm_wday = bcd2dec(date[RX8130_REG_WDAY - 0x10] & 0x7f); |
| 118 | + |
| 119 | + // Read month from RTC (1-12) and convert to tm_mon (0-11) |
| 120 | + int rtc_month = bcd2dec(date[RX8130_REG_MONTH - 0x10] & 0x1f); |
| 121 | + time->tm_mon = rtc_month - 1; |
| 122 | + time->tm_year += 100; |
| 123 | + |
| 124 | + // Fix date overflow issues - RX8130 doesn't handle month/day overflow automatically |
| 125 | + // Only correct when we detect actual invalid dates |
| 126 | + bool dateChanged = false; |
| 127 | + |
| 128 | + // Check for invalid day (day > maximum days in current month) |
| 129 | + int maxDaysInMonth = getDaysInMonth(rtc_month, time->tm_year + 1900); |
| 130 | + if (time->tm_mday > maxDaysInMonth) { |
| 131 | + time->tm_mday = 1; |
| 132 | + rtc_month++; |
| 133 | + if (rtc_month > 12) { |
| 134 | + rtc_month = 1; |
| 135 | + time->tm_year++; |
| 136 | + } |
| 137 | + time->tm_mon = rtc_month - 1; |
| 138 | + dateChanged = true; |
| 139 | + } |
| 140 | + |
| 141 | + // Check for invalid month (month > 12 or month < 1) |
| 142 | + else if (rtc_month > 12) { |
| 143 | + rtc_month = 1; |
| 144 | + time->tm_year++; |
| 145 | + time->tm_mon = rtc_month - 1; |
| 146 | + dateChanged = true; |
| 147 | + } else if (rtc_month < 1) { |
| 148 | + rtc_month = 12; |
| 149 | + time->tm_year--; |
| 150 | + time->tm_mon = rtc_month - 1; |
| 151 | + dateChanged = true; |
| 152 | + } |
| 153 | + |
| 154 | + // If we corrected the date, update the RTC to prevent future issues |
| 155 | + if (dateChanged) { |
| 156 | + // Set STOP bit before changing clock/calendar |
| 157 | + uint8_t rbuf = readRegister8(RX8130_REG_CTRL0); |
| 158 | + rbuf = rbuf | RX8130_BIT_CTRL_STOP; |
| 159 | + writeRegister8(RX8130_REG_CTRL0, rbuf); |
| 160 | + |
| 161 | + // Only update date registers, preserve time |
| 162 | + uint8_t dateRegs[4] = {dec2bcd(time->tm_wday), dec2bcd(time->tm_mday), dec2bcd(rtc_month), |
| 163 | + dec2bcd((time->tm_year - 100) % 100)}; |
| 164 | + writeRegister(RX8130_REG_WDAY, dateRegs, 4); |
| 165 | + |
| 166 | + // Clear STOP bit after changing clock/calendar |
| 167 | + rbuf = readRegister8(RX8130_REG_CTRL0); |
| 168 | + rbuf = rbuf & ~RX8130_BIT_CTRL_STOP; |
| 169 | + writeRegister8(RX8130_REG_CTRL0, rbuf); |
| 170 | + } |
| 171 | +} |
| 172 | + |
| 173 | +void RX8130_Class::clearIrqFlags() |
| 174 | +{ |
| 175 | + writeRegister8(RX8130_REG_FLAG, 0); |
| 176 | +} |
| 177 | + |
| 178 | +void RX8130_Class::disableIrq() |
| 179 | +{ |
| 180 | + writeRegister8(RX8130_REG_CTRL0, 0); |
| 181 | +} |
0 commit comments