diff options
author | David Crocker <dcrocker@eschertech.com> | 2016-06-28 23:50:13 +0300 |
---|---|---|
committer | David Crocker <dcrocker@eschertech.com> | 2016-06-28 23:50:13 +0300 |
commit | f7cff3a05430b862ea50373cea6659c47483fccf (patch) | |
tree | 0aa2731158e004498ba96bf9fbd99d3429630909 /src | |
parent | cddcf711cd51c0f97f4b78fb3e7d3252890c0e86 (diff) |
Version 1.14 very early beta
Changes to use new pin modes in CoreNG
Initialise TMC2660 step/dir/CS pins as early as possible
Allow emergency stop in simulation mode
Disable drives and heaters when doing a software reset
Support 10th drive and 8th heater on Duet WiFi
TMC2660 driver support is now only in Duet WiFi firmware build
Diffstat (limited to 'src')
-rw-r--r-- | src/Configuration.h | 4 | ||||
-rw-r--r-- | src/Duet/Pins_Duet.h | 8 | ||||
-rw-r--r-- | src/DuetNG/Network.cpp | 43 | ||||
-rw-r--r-- | src/DuetNG/Pins_DuetNG.h | 35 | ||||
-rw-r--r-- | src/DuetNG/TMC2660.cpp (renamed from src/ExternalDrivers.cpp) | 88 | ||||
-rw-r--r-- | src/DuetNG/TMC2660.h (renamed from src/ExternalDrivers.h) | 12 | ||||
-rw-r--r-- | src/GCodes.cpp | 5 | ||||
-rw-r--r-- | src/Platform.cpp | 205 | ||||
-rw-r--r-- | src/Platform.h | 43 |
9 files changed, 181 insertions, 262 deletions
diff --git a/src/Configuration.h b/src/Configuration.h index aadff29d..eb6f6cfa 100644 --- a/src/Configuration.h +++ b/src/Configuration.h @@ -26,11 +26,11 @@ Licence: GPL // Firmware name is now defined in the Pins file #ifndef VERSION -# define VERSION "1.13b" +# define VERSION "1.14 beta 1" #endif #ifndef DATE -# define DATE "2016-06-24" +# define DATE "2016-06-27" #endif #define AUTHORS "reprappro, dc42, zpl, t3p3, dnewman" diff --git a/src/Duet/Pins_Duet.h b/src/Duet/Pins_Duet.h index 75ef1853..6fdefe4e 100644 --- a/src/Duet/Pins_Duet.h +++ b/src/Duet/Pins_Duet.h @@ -16,14 +16,10 @@ const size_t NumFirmwareUpdateModules = 1; // The physical capabilities of the machine const size_t DRIVES = 9; // The number of drives in the machine, including X, Y, and Z plus extruder drives -#define DRIVES_(a,b,c,d,e,f,g,h,i) { a,b,c,d,e,f,g,h,i } - -// If enabled, the following control the use of the optional ExternalDrivers module -//#define EXTERNAL_DRIVERS (1) -//#define FIRST_EXTERNAL_DRIVE (5) +#define DRIVES_(a,b,c,d,e,f,g,h,i,j) { a,b,c,d,e,f,g,h,i } const int8_t HEATERS = 7; // The number of heaters in the machine; 0 is the heated bed even if there isn't one -#define HEATERS_(a,b,c,d,e,f,g) { a,b,c,d,e,f,g } +#define HEATERS_(a,b,c,d,e,f,g,h) { a,b,c,d,e,f,g } const size_t AXES = 3; // The number of movement axes in the machine, usually just X, Y and Z. <= DRIVES const size_t NUM_SERIAL_CHANNELS = 3; // The number of serial IO channels (USB and two auxiliary UARTs) diff --git a/src/DuetNG/Network.cpp b/src/DuetNG/Network.cpp index b0868afc..89f5baf8 100644 --- a/src/DuetNG/Network.cpp +++ b/src/DuetNG/Network.cpp @@ -53,8 +53,7 @@ Network::Network(Platform* p) : platform(p), responseCode(0), responseBody(nullp void Network::Init() { // Make sure the ESP8266 is held in the reset state - pinMode(EspResetPin, OUTPUT); - digitalWrite(EspResetPin, LOW); + pinMode(EspResetPin, OUTPUT_LOW); uploader = new WifiFirmwareUploader(Serial1); } @@ -90,27 +89,22 @@ void Network::Start() { // The ESP8266 is held in a reset state by a pulldown resistor until we enable it. // Make sure the ESP8266 is in the reset state - pinMode(EspResetPin, OUTPUT); - digitalWrite(EspResetPin, LOW); + pinMode(EspResetPin, OUTPUT_LOW); // Take the ESP8266 out of power down - pinMode(EspEnablePin, OUTPUT); - digitalWrite(EspEnablePin, HIGH); + pinMode(EspEnablePin, OUTPUT_HIGH); // Set up our transfer request pin (GPIO4) as an output and set it low - pinMode(SamTfrReadyPin, OUTPUT); - digitalWrite(SamTfrReadyPin, LOW); + pinMode(SamTfrReadyPin, OUTPUT_LOW); // Set up our data ready pin (ESP GPIO0) as an output and set it high ready to boot the ESP from flash - pinMode(EspTransferRequestPin, OUTPUT); - digitalWrite(EspTransferRequestPin, HIGH); + pinMode(EspTransferRequestPin, OUTPUT_HIGH); // GPIO2 also needs to be high to boot. It's connected to MISO on the SAM, so set the pullup resistor on that pin pinMode(APIN_SPI_MISO, INPUT_PULLUP); // Set our CS input (ESP GPIO15) low ready for booting the ESP. This also clears the transfer ready latch. - pinMode(SamCsPin, OUTPUT); - digitalWrite(SamCsPin, LOW); + pinMode(SamCsPin, OUTPUT_LOW); // Make sure it has time to reset - no idea how long it needs, but 20ms should be plenty delay(50); @@ -182,7 +176,7 @@ void Network::Spin() { case starting: // See if the ESP8266 has set CS high yet - if (digitalRead(SamCsPin) == HIGH) + if (digitalRead(SamCsPin)) { // Setup the SPI controller in slave mode and assign the CS pin to it platform->Message(HOST_MESSAGE, "WiFi server starting up\n"); @@ -925,7 +919,7 @@ void Network::TryStartTransfer() { PrepareForTransfer(true, true); } - else if (digitalRead(EspTransferRequestPin) == HIGH) + else if (digitalRead(EspTransferRequestPin)) { PrepareForTransfer(false, true); } @@ -1030,8 +1024,7 @@ void Network::SpiInterrupt() // Reset the ESP8266 and leave held in reset void Network::ResetWiFi() { - pinMode(EspResetPin, OUTPUT); - digitalWrite(EspResetPin, LOW); + pinMode(EspResetPin, OUTPUT_LOW); } // Reset the ESP8266 to take commands from the UART. The caller must wait for the reset to complete after calling this. @@ -1043,27 +1036,22 @@ void Network::ResetWiFi() void Network::ResetWiFiForUpload() { // Make sure the ESP8266 is in the reset state - pinMode(EspResetPin, OUTPUT); - digitalWrite(EspResetPin, LOW); + pinMode(EspResetPin, OUTPUT_LOW); // Take the ESP8266 out of power down - pinMode(EspEnablePin, OUTPUT); - digitalWrite(EspEnablePin, HIGH); + pinMode(EspEnablePin, OUTPUT_HIGH); // Set up our transfer request pin (GPIO4) as an output and set it low - pinMode(SamTfrReadyPin, OUTPUT); - digitalWrite(SamTfrReadyPin, LOW); + pinMode(SamTfrReadyPin, OUTPUT_LOW); // Set up our data ready pin (ESP GPIO0) as an output and set it low ready to boot the ESP from UART - pinMode(EspTransferRequestPin, OUTPUT); - digitalWrite(EspTransferRequestPin, LOW); + pinMode(EspTransferRequestPin, OUTPUT_LOW); // GPIO2 also needs to be high to boot up. It's connected to MISO on the SAM, so set the pullup resistor on that pin pinMode(APIN_SPI_MISO, INPUT_PULLUP); // Set our CS input (ESP GPIO15) low ready for booting the ESP. This also clears the transfer ready latch. - pinMode(SamCsPin, OUTPUT); - digitalWrite(SamCsPin, LOW); + pinMode(SamCsPin, OUTPUT_LOW); // Make sure it has time to reset - no idea how long it needs, but 50ms should be plenty delay(50); @@ -1078,8 +1066,7 @@ void Network::ResetWiFiForExternalUpload() ResetWiFiForUpload(); // Set our TxD pin low to make things easier for the FTDI chip to drive the ESP RxD input - pinMode(APIN_UART1_TXD, OUTPUT); - digitalWrite(APIN_UART1_TXD, LOW); + pinMode(APIN_UART1_TXD, OUTPUT_LOW); } // End diff --git a/src/DuetNG/Pins_DuetNG.h b/src/DuetNG/Pins_DuetNG.h index 484b235c..138e3193 100644 --- a/src/DuetNG/Pins_DuetNG.h +++ b/src/DuetNG/Pins_DuetNG.h @@ -22,15 +22,11 @@ const size_t NumFirmwareUpdateModules = 4; // 3 modules, plus one for manual u // The physical capabilities of the machine -const size_t DRIVES = 9; // The number of drives in the machine, including X, Y, and Z plus extruder drives -#define DRIVES_(a,b,c,d,e,f,g,h,i) { a,b,c,d,e,f,g,h,i } +const size_t DRIVES = 10; // The number of drives in the machine, including X, Y, and Z plus extruder drives +#define DRIVES_(a,b,c,d,e,f,g,h,i,j) { a,b,c,d,e,f,g,h,i,j } -// If enabled, the following control the use of the optional ExternalDrivers module -#define EXTERNAL_DRIVERS (9) -#define FIRST_EXTERNAL_DRIVE (0) - -const int8_t HEATERS = 7; // The number of heaters in the machine; 0 is the heated bed even if there isn't one -#define HEATERS_(a,b,c,d,e,f,g) { a,b,c,d,e,f,g } +const int8_t HEATERS = 8; // The number of heaters in the machine; 0 is the heated bed even if there isn't one +#define HEATERS_(a,b,c,d,e,f,g,h) { a,b,c,d,e,f,g,h } const size_t AXES = 3; // The number of movement axes in the machine, usually just X, Y and Z. <= DRIVES const size_t NUM_SERIAL_CHANNELS = 2; // The number of serial IO channels (USB and one auxiliary UART) @@ -41,15 +37,15 @@ const size_t NUM_SERIAL_CHANNELS = 2; // The number of serial IO channels (USB // DRIVES -const Pin ENABLE_PINS[DRIVES] = { 78, 41, 42, 49, 57, 87, 88, 89, 90 }; -const bool ENABLE_VALUES[DRIVES] = { false, false, false, false, false, false, false, false, false }; // What to send to enable a drive -const Pin STEP_PINS[DRIVES] = { 70, 71, 72, 69, 68, 66, 65, 64, 67 }; -const Pin DIRECTION_PINS[DRIVES] = { 75, 76, 77, 01, 73, 92, 86, 80, 81 }; -const bool DIRECTIONS[DRIVES] = { BACKWARDS, FORWARDS, FORWARDS, FORWARDS, FORWARDS, FORWARDS, FORWARDS, FORWARDS, FORWARDS }; // What each axis needs to make it go forwards - defaults +const Pin ENABLE_PINS[DRIVES] = { 78, 41, 42, 49, 57, 87, 88, 89, 90, 31 }; +const bool ENABLE_VALUES[DRIVES] = { false, false, false, false, false, false, false, false, false, false }; // What to send to enable a drive +const Pin STEP_PINS[DRIVES] = { 70, 71, 72, 69, 68, 66, 65, 64, 67, 91 }; +const Pin DIRECTION_PINS[DRIVES] = { 75, 76, 77, 01, 73, 92, 86, 80, 81, 32 }; +const bool DIRECTIONS[DRIVES] = { FORWARDS, FORWARDS, FORWARDS, FORWARDS, FORWARDS, FORWARDS, FORWARDS, FORWARDS, FORWARDS, FORWARDS }; // What each axis needs to make it go forwards - defaults // Endstops // RepRapFirmware only has a single endstop per axis. gcode defines if it is a max ("high end") or min ("low end") endstop. gcode also sets if it is active HIGH or LOW. -const Pin END_STOP_PINS[DRIVES] = { 46, 02, 93, 74, 48, 96, 97, 98, 99 }; +const Pin END_STOP_PINS[DRIVES] = { 46, 02, 93, 74, 48, 96, 97, 98, 99, 17 }; // Indices for motor current digipots (if any): first 4 are for digipot 1 (on duet), second 4 for digipot 2 (on expansion board) #ifdef PROTOTYPE_1 @@ -64,12 +60,12 @@ const float STEPPER_DAC_VOLTAGE_OFFSET = -0.11; // Stepper motor current o const bool HEAT_ON = false; // false for inverted heater (e.g. Duet v0.6), true for not (e.g. Duet v0.4) -const Pin TEMP_SENSE_PINS[HEATERS] = { 45, 47, 44, 61, 62, 63, 59 }; // Thermistor pin numbers +const Pin TEMP_SENSE_PINS[HEATERS] = { 45, 47, 44, 61, 62, 63, 59, 18 }; // Thermistor pin numbers #ifdef PROTOTYPE_1 -const Pin HEAT_ON_PINS[HEATERS] = { 19, 20, 16, 15, 37, 40, 43 }; // Heater pin numbers +const Pin HEAT_ON_PINS[HEATERS] = { 19, 20, 16, 15, 37, 40, 43, 38 }; // Heater pin numbers #else -const Pin HEAT_ON_PINS[HEATERS] = { 19, 20, 16, 35, 37, 40, 43 }; // Heater pin numbers +const Pin HEAT_ON_PINS[HEATERS] = { 19, 20, 16, 35, 37, 40, 43, 38 }; // Heater pin numbers (heater 7 pin TBC) #endif // Default thermistor parameters @@ -167,6 +163,7 @@ const size_t NUM_PINS_ALLOWED = 96; /* pins 88-95 */ 0b00001000 \ } #endif + // SAM4E Flash locations (may be expanded in the future) const uint32_t IAP_FLASH_START = 0x00470000; const uint32_t IAP_FLASH_END = 0x0047FBFF; @@ -179,8 +176,8 @@ const Pin SamTfrReadyPin = 94; // Output from the SAM to the WiFi module indic const Pin SamCsPin = 11; // SPI NPCS pin, input from WiFi module // Timer allocation (no network timer on DuetNG) -// TC0 channel 0 is used for FAM2 -// TC0 channel 1 is used for the TMC clock +// TC0 channel 0 is used for FAN2 +// TC0 channel 1 is currently unused (may use ift for a heater or a fan) // TC0 channel 2 is available for us to use #define STEP_TC (TC0) #define STEP_TC_CHAN (2) diff --git a/src/ExternalDrivers.cpp b/src/DuetNG/TMC2660.cpp index ff8c5345..3161a59a 100644 --- a/src/ExternalDrivers.cpp +++ b/src/DuetNG/TMC2660.cpp @@ -1,5 +1,5 @@ /* - * ExternalDrivers.cpp + * TMC2660.cpp * * Created on: 23 Jan 2016 * Author: David @@ -7,9 +7,9 @@ #include "RepRapFirmware.h" -#ifdef EXTERNAL_DRIVERS +#if !defined(PROTOTYPE_1) -const size_t NumExternalDrivers = DRIVES - FIRST_EXTERNAL_DRIVE; +const size_t NumTmc2660Drivers = DRIVES; static bool driversPowered = false; @@ -41,47 +41,17 @@ static bool driversPowered = false; // CLK 23 connect to ground 2 (GND // 5V_USB 5 +3.3V 3 (+3.3V) -#ifdef DUET_NG - -const Pin DriverSelectPins[NumExternalDrivers] = {78, 41, 42, 49, 57, 87, 88, 89, 90}; - -# ifdef PROTOTYPE_1 - -// Pin assignments for the first prototype, using USART0 SPI -const Pin DriversMosiPin = 27; // PB1 -const Pin DriversMisoPin = 26; // PB0 -const Pin DriversSclkPin = 30; // PB13 -# define USART_EXT_DRV USART0 -# define ID_USART_EXT_DRV ID_USART0 - -# else - -# include "sam/drivers/tc/tc.h" - // Pin assignments for the second prototype, using USART1 SPI const Pin DriversClockPin = 15; // PB15/TIOA1 const Pin DriversMosiPin = 22; // PA13 const Pin DriversMisoPin = 21; // PA22 const Pin DriversSclkPin = 23; // PA23 -# define USART_EXT_DRV USART1 -# define ID_USART_EXT_DRV ID_USART1 -# define TMC_CLOCK_TC TC0 -# define TMC_CLOCK_CHAN 1 -# define TMC_CLOCK_ID ID_TC1 // this is channel 1 on TC0 -# endif -#else - -// Duet 0.6 or 0.8.5 - -const Pin DriverSelectPins[NumExternalDrivers] = {37, X8, 50, 47 /*, X13*/ }; -const Pin DriversMosiPin = 16; // PA13 -const Pin DriversMisoPin = 17; // PA12 -const Pin DriversSclkPin = 54; // PA16 -# define USART_EXT_DRV USART1 -# define ID_USART_EXT_DRV ID_USART1 - -#endif +#define USART_EXT_DRV USART1 +#define ID_USART_EXT_DRV ID_USART1 +#define TMC_CLOCK_TC TC0 +#define TMC_CLOCK_CHAN 1 +#define TMC_CLOCK_ID ID_TC1 // this is channel 1 on TC0 const uint32_t DriversSpiClockFrequency = 1000000; // 1MHz SPI clock for now @@ -364,15 +334,15 @@ uint32_t TmcDriverState::GetStatus() const return SpiSendWord(pin, smartEnReg) & (TMC_RR_SG | TMC_RR_OT | TMC_RR_OTPW | TMC_RR_S2G | TMC_RR_OLA | TMC_RR_OLB | TMC_RR_STST); } -static TmcDriverState driverStates[NumExternalDrivers]; +static TmcDriverState driverStates[NumTmc2660Drivers]; //--------------------------- Public interface --------------------------------- -namespace ExternalDrivers +namespace TMC2660 { // Initialise the driver interface and the drivers, leaving each drive disabled. // It is assumed that the drivers are not powered, so driversPowered(true) must be called after calling this before the motors can be moved. - void Init() + void Init(const Pin driverSelectPins[NumTmc2660Drivers]) { // Set up the SPI pins @@ -396,27 +366,11 @@ namespace ExternalDrivers // Enable the clock to the USART pmc_enable_periph_clk(ID_USART_EXT_DRV); -#if defined(DUET_NG) && !defined(PROTOTYPE_1) - // Set up the 15MHz clock to the TMC drivers on TIOA1 - pmc_enable_periph_clk(TMC_CLOCK_ID); - ConfigurePin(GetPinDescription(DriversClockPin)); // set up TIOA1 to be an output - tc_init(TMC_CLOCK_TC, TMC_CLOCK_CHAN, - TC_CMR_TCCLKS_TIMER_CLOCK1 | // clock is MCLK/2 (fastest available) - TC_CMR_BURST_NONE | // clock is not gated - TC_CMR_WAVE | // Waveform mode - TC_CMR_WAVSEL_UP_RC | // Counter runs up and reset when equals to RC - TC_CMR_EEVT_XC0 | // Set external events from XC0 (this sets up TIOB as output) - TC_CMR_ACPC_TOGGLE); // toggle TIOA output - tc_write_rc(TMC_CLOCK_TC, TMC_CLOCK_CHAN, 2); // divisor = 2, gives us a 15MHz clock with a master clock of 120MHz. - tc_start(TMC_CLOCK_TC, TMC_CLOCK_CHAN); -#endif - // Set up the CS pins and set them all high // When this becomes the standard code, we must set up the STEP and DIR pins here too. - for (size_t drive = 0; drive < NumExternalDrivers; ++drive) + for (size_t drive = 0; drive < NumTmc2660Drivers; ++drive) { - digitalWrite(DriverSelectPins[drive], HIGH); - pinMode(DriverSelectPins[drive], OUTPUT); + pinMode(driverSelectPins[drive], OUTPUT_HIGH); } // Set USART_EXT_DRV in SPI mode, with data changing on the falling edge of the clock and captured on the rising edge @@ -438,15 +392,15 @@ namespace ExternalDrivers delay(10); driversPowered = false; - for (size_t drive = 0; drive < NumExternalDrivers; ++drive) + for (size_t drive = 0; drive < NumTmc2660Drivers; ++drive) { - driverStates[drive].Init(DriverSelectPins[drive]); + driverStates[drive].Init(driverSelectPins[drive]); } } void SetCurrent(size_t drive, float current) { - if (drive < NumExternalDrivers) + if (drive < NumTmc2660Drivers) { driverStates[drive].SetCurrent(current); } @@ -454,7 +408,7 @@ namespace ExternalDrivers void EnableDrive(size_t drive, bool en) { - if (drive < NumExternalDrivers) + if (drive < NumTmc2660Drivers) { driverStates[drive].Enable(en); } @@ -462,12 +416,12 @@ namespace ExternalDrivers uint32_t GetStatus(size_t drive) { - return (drive < NumExternalDrivers) ? driverStates[drive].GetStatus() : 0; + return (drive < NumTmc2660Drivers) ? driverStates[drive].GetStatus() : 0; } bool SetMicrostepping(size_t drive, int microsteps, int mode) { - if (drive < NumExternalDrivers) + if (drive < NumTmc2660Drivers) { if (mode == 999 && microsteps >= 0) { @@ -495,7 +449,7 @@ namespace ExternalDrivers unsigned int GetMicrostepping(size_t drive, bool& interpolation) { - if (drive < NumExternalDrivers) + if (drive < NumTmc2660Drivers) { const uint32_t drvCtrl = driverStates[drive].drvCtrlReg; interpolation = (drvCtrl & TMC_DRVCTRL_INTPOL) != 0; @@ -514,7 +468,7 @@ namespace ExternalDrivers if (powered && !wasPowered) { // Power to the drivers has been provided or restored, so we need to re-initialise them - for (size_t drive = 0; drive < NumExternalDrivers; ++drive) + for (size_t drive = 0; drive < NumTmc2660Drivers; ++drive) { driverStates[drive].WriteAll(); } diff --git a/src/ExternalDrivers.h b/src/DuetNG/TMC2660.h index b966c78a..4b3a1f5a 100644 --- a/src/ExternalDrivers.h +++ b/src/DuetNG/TMC2660.h @@ -5,12 +5,14 @@ * Author: David */ -#ifndef EXTERNALDRIVERS_H_ -#define EXTERNALDRIVERS_H_ +#ifndef TMC2660_H_ +#define TMC2660_H_ -namespace ExternalDrivers +#include "Pins.h" + +namespace TMC2660 { - void Init(); + void Init(const Pin[DRIVES]); void SetCurrent(size_t drive, float current); void EnableDrive(size_t drive, bool en); uint32_t GetStatus(size_t drive); @@ -19,4 +21,4 @@ namespace ExternalDrivers void SetDriversPowered(bool powered); }; -#endif /* EXTERNALDRIVERS_H_ */ +#endif /* TMC2660_H_ */ diff --git a/src/GCodes.cpp b/src/GCodes.cpp index 9cb60545..59589f01 100644 --- a/src/GCodes.cpp +++ b/src/GCodes.cpp @@ -2772,7 +2772,7 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply) bool error = false; int code = gb->GetIValue(); - if (simulationMode != 0 && (code < 20 || code > 37) && code != 0 && code != 1 && code != 82 && code != 83 && code != 111 && code != 105 && code != 122 && code != 408 && code != 999) + if (simulationMode != 0 && (code < 20 || code > 37) && code != 0 && code != 1 && code != 82 && code != 83 && code != 105 && code != 111 && code != 112 && code != 122 && code != 408 && code != 999) { return true; // we don't yet simulate most M codes } @@ -5418,9 +5418,10 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply) break; case 999: - result = DoDwellTime(0.5); // wait half a second to allow the response to be sent back to the web server, otherwise it may retry + result = DoDwellTime(0.5); // wait half a second to allow the response to be sent back to the web server, otherwise it may retry if (result) { + reprap.EmergencyStop(); // this disables heaters and drives - Duet WiFi seems to need drives disabled here uint16_t reason = (gb->Seen('P') && StringStartsWith(gb->GetString(), "ERASE")) ? (uint16_t)SoftwareResetReason::erase : (uint16_t)SoftwareResetReason::user; diff --git a/src/Platform.cpp b/src/Platform.cpp index 5295d4d9..0b4c52b2 100644 --- a/src/Platform.cpp +++ b/src/Platform.cpp @@ -25,8 +25,8 @@ #include "sam/drivers/tc/tc.h" #include "sam/drivers/hsmci/hsmci.h" -#if defined(DUET_NG) || defined (EXTERNAL_DRIVERS) -# include "ExternalDrivers.h" +#if defined(DUET_NG) && !defined(PROTOTYPE_1) +# include <TMC2660.h> #endif #ifdef DUET_NG @@ -60,9 +60,26 @@ uint32_t nextInterruptScheduledAt = 0; uint32_t lastInterruptTime = 0; #endif +// Urgent initialisation function +// This is called before general init has been done, and before constructors for C++ static data have been called. +// Therefore, be very careful what you do here! +void UrgentInit() +{ +#ifdef DUET_NG + // When the reset button is pressed, if the TMC2660 drivers were previously enabled then we get uncommanded motor movements. + // Try to reduce that by initialising the drivers early here. + // On the production board we will also be able to set the ENN line high here. + for (size_t drive = 0; drive < DRIVES; ++drive) + { + pinMode(STEP_PINS[drive], OUTPUT_LOW); + pinMode(DIRECTION_PINS[drive], OUTPUT_LOW); + pinMode(ENABLE_PINS[drive], OUTPUT_HIGH); + } +#endif +} + // Arduino initialise and loop functions // Put nothing in these other than calls to the RepRap equivalents - void setup() { // Fill the free memory with a pattern so that we can check for stack usage and memory corruption @@ -148,8 +165,7 @@ Platform::Platform() : void Platform::Init() { // Deal with power first - digitalWrite(ATX_POWER_PIN, LOW); // ensure ATX power is off by default - pinMode(ATX_POWER_PIN, OUTPUT); + pinMode(ATX_POWER_PIN, OUTPUT_LOW); SetBoardType(BoardType::Auto); @@ -232,7 +248,7 @@ void Platform::Init() // Z PROBE zProbePin = Z_PROBE_PIN; - zProbeAdcChannel = PinToAdcChannel(zProbePin); + zProbeAdcChannel = PinToAdcChannel(zProbePin); // we don't bother to turn the pullup resistor off for this input InitZProbe(); // this also sets up zProbeModulationPin // AXES @@ -271,21 +287,17 @@ void Platform::Init() SetPhysicalDrive(drive, drive); // map drivers directly to axes and extruders if (stepPins[drive] >= 0) { - pinMode(stepPins[drive], OUTPUT); + pinMode(stepPins[drive], OUTPUT_LOW); } if (directionPins[drive] >= 0) { - pinMode(directionPins[drive], OUTPUT); + pinMode(directionPins[drive], OUTPUT_LOW); } #if !defined(DUET_NG) || defined(PROTOTYPE_1) -# ifdef EXTERNAL_DRIVERS - if (drive < FIRST_EXTERNAL_DRIVE && enablePins[drive] >= 0) -# else if (enablePins[drive] >= 0) -# endif { - pinMode(enablePins[drive], OUTPUT); + pinMode(enablePins[drive], OUTPUT_HIGH); } #endif if (endStopPins[drive] >= 0) @@ -305,9 +317,10 @@ void Platform::Init() } } -#ifdef EXTERNAL_DRIVERS +#ifdef DUET_NG + numTMC2660Drivers = DRIVES; // for now assume all drivers are TMC2660 on the Duet NG driversPowered = false; - ExternalDrivers::Init(); + TMC2660::Init(enablePins); #endif extrusionAncilliaryPWM = 0.0; @@ -317,10 +330,10 @@ void Platform::Init() { if (heatOnPins[heater] >= 0) { - digitalWrite(heatOnPins[heater], (HEAT_ON) ? LOW : HIGH); // turn the heater off - pinMode(heatOnPins[heater], OUTPUT); + pinMode(heatOnPins[heater], (HEAT_ON) ? OUTPUT_LOW : OUTPUT_HIGH); } AnalogChannelNumber chan = PinToAdcChannel(tempSensePins[heater]); // translate the Arduino Due Analog pin number to the SAM ADC channel number + pinMode(tempSensePins[heater], AIN); thermistorAdcChannels[heater] = chan; AnalogInEnableChannel(chan, true); @@ -345,24 +358,19 @@ void Platform::Init() inkjetDelayMicroseconds = INKJET_DELAY_MICROSECONDS; inkjetSerialOut = INKJET_SERIAL_OUT; - pinMode(inkjetSerialOut, OUTPUT); - digitalWrite(inkjetSerialOut, 0); + pinMode(inkjetSerialOut, OUTPUT_LOW); inkjetShiftClock = INKJET_SHIFT_CLOCK; - pinMode(inkjetShiftClock, OUTPUT); - digitalWrite(inkjetShiftClock, LOW); + pinMode(inkjetShiftClock, OUTPUT_LOW); inkjetStorageClock = INKJET_STORAGE_CLOCK; - pinMode(inkjetStorageClock, OUTPUT); - digitalWrite(inkjetStorageClock, LOW); + pinMode(inkjetStorageClock, OUTPUT_LOW); inkjetOutputEnable = INKJET_OUTPUT_ENABLE; - pinMode(inkjetOutputEnable, OUTPUT); - digitalWrite(inkjetOutputEnable, HIGH); + pinMode(inkjetOutputEnable, OUTPUT_HIGH); inkjetClear = INKJET_CLEAR; - pinMode(inkjetClear, OUTPUT); - digitalWrite(inkjetClear, HIGH); + pinMode(inkjetClear, OUTPUT_HIGH); } #endif @@ -376,6 +384,7 @@ void Platform::Init() #ifdef DUET_NG vInMonitorAdcChannel = PinToAdcChannel(PowerMonitorVinDetectPin); + pinMode(PowerMonitorVinDetectPin, AIN); AnalogInEnableChannel(vInMonitorAdcChannel, true); currentVin = highestVin = 0; lowestVin = 9999; @@ -464,14 +473,12 @@ void Platform::InitZProbe() case 1: case 2: AnalogInEnableChannel(zProbeAdcChannel, true); - pinMode(zProbeModulationPin, OUTPUT); - digitalWrite(zProbeModulationPin, HIGH); // enable the IR LED + pinMode(zProbeModulationPin, OUTPUT_HIGH); // enable the IR LED break; case 3: AnalogInEnableChannel(zProbeAdcChannel, true); - pinMode(zProbeModulationPin, OUTPUT); - digitalWrite(zProbeModulationPin, LOW); // enable the alternate sensor + pinMode(zProbeModulationPin, OUTPUT_LOW); // enable the alternate sensor break; case 4: @@ -1187,7 +1194,7 @@ void Platform::Spin() { driversPowered = true; } - ExternalDrivers::SetDriversPowered(driversPowered); + TMC2660::SetDriversPowered(driversPowered); #endif ClassReport(longWait); @@ -1693,7 +1700,7 @@ EndStopHit Platform::Stopped(size_t drive) const } else if (endStopPins[drive] >= 0) { - if (digitalRead(endStopPins[drive]) == ((endStopLogicLevel[drive]) ? 1 : 0)) + if (digitalRead(endStopPins[drive]) == endStopLogicLevel[drive]) { return (endStopType[drive] == EndStopType::highEndStop) ? EndStopHit::highHit : EndStopHit::lowHit; } @@ -1756,24 +1763,21 @@ void Platform::EnableDrive(size_t drive) UpdateMotorCurrent(driver); // the current may have been reduced by the idle timeout #if defined(DUET_NG) && !defined(PROTOTYPE_1) - ExternalDrivers::EnableDrive(driver, true); -#else -# ifdef EXTERNAL_DRIVERS - if (driver >= FIRST_EXTERNAL_DRIVE) + TMC2660::EnableDrive(driver, true); + if (driver < numTMC2660Drivers) { - ExternalDrivers::EnableDrive(driver - FIRST_EXTERNAL_DRIVE, true); + TMC2660::EnableDrive(driver, true); } else { -# endif +#endif const int pin = enablePins[driver]; if (pin >= 0) { digitalWrite(pin, enableValues[driver]); } -# ifdef EXTERNAL_DRIVERS +#if defined(DUET_NG) && !defined(PROTOTYPE_1) } -# endif #endif } } @@ -1784,27 +1788,23 @@ void Platform::DisableDrive(size_t drive) { if (drive < DRIVES) { -#if defined(DUET_NG) && !defined(PROTOTYPE_1) - ExternalDrivers::EnableDrive(driverNumbers[drive], false); -#else const size_t driver = driverNumbers[drive]; -# ifdef EXTERNAL_DRIVERS - if (driver >= FIRST_EXTERNAL_DRIVE) +#if defined(DUET_NG) && !defined(PROTOTYPE_1) + if (driver < numTMC2660Drivers) { - ExternalDrivers::EnableDrive(driver - FIRST_EXTERNAL_DRIVE, false); + TMC2660::EnableDrive(driver, false); } else { -# endif +#endif const int pin = enablePins[driver]; if (pin >= 0) { digitalWrite(pin, !enableValues[driver]); } driveState[drive] = DriveStatus::disabled; -# ifdef EXTERNAL_DRIVERS +#if defined(DUET_NG) && !defined(PROTOTYPE_1) } -# endif #endif } } @@ -1846,60 +1846,51 @@ void Platform::UpdateMotorCurrent(size_t drive) const size_t driver = driverNumbers[drive]; #if defined(DUET_NG) && !defined(PROTOTYPE_1) - ExternalDrivers::SetCurrent(driver, current); + if (driver < numTMC2660Drivers) + { + TMC2660::SetCurrent(driver, current); + } + // else we can't set the current +#elif defined (__RADDS__) + // we can't set the current on RADDS #else - -# ifdef EXTERNAL_DRIVERS - if (driver >= FIRST_EXTERNAL_DRIVE) + unsigned short pot = (unsigned short)((0.256*current*8.0*senseResistor + maxStepperDigipotVoltage/2)/maxStepperDigipotVoltage); + if (driver < 4) { - ExternalDrivers::SetCurrent(driver - FIRST_EXTERNAL_DRIVE, current); + mcpDuet.setNonVolatileWiper(potWipes[driver], pot); + mcpDuet.setVolatileWiper(potWipes[driver], pot); } else { -# endif - unsigned short pot = (unsigned short)((0.256*current*8.0*senseResistor + maxStepperDigipotVoltage/2)/maxStepperDigipotVoltage); - if (driver < 4) +# ifndef DUET_NG + if (board == BoardType::Duet_085) { - mcpDuet.setNonVolatileWiper(potWipes[driver], pot); - mcpDuet.setVolatileWiper(potWipes[driver], pot); - } - else - { -# ifndef __RADDS__ -# ifndef DUET_NG - if (board == BoardType::Duet_085) +# endif + // Extruder 0 is on DAC channel 0 + if (driver == 4) { -# endif - // Extruder 0 is on DAC channel 0 - if (driver == 4) - { - float dacVoltage = max<float>(current * 0.008*senseResistor + stepperDacVoltageOffset, 0.0); // the voltage we want from the DAC relative to its minimum - uint32_t dac = (uint32_t)((256 * dacVoltage + 0.5 * stepperDacVoltageRange)/stepperDacVoltageRange); -# ifdef DUET_NG - AnalogWrite(DAC1, dac); -# else - AnalogWrite(DAC0, dac); -# endif - } - else - { - mcpExpansion.setNonVolatileWiper(potWipes[driver-1], pot); - mcpExpansion.setVolatileWiper(potWipes[driver-1], pot); - } -# ifndef DUET_NG + float dacVoltage = max<float>(current * 0.008*senseResistor + stepperDacVoltageOffset, 0.0); // the voltage we want from the DAC relative to its minimum + uint32_t dac = (uint32_t)((256 * dacVoltage + 0.5 * stepperDacVoltageRange)/stepperDacVoltageRange); +# ifdef DUET_NG + AnalogWrite(DAC1, dac); +# else + AnalogWrite(DAC0, dac); +# endif } - else if (driver < 8) // on a Duet 0.6 we have a maximum of 8 drives + else { - mcpExpansion.setNonVolatileWiper(potWipes[driver], pot); - mcpExpansion.setVolatileWiper(potWipes[driver], pot); + mcpExpansion.setNonVolatileWiper(potWipes[driver-1], pot); + mcpExpansion.setVolatileWiper(potWipes[driver-1], pot); } -# endif -# endif +# ifndef DUET_NG + } + else if (driver < 8) // on a Duet 0.6 we have a maximum of 8 drives + { + mcpExpansion.setNonVolatileWiper(potWipes[driver], pot); + mcpExpansion.setVolatileWiper(potWipes[driver], pot); } -# ifdef EXTERNAL_DRIVERS - } # endif - + } #endif } } @@ -1928,13 +1919,10 @@ bool Platform::SetMicrostepping(size_t drive, int microsteps, int mode) if (drive < DRIVES) { #if defined(DUET_NG) && !defined(PROTOTYPE_1) - return ExternalDrivers::SetMicrostepping(driverNumbers[drive], microsteps, mode); -#else -# ifdef EXTERNAL_DRIVERS const size_t driver = driverNumbers[drive]; - if (driver >= FIRST_EXTERNAL_DRIVE) + if (driver < numTMC2660Drivers) { - return ExternalDrivers::SetMicrostepping(driver - FIRST_EXTERNAL_DRIVE, microsteps, mode); + return TMC2660::SetMicrostepping(driver, microsteps, mode); } else { @@ -1942,10 +1930,8 @@ bool Platform::SetMicrostepping(size_t drive, int microsteps, int mode) // On-board drivers only support x16 microstepping. // We ignore the interpolation on/off parameter so that e.g. M350 I1 E16:128 won't give an error if E1 supports interpolation but E0 doesn't. return microsteps == 16; -# ifdef EXTERNAL_DRIVERS +#if defined(DUET_NG) && !defined(PROTOTYPE_1) } -# endif - #endif } return false; @@ -1956,19 +1942,12 @@ unsigned int Platform::GetMicrostepping(size_t drive, bool& interpolation) const #if defined(DUET_NG) && !defined(PROTOTYPE_1) if (drive < DRIVES) { - return ExternalDrivers::GetMicrostepping(driverNumbers[drive], interpolation); - } -# else -# ifdef EXTERNAL_DRIVERS - if (drive < DRIVES) - { const size_t driver = driverNumbers[drive]; - if (driver >= FIRST_EXTERNAL_DRIVE) + if (driver < numTMC2660Drivers) { - return ExternalDrivers::GetMicrostepping(driver - FIRST_EXTERNAL_DRIVE, interpolation); + return TMC2660::GetMicrostepping(driver, interpolation); } } -# endif #endif // On-board drivers only support x16 microstepping without interpolation interpolation = false; @@ -2461,12 +2440,12 @@ void Platform::MessageF(MessageType type, const char *fmt, ...) bool Platform::AtxPower() const { - return (digitalRead(ATX_POWER_PIN) == HIGH); + return (digitalRead(ATX_POWER_PIN)); } void Platform::SetAtxPower(bool on) { - digitalWrite(ATX_POWER_PIN, (on) ? HIGH : LOW); + digitalWrite(ATX_POWER_PIN, on); } @@ -2624,7 +2603,7 @@ bool Platform::SetPin(int pin, int level) #else if ((pinInitialised[index] & mask) == 0) { - pinMode(pin, OUTPUT); + pinMode(pin, (level == 0) ? OUTPUT_LOW : OUTPUT_HIGH); pinInitialised[index] |= mask; } digitalWrite(pin, level); @@ -2816,7 +2795,7 @@ void Platform::Tick() if (driversPowered && currentVin > driverOverVoltageAdcReading) { driversPowered = false; - ExternalDrivers::SetDriversPowered(false); + TMC2660::SetDriversPowered(false); //TODO set ENN high on production boards } #endif diff --git a/src/Platform.h b/src/Platform.h index 8bd7d267..645243af 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -92,10 +92,10 @@ const int INKJET_DELAY_MICROSECONDS = 800; // How long to wait before the nex #endif -const float MAX_FEEDRATES[DRIVES] = DRIVES_(100.0, 100.0, 3.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0); // mm/sec -const float ACCELERATIONS[DRIVES] = DRIVES_(500.0, 500.0, 20.0, 250.0, 250.0, 250.0, 250.0, 250.0, 250.0); // mm/sec^2 -const float DRIVE_STEPS_PER_UNIT[DRIVES] = DRIVES_(87.4890, 87.4890, 4000.0, 420.0, 420.0, 420.0, 420.0, 420.0, 420.0); // steps/mm -const float INSTANT_DVS[DRIVES] = DRIVES_(15.0, 15.0, 0.2, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0); // mm/sec +const float MAX_FEEDRATES[DRIVES] = DRIVES_(100.0, 100.0, 3.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0); // mm/sec +const float ACCELERATIONS[DRIVES] = DRIVES_(500.0, 500.0, 20.0, 250.0, 250.0, 250.0, 250.0, 250.0, 250.0, 250.0); // mm/sec^2 +const float DRIVE_STEPS_PER_UNIT[DRIVES] = DRIVES_(87.4890, 87.4890, 4000.0, 420.0, 420.0, 420.0, 420.0, 420.0, 420.0, 420.0); // steps/mm +const float INSTANT_DVS[DRIVES] = DRIVES_(15.0, 15.0, 0.2, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0); // mm/sec // AXES @@ -112,10 +112,10 @@ const float defaultDeltaHomedHeight = 200; // mm // Bed thermistor: http://uk.farnell.com/epcos/b57863s103f040/sensor-miniature-ntc-10k/dp/1299930?Ntt=129-9930 // Hot end thermistor: http://www.digikey.co.uk/product-search/en?x=20&y=11&KeyWords=480-3137-ND -const float defaultThermistorBetas[HEATERS] = HEATERS_(BED_BETA, EXT_BETA, EXT_BETA, EXT_BETA, EXT_BETA, EXT_BETA, EXT_BETA); // Bed thermistor: B57861S104F40; Extruder thermistor: RS 198-961 -const float defaultThermistorSeriesRs[HEATERS] = HEATERS_(THERMISTOR_SERIES_RS, THERMISTOR_SERIES_RS, THERMISTOR_SERIES_RS, +const float defaultThermistorBetas[HEATERS] = HEATERS_(BED_BETA, EXT_BETA, EXT_BETA, EXT_BETA, EXT_BETA, EXT_BETA, EXT_BETA, EXT_BETA); // Bed thermistor: B57861S104F40; Extruder thermistor: RS 198-961 +const float defaultThermistorSeriesRs[HEATERS] = HEATERS_(THERMISTOR_SERIES_RS, THERMISTOR_SERIES_RS, THERMISTOR_SERIES_RS, THERMISTOR_SERIES_RS, THERMISTOR_SERIES_RS, THERMISTOR_SERIES_RS, THERMISTOR_SERIES_RS, THERMISTOR_SERIES_RS); -const float defaultThermistor25RS[HEATERS] = HEATERS_(BED_R25, EXT_R25, EXT_R25, EXT_R25, EXT_R25, EXT_R25, EXT_R25); // Thermistor ohms at 25 C = 298.15 K +const float defaultThermistor25RS[HEATERS] = HEATERS_(BED_R25, EXT_R25, EXT_R25, EXT_R25, EXT_R25, EXT_R25, EXT_R25, EXT_R25); // Thermistor ohms at 25 C = 298.15 K // Note on hot end PID parameters: // The system is highly nonlinear because the heater power is limited to a maximum value and cannot go negative. @@ -140,17 +140,17 @@ const float defaultThermistor25RS[HEATERS] = HEATERS_(BED_R25, EXT_R25, EXT_R25, // This allows us to switch between PID and bang-bang using the M301 and M304 commands. // We use method 2 (see above) -const float defaultPidKis[HEATERS] = HEATERS_(5.0, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2); // Integral PID constants -const float defaultPidKds[HEATERS] = HEATERS_(500.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0); // Derivative PID constants -const float defaultPidKps[HEATERS] = HEATERS_(-1.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0); // Proportional PID constants, negative values indicate use bang-bang instead of PID -const float defaultPidKts[HEATERS] = HEATERS_(2.7, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4); // approximate PWM value needed to maintain temperature, per degC above room temperature -const float defaultPidKss[HEATERS] = HEATERS_(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0); // PWM scaling factor, to allow for variation in heater power and supply voltage -const float defaultFullBands[HEATERS] = HEATERS_(5.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0); // errors larger than this cause heater to be on or off -const float defaultPidMins[HEATERS] = HEATERS_(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // minimum value of I-term -const float defaultPidMaxes[HEATERS] = HEATERS_(255, 180, 180, 180, 180, 180, 180); // maximum value of I-term, must be high enough to reach 245C for ABS printing - -const float STANDBY_TEMPERATURES[HEATERS] = HEATERS_(ABS_ZERO, ABS_ZERO, ABS_ZERO, ABS_ZERO, ABS_ZERO, ABS_ZERO, ABS_ZERO); // We specify one for the bed, though it's not needed -const float ACTIVE_TEMPERATURES[HEATERS] = HEATERS_(ABS_ZERO, ABS_ZERO, ABS_ZERO, ABS_ZERO, ABS_ZERO, ABS_ZERO, ABS_ZERO); +const float defaultPidKis[HEATERS] = HEATERS_(5.0, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2); // Integral PID constants +const float defaultPidKds[HEATERS] = HEATERS_(500.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0); // Derivative PID constants +const float defaultPidKps[HEATERS] = HEATERS_(-1.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0); // Proportional PID constants, negative values indicate use bang-bang instead of PID +const float defaultPidKts[HEATERS] = HEATERS_(2.7, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4); // approximate PWM value needed to maintain temperature, per degC above room temperature +const float defaultPidKss[HEATERS] = HEATERS_(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0); // PWM scaling factor, to allow for variation in heater power and supply voltage +const float defaultFullBands[HEATERS] = HEATERS_(5.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0); // errors larger than this cause heater to be on or off +const float defaultPidMins[HEATERS] = HEATERS_(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // minimum value of I-term +const float defaultPidMaxes[HEATERS] = HEATERS_(255, 180, 180, 180, 180, 180, 180, 180); // maximum value of I-term, must be high enough to reach 245C for ABS printing + +const float STANDBY_TEMPERATURES[HEATERS] = HEATERS_(ABS_ZERO, ABS_ZERO, ABS_ZERO, ABS_ZERO, ABS_ZERO, ABS_ZERO, ABS_ZERO, ABS_ZERO); // We specify one for the bed, though it's not needed +const float ACTIVE_TEMPERATURES[HEATERS] = HEATERS_(ABS_ZERO, ABS_ZERO, ABS_ZERO, ABS_ZERO, ABS_ZERO, ABS_ZERO, ABS_ZERO, ABS_ZERO); // For the theory behind ADC oversampling, see http://www.atmel.com/Images/doc8003.pdf const unsigned int AD_OVERSAMPLE_BITS = 1; // Number of bits we oversample when reading temperatures @@ -751,10 +751,13 @@ private: float idleCurrentFactor; size_t slowestDrive; float maxAverageAcceleration; + //uint16_t driversUsed[DRIVES]; // Digipots -#if !defined(DUET_NG) || defined(PROTOTYPE_1) +#if defined(DUET_NG) && !defined(PROTOTYPE_1) + size_t numTMC2660Drivers; +#else MCP4461 mcpDuet; MCP4461 mcpExpansion; Pin potWipes[8]; // we have only 8 digipots, on the Duet 0.8.5 we use the DAC for the 9th @@ -1281,7 +1284,7 @@ inline uint16_t Platform::GetRawZProbeReading() const { if (nvData.zProbeType >= 4) { - bool b = (bool)digitalRead(endStopPins[E0_AXIS]); + bool b = digitalRead(endStopPins[E0_AXIS]); if (!endStopLogicLevel[AXES]) { b = !b; |