diff --git a/CHANGELOG.md b/CHANGELOG.md index 3167be4c..87ec6c0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ Please add a note of your changes below this heading if you make a Pull Request. ### Added * Overspeed fault +* Make step dir gpio pins configurable. ### Changed * Increased switching frequency from around 8kHz to 24kHz. Control loops still run at 8kHz. diff --git a/Firmware/MotorControl/axis.cpp b/Firmware/MotorControl/axis.cpp index 0ab726ff..cae62223 100644 --- a/Firmware/MotorControl/axis.cpp +++ b/Firmware/MotorControl/axis.cpp @@ -26,6 +26,8 @@ Axis::Axis(const AxisHardwareConfig_t& hw_config, controller_.axis_ = this; motor_.axis_ = this; trap_.axis_ = this; + + decode_step_dir_pins(); } static void step_cb_wrapper(void* ctx) { @@ -67,24 +69,37 @@ bool Axis::wait_for_current_meas() { // step/direction interface void Axis::step_cb() { if (step_dir_active_) { - GPIO_PinState dir_pin = HAL_GPIO_ReadPin(hw_config_.dir_port, hw_config_.dir_pin); + GPIO_PinState dir_pin = HAL_GPIO_ReadPin(dir_port_, dir_pin_); float dir = (dir_pin == GPIO_PIN_SET) ? 1.0f : -1.0f; controller_.pos_setpoint_ += dir * config_.counts_per_step; } }; -// @brief Enables or disables step/dir input -void Axis::set_step_dir_enabled(bool enable) { - if (enable) { +void Axis::load_default_step_dir_pin_config( + const AxisHardwareConfig_t& hw_config, Config_t* config) { + config->step_gpio_pin = hw_config.step_gpio_pin; + config->dir_gpio_pin = hw_config.dir_gpio_pin; +} + +void Axis::decode_step_dir_pins() { + step_port_ = get_gpio_port_by_pin(config_.step_gpio_pin); + step_pin_ = get_gpio_pin_by_pin(config_.step_gpio_pin); + dir_port_ = get_gpio_port_by_pin(config_.dir_gpio_pin); + dir_pin_ = get_gpio_pin_by_pin(config_.dir_gpio_pin); +} + +// @brief (de)activates step/dir input +void Axis::set_step_dir_active(bool active) { + if (active) { // Set up the direction GPIO as input GPIO_InitTypeDef GPIO_InitStruct; - GPIO_InitStruct.Pin = hw_config_.dir_pin; + GPIO_InitStruct.Pin = dir_pin_; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; - HAL_GPIO_Init(hw_config_.dir_port, &GPIO_InitStruct); + HAL_GPIO_Init(dir_port_, &GPIO_InitStruct); // Subscribe to rising edges of the step GPIO - GPIO_subscribe(hw_config_.step_port, hw_config_.step_pin, GPIO_PULLDOWN, + GPIO_subscribe(step_port_, step_pin_, GPIO_PULLDOWN, step_cb_wrapper, this); step_dir_active_ = true; @@ -92,7 +107,7 @@ void Axis::set_step_dir_enabled(bool enable) { step_dir_active_ = false; // Unsubscribe from step GPIO - GPIO_unsubscribe(hw_config_.step_port, hw_config_.step_pin); + GPIO_unsubscribe(step_port_, step_pin_); } } @@ -167,7 +182,6 @@ bool Axis::run_sensorless_spin_up() { // Note run_sensorless_control_loop and run_closed_loop_control_loop are very similar and differ only in where we get the estimate from. bool Axis::run_sensorless_control_loop() { - set_step_dir_enabled(config_.enable_step_dir); run_control_loop([this](){ if (controller_.config_.control_mode >= Controller::CTRL_MODE_POSITION_CONTROL) return error_ |= ERROR_POS_CTRL_DURING_SENSORLESS, false; @@ -180,12 +194,11 @@ bool Axis::run_sensorless_control_loop() { return false; // set_error should update axis.error_ return true; }); - set_step_dir_enabled(false); return check_for_errors(); } bool Axis::run_closed_loop_control_loop() { - set_step_dir_enabled(config_.enable_step_dir); + set_step_dir_active(config_.enable_step_dir); run_control_loop([this](){ // Note that all estimators are updated in the loop prefix in run_control_loop float current_setpoint; @@ -195,7 +208,7 @@ bool Axis::run_closed_loop_control_loop() { return false; // set_error should update axis.error_ return true; }); - set_step_dir_enabled(false); + set_step_dir_active(false); return check_for_errors(); } diff --git a/Firmware/MotorControl/axis.hpp b/Firmware/MotorControl/axis.hpp index 6e9b8bfc..d9f95ad8 100644 --- a/Firmware/MotorControl/axis.hpp +++ b/Firmware/MotorControl/axis.hpp @@ -45,9 +45,12 @@ public: bool startup_sensorless_control = false; //(ctx)->decode_step_dir_pins(); }, this), + make_protocol_property("dir_gpio_pin", &config_.dir_gpio_pin, + [](void* ctx) { static_cast(ctx)->decode_step_dir_pins(); }, this), make_protocol_property("ramp_up_time", &config_.ramp_up_time), make_protocol_property("ramp_up_distance", &config_.ramp_up_distance), make_protocol_property("spin_up_current", &config_.spin_up_current), diff --git a/Firmware/MotorControl/board_config_v3.h b/Firmware/MotorControl/board_config_v3.h index 1e170fed..7aee4881 100644 --- a/Firmware/MotorControl/board_config_v3.h +++ b/Firmware/MotorControl/board_config_v3.h @@ -21,10 +21,8 @@ typedef struct { - GPIO_TypeDef* step_port; - uint16_t step_pin; - GPIO_TypeDef* dir_port; - uint16_t dir_pin; + uint16_t step_gpio_pin; + uint16_t dir_gpio_pin; size_t thermistor_adc_ch; osPriority thread_priority; } AxisHardwareConfig_t; @@ -74,10 +72,8 @@ const size_t thermistor_num_coeffs = sizeof(thermistor_poly_coeffs)/sizeof(therm const BoardHardwareConfig_t hw_configs[2] = { { //M0 .axis_config = { - .step_port = GPIO_1_GPIO_Port, - .step_pin = GPIO_1_Pin, - .dir_port = GPIO_2_GPIO_Port, - .dir_pin = GPIO_2_Pin, + .step_gpio_pin = 1, + .dir_gpio_pin = 2, .thermistor_adc_ch = 15, .thread_priority = (osPriority)(osPriorityHigh + (osPriority)1), }, @@ -111,15 +107,11 @@ const BoardHardwareConfig_t hw_configs[2] = { { //M1 .axis_config = { #if HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR >= 5 - .step_port = GPIO_7_GPIO_Port, - .step_pin = GPIO_7_Pin, - .dir_port = GPIO_8_GPIO_Port, - .dir_pin = GPIO_8_Pin, + .step_gpio_pin = 7, + .dir_gpio_pin = 8, #else - .step_port = GPIO_3_GPIO_Port, - .step_pin = GPIO_3_Pin, - .dir_port = GPIO_4_GPIO_Port, - .dir_pin = GPIO_4_Pin, + .step_gpio_pin = 3, + .dir_gpio_pin = 4, #endif #if HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR >= 3 .thermistor_adc_ch = 4, diff --git a/Firmware/MotorControl/main.cpp b/Firmware/MotorControl/main.cpp index 4550605e..4146850c 100644 --- a/Firmware/MotorControl/main.cpp +++ b/Firmware/MotorControl/main.cpp @@ -65,6 +65,8 @@ void load_configuration(void) { motor_configs[i] = Motor::Config_t(); trap_configs[i] = TrapezoidalTrajectory::Config_t(); axis_configs[i] = Axis::Config_t(); + // Default step/dir pins are different, so we need to explicitly load them + Axis::load_default_step_dir_pin_config(hw_configs[i].axis_config, &axis_configs[i]); } } else { user_config_loaded_ = true; @@ -178,8 +180,6 @@ int odrive_main(void) { // TODO: make dynamically reconfigurable #if HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR >= 3 if (board_config.enable_uart) { - axes[0]->config_.enable_step_dir = false; - axes[0]->set_step_dir_enabled(false); SetGPIO12toUART(); } #endif diff --git a/docs/interfaces.md b/docs/interfaces.md index ba6ccfb0..ff0ec9ac 100644 --- a/docs/interfaces.md +++ b/docs/interfaces.md @@ -32,7 +32,10 @@ The ODrive can be controlled over various ports and protocols. If you're comfort (+) on ODrive v3.4 and earlier
(*) ODrive v3.5 and later -ODrive v3.3 and onward have 5V tolerant GPIO pins. +Notes: +* ODrive v3.3 and onward have 5V tolerant GPIO pins. +* ODrive v3.5 and later have some noise supression filters on the default step/dir pins +* You can change the step/dir pins using `axis.config._gpio_pin`. ### Pin function priorities 1. PWM in, if enabled. Disabled by default. @@ -89,7 +92,7 @@ There is an Arduino library that gives some expamples on how to use the ASCII pr This is the simplest possible way of controlling the ODrive. It is also the most primitive and fragile one. So don't use it unless you must interoperate with other hardware that you don't control. Pinout: -* Step/dir signals: see [Pinout](#pinout) above. +* Step/dir signals: see [Pinout](#pinout) above. Note in that section how to reassign the pins. * GND: you must connect the grounds of the devices together. Use any GND pin on J3 of the ODrive. To enable step/dir mode for the GPIO, set `.config.enable_step_dir` to true for each axis that you wish to use this on.