Commit 6430d8c22b091b93b0e5f767c8a700da04d81e55
receivedMon, 5. Aug 2024, 07:25:24 (by user sx)
Mon, 5 Aug 2024 05:25:24 +0000 (07:25 +0200)
authorManfred Steiner <sx@htl-kaindorf.at>
Mon, 5 Aug 2024 05:25:17 +0000 (07:25 +0200)
committerManfred Steiner <sx@htl-kaindorf.at>
Mon, 5 Aug 2024 05:25:17 +0000 (07:25 +0200)
30 files changed:
software/arduino-nano-5v/test_2024-07-23/src/main.cpp
software/arduino-nano-5v/test_2024-07-23/src/main.hpp
software/arduino-nano-5v/test_2024-07-23/src/units/encoder.cpp
software/arduino-nano-5v/test_2024-07-23/src/units/encoder.hpp
software/arduino-nano-5v/test_2024-07-23/src/units/i2c.cpp
software/arduino-nano-5v/test_2024-07-23/src/units/i2c.hpp
software/arduino-nano-5v/test_2024-07-23/src/units/ieee485.cpp
software/arduino-nano-5v/test_2024-07-23/src/units/ieee485.hpp
software/arduino-nano-5v/test_2024-07-23/src/units/lcd.cpp
software/arduino-nano-5v/test_2024-07-23/src/units/lcd.hpp
software/arduino-nano-5v/test_2024-07-23/src/units/led.cpp
software/arduino-nano-5v/test_2024-07-23/src/units/led.hpp
software/arduino-nano-5v/test_2024-07-23/src/units/modbus.cpp [new file with mode: 0644]
software/arduino-nano-5v/test_2024-07-23/src/units/modbus.hpp [new file with mode: 0644]
software/arduino-nano-5v/test_2024-07-23/src/units/motor.cpp [new file with mode: 0644]
software/arduino-nano-5v/test_2024-07-23/src/units/motor.hpp [new file with mode: 0644]
software/arduino-nano-5v/test_2024-07-23/src/units/portexp.cpp [new file with mode: 0644]
software/arduino-nano-5v/test_2024-07-23/src/units/portexp.hpp [new file with mode: 0644]
software/arduino-nano-5v/test_2024-07-23/src/units/poti.cpp [new file with mode: 0644]
software/arduino-nano-5v/test_2024-07-23/src/units/poti.hpp [new file with mode: 0644]
software/arduino-nano-5v/test_2024-07-23/src/units/r2r.cpp [new file with mode: 0644]
software/arduino-nano-5v/test_2024-07-23/src/units/r2r.hpp [new file with mode: 0644]
software/arduino-nano-5v/test_2024-07-23/src/units/rgb.cpp [new file with mode: 0644]
software/arduino-nano-5v/test_2024-07-23/src/units/rgb.hpp [new file with mode: 0644]
software/arduino-nano-5v/test_2024-07-23/src/units/seg7.cpp [new file with mode: 0644]
software/arduino-nano-5v/test_2024-07-23/src/units/seg7.hpp [new file with mode: 0644]
software/arduino-nano-5v/test_2024-07-23/src/units/switch.cpp [new file with mode: 0644]
software/arduino-nano-5v/test_2024-07-23/src/units/switch.hpp [new file with mode: 0644]
software/arduino-nano-5v/test_2024-07-23/src/units/uart1.cpp [new file with mode: 0644]
software/arduino-nano-5v/test_2024-07-23/src/units/uart1.hpp [new file with mode: 0644]

index f5b0f3ec761ba9b342358cb7fb7f80d1473abd8f..23bcc90beb40376228fc14c7e470ba98f4ffd747 100644 (file)
 #include "units/ieee485.hpp"
 #include "units/led.hpp"
 #include "units/lcd.hpp"
-
-
-// #include "units/switch.hpp"
-// #include "units/rgb.hpp"
-// #include "units/seg7.hpp"
-// #include "units/poti.hpp"
-// #include "units/r2r.hpp"
-// #include "units/motor.hpp"
-// #include "units/portexp.hpp"
-// #include "units/uart1.hpp"
-// #include "units/modbus.hpp"
-
-
-
+#include "units/switch.hpp"
+#include "units/rgb.hpp"
+#include "units/seg7.hpp"
+#include "units/poti.hpp"
+#include "units/r2r.hpp"
+#include "units/motor.hpp"
+#include "units/portexp.hpp"
+#include "units/uart1.hpp"
+#include "units/modbus.hpp"
 
 extern "C" {
    void __cxa_pure_virtual () {
@@ -87,17 +82,17 @@ extern "C" {
    static volatile int keyUart0 = EOF;
 
    Led led;
-   // Switch sw;
-   // Rgb rgb;
-   // Seg7 seg7;
-   // Poti poti;
+   Switch sw;
+   Rgb rgb;
+   Seg7 seg7;
+   Poti poti;
    Encoder encoder;
-   // R2r r2r;
-   // Motor motor;
-   // PortExp portExp;
+   R2r r2r;
+   Motor motor;
+   PortExp portExp;
    Lcd lcd;
-   // Uart1 uart1;
-   // Modbus modbus;
+   Uart1 uart1;
+   Modbus modbus;
    Ieee485 ieee485;
    I2c i2cSparkfun(I2c::SparkFunEnvCombo);
    I2c i2cMaster(I2c::Master);
@@ -123,6 +118,7 @@ int wait (uint32_t ms) {
 
 int main () {
 
+   #ifdef __AVR_ATmega644P__
    // Nano-644 LEDs (Green, Orange, Red)
    DDRC |= (1 << DDC4) | (1 << DDC3) | (1 << DDC2);
    PORTC &= ~((1 << PORT4) | (1 << PORT3) | (1 << PORT2));
@@ -130,6 +126,12 @@ int main () {
    // Nano-644 push button SW2
    DDRC &= ~(1 << DDC5); 
    PORTC |= (1 << PORT5); // enable internal pullup resistor
+   #endif
+
+   #ifdef __AVR_ATmega328P__
+   DDRB |= (1 << PB5);
+   PORTB &= ~(1 << PB5);
+   #endif
 
    // UART0 interface on Nano-644
    UCSR0A = (1 << U2X0);
@@ -148,15 +150,19 @@ int main () {
 
    sei();
 
-   // TestUnit *unit[] = {
-   //    &led, &sw, &rgb, &seg7, &poti, &encoder, &r2r, &motor, &portExp, &lcd, &uart1, &modbus, &ieee485,
-   //    &i2cMaster, &i2cSlave, &i2cSparkfun
-   // };
+   #ifdef __AVR_ATmega644P__
+      TestUnit *unit[] = {
+         &led, &sw, &rgb, &seg7, &poti, &encoder, &r2r, &motor, &portExp, &lcd, &uart1, &modbus, &ieee485,
+         &i2cMaster, &i2cSlave, &i2cSparkfun
+      };
+   #endif
 
-   TestUnit *unit[] = {
-      &led, &encoder, &lcd,
-      &i2cMaster, &i2cSlave, &i2cSparkfun
-   };
+   #ifdef __AVR_ATmega328P__
+      TestUnit *unit[] = {
+         &led, &sw, &rgb, &seg7, &poti, &encoder, &r2r, &motor, &lcd,
+         &i2cMaster, &i2cSlave, &i2cSparkfun
+      };
+   #endif
 
    while (1) {
       uint16_t i;
@@ -176,9 +182,10 @@ int main () {
       } while (sscanf(s, "%x", &i) != 1 || i < 0 || i >= sizeof(unit) / sizeof(unit[0]) );
       
       TestUnit *pu = unit[i];
-      printf_P(PSTR("\n\n[%s]: "), pu->getName());
+      printf_P(PSTR("\n\n[")); printf_P(pu->getName()); printf_P(PSTR("]: "));
       keyUart0 = EOF;
 
+      pu->init();
       for (uint8_t subtest = 0; subtest < 0xff; subtest++) {
          printf_P(PSTR("\n%4d: "), subtest);
          if (pu->run(subtest) < 0) {
@@ -250,11 +257,9 @@ ISR (TIMER2_COMPA_vect) { // every 100us
    if (encoder.enabled) {
       encoder.tick100us();
    }
-   #ifdef MOTOR_HPP
-      if (motor.enabled) {
-         motor.tick100us();
-      }
-   #endif
+   if (motor.enabled) {
+      motor.tick100us();
+   }
 
    timer100us++;
    if (timer100us >= 10) {
@@ -270,7 +275,14 @@ ISR (TIMER2_COMPA_vect) { // every 100us
 
    timer500ms++;
    if (timer500ms >= 5000) {
-      PORTC ^= (1 << PORTC3); // orange LED blinking
+      #ifdef __AVR_ATmega644P__
+         PORTC ^= (1 << PC3); // orange LED blinking
+      #endif
+      #ifdef __AVR_ATmega328P__
+         if (!seg7.enabled) {
+            PORTB ^= (1 << PB5); // LED L
+         }
+      #endif
       timer500ms = 0;
    }
 }
index f60ec890c1581a98524d4e71330fe57aa32e357b..bef51b6ffc1712c8b8c60dcfa61ebff6f922fe75 100644 (file)
@@ -13,6 +13,7 @@ extern uint64_t millis ();
 class TestUnit {
    public:
       virtual int8_t run (uint8_t subtest) = 0;
+      virtual void init () = 0;
       virtual void cleanup () = 0;
       virtual PGM_P getName () = 0;
 };
index bc84f48f88eedfd21bf1c0ad49cc0988845ff748..975f35810a13f3f2f2addd4d397207f292cdf4bb 100644 (file)
@@ -4,10 +4,6 @@
 #include "encoder.hpp"
 #include "../main.hpp"
 
-// PB0/T0   ... Encoder A
-// PB1/T1   ... Encoder B
-// PB2/INT2 ... push switch of encoder (pushed = 0)
-
 // Encoder signals on rotation clockwise 1 step:
 // A -----____------  one char app. 1ms..2ms (rotation speed)
 // B -------___-----  
 // B --______-----  
 //                    one step when: A = 0, B= 0->1
 
+#ifdef __AVR_ATmega644P__
+
+   // Nano-644
+   // ---------------------------------------------------------------
+   // PB0/T0   ... Encoder A
+   // PB1/T1   ... Encoder B
+   // PB2/INT2 ... push switch of encoder (pushed = 0)
+
+   void Encoder::init () {
+      DDRB &= ~((1 << PB2) | (1 << PB1) | (1 << PB0));
+      PORTB |= (1 << PORTB2) | (1 << PORTB1) | (1 << PORTB0); // enable pullup
+      enabled = 1;
+   }
+   
+   void Encoder::cleanup () {
+      enabled = 0;
+      DDRB &= ~((1 << PB2) | (1 << PB1) | (1 << PB0));
+      PORTB &= ~((1 << PORTB2) | (1 << PORTB1) | (1 << PORTB0));
+   }
+
+   bool Encoder::isPressed () {
+      return (PINB & (1 << PB2)) == 0;
+   }
+
+   bool Encoder::getA () {
+      return (PINB & (1 << PB0)) == 0;
+   }
+
+   bool Encoder::getB () {
+      return (PINB & (1 << PB1)) == 0;
+   }
+
+
+#endif
+
+#ifdef __AVR_ATmega328P__
+
+   // Arduino-Nano-5V
+   // ---------------------------------------------------------------
+   // PD4/T0  ... Encoder A
+   // PB0     ... Encoder B
+   // PD7     ... push switch of encoder (pushed = 0)
+
+   void Encoder::init () {
+      DDRB &= ~(1 << PB0);
+      DDRD &= ~((1 << PD7) | (1 << PD4));
+      PORTB |= (1 << PB0); // enable pullup
+      PORTD |= (1 << PD7) | (1 << PD4); // enable pullup
+      enabled = 1;
+   }
+   
+   void Encoder::cleanup () {
+      enabled = 0;
+      PORTB &= ~(1 << PB0);
+      PORTD &= ~((1 << PD7) | (1 << PD4));
+      DDRB &= ~(1 << PB0);
+      DDRD &= ~((1 << PD7) | (1 << PD4));
+   }
+
+   bool Encoder::isPressed () {
+      return (PIND & (1 << PD7)) == 0;
+   }
+
+   bool Encoder::getA () {
+      return (PIND & (1 << PD4)) == 0;
+   }
+
+   bool Encoder::getB () {
+      return (PINB & (1 << PB0)) == 0;
+   }
+
+#endif
 
-void Encoder::cleanup () {
-   DDRB &= ~((1 << PB2) | (1 << PB1) | (1 << PB0));
-   PORTB &= ~((1 << PORTB2) | (1 << PORTB1) | (1 << PORTB0));
-   enabled = 0;
-}
 
 int8_t Encoder::run (uint8_t subtest) {
    switch (subtest) {
       case 0: {
-         printf_P(PSTR("init"));
-         DDRB &= ~((1 << PB2) | (1 << PB1) | (1 << PB0));
-         PORTB |= (1 << PORTB2) | (1 << PORTB1) | (1 << PORTB0); // enable pullup
-         enabled = 1;
-         return 0;
-      }
-
-      case 1: {
          while (wait(10) == EOF) {
             printf_P(PSTR("\r  => Encoder (push to clear): "));
             printf_P(PSTR("%5d (0x%02x) "), count, (uint8_t)count);
-            if ((PINB & (1 << PINB2)) == 0) {
+            if (isPressed()) {
                reset();
             }
          }
          return 0;
       }
-
-      case 2: {
-         printf_P(PSTR("end"));
-         break;
-      }
    }
 
    return -1;
 }
 
 struct EncoderState {
-   uint8_t a:1; // signal A
-   uint8_t b:1; // signal B
+   int8_t a:1; // signal A
+   int8_t b:1; // signal B
 };
 
 void Encoder::tick100us () {
    static EncoderState lastState = { 1, 1 };
    static EncoderState lastStableState = { 1, 1 };
 
-   if ((DDRB & 0x03) || (PORTB & 0x07) != 0x07) {
+   if (!enabled) {
       count = 0;
-      return; // Enocder pins not configured
+      return;
    }
-   EncoderState nextState = { (PINB & 0x01) == 0x01, (PINB & 0x02) == 0x02 };
+   EncoderState nextState;
+   nextState.a = getA() ? 1 : 0;
+   nextState.b = getB() ? 1 : 0;
    if (nextState.a == lastState.a && nextState.b == lastState.b) {
       if (lastStableState.a == 0 && nextState.b != lastStableState.b) {
          if (nextState.b == 0) {
index 10bcc0f71d3ea33bdf558e8fe24d705dda2a5b75..9b0861be437e6446c59f5a3e4a07b3d91ac4c52a 100644 (file)
@@ -12,11 +12,17 @@ class Encoder : public TestUnit {
 
    public:
       Encoder () { reset(); enabled = 0; };
+      virtual void init ();
       virtual void cleanup ();
       virtual int8_t run (uint8_t subtest);
       virtual PGM_P getName () { return PSTR("Encoder"); }
       void reset () { count = 0; }
       void tick100us ();
+      bool isPressed ();
+
+   private:
+      bool getA ();
+      bool getB ();
 };
 
 #endif
\ No newline at end of file
index 4c5934f50e4accee70f4b72e6f46260d6b57a84b..0c92e13601464d1484fca18ccaa79d019fef5737 100644 (file)
@@ -23,6 +23,16 @@ PGM_P I2c::getName () {
    return "?";
 }
 
+void I2c::init () {
+   TWBR = 13; // 100kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 100000) / (2 * 100000 * 4);
+   TWBR = 28; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4);
+   TWBR = 100; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4);
+   TWCR = (1 << TWEN);
+   ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V
+   ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128
+   enabled = true;
+}
+
 void I2c::cleanup () {
    enabled = false;
    TWCR = (1 << TWEN);
@@ -32,17 +42,7 @@ void I2c::cleanup () {
 }
 
 int8_t I2c::run (uint8_t subtest) {
-   if (subtest == 0) {
-      TWBR = 13; // 100kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 100000) / (2 * 100000 * 4);
-      TWBR = 28; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4);
-      TWBR = 100; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4);
-      TWCR = (1 << TWEN);
-      ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V
-      ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128
-      enabled = true;
-      printf_P(PSTR("init"));
-
-   } else if (subtest == 1 && mode == I2c::SparkFunEnvCombo) {
+   if (subtest == 0 && mode == I2c::SparkFunEnvCombo) {
       printf_P(PSTR(" BM280 ... "));
       if (!bm280.begin()) {
          printf_P(PSTR("E1"));
@@ -156,7 +156,7 @@ int8_t I2c::run (uint8_t subtest) {
 
       } while (wait(1000) == EOF);
 
-   } else if (subtest == 1 && mode == I2c::Master) {
+   } else if (subtest == 0 && mode == I2c::Master) {
       if (!master.begin(0x01)) {
          printf_P(PSTR("E1"));
          return -1;
@@ -180,7 +180,7 @@ int8_t I2c::run (uint8_t subtest) {
       } while (wait(1000) == EOF);
       master.end();
 
-   } else if (subtest == 1 && mode == I2c::Slave) {
+   } else if (subtest == 0 && mode == I2c::Slave) {
       if (!slave.begin(0x01, false)) {
          printf_P(PSTR("E1"));
          return -1;
@@ -214,87 +214,3 @@ void I2c::handleTwiIrq () {
       TWCR |= (1 << TWINT); // clear Interrupt Request
    }
 }
-
-// uint16_t I2c::startRead (uint8_t address) {
-//    TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); // send START condition
-//    while (!(TWCR & (1 << TWINT))) {}; // wait until last action done
-//    uint8_t sr = TWSR & 0xf8;
-//    if (sr != 0x08 && sr != 0x10) {
-//       return 0x0100 | sr;
-//    }
-
-//    TWDR = (address << 1) | 0x01; // address + READ (R/W = 1)
-//    TWCR = (1 << TWINT) | (1 << TWEN); // send address/RW
-//    while (!(TWCR & (1 << TWINT))) {}; // wait until last action done
-//    sr = TWSR & 0xf8;
-//    if (sr != 0x40) {
-//       return 0x0200 | sr;
-//    }
-//    return 0;
-// }
-
-// uint16_t I2c::startWrite (uint8_t address) {
-//    TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); // send START condition
-//    while (!(TWCR & (1 << TWINT))) {}; // wait until last action done
-//    uint8_t sr = TWSR & 0xf8;
-//    if (sr != 0x08 && sr != 0x10) {
-//       return 0x0300 | sr;
-//    }
-
-//    TWDR = (address << 1) | 0x00; // address + WRITE (R/W = 0)
-//    TWCR = (1 << TWINT) | (1 << TWEN); // send address/RW
-//    while (!(TWCR & (1 << TWINT))) {}; // wait until last action done
-//    sr = TWSR & 0xf8;
-//    if (sr != 0x18) {
-//       return 0x0400 | sr;
-//    }
-//    return 0;
-// }
-
-// void I2c::stop () {
-//    TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
-// }
-
-// uint16_t I2c::writeData (uint8_t size, const uint8_t *data) {
-//    while (size-- > 0) {
-//       TWDR = *data++;
-//       TWCR = (1 << TWINT) | (1 << TWEN); // send data byte
-//       while (!(TWCR & (1 << TWINT))) {}; // wait until last action done
-//       uint8_t sr = TWSR & 0xf8;
-//       if (sr != 0x28) {
-//          return 0x0500 | sr;
-//       }
-//    }
-//    return 0;
-// }
-
-// uint16_t I2c::writeByte (uint8_t data) {
-//    return writeData(1, &data);
-// }
-
-// uint16_t I2c::readData (uint8_t size, uint8_t *data) {
-//    while (size-- > 0) {
-//       if (size > 0) {
-//          TWCR = (1 << TWEA) | (1 << TWINT) | (1 << TWEN); // read data byte with ACK enabled
-//       } else {
-//          TWCR = (1 << TWINT) | (1 << TWEN); // read data byte with ACK disabled
-//       }
-//       while (!(TWCR & (1 << TWINT))) {}; // wait until last action done
-//       uint8_t sr = TWSR & 0xf8;
-//       if ((size > 0 && sr != 0x50) || (size == 0 && sr != 0x58)) {
-//          return 0x0600 | sr;
-//       }
-//       *data++ = TWDR;
-//    }
-//    return 0;
-// }
-
-// int32_t I2c::compensateBm280T (int32_t adcT) {
-//    // int32_t var1, var2, t;
-//    // var1 = ((((adcT >> 3) - ((int32_t)bm280.digT[0] << 1))) * ((int32_t)bm280.digT[1])) >> 11;
-//    // var2 = (((((adcT >> 4) - ((int32_t)bm280.digT[0])) * ((adcT >> 4) - ((int32_t)bm280.digT[0]))) >> 12) * ((int32_t)bm280.digT[2])) >> 14;
-//    // bm280.tFine = var1 + var2;
-//    // t = (bm280.tFine * 5 + 128) >> 8;
-//    // return t;
-//    return -1;
-// }
index e1f1802118e264ee9f60d29aee54a4a708311805..f039366e0a81a68eee54875db557f63216c46b86 100644 (file)
@@ -26,6 +26,7 @@ class I2c : public TestUnit {
    public:
       I2c (I2cMode mode) { enabled = false; this->mode = mode; }
       void tick1ms () { master.tick1ms(); slave.tick1ms(); }
+      virtual void init ();
       virtual void cleanup ();
       virtual int8_t run (uint8_t subtest);
       virtual PGM_P getName ();
index 414efb2d03b2086cf5d4ddaaeee676a94ec0eadf..3d0bfca1d5d90ca9796236833156fede330c5817 100644 (file)
@@ -12,6 +12,7 @@
 // ------------------------------------
 // IEE485 not supported (no UART1)
 
+void Ieee485::init () {}
 void Ieee485::cleanup () {}
 int8_t Ieee485::run (uint8_t subtest) {
    return -1;
@@ -32,6 +33,29 @@ int8_t Ieee485::run (uint8_t subtest) {
 #define SET_DE   (PORTB |= (1 << PB1))
 #define CLR_DE   (PORTB &= ~(1 << PB1))
 
+void Ieee485::init () {
+   // Poti
+   ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V
+   ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128
+
+   // Modbus
+   SET_nRE;
+   CLR_DE;
+   DDRB |= (1 << PB1) | (1 << PB0);
+
+   // UART1 interface on Nano-644
+   PORTD |= (1 << PD2); // enable RxD1 pullup
+   UCSR1A = (1 << U2X1);
+   UCSR1B = (1 << RXCIE1) | (1 << RXEN1) | (1 <<TXEN1);
+   UCSR1C = (1 << UCSZ11) | ( 1<< UCSZ10);
+   // UCSR1C |= (1 <<UPM11); // even Parity
+   // UCSR1C |= (1 << UPM11) | (1 << UPM10); // odd Parity
+   UBRR1H = 0;
+   UBRR1L = F_CPU / 8 / 9600 - 1;
+
+   enabled = 1;
+}
+
 void Ieee485::cleanup () {
    enabled = 0;
 
@@ -50,29 +74,6 @@ void Ieee485::cleanup () {
 
 int8_t Ieee485::run (uint8_t subtest) {
    if (subtest == 0) {
-      // Poti
-      ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V
-      ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128
-
-      // Modbus
-      SET_nRE;
-      CLR_DE;
-      DDRB |= (1 << PB1) | (1 << PB0);
-
-      // UART1 interface on Nano-644
-      PORTD |= (1 << PD2); // enable RxD1 pullup
-      UCSR1A = (1 << U2X1);
-      UCSR1B = (1 << RXCIE1) | (1 << RXEN1) | (1 <<TXEN1);
-      UCSR1C = (1 << UCSZ11) | ( 1<< UCSZ10);
-      // UCSR1C |= (1 <<UPM11); // even Parity
-      // UCSR1C |= (1 << UPM11) | (1 << UPM10); // odd Parity
-      UBRR1H = 0;
-      UBRR1L = F_CPU / 8 / 9600 - 1;
-
-      enabled = 1;
-      printf_P(PSTR("init"));
-
-   } else if (subtest == 1) {
       CLR_nRE; CLR_DE;
       while (wait(500) == EOF) {
          ADCSRA |= (1 << ADSC); // start ADC
index 677963f04dcc12219a4110003b43aeb6391d4423..ffbb15c8fcf62c31f7b64c435ec2fbf3d0922144 100644 (file)
@@ -12,6 +12,7 @@ class Ieee485 : public TestUnit {
 
    public:
       Ieee485 () { enabled = 0; receivedByte = -1; }
+      virtual void init ();
       virtual void cleanup ();
       virtual int8_t run (uint8_t subtest);
       virtual const char *getName () { return PSTR("IEEE485"); }
index fa2487982a7ac4416c5997ec2e2b4430c06d06e8..32188425137000ee0792c96f6598c7ee2dc1f284 100644 (file)
       #define DATA_PIN  PINB
    #endif
 
-   void Lcd::initDDR () {
+   void Lcd::init () {
       DDRA |=  (1 << PA3);
       DDRB = 0xff;
       DDRD |= (1 << PD7) | (1 << PD6);
+      initLcd();
+      #ifdef LCD_3V3
+         printf_P(PSTR("init 3.3V LCD"));
+      #else
+         printf_P(PSTR("init 5V LCD"));
+      #endif
    }
 
    void Lcd::cleanup () {
    // PB4 ..... Data6
    // PB5 ..... Data7
 
-   void Lcd::initDDR () {
+   void Lcd::init () {
+      clrRW();
+      clrRS();
+      clrE();
+      setData(0);
       DDRB |= (1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB0);
+      DDRC |= (1 << PC3);
       DDRD |= (1 << PD7) | (1 << PD6) | (1 << PD4) | (1 << PD3) | (1 << PD2);
+      initLcd();
+      #ifdef LCD_3V3
+         printf_P(PSTR("init 3.3V LCD"));
+      #else
+         printf_P(PSTR("init 5V LCD"));
+      #endif
    }
    
    void Lcd::cleanup () {
+      clrRW();
+      clrRS();
+      clrE();
+      setData(0);
       DDRB &= ~((1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB0));
+      DDRC &= ~(1 << PC3);
       DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD4) | (1 << PD3) | (1 << PD2));
    }
 
 
 int8_t Lcd::run (uint8_t subtest) {
    if (subtest == 0) {
-      init();
-      #ifdef LCD_3V3
-         printf_P(PSTR("init 3.3V LCD"));
-      #else
-         printf_P(PSTR("init 5V LCD"));
-      #endif
-
-   } else if (subtest == 1) {
       for (uint8_t i = 0; i < 20 * 4; i++) {
          char c = (char)(i + 32);
          if (i % 20 == 0) {
@@ -137,12 +151,7 @@ int8_t Lcd::run (uint8_t subtest) {
    return 0;
 }
 
-void Lcd::init () {
-   clrRW();
-   clrRS();
-   clrE();
-   setData(0);
-   initDDR();
+void Lcd::initLcd () {
    _delay_ms(16); // min 15ms warten für Reset des Displays
 
    setData( 0b00111011 );   // 8bit Modus, 5x7 Zeichen, Mehrzeilen Display
@@ -192,12 +201,10 @@ uint8_t Lcd::isBusy () {
       // DIR_DATA_PORT = 0xff;
       // return busy != 0;
       _delay_us(200);
-      return 0;
    #else
       _delay_us(200);
-      return 0;
    #endif
-   
+   return 0;   
 }
 
 void Lcd::writeCommand (uint8_t cmd) {
@@ -207,7 +214,7 @@ void Lcd::writeCommand (uint8_t cmd) {
    setE();                  // E = 1 (transfer start)
    _delay_us(10);                // min. 10us 
    clrE();                  // E = 0 (transfer end)
-   writeData(0);
+   setData(0);
 }
 
 void Lcd::setDDRamAddr (uint8_t address) {
@@ -218,7 +225,7 @@ void Lcd::setDDRamAddr (uint8_t address) {
    _delay_us(10);                // min. 10us 
    clrE();                  // E = 0 (transfer end)
    _delay_us(10);           // min. 10us
-   writeData(0);
+   setData(0);
 }
 
 void Lcd::writeString (const char *s) {
@@ -237,7 +244,7 @@ void Lcd::writeData (uint8_t data) {
    clrE();                  // E = 0 (transfer end)
    _delay_us(10);           // min. 10us
    clrRS();
-   writeData(0);
+   setData(0);
 }
 
 void Lcd::setCursor (uint8_t row, uint8_t column) {
index 142a13f4f7da1ec17bdcfb2e104e9c610d298708..3eb445694a5a55f21e0fb8b42ec3e2bd425927cd 100644 (file)
@@ -8,13 +8,13 @@
 class Lcd : public TestUnit {
    public:
       Lcd () {};
+      virtual void init ();
       virtual void cleanup ();
       virtual int8_t run (uint8_t subtest);
       virtual PGM_P getName () { return PSTR("Lcd"); }
    
    private:
-      void init ();
-      void initDDR ();
+      void initLcd ();
       uint8_t isBusy ();
       void writeCommand (uint8_t);
       void setDDRamAddr (uint8_t);
index 6dc625342c7f860715a29653fd54990089ef794c..c3175c172168c898568d1560e9f1df06ec0968a4 100644 (file)
@@ -14,7 +14,8 @@
    // PD6 ..... Green
    // PD7 ..... Blue
 
-   void Led::initDDR () {
+   void Led::init () {
+      PORTD &= ~((1 << PD7) | (1 << PD6) | (1 << PD5) | (1 << PD4));
       DDRD |= (1 << PD7) | (1 << PD6) | (1 << PD5) | (1 << PD4);
    }
 
    }
 
    void Led::ledToggle (LED led) {
-      case RED: PORTD ^= (1 << PD4); break;
-      case ORANGE: PORTD ^= (1 << PD5); break;
-      case GREEN: PORTD ^= (1 << PD6); break;
-      case BLUE: PORTD ^= (1 << PD7); break;
+      switch(led) {
+         case RED: PORTD ^= (1 << PD4); break;
+         case ORANGE: PORTD ^= (1 << PD5); break;
+         case GREEN: PORTD ^= (1 << PD6); break;
+         case BLUE: PORTD ^= (1 << PD7); break;
+      }
    }
 
 #endif
@@ -59,7 +62,9 @@
    // PD3 ..... Green
    // PD2 ..... Blue
 
-   void Led::initDDR () {
+   void Led::init () {
+      PORTD &= ~((1 << PD5) | (1 << PD3) | (1 << PD2));
+      PORTB &= ~(1 << PB1);
       DDRD |= (1 << PD5) | (1 << PD3) | (1 << PD2);
       DDRB |= (1 << PB1);
    }
@@ -110,25 +115,19 @@ void Led::ledOff (LED led) {
 
 
 int8_t Led::run (uint8_t subtest) {
-   if (subtest == 0) {
-      initDDR();
-      printf_P(PSTR("init"));
-
-   } else if (subtest <= 16) {
-      subtest = (subtest - 1) % 4;
+   if (subtest <= 15) {
+      subtest = (subtest) % 4;
       switch (subtest) {
          case 0: ledOff(BLUE); ledOn(RED); break;
          case 1: ledOff(RED); ledOn(ORANGE); break;
          case 2: ledOff(ORANGE); ledOn(GREEN); break;
          case 3: ledOff(GREEN); ledOn(BLUE); break;
       }
-      printf_P(PSTR("Test LED PD%d"), subtest + 4);
-
-   } else {
-      printf_P(PSTR("end"));
-      return -1;
+      printf_P(PSTR("Test LED D%d"), subtest + 1);
+      wait(500);
+      return 0;
    }
-   wait(500);
-   return 0;
+   
+   return -1;
 }
 
index 0a28f2d44b4b51c022842ea85819d28ba2f2b503..780827f4490f72329849ff7530961ee15b32df7f 100644 (file)
@@ -9,9 +9,9 @@ class Led : public TestUnit {
    public:
       enum LED { RED, ORANGE, GREEN, BLUE };
 
-
    public:
       Led () {};
+      virtual void init ();
       virtual void cleanup ();
       virtual int8_t run (uint8_t subtest);
       virtual PGM_P getName () { return PSTR("Led"); }
@@ -20,9 +20,6 @@ class Led : public TestUnit {
       void ledOn (LED led);
       void ledOff (LED led);
       void ledToggle (LED led);
-
-   private:
-      void initDDR ();
 };
 
 #endif
\ No newline at end of file
diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/modbus.cpp b/software/arduino-nano-5v/test_2024-07-23/src/units/modbus.cpp
new file mode 100644 (file)
index 0000000..9faf8db
--- /dev/null
@@ -0,0 +1,160 @@
+#include <stdio.h>
+#include <avr/io.h>
+#include <util/delay.h>
+
+#include "modbus.hpp"
+#include "../main.hpp"
+
+
+#ifdef __AVR_ATmega328P__
+void Modbus::init () {}
+void Modbus::cleanup () {}
+int8_t Modbus::run (uint8_t subtest) { return -1; }
+void Modbus::handleRxByte (uint8_t b) {}
+#endif
+
+#ifdef __AVR_ATmega644P__
+
+// PB0 ... nRE .. Read enable
+// PB1 ...  DE .. Data enable
+
+#define SET_nRE  (PORTB |= (1 << PB0))
+#define CLR_nRE  (PORTB &= ~(1 << PB0))
+#define SET_DE   (PORTB |= (1 << PB1))
+#define CLR_DE   (PORTB &= ~(1 << PB1))
+
+
+void Modbus::init () {
+}
+
+void Modbus::cleanup () {
+   enabled = 0;
+   UCSR1A = 0;
+   UCSR1B = 0;
+   UCSR1C = 0;
+   UBRR1H = 0;
+   UBRR1L = 0;
+   PORTD &= ~(1 << PD2);
+   DDRB &= ~((1 << PB1) | (1 << PB0));
+   PORTB &= ~((1 << PB1) | (1 << PB0));
+}
+
+int8_t Modbus::run (uint8_t subtest) {
+   if (subtest == 0) {
+      SET_nRE;
+      CLR_DE;
+      DDRB |= (1 << PB1) | (1 << PB0);
+
+      // UART1 interface on Nano-644
+      PORTD |= (1 << PD2); // enable RxD1 pullup
+      UCSR1A = (1 << U2X1);
+      UCSR1B = (1 << RXCIE1) | (1 << RXEN1) | (1 <<TXEN1);
+      UCSR1C = (1 << UCSZ11) | ( 1<< UCSZ10);
+      // UCSR1C |= (1 <<UPM11); // even Parity
+      // UCSR1C |= (1 << UPM11) | (1 << UPM10); // odd Parity
+      UBRR1H = 0;
+      UBRR1L = F_CPU / 8 / 9600 - 1;
+
+      enabled = 1;
+      printf_P(PSTR("init"));
+
+   } else if (subtest >= 1 && subtest <= 4) {
+      uint8_t nre, de, b;
+      switch (subtest) {
+         case 1: nre = 1; de = 0; b = 0x01; break;
+         case 2: nre = 1; de = 1; b = 0x8e; break;
+         case 3: nre = 0; de = 0; b = 0x55; break;
+         case 4: nre = 0; de = 1; b = 0xaa; break;
+         default: return -1;
+      }
+      printf_P(PSTR(" DE=%u, nRE=%u send 0x%02x... "), de, nre, b);
+      if (nre) {
+         SET_nRE;
+      } else {
+         CLR_nRE;
+      }
+      if (de) {
+         SET_DE;
+      } else {
+         CLR_DE;
+      }
+      _delay_us(100);
+      receivedBytes = 0;
+      UDR1 = b;
+      _delay_ms(1);
+      if (receivedBytes > 0) {
+         printf_P(PSTR("0x%02x received"), received[0]);
+         receivedBytes = 0;
+      } else {
+         printf_P(PSTR("no byte received"));
+      }
+      printf_P(PSTR(" ... press key to proceed"));
+      while (wait(0xffffffff) == EOF) {}
+      CLR_DE;
+      SET_nRE;
+
+   } else if (subtest == 5) {
+      static uint8_t frame[] = { 0x01, 0x04, 0x00, 0x00, 0x00, 0x02, 0x71, 0xcb };
+      printf_P(PSTR("Modbus: lese Spannung von Eastron SDM-230 (Einphasenzähler)"));
+      SET_DE;
+      CLR_nRE;
+      _delay_us(100);
+      do {
+         SET_DE;
+         receivedBytes = 0;
+         for (uint8_t i = 0; i < sizeof(frame); i++) {
+            UCSR1A |= (1 << TXC1);
+            UDR1 = frame[i];
+            while ((UCSR1A & (1 <<UDRE1)) == 0) {}
+         }
+         while ((UCSR1A & (1 << TXC1)) == 0) {}
+         CLR_DE;
+         printf_P(PSTR("\n => Sending:"));
+         for (uint8_t i = 0; i < sizeof(frame); i++) {
+            printf_P(PSTR(" 0x%02x"), frame[i]);
+         }
+         int k = wait(100);
+      
+         printf_P(PSTR("\n       RxD1:"));
+         if (receivedBytes == 0) {
+            printf_P(PSTR("?"));
+         } else {
+            for (uint8_t i = 0; i < receivedBytes; i++) {
+               if (i == sizeof(frame)) {
+                  printf_P(PSTR("  "));
+               }
+               printf_P(PSTR(" 0x%02x"), received[i]);
+            }
+         }
+         if (receivedBytes >= 16) {
+            union {
+               uint8_t b[4];
+               float value;
+            } f;
+            f.b[0] = received[14];
+            f.b[1] = received[13];
+            f.b[2] = received[12];
+            f.b[3] = received[11];
+            printf_P(PSTR(" -> %4.8fV\n"), (double)f.value);
+         }
+         if (k != EOF) {
+            break;
+         }
+         
+      } while (wait(1000) == EOF);
+
+   } else {
+      printf_P(PSTR("end"));
+      return -1;
+   }
+   wait(500);
+   return 0;
+}
+
+void Modbus::handleRxByte (uint8_t b) {
+   if (receivedBytes < sizeof(received)) {
+      received[receivedBytes++] = b;
+   }
+}
+
+#endif
\ No newline at end of file
diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/modbus.hpp b/software/arduino-nano-5v/test_2024-07-23/src/units/modbus.hpp
new file mode 100644 (file)
index 0000000..44b6a9d
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef MODBUS_HPP
+#define MODBUS_HPP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+class Modbus : public TestUnit {
+   public:
+      uint8_t  enabled;
+      uint8_t  receivedBytes;
+      uint8_t  received[16];
+
+
+   public:
+      Modbus () { enabled = 0; receivedBytes = 0; }
+      virtual void init ();
+      virtual void cleanup ();
+      virtual int8_t run (uint8_t subtest);
+      virtual PGM_P getName () { return PSTR("Modbus"); }
+      void handleRxByte (uint8_t);
+};
+
+#endif
\ No newline at end of file
diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/motor.cpp b/software/arduino-nano-5v/test_2024-07-23/src/units/motor.cpp
new file mode 100644 (file)
index 0000000..eac61bb
--- /dev/null
@@ -0,0 +1,207 @@
+#include <stdio.h>
+#include <avr/io.h>
+#include <util/atomic.h>
+
+#include "motor.hpp"
+#include "../main.hpp"
+
+#ifdef __AVR_ATmega644P__
+
+   // Nano-644
+   // ---------------------------------------------------------------
+   // PB0 ..... rotation-sensor
+   // PB2 ..... nFault
+   // PB3 ..... PWM (OC0A)
+   // PB4 ..... EN
+   // PA3 ..... SW3 -> push button for Motor enable control
+
+   #define ADC0K 64 
+
+   void Motor::init () {
+      ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V
+      ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128
+      TCCR0A = (1 << COM0A1) | (1 << WGM01) | (1 << WGM00); // Fast PWM on OC0A
+      // TCCR0B = (1 << CS02) | ( 1 << CS00); // f = 12 MHz / 1024 = 11,71875 kHz -> fPWM=45Hz
+      TCCR0B = (1 << CS02); // f = 12 MHz / 256 = 46,875 kHz -> fPWM=183,1Hz
+      DDRB |= (1 << PB4) | (1 << PB3); // Motor enable
+      PORTA |= (1 << PORTA3); // push button for Motor enable control
+      setEnable();
+      enabled = 1;
+   }
+
+   void Motor::cleanup () {
+      ADMUX = 0;
+      ADCSRA = 0;
+      TCCR0A = 0;
+      TCCR0B = 0;
+      DDRB &= ~((1 << PB4) | (1 << PB3));
+      PORTA &= ~(1 << PORTA3);
+      enabled = 0;
+   }
+
+   bool Motor::isSW3Pressed () {
+      return (PINA & (1 << PC3)) == 0;
+   }
+
+   void Motor::clearEnable () {
+      PORTB &= ~(1 << PB4);
+   }
+
+   void Motor::setEnable () {
+      PORTB |= (1 << PB4);
+   }
+
+   bool Motor::isFaultLow () {
+      return (PINB & (1 << PB2)) == 0;
+   }
+
+   bool Motor::isSensorHigh () {
+      return (PINB & (1 << PB0)) != 0;
+   }
+#endif 
+
+#ifdef __AVR_ATmega328P__
+
+   // Arduino-Nano-5V
+   // ---------------------------------------------------------------
+   // PD4       ..... rotation-sensor
+   // PD7       ..... nFault
+   // PD6/OC0A  ..... PWM
+   // PB2       ..... EN
+   // PC3       ..... SW3 -> push button for Motor enable control
+
+   #define ADC0K 91
+
+   void Motor::init () {
+      ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=5V
+      ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128
+      TCCR0A = (1 << COM0A1) | (1 << WGM01) | (1 << WGM00); // Fast PWM on OC0A
+      // TCCR0B = (1 << CS02) | ( 1 << CS00); // f = 16 MHz / 1024 = 15,625 kHz -> fPWM=61.04Hz
+      TCCR0B = (1 << CS02); // f = 16 MHz / 256 = 62.5 kHz -> fPWM=244.14Hz
+      DDRB |= (1 << PB2);
+      DDRC &= ~(1 << PC3);
+      DDRD |= (1 << PD6);
+      DDRD &= ~((1 << PD4) | (1 << PD7));
+      PORTC |= ( 1 << PC3);
+      PORTD |= (1 << PD7) | (1 << PD5); 
+      setEnable();
+      enabled = 1;
+   }
+
+   void Motor::cleanup () {
+      enabled = 0;
+      ADMUX = 0;
+      ADCSRA = 0;
+      TCCR0A = 0;
+      TCCR0B = 0;
+      clearEnable();
+      DDRB &= ~((1 << PB2));
+      DDRC &= ~(1 << PC3);
+      DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD4));
+      PORTC &= ~( 1 << PC3);
+      PORTD &= ~((1 << PD7) | (1 << PD6));
+   }
+
+   bool Motor::isSW3Pressed () {
+      return (PINC & (1 << PC3)) == 0;
+   }
+
+   void Motor::clearEnable () {
+      PORTB &= ~(1 << PB2);
+   }
+
+   void Motor::setEnable () {
+      PORTB |= (1 << PB2);
+   }
+
+   bool Motor::isFaultLow () {
+      return (PIND & (1 << PD7)) == 0;
+   }
+
+   bool Motor::isSensorHigh () {
+      return (PIND & (1 << PD4)) != 0;
+   }
+
+#endif
+
+int8_t Motor::run (uint8_t subtest) {
+   switch (subtest) {
+      case 0: {
+         printf_P(PSTR("\n"));
+         while (wait(10) == EOF) {
+
+            printf_P(PSTR("\r SW3=%d->"), isSW3Pressed() ? 0 : 1);
+            if (isSW3Pressed()) {
+               clearEnable();
+               printf_P(PSTR("EN=0"));
+            } else {
+               setEnable();
+               printf_P(PSTR("EN=1"));
+            }
+
+            ADCSRA |= (1 << ADSC); // start ADC
+            while (ADCSRA & (1 << ADSC)) {} // wait for result
+            printf_P(PSTR("\r  => ADC0=%3d"), ADCH);
+
+            ADMUX = (1 << ADLAR) | (1 << REFS1) | (1 << REFS0) | 2; // ADC2, VREF=2.5V
+
+            int16_t x = ((int16_t)(ADCH) - 5) * ADC0K / 64;
+            if (x < 0) x = 0; else if (x > 255) x = 255;
+            uint8_t dutyCycle = 0xff - (uint8_t)x;
+            if (dutyCycle <= 1) {
+               dutyCycle = 0;
+            } else if (dutyCycle > 254) {
+               dutyCycle = 255;
+            }
+            OCR0A = dutyCycle;
+            printf_P(PSTR("  PWM/OC0A=%3d"), dutyCycle);
+
+            ADCSRA |= (1 << ADSC); // start ADC
+            while (ADCSRA & (1 << ADSC)) {} // wait for result
+            printf_P(PSTR(" ADC2=%3d"), ADCH);
+            ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V
+
+            printf_P(PSTR(" nFAULT=%d"), isFaultLow() ? 0 : 1);
+            printf_P(PSTR(" SENSOR=%d "), isSensorHigh());
+            uint16_t timer;
+            ATOMIC_BLOCK(ATOMIC_FORCEON) {
+               timer = rpmTimer;
+            }
+            float rpm = 60.0 / (float)timer / 0.0001;
+            if (timer > 0) {
+               printf_P(PSTR("  n= %4d U/min"), (int)rpm);
+            } else {
+               printf_P(PSTR("  no rotation   "));
+            }
+
+         }
+         return 0;
+      }
+   }
+
+   return -1;
+}
+
+void Motor::tick100us () {
+   static uint16_t timerH = 0;
+   static uint16_t timerL = 0;
+   static bool lastSensorHigh = false;
+
+   bool sensorHigh = isSensorHigh();
+   if (!sensorHigh && sensorHigh != lastSensorHigh && timerL > 10) {
+      rpmTimer = timerL + timerH;
+      timerL = 0;
+      timerH = 0;
+   }
+   if (sensorHigh) {
+      timerH = timerH < 0x4000 ? timerH + 1 : 0x4000;
+   } else {
+      timerL = timerL < 0x4000 ? timerL + 1 : 0x4000;
+   }
+   if (timerH >= 0x4000 || timerL >= 0x4000) {
+      rpmTimer = 0; // no ratation detected
+   }
+   lastSensorHigh = sensorHigh;
+}
+
+
diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/motor.hpp b/software/arduino-nano-5v/test_2024-07-23/src/units/motor.hpp
new file mode 100644 (file)
index 0000000..6dc68f0
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef MOTOR_HPP
+#define MOTOR_HPP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+class Motor : public TestUnit {
+   public:
+      uint8_t  enabled;
+      uint16_t rpmTimer;
+
+   public:
+      Motor () { enabled = 0; rpmTimer = 0; };
+      virtual void init ();
+      virtual void cleanup ();
+      virtual int8_t run (uint8_t subtest);
+      virtual PGM_P getName () { return PSTR("Motor"); }
+      void tick100us ();
+
+   private:
+      bool isSW3Pressed ();
+      void clearEnable ();
+      void setEnable ();
+      bool isFaultLow ();
+      bool isSensorHigh ();
+};
+
+#endif
\ No newline at end of file
diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/portexp.cpp b/software/arduino-nano-5v/test_2024-07-23/src/units/portexp.cpp
new file mode 100644 (file)
index 0000000..409d1f8
--- /dev/null
@@ -0,0 +1,169 @@
+#include <stdio.h>
+#include <avr/io.h>
+#include <util/delay.h>
+
+#include "portexp.hpp"
+#include "../main.hpp"
+
+// Port-Expander MCP23S17
+
+// SN-Print Stecker IO16
+// MCP23S17 | IO16 (MEGA2560) | Ampel-Print |   | MCP23S17 | IO16 (MEGA2560) | Ampel-Print |
+// ------------------------------------------   --------------------------------------------
+//     GPA0 |   IO16O7 (PA7)  | Taster RU   |   |     GPB0 |   IO16U7 (PC7)  | Taster LU   |
+//     GPA1 |   IO16O6 (PA6)  | Taster RO   |   |     GPB1 |   IO16U6 (PC6)  | Taster LO   |
+//     GPA2 |   IO16O5 (PA5)  | U-Gruen     |   |     GPB2 |   IO16U5 (PC5)  | R-Gruen     |
+//     GPA3 |   IO16O4 (PA4)  | U-Gelb      |   |     GPB3 |   IO16U4 (PC4)  | R-Gelb      |
+//     GPA4 |   IO16O3 (PA3)  | U-Rot       |   |     GPB4 |   IO16U3 (PC3)  | R-Rot       |
+//     GPA5 |   IO16O2 (PA2)  | L-Gruen     |   |     GPB5 |   IO16U2 (PC2)  | O-Gruen     |
+//     GPA6 |   IO16O1 (PA1)  | L-Gelb      |   |     GPB6 |   IO16U1 (PC1)  | O-Gelb      |
+//     GPA7 |   IO16O0 (PA0)  | L-Rot       |   |     GPB7 |   IO16U0 (PC0)  | O-Rot       |
+
+#ifdef __AVR_ATmega644P__
+
+   // Nano-644
+   // --------------------------------------------------------
+   // PA7 ... nCS
+   // PB5 ... MOSI
+   // PB6 ... MISO
+   // PB7 ... SCK
+
+   void PortExp::init () {
+      PRR &= (1 << PRSPI);
+      PORTA |= (1 << PA7);
+      DDRA |= (1 << PA7); // SPI nCS
+      // PORTB/DDRB must be configured before SPCR !!
+      PORTB |= (1 << PB4); // nSS must be HIGH, otherwise SPI master will not become active!!
+      DDRB |= (1 << PB7) | (1 << PB5) | (1 << PB4); // SPI SCK (=PB7) and SPI MOSI (=PB5)
+
+      // SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); // SPI enable , Master, f=12MHz/128=93,75kHz
+      SPCR = (1 << SPE) | (1 << MSTR); // SPI enable , Master, f=12MHz/4 = 3MHz
+   }
+
+   void PortExp::cleanup () {
+      DDRB &= ~(1 << PB6); // // SPI MISO (=PB6)
+      DDRB &= ~((1 << PB7) | (1 << PB5)); // SPI SCK (=PB7) and SPI MOSI (=PB5)
+      DDRA &= ~(1 << PA7);
+      PORTA &= ~(1 << PA7); // SPI nCS
+      SPCR = 0;
+   }
+
+   void PortExp::setChipEnable () {
+      PORTA &= ~(1 << PA7);
+   }
+
+   void PortExp::clearChipEnable () {
+      PORTA |= (1 << PA7);
+   }
+
+
+#endif
+
+#ifdef __AVR_ATmega328P__
+
+   // Arduino-Nano-5V
+   // ------------------------------------
+   // PC1 ... nCS    (MANUAL (!) connection PA1 - PA7 required)
+   // PB3 ... MOSI
+   // PB4 ... MISO
+   // PB5 ... SCK
+
+   void PortExp::init () {
+      PRR &= (1 << PRSPI);
+      PORTC |= (1 << PC1);
+      DDRC |= (1 << PC1); // SPI nCS
+      // PORTB/DDRB must be configured before SPCR !!
+      PORTB |= (1 << PB2); // nSS must be HIGH, otherwise SPI master will not become active!!
+      DDRB |= (1 << PB5) | (1 << PB3) | (1 << PB2); // SPI SCK (=PB5), SPI MOSI (=PB3), SPI nSS (=PB2)
+
+      // SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); // SPI enable , Master, f=16MHz/128=125kHz
+      SPCR = (1 << SPE) | (1 << MSTR); // SPI enable , Master, f=12MHz/4 = 3MHz
+   }
+
+   void PortExp::cleanup () {
+      PORTC &= ~(1 << PC1);
+      DDRC &= ~(1 << PC1);
+      PORTB &= ~(1 << PB2);
+      DDRB &= ~((1 << PB5) | (1 << PB3) | (1 << PB2));
+      SPCR = 0;
+   }
+
+   void PortExp::setChipEnable () {
+      PORTC &= ~(1 << PC1);
+   }
+
+   void PortExp::clearChipEnable () {
+      PORTC |= (1 << PC1);
+   }
+
+#endif
+
+
+
+int8_t PortExp::writeByte (uint8_t addr, uint8_t b) {
+
+   setChipEnable();
+
+   SPDR = 0x40; // WRITE BYTE
+   while ((SPSR & (1 << SPIF)) == 0) {}
+   if (SPDR != 0) {
+      printf_P(PSTR("E1"));
+      clearChipEnable();
+      return -1;
+   }
+
+   SPDR = addr; // register address
+   while ((SPSR & (1 << SPIF)) == 0) {}
+   if (SPDR != 0) {
+      printf_P(PSTR("E2"));
+      clearChipEnable();
+      return -1;
+   }
+
+   SPDR = b; // value
+   while ((SPSR & (1 << SPIF)) == 0) {}
+   if (SPDR != 0) {
+      printf_P(PSTR("E3"));
+      clearChipEnable();
+      return -1;
+   }
+
+   clearChipEnable();
+
+   _delay_us(5);
+   return 0;
+}
+
+int8_t PortExp::run (uint8_t subtest) {
+   if (subtest == 0) {
+      while (wait(500) == EOF) {
+         printf_P(PSTR("\n => start ..."));
+         for (uint8_t i = 0; i < 8; i++) {
+            writeByte(0, ~(1 << i)); // IODIRA (Bank = 0)
+            // writeByte(0, 0x00); // IODIRA (Bank = 0) - all output
+            writeByte(0x12, (1 << i)); // GPIOA (Bank = 0)
+            printf_P(PSTR("\n  Bank0 - GPA%d = 1"), i);
+            wait(200);
+            writeByte(0x12, 0); // GPIOA (Bank = 0)
+            printf_P(PSTR("\n  Bank0 - GPA%d = 0"), i);
+            writeByte(0, 0xff); // IODIRA (Bank = 0)
+            wait(200);
+         }
+         for (uint8_t i = 0; i < 8; i++) {
+            writeByte(1, ~(1 << i)); // IODIRB (Bank = 0)
+            // writeByte(1, 0x00); // IODIRB (Bank = 0) - all output
+            writeByte(0x13, (1 << i)); // GPIOB (Bank = 0)
+            printf_P(PSTR("\n  Bank0 - GPB%d = 1"), i);
+            wait(200);
+            writeByte(0x13, 0); // GPIOB (Bank = 0)
+            printf_P(PSTR("\n  Bank0 - GPB%d = 0"), i);
+            writeByte(1, 0xff); // IODIRB (Bank = 0)
+            wait(200);
+         }
+      }
+      return 0;
+   }
+   
+   return -1;
+}
+
diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/portexp.hpp b/software/arduino-nano-5v/test_2024-07-23/src/units/portexp.hpp
new file mode 100644 (file)
index 0000000..2fb665c
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef PORTEXP_HPP
+#define PORTEXP_HPP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+class PortExp : public TestUnit {
+   public:
+      PortExp () {};
+      virtual void init ();
+      virtual void cleanup ();
+      virtual int8_t run (uint8_t subtest);
+      virtual PGM_P getName () { return PSTR("PortExp"); }
+   
+   private:
+      void setChipEnable ();
+      void clearChipEnable ();
+      int8_t writeByte (uint8_t addr, uint8_t b);
+};
+
+#endif
\ No newline at end of file
diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/poti.cpp b/software/arduino-nano-5v/test_2024-07-23/src/units/poti.cpp
new file mode 100644 (file)
index 0000000..94fc5a4
--- /dev/null
@@ -0,0 +1,34 @@
+#include <stdio.h>
+#include <avr/io.h>
+
+#include "poti.hpp"
+#include "../main.hpp"
+
+void Poti::init () {
+   ADMUX = (1 << REFS0); // ADC0, VREF=AVCC=3.3V
+   ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128
+}
+
+void Poti::cleanup () {
+   ADMUX = 0;
+   ADCSRA = 0;
+}
+
+int8_t Poti::run (uint8_t subtest) {
+   switch (subtest) {
+      case 0: {
+         printf_P(PSTR("\n"));
+         while (wait(10) == EOF) {
+            printf_P(PSTR("\r  => Measure ADC0: "));
+            ADCSRA |= (1 << ADSC); // start ADC
+            while (ADCSRA & (1 << ADSC)) {} // wait for result
+            printf_P(PSTR("%4d (0x%03x)"), ADC, ADC);
+         }
+         return 0;
+      }
+   }
+
+   return -1;
+}
+
+
diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/poti.hpp b/software/arduino-nano-5v/test_2024-07-23/src/units/poti.hpp
new file mode 100644 (file)
index 0000000..b13dd29
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef POTI_HPP
+#define POTI_PP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+class Poti : public TestUnit {
+   public:
+      Poti () {};
+      virtual void init ();
+      virtual void cleanup ();
+      virtual int8_t run (uint8_t subtest);
+      virtual PGM_P getName () { return PSTR("Poti"); }
+};
+
+#endif
\ No newline at end of file
diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/r2r.cpp b/software/arduino-nano-5v/test_2024-07-23/src/units/r2r.cpp
new file mode 100644 (file)
index 0000000..ef299ce
--- /dev/null
@@ -0,0 +1,46 @@
+#include <stdio.h>
+#include <avr/io.h>
+
+#include "r2r.hpp"
+#include "../main.hpp"
+
+#ifdef __AVR_ATmega644P__
+   // AVCC=3.3, POTI Vmax=3.3V
+   #define K 1.0
+#endif
+
+#ifdef __AVR_ATmega328P__
+   // AVCC=4.7V, POTI Vmax=3.3V
+   #define K (1023.0 / 738.0)
+#endif
+
+void R2r::init () {
+   ADMUX = (1 << REFS0) | 2; // ADC2, VREF=AVCC=3.3V
+   ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128
+}
+
+void R2r::cleanup () {
+   ADMUX = 0;
+   ADCSRA = 0;
+}
+
+int8_t R2r::run (uint8_t subtest) {
+   switch (subtest) {
+      case 0: {
+         printf_P(PSTR("\n"));
+         while (wait(10) == EOF) {
+            printf_P(PSTR("\r  => Measure ADC2: "));
+            ADCSRA |= (1 << ADSC); // start ADC
+            while (ADCSRA & (1 << ADSC)) {} // wait for result
+            printf_P(PSTR("%4d (0x%03x)"), ADC, ADC);
+            uint8_t sw = (uint8_t)( ((float)(ADC) + 32.0) / 64.0 * K );
+            printf_P(PSTR("  SW9:6 = %d %d% d %d  "), sw >> 3, (sw >> 2) & 0x01, (sw >> 1) & 0x01, sw & 0x01 );
+         }
+         return 0;
+      }
+   }
+
+   return -1;
+}
+
+
diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/r2r.hpp b/software/arduino-nano-5v/test_2024-07-23/src/units/r2r.hpp
new file mode 100644 (file)
index 0000000..84e97e6
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef R2R_HPP
+#define R2R_PP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+class R2r : public TestUnit {
+   public:
+      R2r () {};
+      virtual void init ();
+      virtual void cleanup ();
+      virtual int8_t run (uint8_t subtest);
+      virtual PGM_P getName () { return PSTR("R2R"); }
+};
+
+#endif
\ No newline at end of file
diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/rgb.cpp b/software/arduino-nano-5v/test_2024-07-23/src/units/rgb.cpp
new file mode 100644 (file)
index 0000000..c52454d
--- /dev/null
@@ -0,0 +1,152 @@
+#include <stdio.h>
+#include <avr/io.h>
+
+#include "rgb.hpp"
+#include "../main.hpp"
+
+#ifdef __AVR_ATmega644P__
+
+   // Nano-644
+   // ---------------------------------------------------------------
+   // PB0 ..... Red (inverse logic -> 0 = ON)
+   // PB1 ..... Green (inverse logic -> 0 = ON)
+   // PB2 ..... Blue (inverse logic -> 0 = ON)
+
+   void Rgb::init () {
+      ledOff(RED);
+      ledOff(GREEN);
+      ledOff(BLUE);
+      DDRB |= (1 << PB2) | (1 << PB1) | (1 << PB0);
+   }
+
+   void Rgb::cleanup () {
+      ledOff(RED);
+      ledOff(GREEN);
+      ledOff(BLUE);
+      DDRB &= ~((1 << PB2) | (1 << PB1) | (1 << PB0));
+   }
+
+   void Rgb::setLed (LED led, bool on) {
+      if (on) {
+         switch(led) {
+            case RED: PORTB |= (1 << PB0); break;
+            case GREEN: PORTB |= (1 << PB1); break;
+            case BLUE: PORTB |= (1 << PB2); break;
+         }
+      } else {
+         switch(led) {
+            case RED: PORTB &= ~(1 << PB0); break;
+            case GREEN: PORTB &= ~(1 << PB1); break;
+            case BLUE: PORTB &= ~(1 << PB2); break;
+         }
+      }
+   }
+
+   void Rgb::ledToggle (LED led) {
+      switch(led) {
+         case RED: PORTB ^= (1 << PB0); break;
+         case GREEN: PORTB ^= (1 << PB1); break;
+         case BLUE: PORTB ^= (1 << PB2); break;
+       }
+   }
+
+
+#endif
+
+#ifdef __AVR_ATmega328P__
+
+   // Arduino-Nano-5V
+   // ---------------------------------------------------------------
+   // PD4 ..... Red (inverse logic -> 0 = ON)
+   // PB0 ..... Green (inverse logic -> 0 = ON)
+   // PD7 ..... Blue (inverse logic -> 0 = ON)
+
+   void Rgb::init () {
+      ledOff(RED);
+      ledOff(GREEN);
+      ledOff(BLUE);
+      DDRB |= (1 << PB0);
+      DDRD |= (1 << PD7) | (1 << PD4);
+   }
+
+   void Rgb::cleanup () {
+      ledOff(RED);
+      ledOff(GREEN);
+      ledOff(BLUE);
+      DDRB &= ~(1 << PB0);
+      DDRD &= ~((1 << PD7) | (1 << PD4));
+   }
+
+   void Rgb::setLed (LED led, bool on) {
+      if (on) {
+         switch (led) {
+            case RED: PORTD &= ~(1 << PD4); break;
+            case GREEN: PORTB &= ~(1 << PB0); break;
+            case BLUE: PORTD &= ~(1 << PD7); break;
+         }
+      } else {
+         switch (led) {
+            case RED: PORTD |= (1 << PD4); break;
+            case GREEN: PORTB |= (1 << PB0); break;
+            case BLUE: PORTD |= (1 << PD7); break;
+         }
+      }
+   }
+
+   void Rgb::ledToggle (LED led) {
+      switch (led) {
+         case RED: PORTD ^= (1 << PD4); break;
+         case GREEN: PORTB ^= ~(1 << PB0); break;
+         case BLUE: PORTD ^= (1 << PD7); break;
+       }
+   }
+
+#endif
+
+void Rgb::ledOn (LED led) {
+   setLed(led, true);
+}
+
+void Rgb::ledOff (LED led) {
+   setLed(led, false);
+}
+
+int8_t Rgb::run (uint8_t subtest) {
+   switch (subtest) {
+      case 0: {
+         ledOn(RED);
+         printf_P(PSTR("Red"));
+         wait(3000);
+         ledOff(RED);
+         return 0;
+      }
+
+      case 1: {
+         ledOn(GREEN);
+         printf_P(PSTR("Green"));
+         wait(3000);
+         ledOff(GREEN);
+         return 0;
+      }
+
+      case 2: {
+         ledOn(BLUE);
+         printf_P(PSTR("Blue"));
+         wait(3000);
+         ledOff(BLUE);
+         return 0;
+      }
+
+      case 3: {
+         ledOn(RED); ledOn(GREEN); ledOn(BLUE);
+         printf_P(PSTR("All"));
+         wait(3000);
+         ledOff(RED); ledOff(GREEN); ledOff(BLUE);
+         return 0;
+      }
+   }
+
+   return -1;
+}
+
+
diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/rgb.hpp b/software/arduino-nano-5v/test_2024-07-23/src/units/rgb.hpp
new file mode 100644 (file)
index 0000000..12e9da4
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef RGB_HPP
+#define RGB_PP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+class Rgb : public TestUnit {
+   public:
+      enum LED { RED, GREEN, BLUE };
+
+   public:
+      Rgb () {};
+      virtual void init ();
+      virtual void cleanup ();
+      virtual int8_t run (uint8_t subtest);
+      virtual PGM_P getName () { return PSTR("Rgb"); }
+
+      void setLed (LED led, bool on);
+      void ledOn (LED led);
+      void ledOff (LED led);
+      void ledToggle (LED led);
+};
+
+#endif
\ No newline at end of file
diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/seg7.cpp b/software/arduino-nano-5v/test_2024-07-23/src/units/seg7.cpp
new file mode 100644 (file)
index 0000000..42ae93b
--- /dev/null
@@ -0,0 +1,210 @@
+#include <stdio.h>
+#include <avr/io.h>
+
+#include "seg7.hpp"
+#include "../main.hpp"
+
+#ifdef __AVR_ATmega644P__
+
+   // Nano-644
+   // ---------------------------------------------------------------
+
+   // PA0 ... Cathode Char 1
+   // PA1 ... Cathode Char 2
+   // PA2 ... Cathode Char 3
+   // PA3 ... Cathode Char 4
+
+   // PB0 ... Anode Segment A
+   // PB1 ... Anode Segment B
+   // PB2 ... Anode Segment C
+   // PB3 ... Anode Segment D
+   // PB4 ... Anode Segment E
+   // PB5 ... Anode Segment F
+   // PB6 ... Anode Segment G
+   // PB7 ... Anode DP
+
+   // PD5 ... nOE (Output Enable) for all LEDs
+   // PD6 ... Anode L1:2
+   // PD7 ... Anode L3
+
+void Seg7::init () {
+      setAnodes(0);
+      setCathodes(0);
+      DDRA |= (1 << PA3) | (1 << PA2) | (1 << PA1) | (1 << PA0);
+      DDRB = 0xff;
+      DDRD |= (1 << PD7) | (1 << PD6) | (1 << PD5);
+   }
+
+   void Seg7::cleanup () {
+      setAnodes(0);
+      setCathodes(0);
+      DDRA &= ~((1 << PA3) | (1 << PA2) | (1 << PA1) | (1 << PA0));
+      DDRB = 0x00;
+      DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD5));
+   }
+
+   void Seg7::setAnodes (uint16_t a) {
+      if (a & 0x0001) PORTD |= (1 << PD4); else PORTD &= ~(1 << PD4); // Anode Char A
+      if (a & 0x0002) PORTB |= (1 << PB0); else PORTB &= ~(1 << PB0); // Anode Char B
+      if (a & 0x0004) PORTD |= (1 << PD7); else PORTD &= ~(1 << PD7); // Anode Char C
+      if (a & 0x0008) PORTD |= (1 << PD6); else PORTD &= ~(1 << PD6); // Anode Char D
+      if (a & 0x0010) PORTB |= (1 << PB2); else PORTB &= ~(1 << PB2); // Anode Char E
+      if (a & 0x0020) PORTB |= (1 << PB3); else PORTB &= ~(1 << PB3); // Anode Char F
+      if (a & 0x0040) PORTB |= (1 << PB4); else PORTB &= ~(1 << PB4); // Anode Char G
+      if (a & 0x0080) PORTB |= (1 << PB5); else PORTB &= ~(1 << PB5); // Anode Char DP
+      if (a & 0x0100) PORTD |= (1 << PD3); else PORTD &= ~(1 << PD3); // Anode L1/L2
+      if (a & 0x0200) PORTD |= (1 << PD2); else PORTD &= ~(1 << PD2); // Anode L3
+   }
+
+   void Seg7::setCathodes (uint8_t c) {
+      if (c & 0x01) PORTC |= (1 << PC0); else PORTC &= ~(1 << PC0); // Chathode Char 1 (most left)
+      if (c & 0x02) PORTC |= (1 << PC1); else PORTC &= ~(1 << PC1); // Chathode Char 2
+      if (c & 0x04) PORTC |= (1 << PC2); else PORTC &= ~(1 << PC2); // Chathode Char 3
+      if (c & 0x08) PORTC |= (1 << PC3); else PORTC &= ~(1 << PC3); // Chathode Char 4 (most right)
+   }
+
+   void Seg7::setOE (bool enabled) {
+      if (enabled) {
+         PORTB &= ~(1 << PB1);
+      } else {
+         PORTB |= (1 << PB1);
+      }
+   }
+
+   void Seg7::init () {
+      
+      PORTB = 0;
+      DDRB = 0xff;
+      PORTD &= ~((1 <<PORTD7) | (1 << PORTD6));
+      PORTD |= (1 << PORTD5);
+      DDRD |= (1 <<DDD7) | (1 << DDD6) | (1 << DDD5);
+   }
+
+   void Seg7::cleanup () {
+      PORTA &= ~((1 <<PORTA3) | (1 << PORTA2) | (1 << PORTA1) | (1 << PORTA0));
+      DDRA &= ~((1 <<DDA3) | (1 << DDA2) | (1 << DDA1) | (1 << DDA0));
+      PORTD &= ~((1 <<PORTD7) | (1 << PORTD6) | (1 << PORTD5));
+      DDRD &= ~((1 <<DDD7) | (1 << DDD6) | (1 << DDD5));
+      PORTB = 0;
+      DDRB = 0;
+   }
+#endif
+
+#ifdef __AVR_ATmega328P__
+
+   // Arduino-Nano-5V
+   // ---------------------------------------------------------------
+
+   // PC0 ... Cathode Char 1
+   // PC1 ... Cathode Char 2
+   // PC2 ... Cathode Char 3
+   // PC3 ... Cathode Char 4
+
+   // PD4 ... Anode Segment A
+   // PB0 ... Anode Segment B
+   // PD7 ... Anode Segment C
+   // PD6 ... Anode Segment D
+   // PB2 ... Anode Segment E
+   // PB3 ... Anode Segment F
+   // PB4 ... Anode Segment G
+   // PB5 ... Anode DP
+
+   // PB1 ... nOE (Output Enable) for all LEDs
+   // PD3 ... Anode L1:2
+   // PD2 ,,, Anode L3
+
+   void Seg7::init () {
+      enabled = 1;
+      setAnodes(0);
+      setCathodes(0);
+      DDRB |= (1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB1) | (1 << PB0) ;
+      DDRC |= (1 << PC3) | (1 << PC2) | (1 << PC1) | (1 << PC0);
+      DDRD |= (1 << PD7) | (1 << PD6) | (1 << PD4) | (1 << PD3) | (1 << PD2);
+
+   }
+
+   void Seg7::cleanup () {
+      enabled = 0;
+      setAnodes(0);
+      setCathodes(0);
+      DDRB &= ~((1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB1) | (1 << PB0));
+      DDRC &= ~((1 << PC3) | (1 << PC2) | (1 << PC1) | (1 << PC0));
+      DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD4) | (1 << PD3) | (1 << PD2));
+   }
+
+   void Seg7::setAnodes (uint16_t a) {
+      if (a & 0x0001) PORTD |= (1 << PD4); else PORTD &= ~(1 << PD4); // Anode Char A
+      if (a & 0x0002) PORTB |= (1 << PB0); else PORTB &= ~(1 << PB0); // Anode Char B
+      if (a & 0x0004) PORTD |= (1 << PD7); else PORTD &= ~(1 << PD7); // Anode Char C
+      if (a & 0x0008) PORTD |= (1 << PD6); else PORTD &= ~(1 << PD6); // Anode Char D
+      if (a & 0x0010) PORTB |= (1 << PB2); else PORTB &= ~(1 << PB2); // Anode Char E
+      if (a & 0x0020) PORTB |= (1 << PB3); else PORTB &= ~(1 << PB3); // Anode Char F
+      if (a & 0x0040) PORTB |= (1 << PB4); else PORTB &= ~(1 << PB4); // Anode Char G
+      if (a & 0x0080) PORTB |= (1 << PB5); else PORTB &= ~(1 << PB5); // Anode Char DP
+      if (a & 0x0100) PORTD |= (1 << PD3); else PORTD &= ~(1 << PD3); // Anode L1/L2
+      if (a & 0x0200) PORTD |= (1 << PD2); else PORTD &= ~(1 << PD2); // Anode L3
+   }
+
+   void Seg7::setCathodes (uint8_t c) {
+      if (c & 0x01) PORTC |= (1 << PC0); else PORTC &= ~(1 << PC0); // Chathode Char 1 (most left)
+      if (c & 0x02) PORTC |= (1 << PC1); else PORTC &= ~(1 << PC1); // Chathode Char 2
+      if (c & 0x04) PORTC |= (1 << PC2); else PORTC &= ~(1 << PC2); // Chathode Char 3
+      if (c & 0x08) PORTC |= (1 << PC3); else PORTC &= ~(1 << PC3); // Chathode Char 4 (most right)
+   }
+
+   void Seg7::setOE (bool enabled) {
+      if (enabled) {
+         PORTB &= ~(1 << PB1);
+      } else {
+         PORTB |= (1 << PB1);
+      }
+   }
+
+#endif
+
+const char *segName[] = { "A", "B", "C", "D", "E", "F", "G", "DP" };
+
+
+int8_t Seg7::run (uint8_t subtest) {
+   if (subtest == 0) {
+      setCathodes(0x0f); // all segment cathodes conected to GND
+      setAnodes(0x3ff);  // all segments ON
+      setOE(true);
+      printf_P(PSTR("ON"));
+      wait(2000);
+      setAnodes(0);
+      return 0;
+
+   } else if (subtest == 1) {
+      printf_P(PSTR("OFF"));
+      wait(1000);
+      return 0;
+
+   } else if (subtest == 2) {
+      setAnodes(0x100); // L1/L2 ON
+      printf_P(PSTR("L1/L2 ON"));
+      wait(1000);
+      setAnodes(0);
+      return 0;
+
+   } else if (subtest == 3) {
+      setAnodes(0x200); // L3 ON
+      printf_P(PSTR("L1/L2 ON"));
+      wait(1000);
+      setAnodes(0);
+      return 0;
+
+   } else if (subtest < (4 + 4 * 8)) {
+      uint8_t chIndex = (subtest - 4) / 8;
+      uint8_t segIndex = (subtest - 4) % 8;
+      setCathodes(1 << chIndex);
+      setAnodes(1 << segIndex);
+      printf_P(PSTR("Char %d - %s"), chIndex, segName[segIndex]);
+      wait(400);
+      return 0;
+   }
+
+   return -1;
+}
+
+
diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/seg7.hpp b/software/arduino-nano-5v/test_2024-07-23/src/units/seg7.hpp
new file mode 100644 (file)
index 0000000..0e71fde
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef SEG7_HPP
+#define SEG7_HPP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+class Seg7 : public TestUnit {
+   public:
+      bool enabled;
+   
+   public:
+      Seg7 () { enabled = false; }
+      virtual void init ();
+      virtual void cleanup ();
+      virtual int8_t run (uint8_t subtest);
+      virtual PGM_P getName () { return PSTR("Seg7"); }
+
+   private:
+      void setAnodes (uint16_t);
+      void setCathodes (uint8_t mask);
+      void setOE (bool enabled);
+};
+
+#endif
\ No newline at end of file
diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/switch.cpp b/software/arduino-nano-5v/test_2024-07-23/src/units/switch.cpp
new file mode 100644 (file)
index 0000000..45866a4
--- /dev/null
@@ -0,0 +1,100 @@
+#include <stdio.h>
+#include <avr/io.h>
+#include <util/delay.h>
+
+#include "switch.hpp"
+#include "../main.hpp"
+
+#ifdef __AVR_ATmega644P__
+
+   // Nano-644
+   // ---------------------------------------------------------------
+   // PA0 ..... SW1
+   // PA1 ..... SW2
+   // PA2 ..... SW3
+   // PA3 ..... SW4
+
+   void Switch::init () {
+      DDRA &= ~((1 << PORTA3) | (1 << PORTA2) | (1 << PORTA1) | (1 << PORTA0));
+      PORTA |= (1 << PORTA3) | (1 << PORTA2) | (1 << PORTA1) | (1 << PORTA0);
+   }
+
+   void Switch::cleanup () {
+      PORTA &= ~((1 << PORTA3) | (1 << PORTA2) | (1 << PORTA1) | (1 << PORTA0));
+      DDRA &= ~((1 << PORTA3) | (1 << PORTA2) | (1 << PORTA1) | (1 << PORTA0));
+   }
+
+   bool Switch::isPressed (SWITCH sw) {
+      switch (sw) {
+         case SW1: return (PINA & ( 1 << PA0)) == 0;
+         case SW2: return (PINA & ( 1 << PA1)) == 0;
+         case SW3: return (PINA & ( 1 << PA2)) == 0;
+         case SW4: return (PINA & ( 1 << PA3)) == 0;
+         default: return false;
+      }
+   }
+
+#endif
+
+#ifdef __AVR_ATmega328P__
+
+   // Arduino-Nano-5V
+   // ---------------------------------------------------------------
+   // PC0 ..... SW1
+   // PC1 ..... SW2
+   // PC2 ..... SW3
+   // PC3 ..... SW4
+
+   void Switch::init () {
+      DDRC &= ~((1 << PORTC3) | (1 << PORTC2) | (1 << PORTC1) | (1 << PORTC0));
+      PORTC |= (1 << PORTC3) | (1 << PORTC2) | (1 << PORTC1) | (1 << PORTC0);
+   }
+
+   void Switch::cleanup () {
+      PORTC &= ~((1 << PORTC3) | (1 << PORTC2) | (1 << PORTC1) | (1 << PORTC0));
+      DDRC &= ~((1 << PORTC3) | (1 << PORTC2) | (1 << PORTC1) | (1 << PORTC0));
+   }
+
+   bool Switch::isPressed (SWITCH sw) {
+      switch (sw) {
+         case SW1: return (PINC & ( 1 << PC0)) == 0;
+         case SW2: return (PINC & ( 1 << PC1)) == 0;
+         case SW3: return (PINC & ( 1 << PC2)) == 0;
+         case SW4: return (PINC & ( 1 << PC3)) == 0;
+         default: return false;
+      }
+   }
+
+#endif
+
+int8_t Switch::run (uint8_t subtest) {
+   if (subtest < 16) {
+      SWITCH sw = (SWITCH)(subtest / 4);
+      switch (subtest % 4) {
+         case 1: {
+            if (!isPressed(sw)) {
+               printf_P(PSTR("Press SW%d"), sw + 1);
+               while (!isPressed(sw) && wait(0) == EOF) {}
+               wait(10);
+            }
+            return 0;
+         }
+
+         case 0: case 2: {
+            if (isPressed(sw)) {
+               printf_P(PSTR("Release SW%d "), sw + 1);
+               while (isPressed(sw) && wait(0) == EOF) {}
+               wait(10);
+            }
+            return 0;
+         }
+
+         case 3: {
+            return 0;
+         }
+      }
+
+   }
+   
+   return -1;
+}
diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/switch.hpp b/software/arduino-nano-5v/test_2024-07-23/src/units/switch.hpp
new file mode 100644 (file)
index 0000000..03bf0b2
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef SWITCH_HPP
+#define SWITCH_HPP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+class Switch : public TestUnit {
+   typedef enum { SW1 = 0, SW2 = 1, SW3 = 2, SW4 = 3 } SWITCH;
+
+   public:
+      Switch () {};
+      virtual void init ();
+      virtual void cleanup ();
+      virtual int8_t run (uint8_t subtest);
+      virtual PGM_P getName () { return PSTR("Switch"); }
+      bool isPressed (SWITCH sw);
+};
+
+#endif
\ No newline at end of file
diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/uart1.cpp b/software/arduino-nano-5v/test_2024-07-23/src/units/uart1.cpp
new file mode 100644 (file)
index 0000000..aba6d92
--- /dev/null
@@ -0,0 +1,69 @@
+#include <stdio.h>
+#include <avr/io.h>
+#include <util/delay.h>
+
+#include "uart1.hpp"
+#include "../main.hpp"
+
+#ifdef __AVR_ATmega328P__
+   void Uart1::init () {}
+   void Uart1::cleanup () {}
+   int8_t Uart1::run (uint8_t subtest) { return -1; }
+   void Uart1::handleRxByte (uint8_t b) {}
+#endif
+
+#ifdef __AVR_ATmega644P__
+
+int uart1_putchar(char c, FILE *stream) {
+   if (c == '\n') {
+      uart1_putchar('\r', stream);
+   }
+   loop_until_bit_is_set(UCSR1A, UDRE1);
+   UDR1 = c;
+   return 0;
+}
+
+static FILE mystderr = { 0, 0, _FDEV_SETUP_WRITE , 0, 0, uart1_putchar, NULL, 0 };
+
+void Uart1::cleanup () {
+   enabled = 0;
+   UCSR1A = 0;
+   UCSR1B = 0;
+   UCSR1C = 0;
+   UBRR1H = 0;
+   UBRR1L = 0;
+   stderr = NULL;
+}
+
+int8_t Uart1::run (uint8_t subtest) {
+   if (subtest == 0) {
+      // UART1 interface on Nano-644
+      PORTD |= (1 << PD2); // enable RxD1 pullup
+      UCSR1A = (1 << U2X1);
+      UCSR1B = (1 << RXCIE1) | (1 << RXEN1) | (1 <<TXEN1);
+      UCSR1C = (1 << UCSZ11) | ( 1<< UCSZ10);
+      UBRR1H = 0;
+      UBRR1L = F_CPU / 8 / 115200 - 1;
+      stderr = &mystderr;
+      enabled = 1;
+      printf_P(PSTR("init"));
+
+   } else if (subtest == 1) {
+      do {
+         printf_P(PSTR("\n => send text via UART1 now..."));
+         fprintf_P(stderr, PSTR("Hello UART1, ECHO-Modus active\n"));
+      } while (wait(5000) == EOF);
+
+   } else {
+      printf_P(PSTR("end"));
+      return -1;
+   }
+   wait(500);
+   return 0;
+}
+
+void Uart1::handleRxByte (uint8_t b) {
+   uart1_putchar(b, stderr);
+}
+
+#endif
\ No newline at end of file
diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/uart1.hpp b/software/arduino-nano-5v/test_2024-07-23/src/units/uart1.hpp
new file mode 100644 (file)
index 0000000..40437e1
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef UART1_HPP
+#define UART1_HPP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+class Uart1 : public TestUnit {
+   public:
+      uint8_t  enabled;
+
+   public:
+      Uart1 () { enabled = 0; }
+      virtual void init ();
+      virtual void cleanup ();
+      virtual int8_t run (uint8_t subtest);
+      virtual PGM_P getName () { return PSTR("Uart1"); }
+      void handleRxByte (uint8_t);
+};
+
+#endif
\ No newline at end of file