From c9ba8dbc6478e3cc79f03515615523be9d282b52 Mon Sep 17 00:00:00 2001 From: Manfred Steiner Date: Sat, 17 Aug 2024 12:22:06 +0200 Subject: [PATCH] Test-Software unit Rtc8563 finished (with power off and wakeup via Q1) --- .../test_2024-07-23/src/i2cmaster.cpp | 22 ++- .../test_2024-07-23/src/i2cmaster.hpp | 8 +- .../test_2024-07-23/src/units/rtc8563.cpp | 132 +++++++++++------- .../test_2024-07-23/src/units/rtc8563.hpp | 39 ++++-- 4 files changed, 133 insertions(+), 68 deletions(-) diff --git a/software/nano-644/test_2024-07-23/src/i2cmaster.cpp b/software/nano-644/test_2024-07-23/src/i2cmaster.cpp index 9b1bd5d..ca883d6 100644 --- a/software/nano-644/test_2024-07-23/src/i2cmaster.cpp +++ b/software/nano-644/test_2024-07-23/src/i2cmaster.cpp @@ -1,4 +1,5 @@ #include +#include #include #include "i2cmaster.hpp" @@ -41,7 +42,7 @@ bool I2cMaster::read (uint8_t *buffer, uint8_t len) { bool I2cMaster::write (const uint8_t *buffer, uint8_t len) { if (start(false)) { - if (writeBytes(buffer, len)) { + if (writeBytes(buffer, len, false)) { if (stop()) { return true; } @@ -50,6 +51,18 @@ bool I2cMaster::write (const uint8_t *buffer, uint8_t len) { return false; } +bool I2cMaster::write_P (const uint8_t *buffer, uint8_t len) { + if (start(false)) { + if (writeBytes(buffer, len, true)) { + if (stop()) { + return true; + } + } + } + return false; +} + + bool I2cMaster::writeByteAndBuffer (uint8_t byte, const uint8_t *buffer, uint8_t len) { if (start(false)) { do { @@ -69,7 +82,7 @@ bool I2cMaster::writeByteAndBuffer (uint8_t byte, const uint8_t *buffer, uint8_t bool I2cMaster::write_then_read (const uint8_t *write_buffer, uint8_t write_len, uint8_t *read_buffer, uint8_t read_len) { if (start(false)) { - if (writeBytes(write_buffer, write_len)) { + if (writeBytes(write_buffer, write_len, false)) { if (start(true)) { if (readBytes(read_buffer, read_len)) { if (stop()) { @@ -101,10 +114,10 @@ bool I2cMaster::readBytes (uint8_t *buffer, uint8_t len) { return true; } -bool I2cMaster::writeBytes (const uint8_t *buffer, uint8_t len) { +bool I2cMaster::writeBytes (const uint8_t *buffer, uint8_t len, bool fromFlash) { while (len-- > 0) { // printf_P(PSTR("[wB:len=%d, byte=%02x]"), len + 1, *buffer); - TWDR = *buffer++; + TWDR = fromFlash ? pgm_read_byte(buffer++) : *buffer++; TWCR = (1 << TWINT) | (1 << TWEN); // send data byte timer = 5; while (timer > 0 && !(TWCR & (1 << TWINT))) {}; // wait until last action done @@ -115,7 +128,6 @@ bool I2cMaster::writeBytes (const uint8_t *buffer, uint8_t len) { return true; } - bool I2cMaster::start (bool read) { TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); // send START condition timer = 5; diff --git a/software/nano-644/test_2024-07-23/src/i2cmaster.hpp b/software/nano-644/test_2024-07-23/src/i2cmaster.hpp index e70326c..89b1e46 100644 --- a/software/nano-644/test_2024-07-23/src/i2cmaster.hpp +++ b/software/nano-644/test_2024-07-23/src/i2cmaster.hpp @@ -12,8 +12,9 @@ class I2cMaster { void tick1ms (); bool begin (uint8_t addr); bool read (uint8_t *buffer, uint8_t len); - bool write(const uint8_t *buffer, uint8_t len); - bool write_then_read(const uint8_t *write_buffer, uint8_t write_len, uint8_t *read_buffer, uint8_t read_len); + bool write (const uint8_t *buffer, uint8_t len); + bool write_P (const uint8_t *buffer, uint8_t len); + bool write_then_read (const uint8_t *write_buffer, uint8_t write_len, uint8_t *read_buffer, uint8_t read_len); bool writeByteAndBuffer (uint8_t byte, const uint8_t *buffer, uint8_t len); private: @@ -21,7 +22,8 @@ class I2cMaster { uint8_t timer; bool start (bool read); bool stop (); - bool writeBytes (const uint8_t *buffer, uint8_t len); + bool writeBytes (const uint8_t *buffer, uint8_t len, bool fromFlash); + bool writeBytes_P (const uint8_t *buffer); bool readBytes (uint8_t *buffer, uint8_t len); }; diff --git a/software/nano-644/test_2024-07-23/src/units/rtc8563.cpp b/software/nano-644/test_2024-07-23/src/units/rtc8563.cpp index 5dc07fd..ea8821e 100644 --- a/software/nano-644/test_2024-07-23/src/units/rtc8563.cpp +++ b/software/nano-644/test_2024-07-23/src/units/rtc8563.cpp @@ -12,6 +12,12 @@ 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 } @@ -55,25 +61,24 @@ int8_t Rtc8563::run (uint8_t subtest) { 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 (+/-)")); @@ -84,38 +89,41 @@ int8_t Rtc8563::run (uint8_t subtest) { 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; @@ -132,6 +140,7 @@ int8_t Rtc8563::run (uint8_t subtest) { 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); } @@ -143,11 +152,23 @@ int8_t Rtc8563::run (uint8_t subtest) { 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 { @@ -156,22 +177,28 @@ bool Rtc8563::setTimer (uint8_t seconds) { } } -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); @@ -179,40 +206,45 @@ bool Rtc8563::powerOff () { 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)); } diff --git a/software/nano-644/test_2024-07-23/src/units/rtc8563.hpp b/software/nano-644/test_2024-07-23/src/units/rtc8563.hpp index 07dbf44..ca79713 100644 --- a/software/nano-644/test_2024-07-23/src/units/rtc8563.hpp +++ b/software/nano-644/test_2024-07-23/src/units/rtc8563.hpp @@ -15,16 +15,35 @@ class Rtc8563 : public TestUnit { 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; @@ -43,8 +62,8 @@ class Rtc8563 : public TestUnit { 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); }; -- 2.39.5