diff --git a/DCCTimer.h b/DCCTimer.h
index fa2b854..34b2d91 100644
--- a/DCCTimer.h
+++ b/DCCTimer.h
@@ -85,7 +85,11 @@ private:
static int freeMemory();
static volatile int minimum_free_memory;
static const int DCC_SIGNAL_TIME=58; // this is the 58uS DCC 1-bit waveform half-cycle
+#if defined(ARDUINO_ARCH_STM32) // TODO: PMA temporary hack - assumes 100Mhz F_CPU as STM32 can change frequency
+ static const long CLOCK_CYCLES=(100000000L / 1000000 * DCC_SIGNAL_TIME) >>1;
+#else
static const long CLOCK_CYCLES=(F_CPU / 1000000 * DCC_SIGNAL_TIME) >>1;
+#endif
};
diff --git a/DCCTimerSTM32.cpp b/DCCTimerSTM32.cpp
new file mode 100644
index 0000000..4ca20c0
--- /dev/null
+++ b/DCCTimerSTM32.cpp
@@ -0,0 +1,118 @@
+/*
+ * © 2022 Paul M Antoine
+ * © 2021 Mike S
+ * © 2021 Harald Barth
+ * © 2021 Fred Decker
+ * © 2021 Chris Harlow
+ * © 2021 David Cutting
+ * All rights reserved.
+ *
+ * This file is part of Asbelos DCC API
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * It is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with CommandStation. If not, see .
+ */
+
+// ATTENTION: this file only compiles on a STM32 based boards
+// Please refer to DCCTimer.h for general comments about how this class works
+// This is to avoid repetition and duplication.
+#ifdef ARDUINO_ARCH_STM32
+
+#include "FSH.h" //PMA temp debug
+#include "DIAG.h" //PMA temp debug
+#include "DCCTimer.h"
+
+// STM32 doesn't have Serial1 defined by default
+HardwareSerial Serial1(PA10, PA15); // Rx=PA10, Tx=PA9
+
+INTERRUPT_CALLBACK interruptHandler=0;
+// Let's use STM32's timer #1 until disabused of this notion
+HardwareTimer timer(TIM1);
+
+// Timer IRQ handler
+void Timer1_Handler() {
+ interruptHandler();
+}
+
+void DCCTimer::begin(INTERRUPT_CALLBACK callback) {
+ interruptHandler=callback;
+ noInterrupts();
+
+ timer.pause();
+ timer.setPrescaleFactor(1);
+// timer.setOverflow(CLOCK_CYCLES * 2);
+ timer.setOverflow(DCC_SIGNAL_TIME * 2, MICROSEC_FORMAT);
+ timer.attachInterrupt(Timer1_Handler);
+ timer.refresh();
+ timer.resume();
+
+ interrupts();
+}
+
+bool DCCTimer::isPWMPin(byte pin) {
+ //TODO: SAMD whilst this call to digitalPinHasPWM will reveal which pins can do PWM,
+ // there's no support yet for High Accuracy, so for now return false
+ // return digitalPinHasPWM(pin);
+ return false;
+}
+
+void DCCTimer::setPWM(byte pin, bool high) {
+ // TODO: High Accuracy mode is not supported as yet, and may never need to be
+ (void) pin;
+ (void) high;
+}
+
+void DCCTimer::clearPWM() {
+ return;
+}
+
+void DCCTimer::getSimulatedMacAddress(byte mac[6]) {
+ volatile uint32_t *serno1 = (volatile uint32_t *)0x0080A00C;
+ volatile uint32_t *serno2 = (volatile uint32_t *)0x0080A040;
+// volatile uint32_t *serno3 = (volatile uint32_t *)0x0080A044;
+// volatile uint32_t *serno4 = (volatile uint32_t *)0x0080A048;
+
+ volatile uint32_t m1 = *serno1;
+ volatile uint32_t m2 = *serno2;
+ mac[0] = m1 >> 8;
+ mac[1] = m1 >> 0;
+ mac[2] = m2 >> 24;
+ mac[3] = m2 >> 16;
+ mac[4] = m2 >> 8;
+ mac[5] = m2 >> 0;
+}
+
+volatile int DCCTimer::minimum_free_memory=__INT_MAX__;
+
+// Return low memory value...
+int DCCTimer::getMinimumFreeMemory() {
+ noInterrupts(); // Disable interrupts to get volatile value
+ int retval = freeMemory();
+ interrupts();
+ return retval;
+}
+
+extern "C" char* sbrk(int incr);
+
+int DCCTimer::freeMemory() {
+ char top;
+ return (int)(&top - reinterpret_cast(sbrk(0)));
+}
+
+void DCCTimer::reset() {
+ __disable_irq();
+ NVIC_SystemReset();
+ while(true) {};
+}
+
+#endif
\ No newline at end of file
diff --git a/DCCTimerTEENSY.cpp b/DCCTimerTEENSY.cpp
index dc682df..a29f000 100644
--- a/DCCTimerTEENSY.cpp
+++ b/DCCTimerTEENSY.cpp
@@ -88,8 +88,20 @@ void DCCTimer::getSimulatedMacAddress(byte mac[6]) {
}
#endif
+volatile int DCCTimer::minimum_free_memory=__INT_MAX__;
+
+// Return low memory value...
+int DCCTimer::getMinimumFreeMemory() {
+ noInterrupts(); // Disable interrupts to get volatile value
+ int retval = freeMemory();
+ interrupts();
+ return retval;
+}
+
+extern "C" char* sbrk(int incr);
+
#if !defined(__IMXRT1062__)
-static inline int freeMemory() {
+int DCCTimer::freeMemory() {
char top;
return &top - reinterpret_cast(sbrk(0));
}
@@ -110,7 +122,7 @@ static inline int freeMemory() {
#endif
#endif
-static inline int freeMemory() {
+int DCCTimer::freeMemory() {
extern unsigned long _ebss;
extern unsigned long _sdata;
extern unsigned long _estack;
diff --git a/FSH.h b/FSH.h
index c901fb9..f13e597 100644
--- a/FSH.h
+++ b/FSH.h
@@ -47,6 +47,14 @@ typedef char FSH;
#define FLASH
#define strlen_P strlen
#define strcpy_P strcpy
+#elif defined(ARDUINO_ARCH_STM32)
+typedef __FlashStringHelper FSH;
+#define GETFLASH(addr) pgm_read_byte_near(addr)
+#define GETFLASHW(addr) pgm_read_word_near(addr)
+#ifdef FLASH
+ #undef FLASH
+#endif
+#define FLASH PROGMEM
#else
typedef __FlashStringHelper FSH;
#define GETFLASH(addr) pgm_read_byte_near(addr)
diff --git a/IO_MCP23008.h b/IO_MCP23008.h
index aa4679b..a411117 100644
--- a/IO_MCP23008.h
+++ b/IO_MCP23008.h
@@ -31,7 +31,7 @@ public:
private:
// Constructor
MCP23008(VPIN firstVpin, uint8_t nPins, uint8_t I2CAddress, int interruptPin=-1)
- : GPIOBase((FSH *)F("MCP23008"), firstVpin, min(nPins, 8), I2CAddress, interruptPin) {
+ : GPIOBase((FSH *)F("MCP23008"), firstVpin, min(nPins, (uint8_t)8), I2CAddress, interruptPin) {
requestBlock.setRequestParams(_I2CAddress, inputBuffer, sizeof(inputBuffer),
outputBuffer, sizeof(outputBuffer));
diff --git a/IO_PCF8574.h b/IO_PCF8574.h
index 44eccad..f862984 100644
--- a/IO_PCF8574.h
+++ b/IO_PCF8574.h
@@ -48,7 +48,7 @@ public:
private:
PCF8574(VPIN firstVpin, uint8_t nPins, uint8_t I2CAddress, int interruptPin=-1)
- : GPIOBase((FSH *)F("PCF8574"), firstVpin, min(nPins, 8), I2CAddress, interruptPin)
+ : GPIOBase((FSH *)F("PCF8574"), firstVpin, min(nPins, (uint8_t)8), I2CAddress, interruptPin)
{
requestBlock.setReadParams(_I2CAddress, inputBuffer, 1);
}
diff --git a/MotorDriver.cpp b/MotorDriver.cpp
index 0239d1c..620d996 100644
--- a/MotorDriver.cpp
+++ b/MotorDriver.cpp
@@ -268,6 +268,8 @@ void MotorDriver::getFastPin(const FSH* type,int pin, bool input, FASTPIN & res
(void) type; // avoid compiler warning if diag not used above.
#if defined(ARDUINO_ARCH_SAMD)
PortGroup *port = digitalPinToPort(pin);
+#elif defined(ARDUINO_ARCH_STM32)
+ GPIO_TypeDef *port = digitalPinToPort(pin);
#else
uint8_t port = digitalPinToPort(pin);
#endif
diff --git a/MotorDriver.h b/MotorDriver.h
index 9e32ea0..9e2ff4f 100644
--- a/MotorDriver.h
+++ b/MotorDriver.h
@@ -43,6 +43,20 @@
#if defined(ARDUINO_AVR_UNO)
#define HAVE_PORTB(X) X
#endif
+#if defined(ARDUINO_ARCH_SAMD)
+#define PORTA REG_PORT_OUT0
+#define HAVE_PORTA(X) X
+#define PORTB REG_PORT_OUT1
+#define HAVE_PORTB(X) X
+#endif
+#if defined(ARDUINO_ARCH_STM32)
+#define PORTA GPIOA->ODR
+#define HAVE_PORTA(X) X
+#define PORTB GPIOB->ODR
+#define HAVE_PORTB(X) X
+#define PORTC GPIOC->ODR
+#define HAVE_PORTC(X) X
+#endif
// if macros not defined as pass-through we define
// them here as someting that is valid as a
@@ -63,7 +77,7 @@
#define UNUSED_PIN 127 // inside int8_t
#endif
-#if defined(__IMXRT1062__) || defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_SAMD)
+#if defined(__IMXRT1062__) || defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_STM32)
typedef uint32_t portreg_t;
#else
typedef uint8_t portreg_t;
diff --git a/defines.h b/defines.h
index 23a7993..fa8dd17 100644
--- a/defines.h
+++ b/defines.h
@@ -40,6 +40,7 @@
// figure out if we have enough memory for advanced features
// so define HAS_ENOUGH_MEMORY until proved otherwise.
#define HAS_ENOUGH_MEMORY
+#undef USB_SERIAL // Teensy has this defined by default...
#define USB_SERIAL Serial
#if defined(ARDUINO_AVR_UNO)
@@ -55,16 +56,62 @@
#elif defined(ARDUINO_ARCH_MEGAAVR)
#define ARDUINO_TYPE "MEGAAVR"
#undef HAS_ENOUGH_MEMORY
-#elif defined(ARDUINO_TEENSY32)
-#define ARDUINO_TYPE "TEENSY32"
+#elif defined(ARDUINO_TEENSY31)
+#define ARDUINO_TYPE "TEENSY3132"
+#undef USB_SERIAL
+#define USB_SERIAL SerialUSB
+#ifndef DISABLE_EEPROM
+ #define DISABLE_EEPROM
+#endif
+// Teensy support for native I2C is awaiting development
+#ifndef I2C_NO_INTERRUPTS
+ #define I2C_NO_INTERRUPTS
+#endif
#elif defined(ARDUINO_TEENSY35)
#define ARDUINO_TYPE "TEENSY35"
+#undef USB_SERIAL
+#define USB_SERIAL SerialUSB
+// Teensy support for I2C is awaiting development
+#ifndef DISABLE_EEPROM
+ #define DISABLE_EEPROM
+#endif
+// Teensy support for native I2C is awaiting development
+#ifndef I2C_NO_INTERRUPTS
+ #define I2C_NO_INTERRUPTS
+#endif
#elif defined(ARDUINO_TEENSY36)
#define ARDUINO_TYPE "TEENSY36"
+#undef USB_SERIAL
+#define USB_SERIAL SerialUSB
+#ifndef DISABLE_EEPROM
+ #define DISABLE_EEPROM
+#endif
+// Teensy support for native I2C is awaiting development
+#ifndef I2C_NO_INTERRUPTS
+ #define I2C_NO_INTERRUPTS
+#endif
#elif defined(ARDUINO_TEENSY40)
#define ARDUINO_TYPE "TEENSY40"
+#undef USB_SERIAL
+#define USB_SERIAL SerialUSB
+#ifndef DISABLE_EEPROM
+ #define DISABLE_EEPROM
+#endif
+// Teensy support for native I2C is awaiting development
+#ifndef I2C_NO_INTERRUPTS
+ #define I2C_NO_INTERRUPTS
+#endif
#elif defined(ARDUINO_TEENSY41)
#define ARDUINO_TYPE "TEENSY41"
+#undef USB_SERIAL
+#define USB_SERIAL SerialUSB
+#ifndef DISABLE_EEPROM
+ #define DISABLE_EEPROM
+#endif
+// Teensy support for native I2C is awaiting development
+#ifndef I2C_NO_INTERRUPTS
+ #define I2C_NO_INTERRUPTS
+#endif
#elif defined(ARDUINO_ARCH_ESP8266)
#define ARDUINO_TYPE "ESP8266"
#elif defined(ARDUINO_ARCH_ESP32)
@@ -73,10 +120,21 @@
#define ARDUINO_TYPE "SAMD21"
#undef USB_SERIAL
#define USB_SERIAL SerialUSB
-// SAMD support for I2C is awaiting development
+// STM32 no EEPROM by default
#ifndef DISABLE_EEPROM
#define DISABLE_EEPROM
#endif
+// SAMD support for native I2C is awaiting development
+#ifndef I2C_NO_INTERRUPTS
+ #define I2C_NO_INTERRUPTS
+#endif
+#elif defined(ARDUINO_ARCH_STM32)
+#define ARDUINO_TYPE "STM32"
+// STM32 no EEPROM by default
+#ifndef DISABLE_EEPROM
+ #define DISABLE_EEPROM
+#endif
+// STM32 support for native I2C is awaiting development
#ifndef I2C_NO_INTERRUPTS
#define I2C_NO_INTERRUPTS
#endif
diff --git a/platformio.ini b/platformio.ini
index 0a38cf8..43a4092 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -18,6 +18,12 @@ default_envs =
samd21-dev-usb
samd21-zero-usb
ESP32
+ Nucleo-STM32F411RE
+ Teensy3.2
+ Teensy3.5
+ Teensy3.6
+ Teensy4.0
+ Teensy4.1
src_dir = .
include_dir = .
@@ -164,4 +170,53 @@ platform = espressif32
board = esp32dev
framework = arduino
lib_deps = ${env.lib_deps}
-build_flags = -std=c++17
\ No newline at end of file
+build_flags = -std=c++17
+
+[env:Nucleo-STM32F411RE]
+platform = ststm32
+board = nucleo_f411re
+framework = arduino
+lib_deps = ${env.lib_deps}
+build_flags = -std=c++17 -DDISABLE_EEPROM -Os -g2
+monitor_speed = 115200
+monitor_echo = yes
+
+[env:Teensy3.2]
+platform = teensy
+board = teensy31
+framework = arduino
+build_flags = -std=c++17 -DDISABLE_EEPROM -Os -g2
+lib_deps = ${env.lib_deps}
+lib_ignore = NativeEthernet
+
+[env:Teensy3.5]
+platform = teensy
+board = teensy35
+framework = arduino
+build_flags = -std=c++17 -DDISABLE_EEPROM -Os -g2
+lib_deps = ${env.lib_deps}
+lib_ignore = NativeEthernet
+
+[env:Teensy3.6]
+platform = teensy
+board = teensy36
+framework = arduino
+build_flags = -std=c++17 -DDISABLE_EEPROM -Os -g2
+lib_deps = ${env.lib_deps}
+lib_ignore = NativeEthernet
+
+[env:Teensy4.0]
+platform = teensy
+board = teensy40
+framework = arduino
+build_flags = -std=c++17 -DDISABLE_EEPROM -Os -g2
+lib_deps = ${env.lib_deps}
+lib_ignore = NativeEthernet
+
+[env:Teensy4.1]
+platform = teensy
+board = teensy41
+framework = arduino
+build_flags = -std=c++17 -DDISABLE_EEPROM -Os -g2
+lib_deps = ${env.lib_deps}
+lib_ignore =
\ No newline at end of file