Commit c9ba8dbc6478e3cc79f03515615523be9d282b52
receivedSat, 17. Aug 2024, 12:22:12 (by user sx)
Sat, 17 Aug 2024 10:22:12 +0000 (12:22 +0200)
authorManfred Steiner <sx@htl-kaindorf.at>
Sat, 17 Aug 2024 10:22:06 +0000 (12:22 +0200)
committerManfred Steiner <sx@htl-kaindorf.at>
Sat, 17 Aug 2024 10:22:06 +0000 (12:22 +0200)
4 files changed:
software/nano-644/test_2024-07-23/src/i2cmaster.cpp
software/nano-644/test_2024-07-23/src/i2cmaster.hpp
software/nano-644/test_2024-07-23/src/units/rtc8563.cpp
software/nano-644/test_2024-07-23/src/units/rtc8563.hpp

index 9b1bd5dc36d86b57cbd5922daf7a83e4b7e3d3f3..ca883d67852c60adc9a163c370e5eb148a1df4c0 100644 (file)
@@ -1,4 +1,5 @@
 #include <avr/io.h>
+#include <avr/pgmspace.h>
 #include <stdio.h>
 
 #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;
index e70326c32dfda1f58a39b9cea0b3b6c46311ed3d..89b1e466c59dda5798ad23b3b99c85fcc274469d 100644 (file)
@@ -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);
 };
 
index 5dc07fde3c1a19d65f8b235197796a613612d73e..ea8821eb932e2a535cdd3c585df41f23b0d91fa0 100644 (file)
 
 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 *)&reg;
+      memset(&reg, 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, &reg.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) {
+
+   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, &reg.reg1.byte, 1) && rtc8563.writeByteAndBuffer(14, &reg.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 &reg) {
    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, &reg.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));
 }
 
index 07dbf441912d10ed1b30e5bd2ea9ec77064880e3..ca79713ec462912d0659e645f483ae33994f1df6 100644 (file)
@@ -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 &reg);
+      bool powerOnOff (uint8_t delayOffSeconds, Rtc8563Reg_t &reg);
       bool setClock (int8_t weekday, uint16_t year, int8_t month, int8_t day, int8_t hour, int8_t min, int8_t sec);
 };