From f878c1d01cdf256f4eda074cde5f7d94013e5142 Mon Sep 17 00:00:00 2001 From: pmantoine Date: Fri, 1 Apr 2022 21:28:21 +0800 Subject: [PATCH 01/16] Initial SAMD defines --- DCCTimer.h | 3 +++ defines.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/DCCTimer.h b/DCCTimer.h index fb8184b..04d171f 100644 --- a/DCCTimer.h +++ b/DCCTimer.h @@ -121,6 +121,9 @@ private: #elif defined(ARDUINO_ARCH_ESP32) #define ARDUINO_TYPE "ESP32" #undef HAS_AVR_WDT +#elif defined(ARDUINO_ARCH_SAMD) +#define ARDUINO_TYPE "SAMD21" +#undef HAS_AVR_WDT #else #error CANNOT COMPILE - DCC++ EX ONLY WORKS WITH THE ARCHITECTURES LISTED IN DCCTimer.h #endif diff --git a/defines.h b/defines.h index 9ce154d..c24d6af 100644 --- a/defines.h +++ b/defines.h @@ -40,7 +40,7 @@ // WIFI_ON: All prereqs for running with WIFI are met // Note: WIFI_CHANNEL may not exist in early config.h files so is added here if needed. -#if defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560) || defined(ARDUINO_SAMD_ZERO) || defined(TEENSYDUINO) || defined(ARDUINO_AVR_NANO_EVERY) || defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) +#if defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560) || defined(ARDUINO_SAMD_ZERO) || defined(TEENSYDUINO) || defined(ARDUINO_AVR_NANO_EVERY) || defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_SAMD) #define BIG_RAM #endif #if ENABLE_WIFI From cd0dfc565c8faf1f3c363ea8ed5f7cabe8f779e1 Mon Sep 17 00:00:00 2001 From: pmantoine Date: Fri, 1 Apr 2022 21:28:21 +0800 Subject: [PATCH 02/16] Initial SAMD defines --- DCCTimer.h | 3 +++ defines.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/DCCTimer.h b/DCCTimer.h index fb8184b..04d171f 100644 --- a/DCCTimer.h +++ b/DCCTimer.h @@ -121,6 +121,9 @@ private: #elif defined(ARDUINO_ARCH_ESP32) #define ARDUINO_TYPE "ESP32" #undef HAS_AVR_WDT +#elif defined(ARDUINO_ARCH_SAMD) +#define ARDUINO_TYPE "SAMD21" +#undef HAS_AVR_WDT #else #error CANNOT COMPILE - DCC++ EX ONLY WORKS WITH THE ARCHITECTURES LISTED IN DCCTimer.h #endif diff --git a/defines.h b/defines.h index 9ce154d..c24d6af 100644 --- a/defines.h +++ b/defines.h @@ -40,7 +40,7 @@ // WIFI_ON: All prereqs for running with WIFI are met // Note: WIFI_CHANNEL may not exist in early config.h files so is added here if needed. -#if defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560) || defined(ARDUINO_SAMD_ZERO) || defined(TEENSYDUINO) || defined(ARDUINO_AVR_NANO_EVERY) || defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) +#if defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560) || defined(ARDUINO_SAMD_ZERO) || defined(TEENSYDUINO) || defined(ARDUINO_AVR_NANO_EVERY) || defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_SAMD) #define BIG_RAM #endif #if ENABLE_WIFI From 5dfc014f495d6879fae6d0767f9d5dae7f8aa24f Mon Sep 17 00:00:00 2001 From: pmantoine Date: Tue, 5 Apr 2022 09:24:29 +0800 Subject: [PATCH 03/16] Some useful code plug debug goo --- CommandStation-EX.ino | 31 +++++++-------- DCCEXParser.cpp | 2 + DCCTimerSAMD.cpp | 90 +++++++++++++++++++++++++++++++++++++++++++ I2CManager.h | 4 +- MotorDriver.cpp | 6 ++- MotorDriver.h | 2 +- SerialManager.cpp | 8 +++- defines.h | 17 ++++---- platformio.ini | 16 +++----- 9 files changed, 138 insertions(+), 38 deletions(-) create mode 100644 DCCTimerSAMD.cpp diff --git a/CommandStation-EX.ino b/CommandStation-EX.ino index cd23f0e..d2627ea 100644 --- a/CommandStation-EX.ino +++ b/CommandStation-EX.ino @@ -66,6 +66,7 @@ void setup() SerialManager::init(); DIAG(F("License GPLv3 fsf.org (c) dcc-ex.com")); + DIAG(F("Platform: %s"), F(ARDUINO_TYPE)); // PMA - temporary CONDITIONAL_LCD_START { // This block is still executed for DIAGS if LCD not in use @@ -85,7 +86,7 @@ void setup() #endif // ETHERNET_ON // Initialise HAL layer before reading EEprom or setting up MotorDrivers - IODevice::begin(); +// IODevice::begin(); // Responsibility 3: Start the DCC engine. // Note: this provides DCC with two motor drivers, main and prog, which handle the motor shield(s) @@ -100,18 +101,18 @@ void setup() // Invoke any DCC++EX commands in the form "SETUP("xxxx");"" found in optional file mySetup.h. // This can be used to create turnouts, outputs, sensors etc. through the normal text commands. +// PMA - how to handle __has_include?? #if __has_include ( "mySetup.h") - #define SETUP(cmd) DCCEXParser::parse(F(cmd)) - #include "mySetup.h" - #undef SETUP + #define SETUP(cmd) DCCEXParser::parse(F(cmd)) + #include "mySetup.h" + #undef SETUP #endif - #if defined(LCN_SERIAL) - LCN_SERIAL.begin(115200); - LCN::init(LCN_SERIAL); - #endif - - LCD(3,F("Ready")); +// #if defined(LCN_SERIAL) +// LCN_SERIAL.begin(115200); +// LCN::init(LCN_SERIAL); +// #endif + LCD(3, F("Ready")); CommandDistributor::broadcastPower(); } @@ -121,7 +122,7 @@ void loop() // Responsibility 1: Handle DCC background processes // (loco reminders and power checks) - DCC::loop(); +// DCC::loop(); // Responsibility 2: handle any incoming commands on USB connection SerialManager::loop(); @@ -134,18 +135,18 @@ void loop() EthernetInterface::loop(); #endif - RMFT::loop(); // ignored if no automation +// RMFT::loop(); // ignored if no automation #if defined(LCN_SERIAL) LCN::loop(); #endif - LCDDisplay::loop(); // ignored if LCD not in use +// LCDDisplay::loop(); // ignored if LCD not in use // Handle/update IO devices. - IODevice::loop(); + //IODevice::loop(); - Sensor::checkAll(); // Update and print changes + //Sensor::checkAll(); // Update and print changes // Report any decrease in memory (will automatically trigger on first call) static int ramLowWatermark = __INT_MAX__; // replaced on first loop diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index 2fc8f6b..ad4054d 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -781,7 +781,9 @@ bool DCCEXParser::parseD(Print *stream, int16_t params, int16_t p[]) wdt_enable( WDTO_15MS); // set Arduino watchdog timer for 15ms delay(50); // wait for the prescaller time to expire #else +#ifdef ARDUINO_ARCH_ESP ESP.restart(); +#endif #endif break; // and if we didnt restart } diff --git a/DCCTimerSAMD.cpp b/DCCTimerSAMD.cpp new file mode 100644 index 0000000..74ec18b --- /dev/null +++ b/DCCTimerSAMD.cpp @@ -0,0 +1,90 @@ +/* + * © 2021 Mike S + * © 2021 Harald Barth + * © 2021 Fred Decker + * © 2021 Chris Harlow + * © 2021 David Cutting + * © 2022 Paul M. Antoine + * 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 TEENSY +// Please refer to DCCTimer.h for general comments about how this class works +// This is to avoid repetition and duplication. +#ifdef ARDUINO_ARCH_SAMD + +#include "FSH.h" //PMA temp debug +#include "DIAG.h" //PMA temp debug +#include "DCCTimer.h" + +INTERRUPT_CALLBACK interruptHandler=0; + +void DCCTimer::begin(INTERRUPT_CALLBACK callback) { + interruptHandler=callback; + + + + + } + +bool DCCTimer::isPWMPin(byte pin) { + //SAMD: digitalPinHasPWM, todo + (void) pin; + return false; // TODO what are the relevant pins? + } + +void DCCTimer::setPWM(byte pin, bool high) { + // TODO what are the relevant pins? + (void) pin; + (void) high; +} + +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))); +} + +#endif \ No newline at end of file diff --git a/I2CManager.h b/I2CManager.h index 1163261..67fd1ad 100644 --- a/I2CManager.h +++ b/I2CManager.h @@ -111,10 +111,10 @@ */ // Uncomment following line to enable Wire library instead of native I2C drivers -//#define I2C_USE_WIRE +#define I2C_USE_WIRE // Uncomment following line to disable the use of interrupts by the native I2C drivers. -//#define I2C_NO_INTERRUPTS +#define I2C_NO_INTERRUPTS // Default to use interrupts within the native I2C drivers. #ifndef I2C_NO_INTERRUPTS diff --git a/MotorDriver.cpp b/MotorDriver.cpp index 517e2dd..c40a0f1 100644 --- a/MotorDriver.cpp +++ b/MotorDriver.cpp @@ -192,8 +192,12 @@ int MotorDriver::mA2raw( unsigned int mA) { void MotorDriver::getFastPin(const FSH* type,int pin, bool input, FASTPIN & result) { // DIAG(F("MotorDriver %S Pin=%d,"),type,pin); - (void) type; // avoid compiler warning if diag not used above. + (void) type; // avoid compiler warning if diag not used above. +#if defined(ARDUINO_ARCH_SAMD) + PortGroup *port = digitalPinToPort(pin); +#else uint8_t port = digitalPinToPort(pin); +#endif if (input) result.inout = portInputRegister(port); else diff --git a/MotorDriver.h b/MotorDriver.h index 981b259..3a21b89 100644 --- a/MotorDriver.h +++ b/MotorDriver.h @@ -30,7 +30,7 @@ #define UNUSED_PIN 127 // inside int8_t #endif -#if defined(__IMXRT1062__) || defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) +#if defined(__IMXRT1062__) || defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_SAMD) struct FASTPIN { volatile uint32_t *inout; uint32_t maskHIGH; diff --git a/SerialManager.cpp b/SerialManager.cpp index 8717227..2dce51b 100644 --- a/SerialManager.cpp +++ b/SerialManager.cpp @@ -32,9 +32,15 @@ SerialManager::SerialManager(Stream * myserial) { } void SerialManager::init() { - while (!Serial && millis() < 5000); // wait max 5s for Serial to start +// while (!Serial && millis() < 5000); // wait max 5s for Serial to start +#if defined(ARDUINO_ARCH_SAMD) + SerialUSB.begin(115200); + while (!SerialUSB); // PMA - temporary for debuggering purpoises + new SerialManager(&SerialUSB); +#else Serial.begin(115200); new SerialManager(&Serial); +#endif #ifdef SERIAL3_COMMANDS Serial3.begin(115200); new SerialManager(&Serial3); diff --git a/defines.h b/defines.h index c24d6af..aba5daf 100644 --- a/defines.h +++ b/defines.h @@ -77,14 +77,15 @@ // This defines the speed at which the Arduino will communicate with the ESP8266 module. // Currently only devices which can communicate at 115200 are supported. // -#define WIFI_SERIAL_LINK_SPEED 115200 +#define WIFI_SERIAL_LINK_SPEED 9600 -#if __has_include ( "myAutomation.h") - #if defined(BIG_RAM) || defined(DISABLE_EEPROM) - #define EXRAIL_ACTIVE - #else - #define EXRAIL_WARNING - #endif -#endif +// TODO: PMA - figure out why enabling this causes the CS to crashe immediately after starting the motor driver +//#if __has_include ( "myAutomation.h") +// #if defined(BIG_RAM) || defined(DISABLE_EEPROM) +// #define EXRAIL_ACTIVE +// #else +// #define EXRAIL_WARNING +// #endif +//#endif #endif diff --git a/platformio.ini b/platformio.ini index 8bba297..59136b3 100644 --- a/platformio.ini +++ b/platformio.ini @@ -10,13 +10,9 @@ [platformio] default_envs = - mega2560 - uno - mega328 - unowifiR2 - nano -src_dir = . -include_dir = . + samd21 +src_dir = /Users/paul/Projects/CommandStation-EX +include_dir = /Users/paul/Projects/CommandStation-EX [env] build_flags = -Wall -Wextra @@ -25,12 +21,13 @@ build_flags = -Wall -Wextra platform = atmelsam board = sparkfun_samd21_dev_usb framework = arduino -upload_protocol = atmel-ice +upload_protocol = sam-ba lib_deps = ${env.lib_deps} SparkFun External EEPROM Arduino Library monitor_speed = 115200 monitor_flags = --echo +build_flags = -std=c++17 [env:mega2560-debug] platform = atmelavr @@ -131,7 +128,6 @@ platform = atmelavr board = nanoatmega328new board_upload.maximum_size = 32256 framework = arduino -lib_deps = - ${env.lib_deps} +lib_deps = ${env.lib_deps} monitor_speed = 115200 monitor_flags = --echo From 7312951b2bbde1adc9f91bf43d96c56af0abeceb Mon Sep 17 00:00:00 2001 From: pmantoine Date: Tue, 5 Apr 2022 09:38:33 +0800 Subject: [PATCH 04/16] Platformio.ini to test workflow --- platformio.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index 59136b3..7283f42 100644 --- a/platformio.ini +++ b/platformio.ini @@ -11,8 +11,8 @@ [platformio] default_envs = samd21 -src_dir = /Users/paul/Projects/CommandStation-EX -include_dir = /Users/paul/Projects/CommandStation-EX +src_dir = . +include_dir = . [env] build_flags = -Wall -Wextra From 5ccef35074e47188e11028030a0b2dfe70807f3e Mon Sep 17 00:00:00 2001 From: pmantoine Date: Tue, 5 Apr 2022 12:53:11 +0800 Subject: [PATCH 05/16] ADC config --- CommandStation-EX.ino | 1 - DCCTimerSAMD.cpp | 25 +++++++++++++++++++++++++ MotorDrivers.h | 8 ++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/CommandStation-EX.ino b/CommandStation-EX.ino index d2627ea..219e245 100644 --- a/CommandStation-EX.ino +++ b/CommandStation-EX.ino @@ -101,7 +101,6 @@ void setup() // Invoke any DCC++EX commands in the form "SETUP("xxxx");"" found in optional file mySetup.h. // This can be used to create turnouts, outputs, sensors etc. through the normal text commands. -// PMA - how to handle __has_include?? #if __has_include ( "mySetup.h") #define SETUP(cmd) DCCEXParser::parse(F(cmd)) #include "mySetup.h" diff --git a/DCCTimerSAMD.cpp b/DCCTimerSAMD.cpp index 74ec18b..a3f9c00 100644 --- a/DCCTimerSAMD.cpp +++ b/DCCTimerSAMD.cpp @@ -37,8 +37,33 @@ INTERRUPT_CALLBACK interruptHandler=0; void DCCTimer::begin(INTERRUPT_CALLBACK callback) { interruptHandler=callback; + // PMA - SAMC used on Firebox has 2 ADCs, so choose which to set up based on pin being used + // TODO: this code will need to be fixed - ADCpin is not in scope... as this is stolen from + // the abandoned rf24 branch + #if defined(ARDUINO_ARCH_SAMC) + Adc* ADC; + if ( (g_APinDescription[ADCpin].ulPeripheralAttribute & PER_ATTR_ADC_MASK) == PER_ATTR_ADC_STD ) { + ADC = ADC0; + } else { + ADC = ADC1; + } + #endif + // PMA - Set up ADC to do faster reads... default for Arduino Zero platform configs is 436uS, + // and we need sub-100uS. This code sets it to a read speed of around 21uS, and enables 12-bit + ADC->CTRLA.bit.ENABLE = 0; // disable ADC + while( ADC->STATUS.bit.SYNCBUSY == 1 ); // wait for synchronization + ADC->CTRLB.reg &= 0b1111100011111111; // mask PRESCALER bits + ADC->CTRLB.reg |= ADC_CTRLB_PRESCALER_DIV64 | // divide Clock by 64 + ADC_CTRLB_RESSEL_12BIT; // Result on 12 bits + + ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_1 | // take 1 sample at a time + ADC_AVGCTRL_ADJRES(0x00ul); // adjusting result by 0 + ADC->SAMPCTRL.reg = 0x00; // sampling Time Length = 0 + + ADC->CTRLA.bit.ENABLE = 1; // enable ADC + while(ADC->STATUS.bit.SYNCBUSY == 1); // wait for synchronization } diff --git a/MotorDrivers.h b/MotorDrivers.h index b2b798d..accddf1 100644 --- a/MotorDrivers.h +++ b/MotorDrivers.h @@ -46,9 +46,17 @@ // (HIGH == release brake) // // Arduino standard Motor Shield +#if defined(ARDUINO_ARCH_SAMD) +// PMA - senseFactor for 3.3v systems is 1.95 as calculated when using 10-bit A/D samples, +// and for 12-bit samples it's more like 0.488, but we probably need to tweak both these +#define STANDARD_MOTOR_SHIELD F("STANDARD_MOTOR_SHIELD"), \ + new MotorDriver(3, 12, UNUSED_PIN, 9, A0, 0.488, 2000, UNUSED_PIN), \ + new MotorDriver(11, 13, UNUSED_PIN, 8, A1, 0.488, 2000, UNUSED_PIN) +#else #define STANDARD_MOTOR_SHIELD F("STANDARD_MOTOR_SHIELD"), \ new MotorDriver(3, 12, UNUSED_PIN, 9, A0, 2.99, 2000, UNUSED_PIN), \ new MotorDriver(11, 13, UNUSED_PIN, 8, A1, 2.99, 2000, UNUSED_PIN) +#endif // Pololu Motor Shield #define POLOLU_MOTOR_SHIELD F("POLOLU_MOTOR_SHIELD"), \ From 46e4dc26288fcd8cc8dd7ff6e83bc365b38d9536 Mon Sep 17 00:00:00 2001 From: pmantoine Date: Thu, 7 Apr 2022 16:53:50 +0800 Subject: [PATCH 06/16] Motor driver senseFactor and 10bit ADC --- DCCTimerSAMD.cpp | 2 +- MotorDrivers.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DCCTimerSAMD.cpp b/DCCTimerSAMD.cpp index a3f9c00..eb4849b 100644 --- a/DCCTimerSAMD.cpp +++ b/DCCTimerSAMD.cpp @@ -56,7 +56,7 @@ void DCCTimer::begin(INTERRUPT_CALLBACK callback) { ADC->CTRLB.reg &= 0b1111100011111111; // mask PRESCALER bits ADC->CTRLB.reg |= ADC_CTRLB_PRESCALER_DIV64 | // divide Clock by 64 - ADC_CTRLB_RESSEL_12BIT; // Result on 12 bits + ADC_CTRLB_RESSEL_10BIT; // Result on 10 bits default, 12 bits possible ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_1 | // take 1 sample at a time ADC_AVGCTRL_ADJRES(0x00ul); // adjusting result by 0 diff --git a/MotorDrivers.h b/MotorDrivers.h index accddf1..74aab48 100644 --- a/MotorDrivers.h +++ b/MotorDrivers.h @@ -50,8 +50,8 @@ // PMA - senseFactor for 3.3v systems is 1.95 as calculated when using 10-bit A/D samples, // and for 12-bit samples it's more like 0.488, but we probably need to tweak both these #define STANDARD_MOTOR_SHIELD F("STANDARD_MOTOR_SHIELD"), \ - new MotorDriver(3, 12, UNUSED_PIN, 9, A0, 0.488, 2000, UNUSED_PIN), \ - new MotorDriver(11, 13, UNUSED_PIN, 8, A1, 0.488, 2000, UNUSED_PIN) + new MotorDriver(3, 12, UNUSED_PIN, 9, A0, 1.95, 2000, UNUSED_PIN), \ + new MotorDriver(11, 13, UNUSED_PIN, 8, A1, 1.95, 2000, UNUSED_PIN) #else #define STANDARD_MOTOR_SHIELD F("STANDARD_MOTOR_SHIELD"), \ new MotorDriver(3, 12, UNUSED_PIN, 9, A0, 2.99, 2000, UNUSED_PIN), \ From 63c9ca414d7fcc2af5b9289d369c6962a46b5cb7 Mon Sep 17 00:00:00 2001 From: pmantoine Date: Thu, 7 Apr 2022 16:55:33 +0800 Subject: [PATCH 07/16] Initial timer setup code --- DCCTimerSAMD.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/DCCTimerSAMD.cpp b/DCCTimerSAMD.cpp index a3f9c00..337b1bf 100644 --- a/DCCTimerSAMD.cpp +++ b/DCCTimerSAMD.cpp @@ -65,7 +65,26 @@ void DCCTimer::begin(INTERRUPT_CALLBACK callback) { ADC->CTRLA.bit.ENABLE = 1; // enable ADC while(ADC->STATUS.bit.SYNCBUSY == 1); // wait for synchronization - } + // PMA - actual timer setup goo + // Setup clock sources first + REG_GCLK_GENDIV = GCLK_GENDIV_DIV(1) | // Divide 48MHz by 1 + GCLK_GENDIV_ID(4); // Apply to GCLK4 + while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization + + REG_GCLK_GENCTRL = GCLK_GENCTRL_GENEN | // Enable GCLK + GCLK_GENCTRL_SRC_DFLL48M | // Set the 48MHz clock source + GCLK_GENCTRL_ID(4); // Select GCLK4 + while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization + + REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN | // Enable generic clock + 4 << GCLK_CLKCTRL_GEN_Pos | // Apply to GCLK4 + GCLK_CLKCTRL_ID_TCC0_TCC1; // Feed GCLK to TCC0/1 + while (GCLK->STATUS.bit.SYNCBUSY); + + + + +} bool DCCTimer::isPWMPin(byte pin) { //SAMD: digitalPinHasPWM, todo From 084ddf01e140b76e7d3bc8853e42ca9dc9d06d53 Mon Sep 17 00:00:00 2001 From: pmantoine Date: Fri, 8 Apr 2022 10:59:30 +0800 Subject: [PATCH 08/16] More SAMD timer setup --- DCCTimerMEGAAVR.cpp | 2 +- DCCTimerSAMD.cpp | 50 ++++++++++++++++++++++++++++++--------------- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/DCCTimerMEGAAVR.cpp b/DCCTimerMEGAAVR.cpp index 8b43340..628b469 100644 --- a/DCCTimerMEGAAVR.cpp +++ b/DCCTimerMEGAAVR.cpp @@ -75,7 +75,7 @@ extern char *__malloc_heap_start; // ISR called by timer interrupt every 58uS ISR(TCB0_INT_vect){ - TCB0.INTFLAGS = TCB_CAPT_bm; + TCB0.INTFLAGS = TCB_CAPT_bm; // Clear interrupt request flag interruptHandler(); } diff --git a/DCCTimerSAMD.cpp b/DCCTimerSAMD.cpp index 19684b2..b3324a9 100644 --- a/DCCTimerSAMD.cpp +++ b/DCCTimerSAMD.cpp @@ -36,18 +36,7 @@ INTERRUPT_CALLBACK interruptHandler=0; void DCCTimer::begin(INTERRUPT_CALLBACK callback) { interruptHandler=callback; - - // PMA - SAMC used on Firebox has 2 ADCs, so choose which to set up based on pin being used - // TODO: this code will need to be fixed - ADCpin is not in scope... as this is stolen from - // the abandoned rf24 branch - #if defined(ARDUINO_ARCH_SAMC) - Adc* ADC; - if ( (g_APinDescription[ADCpin].ulPeripheralAttribute & PER_ATTR_ADC_MASK) == PER_ATTR_ADC_STD ) { - ADC = ADC0; - } else { - ADC = ADC1; - } - #endif + noInterrupts(); // PMA - Set up ADC to do faster reads... default for Arduino Zero platform configs is 436uS, // and we need sub-100uS. This code sets it to a read speed of around 21uS, and enables 12-bit @@ -80,20 +69,47 @@ void DCCTimer::begin(INTERRUPT_CALLBACK callback) { 4 << GCLK_CLKCTRL_GEN_Pos | // Apply to GCLK4 GCLK_CLKCTRL_ID_TCC0_TCC1; // Feed GCLK to TCC0/1 while (GCLK->STATUS.bit.SYNCBUSY); - - - + // PMA - assume we're using TCC0 + REG_GCLK_GENDIV = GCLK_GENDIV_DIV(1) | // Divide 48MHz by 1 + GCLK_GENDIV_ID(4); // Apply to GCLK4 + while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization + + REG_GCLK_GENCTRL = GCLK_GENCTRL_GENEN | // Enable GCLK + GCLK_GENCTRL_SRC_DFLL48M | // Set the 48MHz clock source + GCLK_GENCTRL_ID(4); // Select GCLK4 + while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization + + REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN | // Enable generic clock + 4 << GCLK_CLKCTRL_GEN_Pos | // Apply to GCLK4 + GCLK_CLKCTRL_ID_TCC0_TCC1; // Feed GCLK to TCC0/1 + while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization + + TCC0->WAVE.reg = TCC_WAVE_WAVEGEN_NPWM; // Select NPWM as waveform + while (TCC0->SYNCBUSY.bit.WAVE); // Wait for sync + TCC0->INTENSET.reg = TCC_INTENSET_OVF; // Interrupt on overflow + NVIC_EnableIRQ((IRQn_Type)TCC0_IRQn); // Enable the interrupt + interrupts(); } +// PMA - IRQ handler copied from rf24 branch +// TODO: test +void TCC0_Handler() { + if(TCC0->INTFLAG.bit.OVF) { + TCC0->INTFLAG.bit.OVF = 1; + interruptHandler(); + } +} + + bool DCCTimer::isPWMPin(byte pin) { - //SAMD: digitalPinHasPWM, todo + //TODO: SAMD digitalPinHasPWM (void) pin; return false; // TODO what are the relevant pins? } void DCCTimer::setPWM(byte pin, bool high) { - // TODO what are the relevant pins? + // TODO: what are the relevant pins? (void) pin; (void) high; } From a52551babe6cee31f0d08cab4012d910a23a664f Mon Sep 17 00:00:00 2001 From: pmantoine Date: Fri, 8 Apr 2022 12:35:19 +0800 Subject: [PATCH 09/16] SAMD timer code --- DCCTimerSAMD.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/DCCTimerSAMD.cpp b/DCCTimerSAMD.cpp index b3324a9..deff05b 100644 --- a/DCCTimerSAMD.cpp +++ b/DCCTimerSAMD.cpp @@ -88,6 +88,18 @@ void DCCTimer::begin(INTERRUPT_CALLBACK callback) { TCC0->WAVE.reg = TCC_WAVE_WAVEGEN_NPWM; // Select NPWM as waveform while (TCC0->SYNCBUSY.bit.WAVE); // Wait for sync TCC0->INTENSET.reg = TCC_INTENSET_OVF; // Interrupt on overflow + + // PMA - set the frequency + TCC0->CTRLA.reg |= TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV1_Val); + unsigned long cycles = F_CPU / 10000000 * 58; // 58uS to cycles + unsigned long pwmPeriod = cycles / 2; + TCC0->PER.reg = pwmPeriod; + while (TCC0->SYNCBUSY.bit.PER); + + // PMA - start it + TCC0->CTRLA.bit.ENABLE = 1; + while (TCC0->SYNCBUSY.bit.ENABLE); + NVIC_EnableIRQ((IRQn_Type)TCC0_IRQn); // Enable the interrupt interrupts(); } From 8fa1ba3039ba0e985f000302a4be680f8fc0cb92 Mon Sep 17 00:00:00 2001 From: pmantoine Date: Tue, 12 Apr 2022 14:32:10 +0800 Subject: [PATCH 10/16] SAMD21 DCC waveform working --- CommandStation-EX.ino | 22 +++++++++--------- DCCTimerSAMD.cpp | 54 +++++++++++++++++++++++-------------------- MotorDrivers.h | 3 ++- 3 files changed, 42 insertions(+), 37 deletions(-) diff --git a/CommandStation-EX.ino b/CommandStation-EX.ino index 219e245..1834228 100644 --- a/CommandStation-EX.ino +++ b/CommandStation-EX.ino @@ -85,8 +85,8 @@ void setup() EthernetInterface::setup(); #endif // ETHERNET_ON -// Initialise HAL layer before reading EEprom or setting up MotorDrivers -// IODevice::begin(); + // Initialise HAL layer before reading EEprom or setting up MotorDrivers + IODevice::begin(); // Responsibility 3: Start the DCC engine. // Note: this provides DCC with two motor drivers, main and prog, which handle the motor shield(s) @@ -107,10 +107,10 @@ void setup() #undef SETUP #endif -// #if defined(LCN_SERIAL) -// LCN_SERIAL.begin(115200); -// LCN::init(LCN_SERIAL); -// #endif + #if defined(LCN_SERIAL) + LCN_SERIAL.begin(115200); + LCN::init(LCN_SERIAL); + #endif LCD(3, F("Ready")); CommandDistributor::broadcastPower(); } @@ -121,7 +121,7 @@ void loop() // Responsibility 1: Handle DCC background processes // (loco reminders and power checks) -// DCC::loop(); + DCC::loop(); // Responsibility 2: handle any incoming commands on USB connection SerialManager::loop(); @@ -134,18 +134,18 @@ void loop() EthernetInterface::loop(); #endif -// RMFT::loop(); // ignored if no automation + RMFT::loop(); // ignored if no automation #if defined(LCN_SERIAL) LCN::loop(); #endif -// LCDDisplay::loop(); // ignored if LCD not in use + LCDDisplay::loop(); // ignored if LCD not in use // Handle/update IO devices. - //IODevice::loop(); + IODevice::loop(); - //Sensor::checkAll(); // Update and print changes + Sensor::checkAll(); // Update and print changes // Report any decrease in memory (will automatically trigger on first call) static int ramLowWatermark = __INT_MAX__; // replaced on first loop diff --git a/DCCTimerSAMD.cpp b/DCCTimerSAMD.cpp index deff05b..159dd55 100644 --- a/DCCTimerSAMD.cpp +++ b/DCCTimerSAMD.cpp @@ -70,55 +70,59 @@ void DCCTimer::begin(INTERRUPT_CALLBACK callback) { GCLK_CLKCTRL_ID_TCC0_TCC1; // Feed GCLK to TCC0/1 while (GCLK->STATUS.bit.SYNCBUSY); - // PMA - assume we're using TCC0 - REG_GCLK_GENDIV = GCLK_GENDIV_DIV(1) | // Divide 48MHz by 1 - GCLK_GENDIV_ID(4); // Apply to GCLK4 - while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization - - REG_GCLK_GENCTRL = GCLK_GENCTRL_GENEN | // Enable GCLK - GCLK_GENCTRL_SRC_DFLL48M | // Set the 48MHz clock source - GCLK_GENCTRL_ID(4); // Select GCLK4 - while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization - - REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN | // Enable generic clock - 4 << GCLK_CLKCTRL_GEN_Pos | // Apply to GCLK4 - GCLK_CLKCTRL_ID_TCC0_TCC1; // Feed GCLK to TCC0/1 - while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization - + // PMA - assume we're using TCC0... as we're bit-bashing the DCC waveform output pins anyway + // for "normal accuracy" DCC waveform generation. For high accuracy we're going to need + // to a good deal more. The TCC waveform output pins are mux'd on the SAMD, and OP pins + // for each TCC are only available on certain pins TCC0->WAVE.reg = TCC_WAVE_WAVEGEN_NPWM; // Select NPWM as waveform while (TCC0->SYNCBUSY.bit.WAVE); // Wait for sync - TCC0->INTENSET.reg = TCC_INTENSET_OVF; // Interrupt on overflow // PMA - set the frequency TCC0->CTRLA.reg |= TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV1_Val); - unsigned long cycles = F_CPU / 10000000 * 58; // 58uS to cycles - unsigned long pwmPeriod = cycles / 2; - TCC0->PER.reg = pwmPeriod; + TCC0->PER.reg = CLOCK_CYCLES * 2; while (TCC0->SYNCBUSY.bit.PER); // PMA - start it TCC0->CTRLA.bit.ENABLE = 1; while (TCC0->SYNCBUSY.bit.ENABLE); + // PMA - set interrupt condition, priority and enable + TCC0->INTENSET.reg = TCC_INTENSET_OVF; // Only interrupt on overflow + NVIC_SetPriority((IRQn_Type)TCC0_IRQn, 0); // Make this highest priority NVIC_EnableIRQ((IRQn_Type)TCC0_IRQn); // Enable the interrupt interrupts(); } -// PMA - IRQ handler copied from rf24 branch +// PMA - Timer IRQ handlers replace the dummy handlers (cortex_handlers) +// copied from rf24 branch // TODO: test void TCC0_Handler() { if(TCC0->INTFLAG.bit.OVF) { - TCC0->INTFLAG.bit.OVF = 1; + TCC0->INTFLAG.bit.OVF = 1; // writing a 1 clears the flag + interruptHandler(); + } +} + +void TCC1_Handler() { + if(TCC1->INTFLAG.bit.OVF) { + TCC1->INTFLAG.bit.OVF = 1; // writing a 1 clears the flag + interruptHandler(); + } +} + +void TCC2_Handler() { + if(TCC2->INTFLAG.bit.OVF) { + TCC2->INTFLAG.bit.OVF = 1; // writing a 1 clears the flag interruptHandler(); } } bool DCCTimer::isPWMPin(byte pin) { - //TODO: SAMD digitalPinHasPWM - (void) pin; - return false; // TODO what are the relevant pins? - } + //TODO: SAMD test this works! +// return digitalPinHasPWM(pin); + return false; +} void DCCTimer::setPWM(byte pin, bool high) { // TODO: what are the relevant pins? diff --git a/MotorDrivers.h b/MotorDrivers.h index 74aab48..5237298 100644 --- a/MotorDrivers.h +++ b/MotorDrivers.h @@ -47,7 +47,8 @@ // // Arduino standard Motor Shield #if defined(ARDUINO_ARCH_SAMD) -// PMA - senseFactor for 3.3v systems is 1.95 as calculated when using 10-bit A/D samples, +// PMA - Setup for SAMD21 Sparkfun DEV board +// senseFactor for 3.3v systems is 1.95 as calculated when using 10-bit A/D samples, // and for 12-bit samples it's more like 0.488, but we probably need to tweak both these #define STANDARD_MOTOR_SHIELD F("STANDARD_MOTOR_SHIELD"), \ new MotorDriver(3, 12, UNUSED_PIN, 9, A0, 1.95, 2000, UNUSED_PIN), \ From cb365579d8abbcd0990e201cb0a0e8c7c01ea2bd Mon Sep 17 00:00:00 2001 From: pmantoine Date: Thu, 5 May 2022 21:20:49 +0800 Subject: [PATCH 11/16] Minor edits. --- DCCTimerSAMD.cpp | 5 +++-- defines.h | 20 +++++++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/DCCTimerSAMD.cpp b/DCCTimerSAMD.cpp index 159dd55..88603e6 100644 --- a/DCCTimerSAMD.cpp +++ b/DCCTimerSAMD.cpp @@ -119,8 +119,9 @@ void TCC2_Handler() { bool DCCTimer::isPWMPin(byte pin) { - //TODO: SAMD test this works! -// return digitalPinHasPWM(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; } diff --git a/defines.h b/defines.h index aba5daf..19ebb4a 100644 --- a/defines.h +++ b/defines.h @@ -77,15 +77,21 @@ // This defines the speed at which the Arduino will communicate with the ESP8266 module. // Currently only devices which can communicate at 115200 are supported. // +// TODO: PMA remove! Need 9600bps for Sparkfun shield with old firmware! +#if defined(ARDUINO_ARCH_SAMD) #define WIFI_SERIAL_LINK_SPEED 9600 +#else +#define WIFI_SERIAL_LINK_SPEED 115200 +#endif // TODO: PMA - figure out why enabling this causes the CS to crashe immediately after starting the motor driver -//#if __has_include ( "myAutomation.h") -// #if defined(BIG_RAM) || defined(DISABLE_EEPROM) -// #define EXRAIL_ACTIVE -// #else -// #define EXRAIL_WARNING -// #endif -//#endif +// on the SAMD platform - going to try to rebase to current TrackManager in case it's not my bug :-) +#if __has_include ( "myAutomation.h") + #if defined(BIG_RAM) || defined(DISABLE_EEPROM) + #define EXRAIL_ACTIVE + #else + #define EXRAIL_WARNING + #endif +#endif #endif From d2fa44eec706f71cf894efb8a95698da281a2a88 Mon Sep 17 00:00:00 2001 From: Asbelos Date: Thu, 24 Mar 2022 11:56:06 +0000 Subject: [PATCH 12/16] EXRAIL VIRTUAL_TURNOUT --- defines.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/defines.h b/defines.h index 19ebb4a..c24d6af 100644 --- a/defines.h +++ b/defines.h @@ -77,15 +77,8 @@ // This defines the speed at which the Arduino will communicate with the ESP8266 module. // Currently only devices which can communicate at 115200 are supported. // -// TODO: PMA remove! Need 9600bps for Sparkfun shield with old firmware! -#if defined(ARDUINO_ARCH_SAMD) -#define WIFI_SERIAL_LINK_SPEED 9600 -#else #define WIFI_SERIAL_LINK_SPEED 115200 -#endif -// TODO: PMA - figure out why enabling this causes the CS to crashe immediately after starting the motor driver -// on the SAMD platform - going to try to rebase to current TrackManager in case it's not my bug :-) #if __has_include ( "myAutomation.h") #if defined(BIG_RAM) || defined(DISABLE_EEPROM) #define EXRAIL_ACTIVE From 3c01bd9012003ef8f9e21b56cc8c282df18f32af Mon Sep 17 00:00:00 2001 From: Asbelos Date: Thu, 24 Mar 2022 13:56:01 +0000 Subject: [PATCH 13/16] Cleanup version.h --- version.h | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/version.h b/version.h index cb08ff3..8bfc201 100644 --- a/version.h +++ b/version.h @@ -24,29 +24,19 @@ // EXRAIL POWERON // 4.0.0 Major functional and non-functional changes. // Engine Driver "DriveAway" feature enhancement -// 'Discovered Server' multicast Dynamic Network Server (mDNS) displays available WiFi connections to a DCC++EX Command Station -// New EX-RAIL "Extended Railroad Automation Instruction Language" automation capability. -// EX-Rail Function commands for creating Automation, Route & Sequence Scripts -// EX-RAIL “ROSTER” Engines Id & Function key layout on Engine Driver or WiThrottle -// EX-RAIL DCC++EX Commands to Control EX-RAIL via JMRI Send pane and IDE Serial monitors -// New JMRI feature enhancements; -// Reads DCC++EX EEPROM & automatically uploades any Signals, DCC Turnouts, Servo Turnouts, Vpin Turnouts , & Output pane -// Turnout class revised to expand turnout capabilities, new commands added. -// Provides for multiple additional DCC++EX WiFi connections as accessory controllers or CS for a programming track when Motor Shields are added -// Supports Multiple Command Station connections and individual tracking of Send DCC++ Command panes and DCC++ Traffic Monitor panes -// New HAL added for I/O (digital and analogue inputs and outputs, servos etc) -// Automatically detects & connects to supported devices included in your config.h file -// Support for MCP23008, MCP23017 and PCF9584 I2C GPIO Extender modules. -// Support for PCA9685 PWM (servo) control modules. -// Support for analogue inputs on Arduino pins and on ADS111x I2C modules. -// Support for MP3 sound playback via DFPlayer module. -// Support for HC-SR04 Ultrasonic range sensor module. -// Support for VL53L0X Laser range sensor module (Time-Of-Flight). -// Added diagnostic command to show configured devices -// New Processor Support added -// Compiles on Nano Every and Teensy -// Native non-blocking I2C drivers for AVR and Nano architectures (fallback to blocking Wire library for other platforms). -// Can disable EEPROM code +// JMRI feature enhancement. Provides for multiple additional DCC++EX wifi +// connections as accessory controllers or CS for a programming track when +// motor shield is added +// New HAL added for I/O (digital and analogue inputs and outputs, servos etc). +// Support for MCP23008, MCP23017 and PCF9584 I2C GPIO Extender modules. +// Support for PCA9685 PWM (servo) control modules. +// Support for analogue inputs on Arduino pins and on ADS111x I2C modules. +// Support for MP3 sound playback via DFPlayer module. +// Support for HC-SR04 Ultrasonic range sensor module. +// Support for VL53L0X Laser range sensor module (Time-Of-Flight). +// Added diagnostic command to show configured devices +// Native non-blocking I2C drivers for AVR and Nano architectures (fallback +// to blocking Wire library for other platforms). // EEPROM layout change - deletes EEPROM contents on first start following upgrade. // Output class now allows ID > 255. // Configuration options to globally flip polarity of DCC Accessory states when driven from command and command. From a1a2c9ce5b3b7392e7215a01f5cba72bcb8f7bb3 Mon Sep 17 00:00:00 2001 From: Kcsmith0708 Date: Thu, 24 Mar 2022 11:34:11 -0400 Subject: [PATCH 14/16] Update version.h (#223) Rewrite & Updated the 4.0.0 Section --- version.h | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/version.h b/version.h index 8bfc201..cb08ff3 100644 --- a/version.h +++ b/version.h @@ -24,19 +24,29 @@ // EXRAIL POWERON // 4.0.0 Major functional and non-functional changes. // Engine Driver "DriveAway" feature enhancement -// JMRI feature enhancement. Provides for multiple additional DCC++EX wifi -// connections as accessory controllers or CS for a programming track when -// motor shield is added -// New HAL added for I/O (digital and analogue inputs and outputs, servos etc). -// Support for MCP23008, MCP23017 and PCF9584 I2C GPIO Extender modules. -// Support for PCA9685 PWM (servo) control modules. -// Support for analogue inputs on Arduino pins and on ADS111x I2C modules. -// Support for MP3 sound playback via DFPlayer module. -// Support for HC-SR04 Ultrasonic range sensor module. -// Support for VL53L0X Laser range sensor module (Time-Of-Flight). -// Added diagnostic command to show configured devices -// Native non-blocking I2C drivers for AVR and Nano architectures (fallback -// to blocking Wire library for other platforms). +// 'Discovered Server' multicast Dynamic Network Server (mDNS) displays available WiFi connections to a DCC++EX Command Station +// New EX-RAIL "Extended Railroad Automation Instruction Language" automation capability. +// EX-Rail Function commands for creating Automation, Route & Sequence Scripts +// EX-RAIL “ROSTER” Engines Id & Function key layout on Engine Driver or WiThrottle +// EX-RAIL DCC++EX Commands to Control EX-RAIL via JMRI Send pane and IDE Serial monitors +// New JMRI feature enhancements; +// Reads DCC++EX EEPROM & automatically uploades any Signals, DCC Turnouts, Servo Turnouts, Vpin Turnouts , & Output pane +// Turnout class revised to expand turnout capabilities, new commands added. +// Provides for multiple additional DCC++EX WiFi connections as accessory controllers or CS for a programming track when Motor Shields are added +// Supports Multiple Command Station connections and individual tracking of Send DCC++ Command panes and DCC++ Traffic Monitor panes +// New HAL added for I/O (digital and analogue inputs and outputs, servos etc) +// Automatically detects & connects to supported devices included in your config.h file +// Support for MCP23008, MCP23017 and PCF9584 I2C GPIO Extender modules. +// Support for PCA9685 PWM (servo) control modules. +// Support for analogue inputs on Arduino pins and on ADS111x I2C modules. +// Support for MP3 sound playback via DFPlayer module. +// Support for HC-SR04 Ultrasonic range sensor module. +// Support for VL53L0X Laser range sensor module (Time-Of-Flight). +// Added diagnostic command to show configured devices +// New Processor Support added +// Compiles on Nano Every and Teensy +// Native non-blocking I2C drivers for AVR and Nano architectures (fallback to blocking Wire library for other platforms). +// Can disable EEPROM code // EEPROM layout change - deletes EEPROM contents on first start following upgrade. // Output class now allows ID > 255. // Configuration options to globally flip polarity of DCC Accessory states when driven from command and command. From c2d7e7169a2bbc95db2d6d23262a77c360c6a3c5 Mon Sep 17 00:00:00 2001 From: pmantoine Date: Fri, 3 Jun 2022 17:04:32 +0800 Subject: [PATCH 15/16] Starting I2C Native Driver --- I2CManager_SAMD.h | 188 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 I2CManager_SAMD.h diff --git a/I2CManager_SAMD.h b/I2CManager_SAMD.h new file mode 100644 index 0000000..aeabd6c --- /dev/null +++ b/I2CManager_SAMD.h @@ -0,0 +1,188 @@ +/* + * © 2021, Neil McKechnie. All rights reserved. + * + * This file is part of CommandStation-EX + * + * 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 . + */ + +#ifndef I2CMANAGER_SAMD_H +#define I2CMANAGER_SAMD_H + +#include +#include "I2CManager.h" + +//#include +//#include + +#if defined(I2C_USE_INTERRUPTS) && defined(ARDUINO_SAMD_ZERO) +// PMA - IRQ handler, based on SERCOM3 being used for I2C, as per Arduino Zero & Sparkfun SAMD21 +// TODO: test +void SERCOM3_Handler() { + I2CManagerClass::handleInterrupt(); +} +#endif + +/*************************************************************************** + * Set I2C clock speed register. + ***************************************************************************/ +void I2CManagerClass::I2C_setClock(unsigned long i2cClockSpeed) { + unsigned long temp = ((F_CPU / i2cClockSpeed) - 16) / 2; + for (uint8_t preScaler = 0; preScaler<=3; preScaler++) { + if (temp <= 255) { + TWBR = temp; + TWSR = (TWSR & 0xfc) | preScaler; + return; + } else + temp /= 4; + } + // Set slowest speed ~= 500 bits/sec + TWBR = 255; + TWSR |= 0x03; +} + +/*************************************************************************** + * Initialise I2C registers. + ***************************************************************************/ +void I2CManagerClass::I2C_init() +{ + // PMA - broadly we do the following + initialise the clock + initialise the NVIC + software reset the I2C for the sercom + set master mode + do we need smart mode and quick command?? + configure interrupt handlers + enable interrupts + set default baud rate + set SDA/SCL pins as outputs and enable pullups +} + +/*************************************************************************** + * Initiate a start bit for transmission. + ***************************************************************************/ +void I2CManagerClass::I2C_sendStart() { + bytesToSend = currentRequest->writeLen; + bytesToReceive = currentRequest->readLen; + // We may have initiated a stop bit before this without waiting for it. + // Wait for stop bit to be sent before sending start. + while (TWCR & (1<writeBuffer + (txCount++)); + else + TWDR = currentRequest->writeBuffer[txCount++]; + bytesToSend--; + TWCR = (1< 0) { + currentRequest->readBuffer[rxCount++] = TWDR; + bytesToReceive--; + } + /* fallthrough */ + case TWI_MRX_ADR_ACK: // SLA+R has been sent and ACK received + if (bytesToReceive <= 1) { + TWCR = (1< 0) { + currentRequest->readBuffer[rxCount++] = TWDR; + bytesToReceive--; + } + TWCR = (1<i2cAddress << 1) | 1; // SLA+R + else + TWDR = (currentRequest->i2cAddress << 1) | 0; // SLA+W + TWCR = (1< Date: Fri, 3 Jun 2022 17:15:46 +0800 Subject: [PATCH 16/16] Various SAMC/SAMD defs --- DCC.cpp | 5 ++++- EEStore.cpp | 4 ++-- defines.h | 5 ----- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/DCC.cpp b/DCC.cpp index 05fb00a..f59d880 100644 --- a/DCC.cpp +++ b/DCC.cpp @@ -62,8 +62,11 @@ byte DCC::globalSpeedsteps=128; void DCC::begin(const FSH * motorShieldName) { shieldName=(FSH *)motorShieldName; +#if defined(ARDUINO_ARCH_SAMD) + StringFormatter::send(SerialUSB,F("\n"), F(VERSION), F(ARDUINO_TYPE), shieldName, F(GITHUB_SHA)); +#else StringFormatter::send(Serial,F("\n"), F(VERSION), F(ARDUINO_TYPE), shieldName, F(GITHUB_SHA)); - +#endif #ifndef DISABLE_EEPROM // Load stuff from EEprom (void)EEPROM; // tell compiler not to warn this is unused diff --git a/EEStore.cpp b/EEStore.cpp index a441f00..89577aa 100644 --- a/EEStore.cpp +++ b/EEStore.cpp @@ -31,12 +31,12 @@ #include "Sensors.h" #include "Turnouts.h" -#if defined(ARDUINO_ARCH_SAMD) +#if defined(ARDUINO_ARCH_SAMC) ExternalEEPROM EEPROM; #endif void EEStore::init() { -#if defined(ARDUINO_ARCH_SAMD) +#if defined(ARDUINO_ARCH_SAMC) EEPROM.begin(0x50); // Address for Microchip 24-series EEPROM with all three // A pins grounded (0b1010000 = 0x50) #endif diff --git a/defines.h b/defines.h index 19ebb4a..f48811c 100644 --- a/defines.h +++ b/defines.h @@ -77,12 +77,7 @@ // This defines the speed at which the Arduino will communicate with the ESP8266 module. // Currently only devices which can communicate at 115200 are supported. // -// TODO: PMA remove! Need 9600bps for Sparkfun shield with old firmware! -#if defined(ARDUINO_ARCH_SAMD) -#define WIFI_SERIAL_LINK_SPEED 9600 -#else #define WIFI_SERIAL_LINK_SPEED 115200 -#endif // TODO: PMA - figure out why enabling this causes the CS to crashe immediately after starting the motor driver // on the SAMD platform - going to try to rebase to current TrackManager in case it's not my bug :-)