From b1961e8a2944b4b3a917970ea410beb20d8366df Mon Sep 17 00:00:00 2001 From: Unknown Date: Mon, 24 Aug 2020 00:50:23 -0400 Subject: [PATCH 01/14] Add timers for sections --- Firmware/MotorControl/axis.cpp | 14 ++++++++++ Firmware/MotorControl/axis.hpp | 42 +++++++++++++++++++++++++++-- Firmware/MotorControl/low_level.cpp | 8 ++++++ Firmware/MotorControl/utils.cpp | 7 +++++ Firmware/MotorControl/utils.hpp | 1 + Firmware/odrive-interface.yaml | 19 +++++++++++++ 6 files changed, 89 insertions(+), 2 deletions(-) diff --git a/Firmware/MotorControl/axis.cpp b/Firmware/MotorControl/axis.cpp index 04a802c6..2f211a03 100644 --- a/Firmware/MotorControl/axis.cpp +++ b/Firmware/MotorControl/axis.cpp @@ -201,11 +201,23 @@ bool Axis::do_updates() { for (ThermistorCurrentLimiter* thermistor : thermistors_) { thermistor->update(); } + task_times_.thermistor_update = sample_TIM13(); + encoder_.update(); + task_times_.encoder_update = sample_TIM13(); + sensorless_estimator_.update(); + task_times_.sensorless_update = sample_TIM13(); + min_endstop_.update(); + task_times_.min_endstop_update = sample_TIM13(); + max_endstop_.update(); + task_times_.max_endstop_update = sample_TIM13(); + bool ret = check_for_errors(); + task_times_.axis_error_check = sample_TIM13(); + odCAN->send_heartbeat(this); return ret; } @@ -347,10 +359,12 @@ bool Axis::run_closed_loop_control_loop() { float torque_setpoint; if (!controller_.update(&torque_setpoint)) return error_ |= ERROR_CONTROLLER_FAILED, false; + task_times_.controller_update = sample_TIM13(); float phase_vel = (2*M_PI) * encoder_.vel_estimate_ * motor_.config_.pole_pairs; if (!motor_.update(torque_setpoint, encoder_.phase_, phase_vel)) return false; // set_error should update axis.error_ + task_times_.motor_update = sample_TIM13(); return true; }); diff --git a/Firmware/MotorControl/axis.hpp b/Firmware/MotorControl/axis.hpp index 446958d6..71610259 100644 --- a/Firmware/MotorControl/axis.hpp +++ b/Firmware/MotorControl/axis.hpp @@ -21,6 +21,25 @@ public: bool finish_on_enc_idx = false; }; + struct TaskTimes_t { + uint16_t thermistor_update = 0; + uint16_t encoder_update = 0; + uint16_t sensorless_update = 0; + uint16_t min_endstop_update = 0; + uint16_t max_endstop_update = 0; + uint16_t axis_update = 0; + uint16_t axis_error_check = 0; + + uint16_t controller_update = 0; + uint16_t motor_update = 0; + uint16_t update_handler = 0; + + uint16_t brake_update = 0; + uint16_t adc_cb = 0; + uint16_t control_loop = 0; + uint32_t total = 0; + }; + static LockinConfig_t default_calibration(); static LockinConfig_t default_sensorless(); static LockinConfig_t default_lockin(); @@ -140,14 +159,18 @@ public: // go to zero. // // @tparam T Must be a callable type that takes no arguments and returns a bool + uint16_t start = 0; template void run_control_loop(const T& update_handler) { while (requested_state_ == AXIS_STATE_UNDEFINED) { + start = sample_TIM13(); // look for errors at axis level and also all subcomponents bool checks_ok = do_checks(); + // Update all estimators // Note: updates run even if checks fail - bool updates_ok = do_updates(); + bool updates_ok = do_updates(); + task_times_.axis_update = sample_TIM13(); // make sure the watchdog is being fed. bool watchdog_ok = watchdog_check(); @@ -162,10 +185,24 @@ public: // Run main loop function, defer quitting for after wait // TODO: change arming logic to arm after waiting bool main_continue = update_handler(); - + task_times_.update_handler = sample_TIM13(); // Check we meet deadlines after queueing ++loop_counter_; + task_times_.control_loop = sample_TIM13() - task_times_.update_handler; + task_times_.update_handler -= task_times_.axis_update; + task_times_.axis_update -= start; + task_times_.motor_update -= task_times_.controller_update; + task_times_.controller_update -= task_times_.axis_error_check; + task_times_.axis_error_check -= task_times_.max_endstop_update; + task_times_.max_endstop_update -= task_times_.min_endstop_update; + task_times_.min_endstop_update -= task_times_.sensorless_update; + task_times_.sensorless_update -= task_times_.encoder_update; + task_times_.encoder_update -= task_times_.thermistor_update; + task_times_.thermistor_update -= start; + task_times_.total = sample_TIM13() - start; + + // Wait until the current measurement interrupt fires if (!wait_for_current_meas()) { // maybe the interrupt handler is dead, let's be @@ -206,6 +243,7 @@ public: TrapezoidalTrajectory& trap_traj_; Endstop& min_endstop_; Endstop& max_endstop_; + TaskTimes_t task_times_; // List of current_limiters and thermistors to // provide easy iteration. diff --git a/Firmware/MotorControl/low_level.cpp b/Firmware/MotorControl/low_level.cpp index d447539d..1402fbc7 100644 --- a/Firmware/MotorControl/low_level.cpp +++ b/Firmware/MotorControl/low_level.cpp @@ -492,6 +492,7 @@ static void decode_hall_samples(Encoder& enc, uint16_t GPIO_samples[num_GPIO]) { // This is the callback from the ADC that we expect after the PWM has triggered an ADC conversion. // TODO: Document how the phasing is done, link to timing diagram void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { + auto start = sample_TIM13(); #define calib_tau 0.2f //@TOTO make more easily configurable constexpr float calib_filter_k = CURRENT_MEAS_PERIOD / calib_tau; @@ -587,6 +588,9 @@ void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { axis.motor_.DC_calib_.phC += (current - axis.motor_.DC_calib_.phC) * calib_filter_k; } } + auto end = (sample_TIM13() - start); + axes[0]->task_times_.adc_cb = end; + axes[1]->task_times_.adc_cb = end; } void tim_update_cb(TIM_HandleTypeDef* htim) { @@ -620,6 +624,7 @@ void tim_update_cb(TIM_HandleTypeDef* htim) { // @brief Sums up the Ibus contribution of each motor and updates the // brake resistor PWM accordingly. void update_brake_current() { + auto start = sample_TIM13(); float Ibus_sum = 0.0f; for (size_t i = 0; i < AXIS_COUNT; ++i) { if (axes[i]->motor_.armed_state_ == Motor::ARMED_STATE_ARMED) { @@ -666,6 +671,9 @@ void update_brake_current() { int low_off = high_on - TIM_APB1_DEADTIME_CLOCKS; if (low_off < 0) low_off = 0; safety_critical_apply_brake_resistor_timings(low_off, high_on); + + auto end = sample_TIM13() - start; + axes[0]->task_times_.brake_update = end; } diff --git a/Firmware/MotorControl/utils.cpp b/Firmware/MotorControl/utils.cpp index 579a47a7..f089ba4e 100644 --- a/Firmware/MotorControl/utils.cpp +++ b/Firmware/MotorControl/utils.cpp @@ -5,6 +5,8 @@ #include #include +#include + int SVM(float alpha, float beta, float* tA, float* tB, float* tC) { int Sextant; @@ -203,3 +205,8 @@ void delay_us(uint32_t us) __ASM("nop"); } } + +uint16_t sample_TIM13(){ + constexpr uint16_t clocks_per_cnt = (uint16_t)((float)TIM_1_8_CLOCK_HZ / (float)TIM_APB1_CLOCK_HZ); + return clocks_per_cnt * htim13.Instance->CNT; // TODO: Use a hw_config +} \ No newline at end of file diff --git a/Firmware/MotorControl/utils.hpp b/Firmware/MotorControl/utils.hpp index 49f9434d..8dcf09aa 100644 --- a/Firmware/MotorControl/utils.hpp +++ b/Firmware/MotorControl/utils.hpp @@ -121,6 +121,7 @@ int is_in_the_future(uint32_t time_ms); uint32_t micros(void); void delay_us(uint32_t us); +uint16_t sample_TIM13(); float our_arm_sin_f32(float x); float our_arm_cos_f32(float x); diff --git a/Firmware/odrive-interface.yaml b/Firmware/odrive-interface.yaml index 2c9060eb..df4365d6 100644 --- a/Firmware/odrive-interface.yaml +++ b/Firmware/odrive-interface.yaml @@ -364,12 +364,31 @@ interfaces: trap_traj: TrapezoidalTrajectory min_endstop: Endstop max_endstop: Endstop + task_times: TaskTime functions: watchdog_feed: doc: Feed the watchdog to prevent watchdog timeouts. clear_errors: doc: Check the watchdog timer for expiration. Also sets the watchdog error bit if expired. + ODrive.Axis.TaskTime: + c_is_class: False + attributes: + thermistor_update: uint16 + encoder_update: uint16 + sensorless_update: uint16 + min_endstop_update: uint16 + max_endstop_update: uint16 + axis_update: uint16 + axis_error_check: uint16 + controller_update: uint16 + motor_update: uint16 + control_loop: uint16 + update_handler: uint16 + brake_update: uint16 + adc_cb: uint16 + total: uint32 + ODrive.Axis.LockinConfig: c_is_class: False attributes: From 05bf4da3f5549df814ebd9b44e0de8195559a435 Mon Sep 17 00:00:00 2001 From: Samuel Sadok Date: Mon, 24 Aug 2020 18:07:03 +0200 Subject: [PATCH 02/14] Revert "remove test artifact" This reverts commit dc47edf450e5f3ac39e0e2bf63a49bbd2ae345be. --- tools/odrive/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/odrive/utils.py b/tools/odrive/utils.py index 0add96dc..e1ba95c2 100755 --- a/tools/odrive/utils.py +++ b/tools/odrive/utils.py @@ -77,7 +77,7 @@ def dump_errors(odrv, clear=False): module_decode_map = [ (name, odrv, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("AXIS_ERROR_")}), ('motor', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("MOTOR_ERROR_")}), - ('fet_thermistor', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("THERMISTOR_CURRENT_LIMITER_ERROR")}), + ('fet_thermistorr', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("THERMISTOR_CURRENT_LIMITER_ERROR")}), ('motor_thermistor', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("THERMISTOR_CURRENT_LIMITER_ERROR")}), ('encoder', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("ENCODER_ERROR_")}), ('controller', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("CONTROLLER_ERROR_")}), From 41597141525d1109647134abd206d59ceffe1b43 Mon Sep 17 00:00:00 2001 From: Samuel Sadok Date: Mon, 24 Aug 2020 13:58:22 +0200 Subject: [PATCH 03/14] Revert "improve compatibility of dump_errors()" This reverts commit 21357115126258b0afa7b3a5a77ecabb919c7da8. --- tools/odrive/utils.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/tools/odrive/utils.py b/tools/odrive/utils.py index e1ba95c2..04fa2d15 100755 --- a/tools/odrive/utils.py +++ b/tools/odrive/utils.py @@ -75,20 +75,18 @@ def dump_errors(odrv, clear=False): # Flatten axis and submodules # (name, remote_obj, errorcode) module_decode_map = [ - (name, odrv, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("AXIS_ERROR_")}), - ('motor', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("MOTOR_ERROR_")}), - ('fet_thermistorr', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("THERMISTOR_CURRENT_LIMITER_ERROR")}), - ('motor_thermistor', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("THERMISTOR_CURRENT_LIMITER_ERROR")}), - ('encoder', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("ENCODER_ERROR_")}), - ('controller', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("CONTROLLER_ERROR_")}), + ('axis', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("AXIS_ERROR_")}), + ('motor', axis.motor, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("MOTOR_ERROR_")}), + ('fet_thermistor', axis.fet_thermistor, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("THERMISTOR_CURRENT_LIMITER_ERROR")}), + ('motor_thermistor', axis.motor_thermistor, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("THERMISTOR_CURRENT_LIMITER_ERROR")}), + ('encoder', axis.encoder, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("ENCODER_ERROR_")}), + ('controller', axis.controller, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("CONTROLLER_ERROR_")}), ] # Module error decode for name, remote_obj, errorcodes in module_decode_map: - prefix = ' '*2 + name.strip('0123456789') + ": " - if not hasattr(remote_obj, name): - print(prefix + _VT100Colors['yellow'] + "not found" + _VT100Colors['default']) - elif getattr(remote_obj, name).error != 0: + prefix = ' '*2 + name + ": " + if (remote_obj.error != 0): foundError = False print(prefix + _VT100Colors['red'] + "Error(s):" + _VT100Colors['default']) errorcodes_dict = {val: name for name, val in errorcodes.items() if 'ERROR_' in name} From 2bb990937a533b2749edcdfdc019804e3d61981b Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 25 Aug 2020 21:40:24 -0400 Subject: [PATCH 04/14] Add TaskTimer class --- Firmware/MotorControl/axis.cpp | 23 +++++++---- Firmware/MotorControl/axis.hpp | 62 ++++++++++++++-------------- Firmware/MotorControl/controller.cpp | 2 - Firmware/MotorControl/low_level.cpp | 16 +++---- Firmware/MotorControl/odrive_main.h | 3 +- Firmware/MotorControl/taskTimer.hpp | 27 ++++++++++++ Firmware/MotorControl/utils.cpp | 4 -- Firmware/MotorControl/utils.hpp | 1 - Firmware/odrive-interface.yaml | 40 +++++++++++------- 9 files changed, 106 insertions(+), 72 deletions(-) create mode 100644 Firmware/MotorControl/taskTimer.hpp diff --git a/Firmware/MotorControl/axis.cpp b/Firmware/MotorControl/axis.cpp index a69fc140..b44f0b8c 100644 --- a/Firmware/MotorControl/axis.cpp +++ b/Firmware/MotorControl/axis.cpp @@ -198,25 +198,29 @@ bool Axis::do_checks() { // @brief Update all esitmators bool Axis::do_updates() { // Sub-components should use set_error which will propegate to this error_ + task_times_.thermistor_update.beginTimer(); for (ThermistorCurrentLimiter* thermistor : thermistors_) { thermistor->update(); } - task_times_.thermistor_update = sample_TIM13(); + task_times_.thermistor_update.stopTimer(); + task_times_.encoder_update.beginTimer(); encoder_.update(); - task_times_.encoder_update = sample_TIM13(); + task_times_.encoder_update.stopTimer(); + task_times_.sensorless_update.beginTimer(); sensorless_estimator_.update(); - task_times_.sensorless_update = sample_TIM13(); + task_times_.sensorless_update.stopTimer(); + task_times_.min_endstop_update.beginTimer(); min_endstop_.update(); - task_times_.min_endstop_update = sample_TIM13(); + task_times_.min_endstop_update.stopTimer(); + task_times_.max_endstop_update.beginTimer(); max_endstop_.update(); - task_times_.max_endstop_update = sample_TIM13(); + task_times_.max_endstop_update.stopTimer(); bool ret = check_for_errors(); - task_times_.axis_error_check = sample_TIM13(); odCAN->send_heartbeat(this); return ret; @@ -356,15 +360,18 @@ bool Axis::run_closed_loop_control_loop() { 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 + + task_times_.controller_update.beginTimer(); float torque_setpoint; if (!controller_.update(&torque_setpoint)) return error_ |= ERROR_CONTROLLER_FAILED, false; - task_times_.controller_update = sample_TIM13(); + task_times_.controller_update.stopTimer(); + task_times_.motor_update.beginTimer(); float phase_vel = (2*M_PI) * encoder_.vel_estimate_ * motor_.config_.pole_pairs; if (!motor_.update(torque_setpoint, encoder_.phase_, phase_vel)) return false; // set_error should update axis.error_ - task_times_.motor_update = sample_TIM13(); + task_times_.motor_update.stopTimer(); return true; }); diff --git a/Firmware/MotorControl/axis.hpp b/Firmware/MotorControl/axis.hpp index 3cf5dd91..13c631d8 100644 --- a/Firmware/MotorControl/axis.hpp +++ b/Firmware/MotorControl/axis.hpp @@ -11,6 +11,7 @@ class Axis; #include "low_level.h" #include "utils.hpp" #include "communication/interface_uart.h" // TODO: remove once uart_poll() is gone +#include "taskTimer.hpp" #include @@ -29,22 +30,24 @@ public: }; struct TaskTimes_t { - uint16_t thermistor_update = 0; - uint16_t encoder_update = 0; - uint16_t sensorless_update = 0; - uint16_t min_endstop_update = 0; - uint16_t max_endstop_update = 0; - uint16_t axis_update = 0; - uint16_t axis_error_check = 0; + TaskTimer thermistor_update; + TaskTimer encoder_update; + TaskTimer sensorless_update; + TaskTimer min_endstop_update; + TaskTimer max_endstop_update; + TaskTimer axis_update; + TaskTimer axis_error_check; - uint16_t controller_update = 0; - uint16_t motor_update = 0; - uint16_t update_handler = 0; + TaskTimer controller_update; + TaskTimer motor_update; + TaskTimer update_handler; - uint16_t brake_update = 0; - uint16_t adc_cb = 0; - uint16_t control_loop = 0; - uint32_t total = 0; + TaskTimer brake_update; + TaskTimer adc_cb; + TaskTimer control_loop; + TaskTimer total; + + TaskTimer uart_poll; }; static LockinConfig_t default_calibration(); @@ -166,18 +169,21 @@ public: // go to zero. // // @tparam T Must be a callable type that takes no arguments and returns a bool - uint16_t start = 0; template void run_control_loop(const T& update_handler) { while (requested_state_ == AXIS_STATE_UNDEFINED) { - start = sample_TIM13(); + task_times_.control_loop.beginTimer(); + // look for errors at axis level and also all subcomponents + task_times_.axis_error_check.beginTimer(); bool checks_ok = do_checks(); + task_times_.axis_error_check.stopTimer(); // Update all estimators // Note: updates run even if checks fail + task_times_.axis_update.beginTimer(); bool updates_ok = do_updates(); - task_times_.axis_update = sample_TIM13(); + task_times_.axis_update.stopTimer(); // make sure the watchdog is being fed. bool watchdog_ok = watchdog_check(); @@ -191,29 +197,21 @@ public: // Run main loop function, defer quitting for after wait // TODO: change arming logic to arm after waiting + task_times_.update_handler.beginTimer(); bool main_continue = update_handler(); - task_times_.update_handler = sample_TIM13(); + task_times_.update_handler.stopTimer(); if (axis_num_ == 0) { + task_times_.uart_poll.beginTimer(); uart_poll(); // TODO: move to board-level control loop once it exists + task_times_.uart_poll.stopTimer(); } // Check we meet deadlines after queueing ++loop_counter_; - task_times_.control_loop = sample_TIM13() - task_times_.update_handler; - task_times_.update_handler -= task_times_.axis_update; - task_times_.axis_update -= start; - task_times_.motor_update -= task_times_.controller_update; - task_times_.controller_update -= task_times_.axis_error_check; - task_times_.axis_error_check -= task_times_.max_endstop_update; - task_times_.max_endstop_update -= task_times_.min_endstop_update; - task_times_.min_endstop_update -= task_times_.sensorless_update; - task_times_.sensorless_update -= task_times_.encoder_update; - task_times_.encoder_update -= task_times_.thermistor_update; - task_times_.thermistor_update -= start; - task_times_.total = sample_TIM13() - start; - + task_times_.control_loop.stopTimer(); + task_times_.total.stopTimer(); // Wait until the current measurement interrupt fires if (!wait_for_current_meas()) { @@ -225,6 +223,8 @@ public: break; } + task_times_.total.beginTimer(); + if (!main_continue) break; } diff --git a/Firmware/MotorControl/controller.cpp b/Firmware/MotorControl/controller.cpp index 1524dce6..73e5fc00 100644 --- a/Firmware/MotorControl/controller.cpp +++ b/Firmware/MotorControl/controller.cpp @@ -2,8 +2,6 @@ #include "odrive_main.h" #include -#include - bool Controller::apply_config() { config_.parent = this; update_filter_gains(); diff --git a/Firmware/MotorControl/low_level.cpp b/Firmware/MotorControl/low_level.cpp index 0f9da174..c4495e5e 100644 --- a/Firmware/MotorControl/low_level.cpp +++ b/Firmware/MotorControl/low_level.cpp @@ -382,7 +382,8 @@ void vbus_sense_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { // This is the callback from the ADC that we expect after the PWM has triggered an ADC conversion. // TODO: Document how the phasing is done, link to timing diagram void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { - auto start = sample_TIM13(); + axes[0].task_times_.adc_cb.beginTimer(); + axes[1].task_times_.adc_cb.beginTimer(); #define calib_tau 0.2f //@TOTO make more easily configurable constexpr float calib_filter_k = CURRENT_MEAS_PERIOD / calib_tau; @@ -478,15 +479,15 @@ void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { axis.motor_.DC_calib_.phC += (current - axis.motor_.DC_calib_.phC) * calib_filter_k; } } - auto end = (sample_TIM13() - start); - axes[0]->task_times_.adc_cb = end; - axes[1]->task_times_.adc_cb = end; + axes[0].task_times_.adc_cb.stopTimer(); + axes[1].task_times_.adc_cb.stopTimer(); } // @brief Sums up the Ibus contribution of each motor and updates the // brake resistor PWM accordingly. void update_brake_current() { - auto start = sample_TIM13(); + axes[0].task_times_.brake_update.beginTimer(); + axes[1].task_times_.brake_update.beginTimer(); float Ibus_sum = 0.0f; for (size_t i = 0; i < AXIS_COUNT; ++i) { if (axes[i].motor_.armed_state_ == Motor::ARMED_STATE_ARMED) { @@ -533,9 +534,8 @@ void update_brake_current() { int low_off = high_on - TIM_APB1_DEADTIME_CLOCKS; if (low_off < 0) low_off = 0; safety_critical_apply_brake_resistor_timings(low_off, high_on); - - auto end = sample_TIM13() - start; - axes[0]->task_times_.brake_update = end; + axes[0].task_times_.brake_update.stopTimer(); + axes[1].task_times_.brake_update.stopTimer(); } diff --git a/Firmware/MotorControl/odrive_main.h b/Firmware/MotorControl/odrive_main.h index 2a5c9f5c..41fecc58 100644 --- a/Firmware/MotorControl/odrive_main.h +++ b/Firmware/MotorControl/odrive_main.h @@ -128,9 +128,8 @@ inline ENUMTYPE &operator &= (ENUMTYPE &a, ENUMTYPE b) { return reinterpret_cast inline ENUMTYPE &operator ^= (ENUMTYPE &a, ENUMTYPE b) { return reinterpret_cast(reinterpret_cast&>(a) ^= static_cast>(b)); } \ inline ENUMTYPE operator ~ (ENUMTYPE a) { return static_cast(~static_cast>(a)); } - - #include "autogen/interfaces.hpp" +#include // ODrive specific includes #include diff --git a/Firmware/MotorControl/taskTimer.hpp b/Firmware/MotorControl/taskTimer.hpp new file mode 100644 index 00000000..b9363aa8 --- /dev/null +++ b/Firmware/MotorControl/taskTimer.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include +#include +#include + +inline uint16_t sample_TIM13(){ + constexpr uint16_t clocks_per_cnt = (uint16_t)((float)TIM_1_8_CLOCK_HZ / (float)TIM_APB1_CLOCK_HZ); + return clocks_per_cnt * htim13.Instance->CNT; // TODO: Use a hw_config +} + +struct TaskTimer { + uint32_t startTime = 0; + uint32_t endTime = 0; + uint32_t length = 0; + uint32_t maxLength = 0; + + void beginTimer(){ + startTime = sample_TIM13(); + } + + void stopTimer(){ + endTime = sample_TIM13(); + length = endTime - startTime; + maxLength = std::max(maxLength, length); + } +}; \ No newline at end of file diff --git a/Firmware/MotorControl/utils.cpp b/Firmware/MotorControl/utils.cpp index 3dada0c8..a267aeea 100644 --- a/Firmware/MotorControl/utils.cpp +++ b/Firmware/MotorControl/utils.cpp @@ -206,7 +206,3 @@ void delay_us(uint32_t us) } } -uint16_t sample_TIM13(){ - constexpr uint16_t clocks_per_cnt = (uint16_t)((float)TIM_1_8_CLOCK_HZ / (float)TIM_APB1_CLOCK_HZ); - return clocks_per_cnt * htim13.Instance->CNT; // TODO: Use a hw_config -} \ No newline at end of file diff --git a/Firmware/MotorControl/utils.hpp b/Firmware/MotorControl/utils.hpp index 8dcf09aa..49f9434d 100644 --- a/Firmware/MotorControl/utils.hpp +++ b/Firmware/MotorControl/utils.hpp @@ -121,7 +121,6 @@ int is_in_the_future(uint32_t time_ms); uint32_t micros(void); void delay_us(uint32_t us); -uint16_t sample_TIM13(); float our_arm_sin_f32(float x); float our_arm_cos_f32(float x); diff --git a/Firmware/odrive-interface.yaml b/Firmware/odrive-interface.yaml index 3f991961..c1ff609b 100644 --- a/Firmware/odrive-interface.yaml +++ b/Firmware/odrive-interface.yaml @@ -454,30 +454,38 @@ interfaces: trap_traj: TrapezoidalTrajectory min_endstop: Endstop max_endstop: Endstop - task_times: TaskTime + task_times: TaskTimes functions: watchdog_feed: doc: Feed the watchdog to prevent watchdog timeouts. clear_errors: doc: Check the watchdog timer for expiration. Also sets the watchdog error bit if expired. - ODrive.Axis.TaskTime: + ODrive.Axis.TaskTimes: c_is_class: False attributes: - thermistor_update: uint16 - encoder_update: uint16 - sensorless_update: uint16 - min_endstop_update: uint16 - max_endstop_update: uint16 - axis_update: uint16 - axis_error_check: uint16 - controller_update: uint16 - motor_update: uint16 - control_loop: uint16 - update_handler: uint16 - brake_update: uint16 - adc_cb: uint16 - total: uint32 + thermistor_update: TaskTimer + encoder_update: TaskTimer + sensorless_update: TaskTimer + min_endstop_update: TaskTimer + max_endstop_update: TaskTimer + axis_update: TaskTimer + axis_error_check: TaskTimer + controller_update: TaskTimer + motor_update: TaskTimer + control_loop: TaskTimer + update_handler: TaskTimer + brake_update: TaskTimer + adc_cb: TaskTimer + total: TaskTimer + + ODrive.TaskTimer: + c_is_class: False + attributes: + startTime: readonly uint32 + endTime: readonly uint32 + length: readonly uint32 + maxLength: readonly uint32 ODrive.Axis.LockinConfig: c_is_class: False From 499dd64d87426e15814ba9ec7d837f21d78548b4 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 26 Aug 2020 01:42:03 -0400 Subject: [PATCH 05/14] Ensure sample trigger occurs at the right spot, and only once. --- Firmware/MotorControl/axis.hpp | 3 ++- Firmware/MotorControl/low_level.cpp | 26 ++++++++++++++++++++------ Firmware/MotorControl/low_level.h | 1 + Firmware/MotorControl/odrive_main.h | 1 + Firmware/MotorControl/taskTimer.cpp | 4 ++++ Firmware/MotorControl/taskTimer.hpp | 29 +++++++++++++++++++---------- Firmware/odrive-interface.yaml | 1 + Firmware/sampler.py | 11 ++++++++++- 8 files changed, 58 insertions(+), 18 deletions(-) create mode 100644 Firmware/MotorControl/taskTimer.cpp diff --git a/Firmware/MotorControl/axis.hpp b/Firmware/MotorControl/axis.hpp index 13c631d8..32f64dbd 100644 --- a/Firmware/MotorControl/axis.hpp +++ b/Firmware/MotorControl/axis.hpp @@ -212,6 +212,8 @@ public: task_times_.control_loop.stopTimer(); task_times_.total.stopTimer(); + if(axis_num_ == 1) + TaskTimer::sample_next = false; // Wait until the current measurement interrupt fires if (!wait_for_current_meas()) { @@ -222,7 +224,6 @@ public: error_ |= ERROR_CURRENT_MEASUREMENT_TIMEOUT; break; } - task_times_.total.beginTimer(); if (!main_continue) diff --git a/Firmware/MotorControl/low_level.cpp b/Firmware/MotorControl/low_level.cpp index c4495e5e..e248232d 100644 --- a/Firmware/MotorControl/low_level.cpp +++ b/Firmware/MotorControl/low_level.cpp @@ -31,6 +31,7 @@ constexpr float adc_ref_voltage = 3.3f; // Arbitrary non-zero inital value to avoid division by zero if ADC reading is late float vbus_voltage = 12.0f; float ibus_ = 0.0f; // exposed for monitoring only +bool task_timers_armed = false; bool brake_resistor_armed = false; bool brake_resistor_saturated = false; /* Private constant data -----------------------------------------------------*/ @@ -382,8 +383,8 @@ void vbus_sense_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { // This is the callback from the ADC that we expect after the PWM has triggered an ADC conversion. // TODO: Document how the phasing is done, link to timing diagram void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { - axes[0].task_times_.adc_cb.beginTimer(); - axes[1].task_times_.adc_cb.beginTimer(); + + adc_timestamp = sample_TIM13(); #define calib_tau 0.2f //@TOTO make more easily configurable constexpr float calib_filter_k = CURRENT_MEAS_PERIOD / calib_tau; @@ -404,10 +405,12 @@ void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { bool current_meas_not_DC_CAL = !counting_down; // Check the timing of the sequencing - if (current_meas_not_DC_CAL) + if (current_meas_not_DC_CAL) { axis.motor_.log_timing(TIMING_LOG_ADC_CB_I); - else + } + else { axis.motor_.log_timing(TIMING_LOG_ADC_CB_DC); + } bool update_timings = false; if (hadc == &hadc2) { @@ -452,6 +455,19 @@ void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { } float current = axis.motor_.phase_current_from_adcval(ADCValue); + + if(current_meas_not_DC_CAL && axis_num == 0 && hadc == &hadc2){ + if (task_timers_armed) { + TaskTimer::sample_next = true; + task_timers_armed = false; + axes[0].task_times_.adc_cb.startTime = adc_timestamp; // Start of ADC2 + } + } + + if(current_meas_not_DC_CAL && axis_num == 0 && hadc == &hadc3){ + axes[0].task_times_.adc_cb.stopTimer(); // End of ADC3 + } + if (current_meas_not_DC_CAL) { // ADC2 and ADC3 record the phB and phC currents concurrently, // and their interrupts should arrive on the same clock cycle. @@ -479,8 +495,6 @@ void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { axis.motor_.DC_calib_.phC += (current - axis.motor_.DC_calib_.phC) * calib_filter_k; } } - axes[0].task_times_.adc_cb.stopTimer(); - axes[1].task_times_.adc_cb.stopTimer(); } // @brief Sums up the Ibus contribution of each motor and updates the diff --git a/Firmware/MotorControl/low_level.h b/Firmware/MotorControl/low_level.h index e02ef5c2..a1e5a470 100644 --- a/Firmware/MotorControl/low_level.h +++ b/Firmware/MotorControl/low_level.h @@ -19,6 +19,7 @@ extern const float adc_ref_voltage; /* Exported variables --------------------------------------------------------*/ extern float vbus_voltage; extern float ibus_; +extern bool task_timers_armed; extern bool brake_resistor_armed; extern bool brake_resistor_saturated; extern uint16_t adc_measurements_[ADC_CHANNEL_COUNT]; diff --git a/Firmware/MotorControl/odrive_main.h b/Firmware/MotorControl/odrive_main.h index 41fecc58..35b10dee 100644 --- a/Firmware/MotorControl/odrive_main.h +++ b/Firmware/MotorControl/odrive_main.h @@ -217,6 +217,7 @@ public: const uint8_t fw_version_revision_ = ::fw_version_revision_; const uint8_t fw_version_unreleased_ = ::fw_version_unreleased_; // 0 for official releases, 1 otherwise + bool& task_timers_armed_ = ::task_timers_armed; bool& brake_resistor_armed_ = ::brake_resistor_armed; // TODO: make this the actual variable bool& brake_resistor_saturated_ = ::brake_resistor_saturated; // TODO: make this the actual variable diff --git a/Firmware/MotorControl/taskTimer.cpp b/Firmware/MotorControl/taskTimer.cpp new file mode 100644 index 00000000..bc55573b --- /dev/null +++ b/Firmware/MotorControl/taskTimer.cpp @@ -0,0 +1,4 @@ +#include "taskTimer.hpp" + +bool TaskTimer::sample_next = false; +volatile uint32_t adc_timestamp = 0; diff --git a/Firmware/MotorControl/taskTimer.hpp b/Firmware/MotorControl/taskTimer.hpp index b9363aa8..8a2e17e4 100644 --- a/Firmware/MotorControl/taskTimer.hpp +++ b/Firmware/MotorControl/taskTimer.hpp @@ -1,12 +1,14 @@ #pragma once -#include #include +#include + #include -inline uint16_t sample_TIM13(){ + +inline uint16_t sample_TIM13() { constexpr uint16_t clocks_per_cnt = (uint16_t)((float)TIM_1_8_CLOCK_HZ / (float)TIM_APB1_CLOCK_HZ); - return clocks_per_cnt * htim13.Instance->CNT; // TODO: Use a hw_config + return clocks_per_cnt * htim13.Instance->CNT; // TODO: Use a hw_config } struct TaskTimer { @@ -15,13 +17,20 @@ struct TaskTimer { uint32_t length = 0; uint32_t maxLength = 0; - void beginTimer(){ - startTime = sample_TIM13(); + static bool sample_next; + + void beginTimer() { + if (sample_next) + startTime = sample_TIM13(); } - void stopTimer(){ - endTime = sample_TIM13(); - length = endTime - startTime; - maxLength = std::max(maxLength, length); + void stopTimer() { + if (sample_next) { + endTime = sample_TIM13(); + length = endTime - startTime; + maxLength = std::max(maxLength, length); + } } -}; \ No newline at end of file +}; + +extern volatile uint32_t adc_timestamp; \ No newline at end of file diff --git a/Firmware/odrive-interface.yaml b/Firmware/odrive-interface.yaml index c1ff609b..276a96ee 100644 --- a/Firmware/odrive-interface.yaml +++ b/Firmware/odrive-interface.yaml @@ -13,6 +13,7 @@ interfaces: The odrv0, odrv1, ... objects that appear in odrivetool implement this toplevel interface. attributes: + task_timers_armed: bool vbus_voltage: type: readonly float32 unit: V diff --git a/Firmware/sampler.py b/Firmware/sampler.py index 70a59115..c3f7c353 100644 --- a/Firmware/sampler.py +++ b/Firmware/sampler.py @@ -88,6 +88,7 @@ if __name__ == '__main__': total = 0 countmap = { } pcmap = { } + funcmap = { } start = time.time() try: @@ -101,6 +102,9 @@ if __name__ == '__main__': func, addr = sampler.func(pc) + if(func == 'ADC_IRQ_Dispatch'): + funcmap[pc] = 1 + if not addr: continue @@ -112,7 +116,12 @@ if __name__ == '__main__': total += 1 cur = time.time() - if cur - start > 1.0: + if cur - start > 5.0: + + # tmp = sorted(funcmap) + # for k in tmp: + # print(hex(k)) + tmp = sorted(countmap.items(), key=operator.itemgetter(1)) #, reverse=True) for k, v in tmp: print('{:05.2f}% {}'.format((v * 100.) / total, k)) From c834533be69dc83ab063b21c05222400b497af17 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 26 Aug 2020 02:23:57 -0400 Subject: [PATCH 06/14] Add missing taskTimer compile command --- Firmware/Tupfile.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/Firmware/Tupfile.lua b/Firmware/Tupfile.lua index 040db512..9fb16b98 100644 --- a/Firmware/Tupfile.lua +++ b/Firmware/Tupfile.lua @@ -194,6 +194,7 @@ sources = { 'MotorControl/trapTraj.cpp', 'MotorControl/pwm_input.cpp', 'MotorControl/main.cpp', + 'MotorControl/taskTimer.cpp', 'Drivers/STM32/stm32_system.cpp', 'Drivers/STM32/stm32_gpio.cpp', 'Drivers/STM32/stm32_nvm.c', From ea03574ce3df68c74ccf617e32fc4dfd63583682 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 27 Aug 2020 18:09:44 -0400 Subject: [PATCH 07/14] Add FOC_Current timer --- Firmware/MotorControl/axis.hpp | 1 + Firmware/MotorControl/motor.cpp | 2 ++ Firmware/odrive-interface.yaml | 1 + 3 files changed, 4 insertions(+) diff --git a/Firmware/MotorControl/axis.hpp b/Firmware/MotorControl/axis.hpp index 32f64dbd..12904f09 100644 --- a/Firmware/MotorControl/axis.hpp +++ b/Firmware/MotorControl/axis.hpp @@ -48,6 +48,7 @@ public: TaskTimer total; TaskTimer uart_poll; + TaskTimer FOC_Current; }; static LockinConfig_t default_calibration(); diff --git a/Firmware/MotorControl/motor.cpp b/Firmware/MotorControl/motor.cpp index 9bdbaa75..5eff545c 100644 --- a/Firmware/MotorControl/motor.cpp +++ b/Firmware/MotorControl/motor.cpp @@ -292,6 +292,7 @@ bool Motor::FOC_voltage(float v_d, float v_q, float pwm_phase) { } bool Motor::FOC_current(float Id_des, float Iq_des, float I_phase, float pwm_phase, float phase_vel) { + axis_->task_times_.FOC_Current.beginTimer(); // Syntactic sugar CurrentControl_t& ictrl = current_control_; @@ -404,6 +405,7 @@ bool Motor::FOC_current(float Id_des, float Iq_des, float I_phase, float pwm_pha } } + axis_->task_times_.FOC_Current.stopTimer(); return true; } diff --git a/Firmware/odrive-interface.yaml b/Firmware/odrive-interface.yaml index 276a96ee..105b0d4c 100644 --- a/Firmware/odrive-interface.yaml +++ b/Firmware/odrive-interface.yaml @@ -479,6 +479,7 @@ interfaces: brake_update: TaskTimer adc_cb: TaskTimer total: TaskTimer + FOC_Current: TaskTimer ODrive.TaskTimer: c_is_class: False From cfb5523001ebe1482375616c316bf2c5fff5ca17 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 3 Sep 2020 00:33:31 -0400 Subject: [PATCH 08/14] Fix dump_errors on this branch(?) --- tools/odrive/utils.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tools/odrive/utils.py b/tools/odrive/utils.py index 505bba79..329cda81 100755 --- a/tools/odrive/utils.py +++ b/tools/odrive/utils.py @@ -78,18 +78,20 @@ def dump_errors(odrv, clear=False): # Flatten axis and submodules # (name, remote_obj, errorcode) module_decode_map = [ - ('axis', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("AXIS_ERROR_")}), - ('motor', axis.motor, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("MOTOR_ERROR_")}), - ('fet_thermistor', axis.fet_thermistor, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("THERMISTOR_CURRENT_LIMITER_ERROR")}), - ('motor_thermistor', axis.motor_thermistor, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("THERMISTOR_CURRENT_LIMITER_ERROR")}), - ('encoder', axis.encoder, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("ENCODER_ERROR_")}), - ('controller', axis.controller, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("CONTROLLER_ERROR_")}), + (name, odrv, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("AXIS_ERROR_")}), + ('motor', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("MOTOR_ERROR_")}), + ('fet_thermistor', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("THERMISTOR_CURRENT_LIMITER_ERROR")}), + ('motor_thermistor', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("THERMISTOR_CURRENT_LIMITER_ERROR")}), + ('encoder', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("ENCODER_ERROR_")}), + ('controller', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("CONTROLLER_ERROR_")}), ] # Module error decode for name, remote_obj, errorcodes in module_decode_map: - prefix = ' '*2 + name + ": " - if (remote_obj.error != 0): + prefix = ' '*2 + name.strip('0123456789') + ": " + if not hasattr(remote_obj, name): + print(prefix + _VT100Colors['yellow'] + "not found" + _VT100Colors['default']) + elif getattr(remote_obj, name).error != 0: foundError = False print(prefix + _VT100Colors['red'] + "Error(s):" + _VT100Colors['default']) errorcodes_dict = {val: name for name, val in errorcodes.items() if 'ERROR_' in name} From 8419e0ab1705ba6f6f12372f5e93842288d0e850 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sat, 5 Sep 2020 17:30:07 -0700 Subject: [PATCH 09/14] decode functions using nm with name demangling --- Firmware/sampler.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/Firmware/sampler.py b/Firmware/sampler.py index a51e4c7e..6f032b32 100644 --- a/Firmware/sampler.py +++ b/Firmware/sampler.py @@ -45,17 +45,22 @@ class OpenOCDCMSampler(object): return 0 - def initSymbols(self, elf, readelf='arm-none-eabi-readelf'): - proc = subprocess.Popen([readelf, '-s', elf], stdout=subprocess.PIPE) + def initSymbols(self, elf, symbol_dump_cmd='arm-none-eabi-nm'): + proc = subprocess.Popen([symbol_dump_cmd, '-CS', elf], stdout=subprocess.PIPE) for line in proc.stdout.readlines(): field = line.split() - # for i,txt in enumerate(field): - # print("{}, {}".format(i, txt)) + try: - if field[3] == b'FUNC': - addr = int(field[1], 16) - 1 # For some reason readelf dumps the func addr off by 1 - func = field[7] - size = int(field[2]) + # For using nm -CS + if field[2] in ('t', 'T', 'w', 'W'): + addr = int(field[0], 16) + func = field[3] + size = int(field[1], 16) + # # For using readelf -s + # if field[3] == b'FUNC': + # addr = int(field[1], 16) - 1 # For some reason readelf dumps the func addr off by 1 + # func = field[7] + # size = int(field[2]) if addr not in self.indexes: self.table.append((addr, func, size)) self.indexes.add(addr) From d788fa71488871fc0638786b4d81e1356dea4c6f Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sat, 5 Sep 2020 17:38:31 -0700 Subject: [PATCH 10/14] use --size-sort to force always print a size --- Firmware/sampler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/sampler.py b/Firmware/sampler.py index 6f032b32..694b783c 100644 --- a/Firmware/sampler.py +++ b/Firmware/sampler.py @@ -46,7 +46,7 @@ class OpenOCDCMSampler(object): def initSymbols(self, elf, symbol_dump_cmd='arm-none-eabi-nm'): - proc = subprocess.Popen([symbol_dump_cmd, '-CS', elf], stdout=subprocess.PIPE) + proc = subprocess.Popen([symbol_dump_cmd, '-CS', '--size-sort', elf], stdout=subprocess.PIPE) for line in proc.stdout.readlines(): field = line.split() From 7d92018ee8952998ef8d19ec342c4a898c633687 Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 5 Sep 2020 20:44:10 -0400 Subject: [PATCH 11/14] Fix character matching --- Firmware/sampler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/sampler.py b/Firmware/sampler.py index 694b783c..a033f66f 100644 --- a/Firmware/sampler.py +++ b/Firmware/sampler.py @@ -52,7 +52,7 @@ class OpenOCDCMSampler(object): try: # For using nm -CS - if field[2] in ('t', 'T', 'w', 'W'): + if field[2] in (b't', b'T', b'w', b'W'): addr = int(field[0], 16) func = field[3] size = int(field[1], 16) From 682f8bfada7b5ae2778584617456744a2af4915d Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 5 Sep 2020 20:45:48 -0400 Subject: [PATCH 12/14] Decode function name as UTF-8 --- Firmware/sampler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/sampler.py b/Firmware/sampler.py index a033f66f..3c97617c 100644 --- a/Firmware/sampler.py +++ b/Firmware/sampler.py @@ -129,7 +129,7 @@ if __name__ == '__main__': tmp = sorted(countmap.items(), key=operator.itemgetter(1)) #, reverse=True) for k, v in tmp: - print('{:05.2f}% {}'.format((v * 100.) / total, k)) + print('{:05.2f}% {}'.format((v * 100.) / total, k.decode('UTF-8'))) # print('{:06.2f} clocks : {}'.format((v * 10500) / total, k)) start = cur print('{} Samples'.format(total)) From 4a45314c978dc3d18259e209dff2273bb806e4ed Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sat, 5 Sep 2020 18:09:14 -0700 Subject: [PATCH 13/14] all words in function names --- Firmware/sampler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/sampler.py b/Firmware/sampler.py index 3c97617c..7ad9392d 100644 --- a/Firmware/sampler.py +++ b/Firmware/sampler.py @@ -54,7 +54,7 @@ class OpenOCDCMSampler(object): # For using nm -CS if field[2] in (b't', b'T', b'w', b'W'): addr = int(field[0], 16) - func = field[3] + func = ' '.join(field[3:-1]) size = int(field[1], 16) # # For using readelf -s # if field[3] == b'FUNC': From f9fa06c86fe1720568c6e57f4bd93fecaec4fc8b Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 5 Sep 2020 21:15:45 -0400 Subject: [PATCH 14/14] Fix all words in func names --- Firmware/sampler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/sampler.py b/Firmware/sampler.py index 7ad9392d..4fc25a97 100644 --- a/Firmware/sampler.py +++ b/Firmware/sampler.py @@ -54,7 +54,7 @@ class OpenOCDCMSampler(object): # For using nm -CS if field[2] in (b't', b'T', b'w', b'W'): addr = int(field[0], 16) - func = ' '.join(field[3:-1]) + func = b' '.join(field[3:]) size = int(field[1], 16) # # For using readelf -s # if field[3] == b'FUNC':