diff options
Diffstat (limited to 'src/Movement')
-rw-r--r-- | src/Movement/StepperDrivers/TMC22xx.cpp | 120 | ||||
-rw-r--r-- | src/Movement/StepperDrivers/TMC2660.cpp | 54 | ||||
-rw-r--r-- | src/Movement/StepperDrivers/TMC51xx.cpp | 48 |
3 files changed, 151 insertions, 71 deletions
diff --git a/src/Movement/StepperDrivers/TMC22xx.cpp b/src/Movement/StepperDrivers/TMC22xx.cpp index b3ed6cc0..5bab7a0b 100644 --- a/src/Movement/StepperDrivers/TMC22xx.cpp +++ b/src/Movement/StepperDrivers/TMC22xx.cpp @@ -419,6 +419,7 @@ public: void AppendStallConfig(const StringRef& reply) const noexcept; #endif void AppendDriverStatus(const StringRef& reply) noexcept; + StandardDriverStatus GetStandardDriverStatus() const noexcept; uint8_t GetDriverNumber() const noexcept { return driverNumber; } bool UpdatePending() const noexcept; #if TMC22xx_HAS_ENABLE_PINS @@ -483,8 +484,7 @@ private: #if HAS_STALL_DETECT void ResetLoadRegisters() noexcept { - minSgLoadRegister = 1023; - maxSgLoadRegister = 0; + minSgLoadRegister = 9999; // values read from the driver are in the range 0 to 1023, so 9999 indicates that it hasn't been read } #endif @@ -552,8 +552,7 @@ private: uint32_t maxOpenLoadStepInterval; // the maximum step pulse interval for which we consider open load detection to be reliable #if HAS_STALL_DETECT - uint32_t minSgLoadRegister; // the minimum value of the StallGuard bits we read - uint32_t maxSgLoadRegister; // the maximum value of the StallGuard bits we read + uint16_t minSgLoadRegister; // the minimum value of the StallGuard bits we read #endif #if TMC22xx_HAS_MUX || TMC22xx_SINGLE_DRIVER @@ -1300,13 +1299,13 @@ void TmcDriverState::AppendDriverStatus(const StringRef& reply) noexcept } #if HAS_STALL_DETECT - if (minSgLoadRegister <= maxSgLoadRegister) + if (minSgLoadRegister <= 1023) { - reply.catf(", SG min/max %" PRIu32 "/%" PRIu32, minSgLoadRegister, maxSgLoadRegister); + reply.catf(", SG min %u", minSgLoadRegister); } else { - reply.cat(", SG min/max n/a"); + reply.cat(", SG min n/a"); } ResetLoadRegisters(); #endif @@ -1321,6 +1320,20 @@ void TmcDriverState::AppendDriverStatus(const StringRef& reply) noexcept readErrors = writeErrors = numReads = numWrites = numTimeouts = numDmaErrors = 0; } +StandardDriverStatus TmcDriverState::GetStandardDriverStatus() const noexcept +{ + StandardDriverStatus rslt; + const uint32_t status = ReadLiveStatus(); + // The lowest 8 bits of StandardDriverStatus have the same meanings as for the TMC2209 status + rslt.all = status & 0x000000FF; + rslt.all |= ExtractBit(status, TMC_RR_STST_BIT_POS, StandardDriverStatus::StandstillBitPos); // put the standstill bit in the right place + rslt.all |= ExtractBit(status, TMC_RR_SG_BIT_POS, StandardDriverStatus::StallBitPos); // put the stall bit in the right place +#if HAS_STALL_DETECT + rslt.sgresultMin = minSgLoadRegister; +#endif + return rslt; +} + // This is called by the ISR when the SPI transfer has completed inline void TmcDriverState::TransferDone() noexcept { @@ -1377,15 +1390,11 @@ inline void TmcDriverState::TransferDone() noexcept #if HAS_STALL_DETECT else if (registerToRead == ReadSgResult) { - const uint32_t sgResult = regVal & SG_RESULT_MASK; + const uint16_t sgResult = regVal & SG_RESULT_MASK; if (sgResult < minSgLoadRegister) { minSgLoadRegister = sgResult; } - if (sgResult > maxSgLoadRegister) - { - maxSgLoadRegister = sgResult; - } } #endif readRegisters[registerToRead] = regVal; @@ -2140,24 +2149,91 @@ GCodeResult SmartDrivers::SetAnyRegister(size_t driver, const StringRef& reply, StandardDriverStatus SmartDrivers::GetStandardDriverStatus(size_t driver) noexcept { - StandardDriverStatus rslt; if (driver < GetNumTmcDrivers()) { - const uint32_t status = driverStates[driver].ReadLiveStatus(); - // The lowest 8 bits of StandardDriverStatus have the same meanings as for the TMC2209 status - rslt.all = status & 0x000000FF; - rslt.all |= ExtractBit(status, TMC_RR_STST_BIT_POS, StandardDriverStatus::StandstillBitPos); // put the standstill bit in the right place - rslt.all |= ExtractBit(status, TMC_RR_SG_BIT_POS, StandardDriverStatus::StallBitPos); // put the stall bit in the right place - } - else - { - rslt.all = 0; + return driverStates[driver].GetStandardDriverStatus(); } + StandardDriverStatus rslt; + rslt.all = 0; return rslt; } #if HAS_STALL_DETECT +# ifdef DUET3MINI + +// Stall detection for Duet 3 Mini v0.4 and later +// Each TMC2209 DIAG output is routed to its own MCU pin, however we don't have enough EXINTs on the SAME54 to give each one its own interrupt. +// So we route them all to CCL input pins instead, which lets us selectively OR them together in 3 groups and generate an interrupt from the resulting events + +// Set up to generate interrupts on the specified drivers stalling +void EnableStallInterrupt(DriversBitmap drivers) noexcept +{ + // Disable all the Diag event interrupts + for (unsigned int i = 1; i < 3; ++i) + { + CCL->LUTCTRL[i].reg &= ~CCL_LUTCTRL_ENABLE; + EVSYS->Channel[CclLut0Event + i].CHINTENCLR.reg = EVSYS_CHINTENCLR_EVD | EVSYS_CHINTENCLR_OVR; + EVSYS->Channel[CclLut0Event + i].CHINTFLAG.reg = EVSYS_CHINTFLAG_EVD | EVSYS_CHINTENCLR_OVR; + } + + if (!drivers.IsEmpty()) + { + // Calculate the new LUT control values + constexpr uint32_t lutDefault = CCL_LUTCTRL_TRUTH(0xFE) | CCL_LUTCTRL_LUTEO; // OR function, disabled, event output enabled + uint32_t lutInputControls[4] = { lutDefault, lutDefault, lutDefault, lutDefault }; + drivers.IterateWhile([&lutInputControls](unsigned int driver, unsigned int count) -> bool + { if (driver < GetNumTmcDrivers()) + { + const uint32_t cclInput = CclDiagInputs[driver]; + lutInputControls[cclInput & 3] |= cclInput & 0x000000FFFFFF0000; + return true; + } + else + { + return false; + } + } ); + + // Now set up the CCL with those inputs. We only use CCL 1-3 so leave 0 alone for possible other applications. + for (unsigned int i = 1; i < 4; ++i) + { + if (lutInputControls[i] & 0x000000FFFFFF0000) // if any inputs are enabled + { + CCL->LUTCTRL[i].reg = lutInputControls[i]; + CCL->LUTCTRL[i].reg = lutInputControls[i] | CCL_LUTCTRL_ENABLE; + EVSYS->Channel[CclLut0Event + i].CHINTENSET.reg = EVSYS_CHINTENCLR_EVD; + } + } + } +} + +// Initialise the stall detection logic that is external to the drivers. Only needs to be called once. +static void InitStallDetectionLogic() noexcept +{ + // Set up the DIAG inputs as CCL inputs + for (Pin p : DriverDiagPins) + { + pinMode(p, INPUT_PULLDOWN); // enable pulldown in case of missing drivers + SetPinFunction(p, GpioPinFunction::N); + } + + // Set up the event channels for CCL LUTs 1 to 3. We only use CCL 1-3 so leave 0 alone for possible other applications. + for (unsigned int i = 1; i < 4; ++i) + { + GCLK->PCHCTRL[EVSYS_GCLK_ID_0 + i].reg = GCLK_PCHCTRL_GEN(GclkNum60MHz) | GCLK_PCHCTRL_CHEN; // enable the GCLK, needed to use the resynchronised path + EVSYS->Channel[CclLut0Event + i].CHANNEL.reg = EVSYS_CHANNEL_EVGEN(0x74 + i) | EVSYS_CHANNEL_PATH_RESYNCHRONIZED; + // LUT output events on the SAME5x are event generator numbers 0x74 to 0x77. Resynchronised path allows interrupts. + EVSYS->Channel[CclLut0Event + i].CHINTENCLR.reg = EVSYS_CHINTENCLR_EVD | EVSYS_CHINTENCLR_OVR; // disable interrupts for now + NVIC_SetPriority((IRQn)(EVSYS_0_IRQn + i), NvicPriorityDriverDiag); + NVIC_EnableIRQ((IRQn)(EVSYS_0_IRQn + i)); // enable the interrupt for this event channel in the NVIC + } + + CCL->CTRL.reg = CCL_CTRL_ENABLE; // enable the CCL +} + +# endif + DriversBitmap SmartDrivers::GetStalledDrivers(DriversBitmap driversOfInterest) noexcept { DriversBitmap rslt; diff --git a/src/Movement/StepperDrivers/TMC2660.cpp b/src/Movement/StepperDrivers/TMC2660.cpp index de545401..44f18bd0 100644 --- a/src/Movement/StepperDrivers/TMC2660.cpp +++ b/src/Movement/StepperDrivers/TMC2660.cpp @@ -227,6 +227,7 @@ public: void SetStallMinimumStepsPerSecond(unsigned int stepsPerSecond) noexcept; void AppendStallConfig(const StringRef& reply) const noexcept; void AppendDriverStatus(const StringRef& reply) noexcept; + StandardDriverStatus GetStandardDriverStatus() const noexcept; bool SetRegister(SmartDriverRegister reg, uint32_t regVal) noexcept; uint32_t GetRegister(SmartDriverRegister reg) const noexcept; @@ -245,8 +246,7 @@ private: void ResetLoadRegisters() noexcept { - minSgLoadRegister = 1023; - maxSgLoadRegister = 0; + minSgLoadRegister = 9999; // values read from the driver are in the range 0 to 1023, so 9999 indicates that it hasn't been read } static void SetupDMA(uint32_t outVal) noexcept SPEED_CRITICAL; // set up the PDC to send a register and receive the status @@ -270,12 +270,12 @@ private: uint32_t axisNumber; // the axis number of this driver as used to index the DriveMovements in the DDA uint32_t microstepShiftFactor; // how much we need to shift 1 left by to get the current microstepping uint32_t maxStallStepInterval; // maximum interval between full steps to take any notice of stall detection - uint32_t minSgLoadRegister; // the minimum value of the StallGuard bits we read - uint32_t maxSgLoadRegister; // the maximum value of the StallGuard bits we read uint32_t mstepPosition; // the current microstep position, or 0xFFFFFFFF if unknown volatile uint32_t lastReadStatus; // the status word that we read most recently, updated by the ISR volatile uint32_t accumulatedStatus; + + uint16_t minSgLoadRegister; // the minimum value of the StallGuard bits we read bool enabled; volatile uint8_t rdselState; // 0-3 = actual RDSEL value, 0xFF = unknown }; @@ -718,13 +718,13 @@ void TmcDriverState::AppendDriverStatus(const StringRef& reply) noexcept reply.cat("ok, "); } - if (minSgLoadRegister <= maxSgLoadRegister) + if (minSgLoadRegister <= 1023) { - reply.catf("SG min/max %" PRIu32 "/%" PRIu32, minSgLoadRegister, maxSgLoadRegister); + reply.catf("SG min %u", minSgLoadRegister); } else { - reply.cat("SG min/max n/a"); + reply.cat("SG min n/a"); } ResetLoadRegisters(); } @@ -736,6 +736,23 @@ unsigned int TmcDriverState::GetMicrostepping(bool& interpolation) const noexcep return 1u << microstepShiftFactor; } +// Get the status of the driver +StandardDriverStatus TmcDriverState::GetStandardDriverStatus() const noexcept +{ + const uint32_t status = ReadLiveStatus(); + StandardDriverStatus rslt; + // The lowest 8 bits of StandardDriverStatus have the same meanings as for the TMC2209 status, but the TMC2660 uses different bit assignments + rslt.all = ExtractBit(status, TMC_RR_OT_BIT_POS, StandardDriverStatus::OtBitPos); + rslt.all |= ExtractBit(status, TMC_RR_OTPW_BIT_POS, StandardDriverStatus::OtpwBitPos); + rslt.all |= (status & TMC_RR_S2G) >> 1; // put the S2G bits in the right place + rslt.all |= (status & (TMC_RR_OLA | TMC_RR_OLB)) << 1; // put the open load bits in the right place + rslt.all |= ExtractBit(status, TMC_RR_STST_BIT_POS, StandardDriverStatus::StandstillBitPos); // put the standstill bit in the right place + rslt.all |= ExtractBit(status, TMC_RR_SG_BIT_POS, StandardDriverStatus::StallBitPos); // put the stall bit in the right place + rslt.sgresultMin = minSgLoadRegister; + return rslt; +} + + // This is called by the ISR when the SPI transfer has completed inline void TmcDriverState::TransferDone() noexcept { @@ -752,15 +769,11 @@ inline void TmcDriverState::TransferDone() noexcept } else if (rdselState == 1) { - const uint32_t sgLoad = (status >> TMC_RR_SG_LOAD_SHIFT) & 1023; // get the StallGuard load register + const uint16_t sgLoad = (status >> TMC_RR_SG_LOAD_SHIFT) & 1023; // get the StallGuard load register if (sgLoad < minSgLoadRegister) { minSgLoadRegister = sgLoad; } - if (sgLoad > maxSgLoadRegister) - { - maxSgLoadRegister = sgLoad; - } if ((status & TMC_RR_SG) != 0) { EndstopOrZProbe::SetDriversStalled(driverBit); @@ -1243,24 +1256,15 @@ uint32_t SmartDrivers::GetRegister(size_t driver, SmartDriverRegister reg) noexc StandardDriverStatus SmartDrivers::GetStandardDriverStatus(size_t driver) noexcept { - StandardDriverStatus rslt; if (driver < numTmc2660Drivers) { - const uint32_t status = driverStates[driver].ReadLiveStatus(); - // The lowest 8 bits of StandardDriverStatus have the same meanings as for the TMC2209 status, but the TMC2660 uses different bit assignments - rslt.all = ExtractBit(status, TMC_RR_OT_BIT_POS, StandardDriverStatus::OtBitPos); - rslt.all |= ExtractBit(status, TMC_RR_OTPW_BIT_POS, StandardDriverStatus::OtpwBitPos); - rslt.all |= (status & TMC_RR_S2G) >> 1; // put the S2G bits in the right place - rslt.all |= (status & (TMC_RR_OLA | TMC_RR_OLB)) << 1; // put the open load bits in the right place - rslt.all |= ExtractBit(status, TMC_RR_STST_BIT_POS, StandardDriverStatus::StandstillBitPos); // put the standstill bit in the right place - rslt.all |= ExtractBit(status, TMC_RR_SG_BIT_POS, StandardDriverStatus::StallBitPos); // put the stall bit in the right place - } - else - { - rslt.all = 0; + return driverStates[driver].GetStandardDriverStatus(); } + StandardDriverStatus rslt; + rslt.all = 0; return rslt; } + #endif // End diff --git a/src/Movement/StepperDrivers/TMC51xx.cpp b/src/Movement/StepperDrivers/TMC51xx.cpp index ca2201ec..e105fe0b 100644 --- a/src/Movement/StepperDrivers/TMC51xx.cpp +++ b/src/Movement/StepperDrivers/TMC51xx.cpp @@ -288,6 +288,7 @@ public: void SetStallDetectFilter(bool sgFilter) noexcept; void SetStallMinimumStepsPerSecond(unsigned int stepsPerSecond) noexcept; void AppendStallConfig(const StringRef& reply) const noexcept; + StandardDriverStatus GetStandardDriverStatus() const noexcept; bool SetRegister(SmartDriverRegister reg, uint32_t regVal) noexcept; uint32_t GetRegister(SmartDriverRegister reg) const noexcept; @@ -314,8 +315,7 @@ private: void ResetLoadRegisters() noexcept { - minSgLoadRegister = 1023; - maxSgLoadRegister = 0; + minSgLoadRegister = 9999; // values read from the driver are in the range 0 to 1023, so 9999 indicates that it hasn't been read } // Write register numbers are in priority order, most urgent first, in same order as WriteRegNumbers @@ -359,8 +359,6 @@ private: uint32_t configuredChopConfReg; // the configured chopper control register, in the Enabled state, without the microstepping bits uint32_t maxStallStepInterval; // maximum interval between full steps to take any notice of stall detection - uint32_t minSgLoadRegister; // the minimum value of the StallGuard bits we read - uint32_t maxSgLoadRegister; // the maximum value of the StallGuard bits we read volatile uint32_t newRegistersToUpdate; // bitmap of register indices whose values need to be sent to the driver chip uint32_t registersToUpdate; // bitmap of register indices whose values need to be sent to the driver chip @@ -369,6 +367,7 @@ private: uint32_t microstepShiftFactor; // how much we need to shift 1 left by to get the current microstepping uint32_t motorCurrent; // the configured motor current in mA + uint16_t minSgLoadRegister; // the minimum value of the StallGuard bits we read uint16_t numReads, numWrites; // how many successful reads and writes we had static uint16_t numTimeouts; // how many times a transfer timed out @@ -794,13 +793,13 @@ void TmcDriverState::AppendDriverStatus(const StringRef& reply, bool clearGlobal reply.cat(" ok"); } - if (minSgLoadRegister <= maxSgLoadRegister) + if (minSgLoadRegister <= 1023) { - reply.catf(", SG min/max %" PRIu32 "/%" PRIu32, minSgLoadRegister, maxSgLoadRegister); + reply.catf(", SG min %u", minSgLoadRegister); } else { - reply.cat(", SG min/max n/a"); + reply.cat(", SG min n/a"); } ResetLoadRegisters(); @@ -813,6 +812,20 @@ void TmcDriverState::AppendDriverStatus(const StringRef& reply, bool clearGlobal } +StandardDriverStatus TmcDriverState::GetStandardDriverStatus() const noexcept +{ + StandardDriverStatus rslt; + const uint32_t status = ReadLiveStatus(); + // The lowest 8 bits of StandardDriverStatus have the same meanings as for the TMC2209 status, but the TMC51xx uses different bit assignments + rslt.all = (status >> (25 - 0)) & (0x0F << 0); // this puts the ot, otpw, s2ga and s2gb bits in the right place + rslt.all |= (status >> (12 - 4)) & (3u << 4); // put s2vsa and s2vsb in the right place + rslt.all |= (status >> (29 - 6)) & (3u << 6); // put ola and olb in the right place + rslt.all |= ExtractBit(status, TMC_RR_STST_BIT_POS, StandardDriverStatus::StandstillBitPos); // put the standstill bit in the right place + rslt.all |= ExtractBit(status, TMC_RR_SG_BIT_POS, StandardDriverStatus::StallBitPos); // put the stall bit in the right place + rslt.sgresultMin = minSgLoadRegister; + return rslt; +} + void TmcDriverState::SetStallDetectFilter(bool sgFilter) noexcept { if (sgFilter) @@ -914,15 +927,11 @@ void TmcDriverState::TransferSucceeded(const uint8_t *rcvDataBlock) noexcept // We treat the DRV_STATUS register separately if ((regVal & TMC_RR_STST) == 0) // in standstill, SG_RESULT returns the chopper on-time instead { - const uint32_t sgResult = regVal & TMC_RR_SGRESULT; + const uint16_t sgResult = regVal & TMC_RR_SGRESULT; if (sgResult < minSgLoadRegister) { minSgLoadRegister = sgResult; } - if (sgResult > maxSgLoadRegister) - { - maxSgLoadRegister = sgResult; - } } if ((regVal & (TMC_RR_OLA | TMC_RR_OLB)) != 0) @@ -1602,21 +1611,12 @@ GCodeResult SmartDrivers::SetAnyRegister(size_t driver, const StringRef& reply, StandardDriverStatus SmartDrivers::GetStandardDriverStatus(size_t driver) noexcept { - StandardDriverStatus rslt; if (driver < numTmc51xxDrivers) { - const uint32_t status = driverStates[driver].ReadLiveStatus(); - // The lowest 8 bits of StandardDriverStatus have the same meanings as for the TMC2209 status, but the TMC51xx uses different bit assignments - rslt.all = (status >> (25 - 0)) & (0x0F << 0); // this puts the ot, otpw, s2ga and s2gb bits in the right place - rslt.all |= (status >> (12 - 4)) & (3u << 4); // put s2vsa and s2vsb in the right place - rslt.all |= (status >> (29 - 6)) & (3u << 6); // put ola and olb in the right place - rslt.all |= ExtractBit(status, TMC_RR_STST_BIT_POS, StandardDriverStatus::StandstillBitPos); // put the standstill bit in the right place - rslt.all |= ExtractBit(status, TMC_RR_SG_BIT_POS, StandardDriverStatus::StallBitPos); // put the stall bit in the right place - } - else - { - rslt.all = 0; + return driverStates[driver].GetStandardDriverStatus(); } + StandardDriverStatus rslt; + rslt.all = 0; return rslt; } |