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