const char PSTR_WEEKDAYS[] PROGMEM = "So\0Mo\0Di\0Mi\0Do\0Fr\0Sa\0";
+// const uint8_t CONFIG[] PROGMEM = {
+// /* config -> */ 0x00, 0x00,
+// /* enable nINT -> */ 0x01, 0x01, // TIE = 1
+// /* set clock -> */ 0x02, 0x00, 0x00, 0x08, 0x16, 0x02, 0x08, 0x24
+// };
+
void Rtc8563::handleTwiIrq () {
TWCR |= (1 << TWINT); // clear Interrupt Request
}
if (subtest == 0) {
// printf_P(PSTR(" BM280 ... "));
rtc8563.begin(0x51);
- Clock_t clock; memset(&clock, 0, sizeof(clock));
- uint8_t bufferConfig[] = { 0x00, 0x00, 0x01, 0x01 };
+ Clock_t clock;
+ // uint8_t bufferConfig[] = { 0x00, 0x00, 0x01, 0x01 };
// uint8_t bufferSetClock[] = { 0x02, 0x00, 0x00, 0x08, 0x16, 0x02, 0x08, 0x24 };
- uint8_t buffer[16] = {
- /* config -> */ 0x00, 0x00,
- /* enable nINT -> */ 0x01, 0x01, // TIE = 1
- /* set clock -> */ 0x02, 0x00, 0x00, 0x08, 0x16, 0x02, 0x08, 0x24
- } ;
+ Rtc8563Reg_t reg;
+ uint8_t *pReg = (uint8_t *)(void *)®
+ memset(®, 0, sizeof(reg));
printf_P(PSTR("\n => config 8563 ... "));
- if (!rtc8563.write(&bufferConfig[0], 2) || !rtc8563.write(&bufferConfig[2], 2)) {
+ reg.reg1.field.tie = 1;
+ if (!rtc8563.write(pReg, 2)) {
printf_P(PSTR_ERROR);
} else {
printf_P(PSTR_Done);
}
printf_P(PSTR("\n press:"));
- printf_P(PSTR("\n t .... set timer"));
- printf_P(PSTR("\n p .... power off (PC7=1)"));
+ printf_P(PSTR("\n t .... timer on/off"));
+ printf_P(PSTR("\n p .... power on/off (PC7->Q1)"));
printf_P(PSTR("\n c .... init clock"));
printf_P(PSTR("\n w/W .. weekday (+/-)\n"));
printf_P(PSTR("\n y/Y .. year (+/-)"));
printf_P(PSTR("\n s/S .. second (+/-)\n"));
do {
- buffer[0] = 0;
- printf_P(PSTR("\n => read register 0-15: "));
- if (!rtc8563.write_then_read(buffer, 1, buffer, 16)) {
+ uint8_t addr = 0x00;
+ printf_P(PSTR("\n => read register 0-15 (hex):"));
+ if (!rtc8563.write_then_read(&addr, 1, pReg, sizeof(reg))) {
printf_P(PSTR_ERROR);
key = waitAndReadKey(1000);
continue;
}
- memccpy(&clock, &buffer[2], sizeof(clock), sizeof(clock));
- for (uint8_t i = 0; i < 7; i++) {
- printf_P(PSTR(" 0x%02x"), buffer[i]);
+ memccpy(&clock, ®.clock, sizeof(clock), sizeof(clock));
+ for (uint8_t i = 0; i < 16; i++) {
+ if (i % 4 == 0) {
+ printf_P(PSTR(" "));
+ }
+ printf_P(PSTR(" %02X"), pReg[i]);
}
- uint16_t year = (clock.century ? 2100 : 2000) + bcd2bin(clock.yearH << 4 | clock.yearL);
- int8_t month = bcd2bin(clock.monthH << 4 | clock.monthL);
- int8_t day = bcd2bin(clock.dayH << 4 | clock.dayL);
- int8_t hrs = bcd2bin(clock.hourH << 4 | clock.hourL);
- int8_t min = bcd2bin(clock.minH << 4 | clock.minL);
- int8_t sec = bcd2bin(clock.secH << 4 | clock.secL);
- int8_t weekday = clock.weekday;
-
- PGM_P d = clock.weekday >= 0 && clock.weekday < 7 ? &PSTR_WEEKDAYS[clock.weekday * 3] : PSTR("??");
- printf_P(PSTR(" --> "));
+ uint16_t year = (clock.month.field.century ? 2100 : 2000) + bcd2bin(clock.year.byte);
+ int8_t month = bcd2bin(clock.month.byte);
+ int8_t day = bcd2bin(clock.day.byte);
+ int8_t hrs = bcd2bin(clock.hour.byte);
+ int8_t min = bcd2bin(clock.min.byte);
+ int8_t sec = bcd2bin(clock.sec.byte);
+ int8_t weekday = clock.weekday.byte;
+
+ PGM_P d = weekday >= 0 && weekday < 7 ? &PSTR_WEEKDAYS[weekday * 3] : PSTR("??");
+ printf_P(PSTR(" --> "));
printf_P(d);
- printf_P(PSTR(", %04d-%02d-%02d %02d:%02d:%02d"), year, month, day, hrs, min, sec);
- printf_P(PSTR(" - Timer=0x%02x"), buffer[15]);
+ printf_P(PSTR(", %d %04d-%02d-%02d %02d:%02d:%02d"), weekday, year, month, day, hrs, min, sec);
+ printf_P(PSTR(" - Timer=0x%02x"), reg.timer);
key = waitAndReadKey(1000);
bool ok = true;
bool change = false;
switch (key) {
- case 't': ok &= setTimer(10); break;
+ case 't': ok &= setTimer(reg.timerControl.field.enable ? 0 : 10, reg); break;
case 'c': ok &= setClock(5, 2024,8,16, 17,12,10 ); break; // ok &= rtc8563.write(bufferSetClock, sizeof(bufferSetClock)); break;
- case 'p': powerOff(); break;
+ case 'p': powerOnOff(10, reg); break;
case 'y': year++; change = true; break;
case 'Y': year--; change = true; break;
case 'm': month++; change = true; break;
case 'W': weekday--; change = true; break;
}
if (change) {
+ printf_P(PSTR("\n set: %04d-%02d-%02d %02d:%02d:%02d"), year, month, day, hrs, min, sec);
setClock(weekday, year, month, day, hrs, min, sec);
}
return -1;
}
-bool Rtc8563::setTimer (uint8_t seconds) {
- uint8_t i2cTimer[] = { 0x0f, seconds };
- uint8_t i2cControl[] = { 0x0e, 0x80 | 0x02 }; // timer enable, 1Hz clock
- printf_P(PSTR("\n Timer set to %ds ... "), seconds);
- if (rtc8563.write(i2cTimer, 2) && rtc8563.write(i2cControl, 2)) {
+bool Rtc8563::setTimer (uint8_t seconds, Rtc8563Reg_t ®) {
+
+ reg.timerControl.field.fd = FDTIMER_1HZ;
+ reg.timerControl.field.enable = seconds > 0;
+ reg.timer = seconds;
+ reg.reg1.field.tie = seconds > 0;
+ // clear and alarm flag behavior on I2C write different to datasheet
+ // datasheet: tf cleared to 0, af remains unchanged
+ // realchip: tf remains 1 and af is set to 1 (no negative result because tie=0 and aie=0)
+ reg.reg1.field.tf = 0; // clear timer flag
+ reg.reg1.field.af = 1; // alarm flag remains unchanged
+ if (seconds > 0) {
+ printf_P(PSTR("\n Timer set to %ds (1:%02X) ... "), seconds, reg.reg1.byte);
+ } else {
+ printf_P(PSTR("\n Timer off ... "));
+ }
+ if (rtc8563.writeByteAndBuffer(0x01, ®.reg1.byte, 1) && rtc8563.writeByteAndBuffer(14, ®.timerControl.byte, 2)) {
printf_P(PSTR("OK"));
return true;
} else {
}
}
-bool Rtc8563::powerOff () {
+bool Rtc8563::powerOnOff (uint8_t delayOffSeconds, Rtc8563Reg_t ®) {
int key = EOF;
if (PORTC & (1 << PC7)) {
printf_P(PSTR("\n power on ..."));
DDRC |= ( 1<< PC7);
PORTC &= ~(1 << PC7);
+ setTimer(0, reg);
} else {
printf_P(PSTR("\n"));
key = EOF;
- for (int8_t i = 9; i > 0 && key != ESCAPE; i--) {
- printf_P(PSTR("\r press escape or power off in %ds "), i);
+ for (int8_t i = 9; i > 0 && key == EOF; i--) {
+ printf_P(PSTR("\r press ESC to abort, power off in %ds (press key to skip timer) "), i);
key = waitAndReadKey(1000);
}
- setTimer(10);
- uint8_t b = 0x01; // clear timer flag and activate TIE
- rtc8563.writeByteAndBuffer(0x01, &b, 1);
+ if (key == ESCAPE) {
+ return true;
+ }
+ setTimer(10, reg);
+ reg.reg1.field.af = 1; // alarm flag remains unchanged
+ reg.reg1.field.tf = 0; // timer flag clear
+ reg.reg1.field.tie = 1; // enable timer interrupt
+ rtc8563.writeByteAndBuffer(0x01, ®.reg1.byte, 1);
printf_P(PSTR("\n power off now ..."));
DDRC |= ( 1<< PC7);
PORTC |= (1 << PC7);
DDRC &= ~( 1<< PC7);
PORTC &= ~(1 << PC7);
waitAndReadKey(5000);
- printf_P(PSTR("proceed"));
+ printf_P(PSTR("power off fails, I am still alive :-) ... proceed"));
}
return true;
}
+
bool Rtc8563::setClock (int8_t weekday, uint16_t year, int8_t month, int8_t day, int8_t hour, int8_t min, int8_t sec) {
Clock_t clock;
- clock.century = (year < 2000 || year > 2100) ? 1: 0;
- uint8_t y = year % 100; clock.yearL = y % 10; clock.yearH = y / 10;
+ clock.month.field.century = (year < 2000 || year > 2100) ? 1: 0;
+ uint8_t y = year % 100; clock.year.field.bcdL = y % 10; clock.year.field.bcdH = y / 10;
while (weekday < 0) { weekday += 7; }
while (weekday > 6) { weekday -= 7; }
- clock.weekday = weekday;
+ clock.weekday.field.bcdL = weekday;
while (month < 1) { month += 12; }
while (month > 12) { month -= 12; }
- clock.monthL = month % 10; clock.monthH = month / 10;
+ clock.month.field.bcdL = month % 10; clock.month.field.bcdH = month / 10;
while (day < 1) { day += 31; }
while (day > 31) { day -= 31; }
- clock.dayL = day % 10; clock.dayH = day / 10;
+ clock.day.field.bcdL = day % 10; clock.day.field.bcdH = day / 10;
while (hour < 0) { hour += 24; }
while (hour > 23) { hour -= 24; }
- clock.hourL = hour % 10; clock.hourH = hour / 10;
+ clock.hour.field.bcdL = hour % 10; clock.hour.field.bcdH = hour / 10;
while (min < 0) { min += 60; }
while (min > 59) { min -= 60; }
- clock.minL = min % 10; clock.minH = min / 10;
+ clock.min.field.bcdL = min % 10; clock.min.field.bcdH = min / 10;
while (sec < 0) { sec += 60; }
while (sec > 59) { sec -= 60; }
- clock.secL = sec % 10; clock.secH = sec / 10;
+ clock.sec.field.bcdL = sec % 10; clock.sec.field.bcdH = sec / 10;
+ printf_P(PSTR("\n %p %p %p %p %p %p %p -> write: "), &clock.sec.byte, &clock.min.byte, &clock.hour.byte, &clock.day.byte, &clock.weekday.byte, &clock.month.byte, &clock.year.byte );
+ for (uint8_t i = 0; i < sizeof(clock); i++) {
+ printf_P(PSTR(" %02x"), ((uint8_t *)(void *)&clock)[i]);
+ }
return rtc8563.writeByteAndBuffer(0x02, (uint8_t *)(void *)&clock, sizeof(clock));
}
private:
I2cMaster rtc8563;
+ typedef enum { FDCLOCKOUT_32768HZ = 0, FDCLOCKOUT_1024HZ = 1, FDCLOCKOUT_32HZ = 2, FDCLOCKOUT_1HZ = 3 } FDCLOCKOUT_t;
+ typedef enum { FDTIMER_4096HZ = 0, FDTIMER_64HZ = 1, FDTIMER_1HZ = 2, FDTIMER_1D60HZ = 3 } FDTIMER_t;
typedef struct {
- uint8_t secL:4; uint8_t secH:3; uint8_t voltageLow:1;
- uint8_t minL:4; uint8_t minH:2; uint8_t minuteBit76:2;
- uint8_t hourL:4; uint8_t hourH:2; uint8_t hourBit76:2;
- uint8_t dayL:4; uint8_t dayH:2; uint8_t dayBit76:2;
- uint8_t weekday:3; uint8_t bit73:5;
- uint8_t monthL:4; uint8_t monthH:1; uint8_t bit65:2; uint8_t century:1;
- uint8_t yearL:4; uint8_t yearH:4;
+ union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:3; uint8_t voltageLow:1; } field; } sec;
+ union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:3; uint8_t notUsed:1; } field; } min;
+ union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:2; uint8_t notUsed:2; } field; } hour;
+ union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:2; uint8_t notUsed:2; } field; } day;
+ union { uint8_t byte; struct { uint8_t bcdL:3; } field; uint8_t notUsed:5; } weekday;
+ union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:1; uint8_t notUsed:2; uint8_t century:1; } field; } month;
+ union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:4; } field; } year;
} Clock_t; // identical to 8563 register 2..8
-
+
+ typedef struct {
+ union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:3; uint8_t enable:1; } field; } min;
+ union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:2; uint8_t notUsed:1; uint8_t enable:1; } field; } hour;
+ union { uint8_t byte; struct { uint8_t bcdL:4; uint8_t bcdH:2; uint8_t notUsed:1; uint8_t enable:1; } field; } day;
+ union { uint8_t byte; struct { uint8_t bcdL:3; } field; uint8_t notUsed:4; uint8_t enable_W:1; } weekday;
+ } Alarm_t;
+
+ typedef struct {
+ union { uint8_t byte; struct { uint8_t notUsed210:3; uint8_t testC:1; uint8_t notUsed4:1; uint8_t stop:1; uint8_t notUsed6:1; uint8_t test1:1; } field; } reg0;
+ union { uint8_t byte; struct { uint8_t tie:1; uint8_t aie:1; uint8_t tf:1; uint8_t af:1; uint8_t ti_tp:1; uint8_t notUsed:3; } field; } reg1;
+ Clock_t clock;
+ Alarm_t alarm;
+ union { uint8_t byte; struct { FDCLOCKOUT_t fd:2; uint8_t notUsed65432:5; uint8_t enable:1; } field; } clockoutControl;
+ union { uint8_t byte; struct { FDTIMER_t fd:2; uint8_t notUsed65432:5; uint8_t enable:1; } field; } timerControl;
+ uint8_t timer;
+ } Rtc8563Reg_t;
+
public:
bool enabled;
uint8_t bcd2bin (uint8_t value);
int8_t runModeNormal (uint8_t subtest);
int8_t runModeBattery (uint8_t subtest);
- bool setTimer (uint8_t seconds);
- bool powerOff ();
+ bool setTimer (uint8_t seconds, Rtc8563Reg_t ®);
+ bool powerOnOff (uint8_t delayOffSeconds, Rtc8563Reg_t ®);
bool setClock (int8_t weekday, uint16_t year, int8_t month, int8_t day, int8_t hour, int8_t min, int8_t sec);
};