Commit 51fd30674cd8ce7f1e1a5c927f7ec215a0b1a1dd
receivedMon, 29. Jul 2024, 17:15:59 (by user sx)
Mon, 29 Jul 2024 15:15:59 +0000 (17:15 +0200)
authorManfred Steiner <sx@htl-kaindorf.at>
Mon, 29 Jul 2024 15:15:56 +0000 (17:15 +0200)
committerManfred Steiner <sx@htl-kaindorf.at>
Mon, 29 Jul 2024 15:15:56 +0000 (17:15 +0200)
4 files changed:
software/test_2024-07-23/Makefile
software/test_2024-07-23/src/main.cpp
software/test_2024-07-23/src/units/modbus.cpp [new file with mode: 0644]
software/test_2024-07-23/src/units/modbus.hpp [new file with mode: 0644]

index 8f5c7f277caca3535c668f3ae8966b54d42326b0..12a996ab34a9b210fe38061a795fc92f051fc4dc 100644 (file)
@@ -12,10 +12,10 @@ DEVICE=atmega644p
 
 CC= avr-g++
 CFLAGS= -Wall -mmcu=$(DEVICE) -Os -DF_CPU=12000000 -c
-LFLAGS= -Wall -mmcu=$(DEVICE) -Os -DF_CPU=12000000
+LFLAGS= -Wall -mmcu=$(DEVICE) -Os -DF_CPU=12000000 -Wl,-u,vfprintf -lprintf_flt -lm
 
 CFLAGS_SIM= -Wall -mmcu=$(DEVICE) -Og -DF_CPU=12000000 -g -c
-LFLAGS_SIM= -Wall -mmcu=$(DEVICE) -Og -DF_CPU=12000000 -g
+LFLAGS_SIM= -Wall -mmcu=$(DEVICE) -Og -DF_CPU=12000000 -g -Wl,-u,vfprintf -lprintf_flt -lm
 
 
 all: dist/$(NAME).elf dist/$(NAME).s dist/$(NAME).hex sim/$(NAME).elf sim/$(NAME).s info
index c9fa88043d96499f608da28e49fba1ccc62a398e..9023e1ac3490ea97262f04bee9343931cd2a447f 100644 (file)
@@ -15,6 +15,7 @@
 #include "units/motor.hpp"
 #include "units/portexp.hpp"
 #include "units/lcd.hpp"
+#include "units/modbus.hpp"
 
 extern "C" {
    void __cxa_pure_virtual () {
@@ -34,8 +35,36 @@ extern "C" {
       return 0;
    }
 
-   static FILE mystdout = { 0, 0, _FDEV_SETUP_WRITE , 0, 0, uart_putchar, NULL, 0 } ;
-   static FILE mystderr = { 0, 0, _FDEV_SETUP_WRITE , 0, 0, uart_putchar, NULL, 0 } ;
+
+   uint8_t volatile uartBuffer[32];
+   uint8_t volatile rIndex = 0;
+   uint8_t volatile wIndex = 0;
+
+   int uart_getchar (FILE *stream) {
+    // if (rIndex == wIndex) {
+    //     // nothing in buffer
+    //     return EOF;
+    // }
+    // printf(" r%d", rIndex);
+    while (rIndex == wIndex) {
+        // wait for character
+    }
+    
+    // don't use "char c" because german special characters would lead to negative return -> stream error
+    // char c = uartBuffer[rIndex++];
+    
+    uint8_t c = uartBuffer[rIndex++];
+    // printf("(%02x) ", c);
+    if (c == '\r') {
+      c = '\n';
+    }
+    putchar(c); // echo on terminal
+    return c;
+   }
+
+   static FILE mystdout = { 0, 0, _FDEV_SETUP_WRITE , 0, 0, uart_putchar, NULL, 0 };
+   static FILE mystderr = { 0, 0, _FDEV_SETUP_WRITE , 0, 0, uart_putchar, NULL, 0 };
+   static FILE mystdin  = { 0, 0, _FDEV_SETUP_READ  , 0, 0, NULL, uart_getchar, 0 };
 
    static volatile uint32_t timer1ms = 0;
    static volatile int keyUart0 = EOF;
@@ -50,6 +79,7 @@ extern "C" {
    Motor motor;
    PortExp portExp;
    Lcd lcd;
+   Modbus modbus;
 
 }
 
@@ -93,24 +123,29 @@ int main () {
 
    stdout = &mystdout;
    stderr = &mystderr;
+   stdin = &mystdin;
 
    sei();
 
-   printf("\n\nTEST Nano-X-Base\n");
-   printf("======================================");
-
-
-   TestUnit *unit[] = { &led, &sw, &rgb, &seg7, &poti, &encoder, &r2r, &motor, &portExp, &lcd };
-
-   for (uint8_t i = 0; i < sizeof(unit) / sizeof(unit[0]); i++) {
+   TestUnit *unit[] = { &led, &sw, &rgb, &seg7, &poti, &encoder, &r2r, &motor, &portExp, &lcd, &modbus };
+
+   while (1) {
+      uint16_t i;
+      char s[4];
+      do {
+         printf("\n\n=============================\n\n");
+         printf("Available units:\n\n");
+         for (i = 0; i < sizeof(unit) / sizeof(unit[0]); i++) {
+            TestUnit *pu = unit[i];
+            printf("%3x ... %s\n", i, pu->getName());
+         }
+         printf("\nSelect unit: ");
+         rIndex = 0; wIndex = 0;
+         fgets(s, sizeof(s), stdin);
+      } while (sscanf(s, "%x", &i) != 1 || i < 0 || i >= sizeof(unit) / sizeof(unit[0]) );
+      
       TestUnit *pu = unit[i];
       printf("\n\n[%s]: ", pu->getName());
-      printf("Press >ESC< to skip unit, any other key to start\n");
-      wait(0xffffffff);
-      if (keyUart0 == 27) {
-         keyUart0 = EOF;
-         continue;
-      }
       keyUart0 = EOF;
 
       for (uint8_t subtest = 0; subtest < 0xff; subtest++) {
@@ -126,14 +161,24 @@ int main () {
       }
       pu->cleanup();
    }
-
-   printf("\n\nTest finished. \n");
-   return 0;
 }
 
 ISR (USART0_RX_vect) {
    uint8_t b = UDR0;
    keyUart0 = b;
+   uartBuffer[wIndex++] = b;
+   // printf(" w%d(%02x)", wIndex, b);
+   if (wIndex == rIndex) {
+      // buffer overflow, kick out oldest byte
+      rIndex++;
+   }
+}
+
+ISR (USART1_RX_vect) {
+   uint8_t b = UDR1;
+   if (modbus.enabled) {
+      modbus.handleRxByte(b);
+   }
 }
 
 ISR (TIMER2_COMPA_vect) { // every 100us
diff --git a/software/test_2024-07-23/src/units/modbus.cpp b/software/test_2024-07-23/src/units/modbus.cpp
new file mode 100644 (file)
index 0000000..28b1bca
--- /dev/null
@@ -0,0 +1,145 @@
+#include <stdio.h>
+#include <avr/io.h>
+#include <util/delay.h>
+
+#include "modbus.hpp"
+#include "../main.hpp"
+
+// 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::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("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(" 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("0x%02x received", received[0]);
+         receivedBytes = 0;
+      } else {
+         printf("no byte received");
+      }
+      printf(" ... 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("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("\n => Sending:");
+         for (uint8_t i = 0; i < sizeof(frame); i++) {
+            printf(" 0x%02x", frame[i]);
+         }
+         int k = wait(100);
+      
+         printf("\n       RxD1:");
+         if (receivedBytes == 0) {
+            printf("?");
+         } else {
+            for (uint8_t i = 0; i < receivedBytes; i++) {
+               if (i == sizeof(frame)) {
+                  printf("  ");
+               }
+               printf(" 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(" -> %4.8fV\n", (double)f.value);
+         }
+         if (k != EOF) {
+            break;
+         }
+         
+      } while (wait(1000) == EOF);
+
+   } else {
+      printf("end");
+      return -1;
+   }
+   wait(500);
+   return 0;
+}
+
+void Modbus::handleRxByte (uint8_t b) {
+   if (receivedBytes < sizeof(received)) {
+      received[receivedBytes++] = b;
+   }
+}
diff --git a/software/test_2024-07-23/src/units/modbus.hpp b/software/test_2024-07-23/src/units/modbus.hpp
new file mode 100644 (file)
index 0000000..14580f8
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef MODBUS_HPP
+#define MODBUS_HPP
+
+#include <stdint.h>
+#include "../main.hpp"
+
+class Modbus : public TestUnit {
+   public:
+      uint8_t  enabled;
+      uint8_t  receivedBytes;
+      uint8_t  received[16];
+
+
+   public:
+      Modbus () { enabled = 0; receivedBytes = 0; }
+      virtual void cleanup ();
+      virtual int8_t run (uint8_t subtest);
+      virtual const char *getName () { return "Modbus"; }
+      void handleRxByte (uint8_t);
+};
+
+#endif
\ No newline at end of file