First pass/WIP
parent
860b91e42b
commit
973db11bec
|
|
@ -109,6 +109,11 @@ public:
|
||||||
gpio::TogglePin(params.stepPin); // assumes DEDGE
|
gpio::TogglePin(params.stepPin); // assumes DEDGE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set step to an explicit state
|
||||||
|
static inline void SetStep(const MotorParams ¶ms, bool state) {
|
||||||
|
gpio::WritePin(params.stepPin, (state ? gpio::Level::high : gpio::Level::low));
|
||||||
|
}
|
||||||
|
|
||||||
/// Return SG state
|
/// Return SG state
|
||||||
static inline bool SampleDiag(const MotorParams ¶ms) {
|
static inline bool SampleDiag(const MotorParams ¶ms) {
|
||||||
return gpio::ReadPin(params.sgPin) == gpio::Level::low;
|
return gpio::ReadPin(params.sgPin) == gpio::Level::low;
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ target_sources(
|
||||||
feed_to_bondtech.cpp
|
feed_to_bondtech.cpp
|
||||||
feed_to_finda.cpp
|
feed_to_finda.cpp
|
||||||
home.cpp
|
home.cpp
|
||||||
|
hw_sanity.cpp
|
||||||
load_filament.cpp
|
load_filament.cpp
|
||||||
move_selector.cpp
|
move_selector.cpp
|
||||||
no_command.cpp
|
no_command.cpp
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,13 @@ enum class ErrorCode : uint_fast16_t {
|
||||||
/// - E34240 All 3 TMC driver
|
/// - E34240 All 3 TMC driver
|
||||||
TMC_RESET = 0x8400,
|
TMC_RESET = 0x8400,
|
||||||
|
|
||||||
|
/// TMC driver - IO pins are unreliable. While in theory it's recoverable, in practice it most likely
|
||||||
|
/// means your hardware is borked (we can't command the drivers reliably via STEP/EN/DIR due to electrical
|
||||||
|
/// issues or hardware fault. Possible "fixable" cause is undervoltage on the 5v logic line.
|
||||||
|
/// Unfixable possible cause: bad or cracked solder joints on the PCB, failed shift register, failed driver.
|
||||||
|
/// TODO: DRRacer - Separate codes per channel.
|
||||||
|
TMC_PINS_UNRELIABLE = 0x8600,
|
||||||
|
|
||||||
/// not enough current for the TMC, NOT RECOVERABLE
|
/// not enough current for the TMC, NOT RECOVERABLE
|
||||||
/// - E34880 Pulley TMC driver
|
/// - E34880 Pulley TMC driver
|
||||||
/// - E34944 Selector TMC driver
|
/// - E34944 Selector TMC driver
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,143 @@
|
||||||
|
/// @file hw_sanity.cpp
|
||||||
|
#include "hw_sanity.h"
|
||||||
|
#include "../modules/globals.h"
|
||||||
|
#include "../modules/motion.h"
|
||||||
|
#include "../modules/leds.h"
|
||||||
|
#include "../modules/timebase.h"
|
||||||
|
#include "config/axis.h"
|
||||||
|
|
||||||
|
namespace logic {
|
||||||
|
|
||||||
|
// Copy-pasta from command_base, they're inline
|
||||||
|
// so this shouldn't affect code size.
|
||||||
|
inline ErrorCode &operator|=(ErrorCode &a, ErrorCode b) {
|
||||||
|
return a = (ErrorCode)((uint16_t)a | (uint16_t)b);
|
||||||
|
}
|
||||||
|
|
||||||
|
using Axis = config::Axis;
|
||||||
|
using TMC2130 = hal::tmc2130::TMC2130;
|
||||||
|
|
||||||
|
static constexpr uint8_t LED_WAIT_MS = 50U;
|
||||||
|
static constexpr uint8_t TEST_PASSES = 6U;
|
||||||
|
static_assert(TEST_PASSES < 32); // Would overflow counters
|
||||||
|
|
||||||
|
HWSanity hwSanity;
|
||||||
|
|
||||||
|
uint8_t HWSanity::test_step = 0;
|
||||||
|
uint8_t HWSanity::fault_masks[] = { 0 };
|
||||||
|
uint16_t HWSanity::wait_start = 0;
|
||||||
|
Axis HWSanity::axis;
|
||||||
|
ProgressCode HWSanity::next_state = ProgressCode::HWTestBegin;
|
||||||
|
|
||||||
|
bool HWSanity::Reset(uint8_t param) {
|
||||||
|
state = ProgressCode::HWTestBegin;
|
||||||
|
error = ErrorCode::RUNNING;
|
||||||
|
axis = config::Axis::Idler;
|
||||||
|
fault_masks[0] = 0;
|
||||||
|
fault_masks[1] = 0;
|
||||||
|
fault_masks[2] = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum pin_bits {
|
||||||
|
BIT_STEP = 0b001,
|
||||||
|
BIT_DIR = 0b010,
|
||||||
|
BIT_ENA = 0b100,
|
||||||
|
};
|
||||||
|
|
||||||
|
bool HWSanity::StepInner() {
|
||||||
|
switch (state) {
|
||||||
|
case ProgressCode::HWTestBegin:
|
||||||
|
//auto& driver = mm::motion.DriverForAxis(config::Axis::Pulley);
|
||||||
|
test_step = 0;
|
||||||
|
// Todo - set TOFF so the output bridge is disabled.
|
||||||
|
state = ProgressCode::HWTestIdler;
|
||||||
|
break;
|
||||||
|
case ProgressCode::HWTestIdler:
|
||||||
|
axis = config::Axis::Idler;
|
||||||
|
ml::leds.SetPairButOffOthers(5, ml::on, ml::off);
|
||||||
|
state = ProgressCode::HWTestExec;
|
||||||
|
next_state = ProgressCode::HWTestSelector;
|
||||||
|
break;
|
||||||
|
case ProgressCode::HWTestSelector:
|
||||||
|
axis = config::Axis::Selector;
|
||||||
|
ml::leds.SetPairButOffOthers(5, ml::off, ml::on);
|
||||||
|
state = ProgressCode::HWTestExec;
|
||||||
|
next_state = ProgressCode::HWTestPulley;
|
||||||
|
break;
|
||||||
|
case ProgressCode::HWTestPulley:
|
||||||
|
axis = config::Axis::Pulley;
|
||||||
|
ml::leds.SetPairButOffOthers(5, ml::on, ml::on);
|
||||||
|
state = ProgressCode::HWTestExec;
|
||||||
|
next_state = ProgressCode::HWTestCleanup;
|
||||||
|
break;
|
||||||
|
// The main test loop for a given axis.
|
||||||
|
case ProgressCode::HWTestDisplay:
|
||||||
|
// Hold for a few ms while we display the last step result.
|
||||||
|
if (!mt::timebase.Elapsed(wait_start, LED_WAIT_MS)) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
state = ProgressCode::HWTestExec;
|
||||||
|
}
|
||||||
|
/* FALLTHRU */
|
||||||
|
case ProgressCode::HWTestExec: {
|
||||||
|
auto driver = mm::motion.DriverForAxis(axis);
|
||||||
|
auto params = mm::axisParams[axis].params;
|
||||||
|
if (test_step < (TEST_PASSES * 8)) // 8 combos per axis
|
||||||
|
{
|
||||||
|
uint8_t set_state = test_step % 8;
|
||||||
|
// The order of the bits here is roughly the same as that of IOIN.
|
||||||
|
driver.SetStep(params, set_state & BIT_STEP);
|
||||||
|
driver.SetDir(params, set_state & BIT_DIR);
|
||||||
|
driver.SetEnabled(params, set_state & BIT_ENA);
|
||||||
|
uint16_t drv_ioin = driver.ReadRegister(params, TMC2130::Registers::IOIN);
|
||||||
|
// Compose IOIN to look like set_state.
|
||||||
|
drv_ioin = (drv_ioin & 0b11) | ((drv_ioin & 0b10000) >> 2);
|
||||||
|
uint8_t bit_errs = (drv_ioin ^ set_state);
|
||||||
|
// Set the LEDs. Note RED is index 0 in the enum, so we want the expression FALSE if there's an error.
|
||||||
|
ml::leds.SetMode(0, static_cast<ml::Color>((bit_errs & BIT_STEP) == 0), ml::on);
|
||||||
|
ml::leds.SetMode(1, static_cast<ml::Color>((bit_errs & BIT_DIR) == 0), ml::on);
|
||||||
|
ml::leds.SetMode(2, static_cast<ml::Color>((bit_errs & BIT_ENA) == 0), ml::on);
|
||||||
|
// Capture the error for later.
|
||||||
|
fault_masks[axis] |= bit_errs;
|
||||||
|
// Enter the wait state:
|
||||||
|
wait_start = mt::timebase.Millis();
|
||||||
|
state = ProgressCode::HWTestDisplay;
|
||||||
|
// Next iteration.
|
||||||
|
test_step++;
|
||||||
|
} else {
|
||||||
|
// This pass is complete. Move on to the next motor or cleanup.
|
||||||
|
test_step = 0;
|
||||||
|
state = next_state;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case ProgressCode::HWTestCleanup:
|
||||||
|
if (fault_masks[0] || fault_masks[1] || fault_masks[2]) {
|
||||||
|
// error, display it and return the code.
|
||||||
|
state = ProgressCode::ErrHwTestFailed;
|
||||||
|
error = ErrorCode::TMC_PINS_UNRELIABLE;
|
||||||
|
if (fault_masks[Axis::Idler]) {
|
||||||
|
error |= ErrorCode::TMC_IDLER_BIT;
|
||||||
|
}
|
||||||
|
if (fault_masks[Axis::Pulley]) {
|
||||||
|
error |= ErrorCode::TMC_PULLEY_BIT;
|
||||||
|
}
|
||||||
|
if (fault_masks[Axis::Selector]) {
|
||||||
|
error |= ErrorCode::TMC_SELECTOR_BIT;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
//TODO: Re-enable TOFF here
|
||||||
|
FinishedOK();
|
||||||
|
}
|
||||||
|
case ProgressCode::OK:
|
||||||
|
return true;
|
||||||
|
default: // we got into an unhandled state, better report it
|
||||||
|
state = ProgressCode::ERRInternal;
|
||||||
|
error = ErrorCode::INTERNAL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace logic
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
/// @file hw_sanity.h
|
||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "command_base.h"
|
||||||
|
#include "config/axis.h"
|
||||||
|
|
||||||
|
namespace logic {
|
||||||
|
|
||||||
|
/// @brief Performs a sanity check of the hardware at reset/boot. Checks the following:
|
||||||
|
/// - TMC drivers using their IOIN registers (DIR/STEP/DRV_EN)
|
||||||
|
/// - ...
|
||||||
|
/// - Profit!
|
||||||
|
|
||||||
|
class HWSanity : public CommandBase {
|
||||||
|
public:
|
||||||
|
inline HWSanity()
|
||||||
|
: CommandBase() {}
|
||||||
|
|
||||||
|
/// Restart the automaton
|
||||||
|
bool Reset(uint8_t param) override;
|
||||||
|
|
||||||
|
/// @returns true if the state machine finished its job, false otherwise.
|
||||||
|
/// LED indicators during the test execution:
|
||||||
|
/// Slots 1-3: Pin states for STEP, DIR, and ENA
|
||||||
|
/// Slot 4: Axis under test - G: Idler, R: Selector, RG: Pully.
|
||||||
|
/// Slot 5: G: Blinking to indicate test progression. R: Solid to indicate completed test w/ fault.
|
||||||
|
/// Indicators at test end (fault condition):
|
||||||
|
/// Slots 1-3 now indicate pin
|
||||||
|
/// - Off: No faults detected.
|
||||||
|
/// - G: STEP fault
|
||||||
|
/// - R: DIR fault
|
||||||
|
/// - RG: EN fault.
|
||||||
|
/// - Blinking R/G: Multiple fault, e.g both an EN fault together with STEP and/or DIR.
|
||||||
|
/// Slot 4: Reserved
|
||||||
|
/// Slot 5: R: Solid
|
||||||
|
bool StepInner() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static uint8_t test_step;
|
||||||
|
static config::Axis axis;
|
||||||
|
static uint8_t fault_masks[3];
|
||||||
|
static ProgressCode next_state;
|
||||||
|
static uint16_t wait_start;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The one and only instance of hwSanity state machine in the FW
|
||||||
|
extern HWSanity hwSanity;
|
||||||
|
|
||||||
|
} // namespace logic
|
||||||
|
|
@ -41,5 +41,14 @@ enum class ProgressCode : uint_fast8_t {
|
||||||
|
|
||||||
FeedingToFSensor, // P28
|
FeedingToFSensor, // P28
|
||||||
|
|
||||||
|
HWTestBegin, // P29
|
||||||
|
HWTestIdler, // P30
|
||||||
|
HWTestSelector, // P31
|
||||||
|
HWTestPulley, // P32
|
||||||
|
HWTestCleanup, // P33
|
||||||
|
HWTestExec, // P34
|
||||||
|
HWTestDisplay, // P35
|
||||||
|
ErrHwTestFailed, // P36
|
||||||
|
|
||||||
Empty = 0xff // dummy empty state
|
Empty = 0xff // dummy empty state
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue