From 7de0d921394aef0c8744960763ec0c066be58297 Mon Sep 17 00:00:00 2001 From: Yannis Chatzikonstantinou Date: Wed, 30 Aug 2023 01:50:09 +0300 Subject: [PATCH 01/19] update protocol with units --- firmware/src/can/can_endpoints.c | 2 +- studio/Python/tinymovr/config/device.yaml | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/firmware/src/can/can_endpoints.c b/firmware/src/can/can_endpoints.c index 97f4ad10..fda40fc4 100644 --- a/firmware/src/can/can_endpoints.c +++ b/firmware/src/can/can_endpoints.c @@ -19,7 +19,7 @@ uint8_t (*avlos_endpoints[81])(uint8_t * buffer, uint8_t * buffer_len, Avlos_Command cmd) = {&avlos_protocol_hash, &avlos_uid, &avlos_fw_version, &avlos_hw_revision, &avlos_Vbus, &avlos_Ibus, &avlos_power, &avlos_temp, &avlos_calibrated, &avlos_errors, &avlos_save_config, &avlos_erase_config, &avlos_reset, &avlos_invoke_bootloader, &avlos_scheduler_total, &avlos_scheduler_busy, &avlos_scheduler_errors, &avlos_controller_state, &avlos_controller_mode, &avlos_controller_warnings, &avlos_controller_errors, &avlos_controller_position_setpoint, &avlos_controller_position_p_gain, &avlos_controller_velocity_setpoint, &avlos_controller_velocity_limit, &avlos_controller_velocity_p_gain, &avlos_controller_velocity_i_gain, &avlos_controller_velocity_deadband, &avlos_controller_velocity_increment, &avlos_controller_current_Iq_setpoint, &avlos_controller_current_Id_setpoint, &avlos_controller_current_Iq_limit, &avlos_controller_current_Iq_estimate, &avlos_controller_current_bandwidth, &avlos_controller_current_Iq_p_gain, &avlos_controller_current_max_Ibus_regen, &avlos_controller_current_max_Ibrake, &avlos_controller_voltage_Vq_setpoint, &avlos_controller_calibrate, &avlos_controller_idle, &avlos_controller_position_mode, &avlos_controller_velocity_mode, &avlos_controller_current_mode, &avlos_controller_set_pos_vel_setpoints, &avlos_comms_can_rate, &avlos_comms_can_id, &avlos_motor_R, &avlos_motor_L, &avlos_motor_pole_pairs, &avlos_motor_type, &avlos_motor_offset, &avlos_motor_direction, &avlos_motor_calibrated, &avlos_motor_I_cal, &avlos_motor_errors, &avlos_encoder_position_estimate, &avlos_encoder_velocity_estimate, &avlos_encoder_type, &avlos_encoder_bandwidth, &avlos_encoder_calibrated, &avlos_encoder_errors, &avlos_traj_planner_max_accel, &avlos_traj_planner_max_decel, &avlos_traj_planner_max_vel, &avlos_traj_planner_t_accel, &avlos_traj_planner_t_decel, &avlos_traj_planner_t_total, &avlos_traj_planner_move_to, &avlos_traj_planner_move_to_tlimit, &avlos_traj_planner_errors, &avlos_homing_velocity, &avlos_homing_max_homing_t, &avlos_homing_retract_dist, &avlos_homing_warnings, &avlos_homing_stall_detect_velocity, &avlos_homing_stall_detect_delta_pos, &avlos_homing_stall_detect_t, &avlos_homing_home, &avlos_watchdog_enabled, &avlos_watchdog_triggered, &avlos_watchdog_timeout }; -uint32_t avlos_proto_hash = 4244018107; +uint32_t avlos_proto_hash = 3868913670; uint32_t _avlos_get_proto_hash(void) { diff --git a/studio/Python/tinymovr/config/device.yaml b/studio/Python/tinymovr/config/device.yaml index febda580..3f414448 100644 --- a/studio/Python/tinymovr/config/device.yaml +++ b/studio/Python/tinymovr/config/device.yaml @@ -260,8 +260,10 @@ remote_attributes: arguments: - name: pos_setpoint dtype: float + unit: tick - name: vel_setpoint dtype: float + unit: tick - name: comms remote_attributes: - name: can @@ -441,6 +443,7 @@ remote_attributes: arguments: - name: pos_setpoint dtype: float + unit: tick - name: move_to_tlimit summary: Move to target position respecting time limits for each sector. caller_name: planner_move_to_tlimit @@ -448,6 +451,7 @@ remote_attributes: arguments: - name: pos_setpoint dtype: float + unit: tick - name: errors flags: [INVALID_INPUT, VCRUISE_OVER_LIMIT] getter_name: planner_get_errors From 6e53727e0a1bf55c6c35154047d70fdbf793d8ee Mon Sep 17 00:00:00 2001 From: Yannis Chatzikonstantinou Date: Wed, 30 Aug 2023 01:50:27 +0300 Subject: [PATCH 02/19] add argument setting dialog --- studio/Python/tinymovr/gui/__init__.py | 3 +- studio/Python/tinymovr/gui/widgets.py | 49 +++++++++++++++++++++++++- studio/Python/tinymovr/gui/window.py | 33 +++++++++++++---- 3 files changed, 77 insertions(+), 8 deletions(-) diff --git a/studio/Python/tinymovr/gui/__init__.py b/studio/Python/tinymovr/gui/__init__.py index 66250ad0..555bde3e 100644 --- a/studio/Python/tinymovr/gui/__init__.py +++ b/studio/Python/tinymovr/gui/__init__.py @@ -16,7 +16,8 @@ ) from tinymovr.gui.widgets import ( OurQTreeWidget, - IconComboBoxWidget + IconComboBoxWidget, + ArgumentInputDialog ) from tinymovr.gui.worker import Worker from tinymovr.gui.window import MainWindow diff --git a/studio/Python/tinymovr/gui/widgets.py b/studio/Python/tinymovr/gui/widgets.py index fee21b3a..05cee938 100644 --- a/studio/Python/tinymovr/gui/widgets.py +++ b/studio/Python/tinymovr/gui/widgets.py @@ -1,8 +1,22 @@ from PySide6 import QtGui from PySide6.QtGui import QPixmap -from PySide6.QtWidgets import QWidget, QTreeWidget, QHBoxLayout, QLabel, QComboBox +from PySide6.QtWidgets import ( + QWidget, + QTreeWidget, + QHBoxLayout, + QLabel, + QComboBox, + QDialog, + QVBoxLayout, + QLabel, + QLineEdit, + QPushButton, + QFormLayout, +) + from tinymovr.gui.helpers import load_pixmap + class OurQTreeWidget(QTreeWidget): def __init__(self, parent=None): super().__init__(parent) @@ -45,3 +59,36 @@ def __init__(self, icon_path, parent=None): layout.addWidget(self.combo) self.setLayout(layout) + + +class ArgumentInputDialog(QDialog): + def __init__(self, arguments, parent=None): + super(ArgumentInputDialog, self).__init__(parent) + self.arguments = arguments + self.inputs = {} + + layout = QFormLayout(self) + + # For each argument, create a label and input line edit + for arg in arguments: + label = QLabel(f"{arg.name} ({arg.dtype.nickname}):") + line_edit = QLineEdit(self) + layout.addRow(label, line_edit) + self.inputs[arg.name] = line_edit + + # Add Ok and Cancel buttons + button_layout = QVBoxLayout() + ok_button = QPushButton("Ok", self) + ok_button.clicked.connect(self.accept) + cancel_button = QPushButton("Cancel", self) + cancel_button.clicked.connect(self.reject) + button_layout.addWidget(ok_button) + button_layout.addWidget(cancel_button) + + layout.addRow(button_layout) + self.setLayout(layout) + + def get_values(self): + return { + arg_name: line_edit.text() for arg_name, line_edit in self.inputs.items() + } diff --git a/studio/Python/tinymovr/gui/window.py b/studio/Python/tinymovr/gui/window.py index 504d5c69..a45145ba 100644 --- a/studio/Python/tinymovr/gui/window.py +++ b/studio/Python/tinymovr/gui/window.py @@ -24,6 +24,7 @@ from PySide6.QtCore import Signal from PySide6.QtWidgets import ( QMainWindow, + QDialog, QMenu, QMenuBar, QWidget, @@ -34,7 +35,7 @@ QLabel, QTreeWidgetItem, QPushButton, - QMessageBox + QMessageBox, ) from pint.errors import UndefinedUnitError from PySide6.QtGui import QAction @@ -48,6 +49,7 @@ Worker, OurQTreeWidget, IconComboBoxWidget, + ArgumentInputDialog, format_value, load_icon, display_file_open_dialog, @@ -58,7 +60,6 @@ class MainWindow(QMainWindow): - TreeItemCheckedSignal = Signal(dict) def __init__(self, app, arguments): @@ -306,7 +307,22 @@ def attrs_updated(self, data): @QtCore.Slot() def f_call_clicked(self, f): - f() + args = [] + + # Check if the function has any arguments + if f.arguments: + dialog = ArgumentInputDialog(f.arguments, self) + if dialog.exec_() == QDialog.Accepted: + input_values = dialog.get_values() + args = [input_values[arg.name] for arg in f.arguments] + else: + return # User cancelled, stop the entire process + + # Convert arguments as required using pint + args = [get_registry()(arg) for arg in args] + + # Call the function with the collected arguments + f(*args) if "reload_data" in f.meta and f.meta["reload_data"]: self.worker.reset() @@ -353,7 +369,12 @@ def delete_graphs(self): self.delete_graph_by_attr_name(attr_name) def show_about_box(self): - version_str = (pkg_resources.require("tinymovr")[0].version) + version_str = pkg_resources.require("tinymovr")[0].version app_str = "{} {}".format(app_name, version_str) - QMessageBox.about(self, "About Tinymovr", "{}\nhttps://tinymovr.com\n\nCat Sleeping Icon by Denis Sazhin from Noun Project".format(app_str)) - + QMessageBox.about( + self, + "About Tinymovr", + "{}\nhttps://tinymovr.com\n\nCat Sleeping Icon by Denis Sazhin from Noun Project".format( + app_str + ), + ) From 8c0ed60491a2aa38bf3f2861ebba3d688c9da8cd Mon Sep 17 00:00:00 2001 From: Yannis Chatzikonstantinou Date: Thu, 31 Aug 2023 14:02:00 +0300 Subject: [PATCH 03/19] add gate driver error status --- firmware/src/system/system.c | 10 ++++++++++ studio/Python/tinymovr/config/device.yaml | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/firmware/src/system/system.c b/firmware/src/system/system.c index 1351dba2..2fec3201 100644 --- a/firmware/src/system/system.c +++ b/firmware/src/system/system.c @@ -110,6 +110,16 @@ TM_RAMFUNC void system_update(void) { state.errors |= ERRORS_UNDERVOLTAGE; } + const uint8_t drv_status = pac5xxx_tile_register_read(ADDR_STATDRV); + if (drv_status > 0) + { + state.errors |= ((drv_status & 0x7) << 4); + } + const uint8_t drv_fault = pac5xxx_tile_register_read(ADDR_DRV_FLT); + if (drv_fault > 0) + { + state.errors |= ((drv_fault & 0x7) << 1); + } } void system_reset(void) diff --git a/studio/Python/tinymovr/config/device.yaml b/studio/Python/tinymovr/config/device.yaml index 3f414448..8247e8e1 100644 --- a/studio/Python/tinymovr/config/device.yaml +++ b/studio/Python/tinymovr/config/device.yaml @@ -47,7 +47,7 @@ remote_attributes: getter_name: system_get_calibrated summary: Whether the system has been calibrated. - name: errors - flags: [UNDERVOLTAGE, DRIVER_FAULT] + flags: [UNDERVOLTAGE, DRIVER_FAULT, CHARGE_PUMP_FAULT_STAT, CHARGE_PUMP_FAULT, DRV10_DISABLE, DRV32_DISABLE, DRV54_DISABLE] meta: {dynamic: True} getter_name: system_get_errors summary: Any system errors, as a bitmask From 4ba67e74195b55d25bbec1389e06574ec56bcc67 Mon Sep 17 00:00:00 2001 From: Yannis Chatzikonstantinou Date: Thu, 31 Aug 2023 14:02:15 +0300 Subject: [PATCH 04/19] better formatting for bitmasks and enums --- studio/Python/tinymovr/gui/helpers.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/studio/Python/tinymovr/gui/helpers.py b/studio/Python/tinymovr/gui/helpers.py index dd40c65e..8bb3cdfb 100644 --- a/studio/Python/tinymovr/gui/helpers.py +++ b/studio/Python/tinymovr/gui/helpers.py @@ -336,13 +336,18 @@ def format_value(value, include_unit=True): type and return the formatted string """ if isinstance(value, enum.IntFlag): - return str(value) if value > 0 else "(no flags)" + return bitmask_string_representation(value) if value > 0 else "(no flags)" + if isinstance(value, enum.IntEnum): + return value.name if not include_unit and isinstance(value, pint.Quantity): return str(value.magnitude) if isinstance(value, float): return "{0:.6g}".format(value) return str(value) +def bitmask_string_representation(bitmask_value): + labels_in_bitmask = [label.name for label in type(bitmask_value) if label & bitmask_value] + return ', '.join(labels_in_bitmask) def load_pixmap(filename, dark_mode_suffix='_dark', high_dpi_suffix='@2x'): """ From cd9084e7b1144b776e4e72df890fb1e6d76a33a7 Mon Sep 17 00:00:00 2001 From: Yannis Chatzikonstantinou Date: Thu, 31 Aug 2023 14:02:42 +0300 Subject: [PATCH 05/19] use actual gate driver state --- firmware/src/gatedriver/gatedriver.c | 11 +---------- firmware/src/gatedriver/gatedriver.h | 10 ---------- firmware/src/main.c | 1 - 3 files changed, 1 insertion(+), 21 deletions(-) diff --git a/firmware/src/gatedriver/gatedriver.c b/firmware/src/gatedriver/gatedriver.c index eaf96832..0572390c 100644 --- a/firmware/src/gatedriver/gatedriver.c +++ b/firmware/src/gatedriver/gatedriver.c @@ -19,13 +19,6 @@ #include #include -struct GateDriver_ gateDriver = -{ - .state = GATEDRIVER_DISABLED -}; - -void GateDriver_Init(void) {} - TM_RAMFUNC void gate_driver_enable(void) { // Select PWMA peripheral for Port B @@ -47,7 +40,6 @@ TM_RAMFUNC void gate_driver_enable(void) pac5xxx_tile_register_write(ADDR_CFGDRV4, pac5xxx_tile_register_read(ADDR_CFGDRV4) | 0x1); // BBM is bit 0 - gateDriver.state = GATEDRIVER_ENABLED; } TM_RAMFUNC void gate_driver_disable(void) @@ -66,12 +58,11 @@ TM_RAMFUNC void gate_driver_disable(void) // Turn on output enables PAC55XX_GPIOB->OUTMASK.w = 0x00; - gateDriver.state = GATEDRIVER_DISABLED; } TM_RAMFUNC bool gate_driver_is_enabled(void) { - return (GATEDRIVER_ENABLED == gateDriver.state); + return ((pac5xxx_tile_register_read(ADDR_ENDRV) & 0x1) == 1); } TM_RAMFUNC void gate_driver_set_duty_cycle(const FloatTriplet *dutycycles) diff --git a/firmware/src/gatedriver/gatedriver.h b/firmware/src/gatedriver/gatedriver.h index a70f65dc..388f73ee 100644 --- a/firmware/src/gatedriver/gatedriver.h +++ b/firmware/src/gatedriver/gatedriver.h @@ -18,17 +18,7 @@ #ifndef GATEDRIVER_GATEDRIVER_H_ #define GATEDRIVER_GATEDRIVER_H_ -typedef enum { - GATEDRIVER_DISABLED = 0, - GATEDRIVER_ENABLED = 1 -} GateDriverState; -struct GateDriver_ -{ - GateDriverState state; -}; - -void GateDriver_Init(void); void gate_driver_enable(void); void gate_driver_disable(void); bool gate_driver_is_enabled(void); diff --git a/firmware/src/main.c b/firmware/src/main.c index d0704fd2..4a96126f 100644 --- a/firmware/src/main.c +++ b/firmware/src/main.c @@ -39,7 +39,6 @@ int main(void) UART_Init(); observer_init(); ADC_Init(); - GateDriver_Init(); CAN_init(); Timer_Init(); Watchdog_init(); From f5f69b795ac45dff6c363d7fe13ffb71b188dfcf Mon Sep 17 00:00:00 2001 From: Yannis Chatzikonstantinou Date: Thu, 31 Aug 2023 14:03:55 +0300 Subject: [PATCH 06/19] update system in systick --- firmware/src/config.h | 3 ++- firmware/src/scheduler/scheduler.c | 5 +++-- firmware/src/system/system.c | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/firmware/src/config.h b/firmware/src/config.h index ad2f5f69..ab0bd536 100644 --- a/firmware/src/config.h +++ b/firmware/src/config.h @@ -27,8 +27,9 @@ // Timer clock divider #define TXCTL_PS_DIV TXCTL_PS_DIV2 -// Desired PWM Frequency (Hz). +// PWM and Systick frequency #define PWM_FREQ_HZ (20000) +#define SYSTICK_FREQ_HZ (1000) // Control parameters #define PWM_LIMIT (0.8f) diff --git a/firmware/src/scheduler/scheduler.c b/firmware/src/scheduler/scheduler.c index 43018af0..5914979b 100644 --- a/firmware/src/scheduler/scheduler.c +++ b/firmware/src/scheduler/scheduler.c @@ -80,7 +80,7 @@ void WaitForControlLoopInterrupt(void) ma7xx_send_angle_cmd(); } ADC_update(); - system_update(); + encoder_update(true); observer_update(); // At this point control is returned to main loop. @@ -118,7 +118,8 @@ void CAN_IRQHandler(void) void SysTick_Handler(void) { msTicks = msTicks + 1; - CAN_task(); + CAN_update(); + system_update(); } void UART_ReceiveMessageHandler(void) diff --git a/firmware/src/system/system.c b/firmware/src/system/system.c index 2fec3201..04be95ca 100644 --- a/firmware/src/system/system.c +++ b/firmware/src/system/system.c @@ -97,7 +97,7 @@ void system_init(void) state.Vbus = 12.0f; // Derive VBus D value for given tau value - config.Vbus_D = 1.0f - powf(EPSILON, -1.0f / (config.Vbus_tau * PWM_FREQ_HZ)); + config.Vbus_D = 1.0f - powf(EPSILON, -1.0f / (config.Vbus_tau * SYSTICK_FREQ_HZ)); /* Initialize Systick per 1ms */ SysTick_Config(150000); // TODO: Use var From c73a7734cd9daea19fd8d3d6bc33d5ec0786ec2a Mon Sep 17 00:00:00 2001 From: Yannis Chatzikonstantinou Date: Thu, 31 Aug 2023 14:04:07 +0300 Subject: [PATCH 07/19] update device spec --- docs/protocol/reference.rst | 5 +++++ firmware/src/can/can.c | 2 +- firmware/src/can/can.h | 2 +- firmware/src/can/can_endpoints.c | 2 +- firmware/src/can/can_endpoints.h | 7 ++++++- 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/docs/protocol/reference.rst b/docs/protocol/reference.rst index 106b1a22..26d722be 100644 --- a/docs/protocol/reference.rst +++ b/docs/protocol/reference.rst @@ -126,6 +126,11 @@ Any system errors, as a bitmask Flags: - UNDERVOLTAGE - DRIVER_FAULT +- CHARGE_PUMP_FAULT_STAT +- CHARGE_PUMP_FAULT +- DRV10_DISABLE +- DRV32_DISABLE +- DRV54_DISABLE save_config() -> void diff --git a/firmware/src/can/can.c b/firmware/src/can/can.c index d8fc77cb..512f5212 100644 --- a/firmware/src/can/can.c +++ b/firmware/src/can/can.c @@ -161,7 +161,7 @@ void CAN_restore_config(CANConfig *config_) config = *config_; } -void CAN_task(void) { +void CAN_update(void) { // Transmit heartbeat const uint32_t msg_diff = msTicks - state.last_msg_ms; if (msg_diff >= config.heartbeat_period && PAC55XX_CAN->SR.TBS != 0) diff --git a/firmware/src/can/can.h b/firmware/src/can/can.h index a218bab5..4b56340a 100644 --- a/firmware/src/can/can.h +++ b/firmware/src/can/can.h @@ -40,4 +40,4 @@ void CAN_process_interrupt(void); CANConfig *CAN_get_config(void); void CAN_restore_config(CANConfig *config_); -void CAN_task(void); +void CAN_update(void); diff --git a/firmware/src/can/can_endpoints.c b/firmware/src/can/can_endpoints.c index fda40fc4..6773e418 100644 --- a/firmware/src/can/can_endpoints.c +++ b/firmware/src/can/can_endpoints.c @@ -19,7 +19,7 @@ uint8_t (*avlos_endpoints[81])(uint8_t * buffer, uint8_t * buffer_len, Avlos_Command cmd) = {&avlos_protocol_hash, &avlos_uid, &avlos_fw_version, &avlos_hw_revision, &avlos_Vbus, &avlos_Ibus, &avlos_power, &avlos_temp, &avlos_calibrated, &avlos_errors, &avlos_save_config, &avlos_erase_config, &avlos_reset, &avlos_invoke_bootloader, &avlos_scheduler_total, &avlos_scheduler_busy, &avlos_scheduler_errors, &avlos_controller_state, &avlos_controller_mode, &avlos_controller_warnings, &avlos_controller_errors, &avlos_controller_position_setpoint, &avlos_controller_position_p_gain, &avlos_controller_velocity_setpoint, &avlos_controller_velocity_limit, &avlos_controller_velocity_p_gain, &avlos_controller_velocity_i_gain, &avlos_controller_velocity_deadband, &avlos_controller_velocity_increment, &avlos_controller_current_Iq_setpoint, &avlos_controller_current_Id_setpoint, &avlos_controller_current_Iq_limit, &avlos_controller_current_Iq_estimate, &avlos_controller_current_bandwidth, &avlos_controller_current_Iq_p_gain, &avlos_controller_current_max_Ibus_regen, &avlos_controller_current_max_Ibrake, &avlos_controller_voltage_Vq_setpoint, &avlos_controller_calibrate, &avlos_controller_idle, &avlos_controller_position_mode, &avlos_controller_velocity_mode, &avlos_controller_current_mode, &avlos_controller_set_pos_vel_setpoints, &avlos_comms_can_rate, &avlos_comms_can_id, &avlos_motor_R, &avlos_motor_L, &avlos_motor_pole_pairs, &avlos_motor_type, &avlos_motor_offset, &avlos_motor_direction, &avlos_motor_calibrated, &avlos_motor_I_cal, &avlos_motor_errors, &avlos_encoder_position_estimate, &avlos_encoder_velocity_estimate, &avlos_encoder_type, &avlos_encoder_bandwidth, &avlos_encoder_calibrated, &avlos_encoder_errors, &avlos_traj_planner_max_accel, &avlos_traj_planner_max_decel, &avlos_traj_planner_max_vel, &avlos_traj_planner_t_accel, &avlos_traj_planner_t_decel, &avlos_traj_planner_t_total, &avlos_traj_planner_move_to, &avlos_traj_planner_move_to_tlimit, &avlos_traj_planner_errors, &avlos_homing_velocity, &avlos_homing_max_homing_t, &avlos_homing_retract_dist, &avlos_homing_warnings, &avlos_homing_stall_detect_velocity, &avlos_homing_stall_detect_delta_pos, &avlos_homing_stall_detect_t, &avlos_homing_home, &avlos_watchdog_enabled, &avlos_watchdog_triggered, &avlos_watchdog_timeout }; -uint32_t avlos_proto_hash = 3868913670; +uint32_t avlos_proto_hash = 2762144808; uint32_t _avlos_get_proto_hash(void) { diff --git a/firmware/src/can/can_endpoints.h b/firmware/src/can/can_endpoints.h index 5e630039..2384168f 100644 --- a/firmware/src/can/can_endpoints.h +++ b/firmware/src/can/can_endpoints.h @@ -27,7 +27,12 @@ typedef enum { ERRORS_NONE = 0, ERRORS_UNDERVOLTAGE = (1 << 0), - ERRORS_DRIVER_FAULT = (1 << 1) + ERRORS_DRIVER_FAULT = (1 << 1), + ERRORS_CHARGE_PUMP_FAULT_STAT = (1 << 2), + ERRORS_CHARGE_PUMP_FAULT = (1 << 3), + ERRORS_DRV10_DISABLE = (1 << 4), + ERRORS_DRV32_DISABLE = (1 << 5), + ERRORS_DRV54_DISABLE = (1 << 6) } errors_flags; typedef enum From cda4986aaaf7ced5f605037ba885001dda7ab234 Mon Sep 17 00:00:00 2001 From: Yannis Chatzikonstantinou Date: Thu, 31 Aug 2023 15:24:16 +0300 Subject: [PATCH 08/19] remove cycle reporting --- docs/protocol/reference.rst | 154 +++++++++------------- firmware/src/can/can_endpoints.c | 30 +---- firmware/src/can/can_endpoints.h | 22 +--- firmware/src/scheduler/scheduler.c | 16 --- firmware/src/scheduler/scheduler.h | 7 - firmware/src/system/system.c | 5 - studio/Python/tests/test_board.py | 14 +- studio/Python/tinymovr/config/device.yaml | 12 +- 8 files changed, 77 insertions(+), 183 deletions(-) diff --git a/docs/protocol/reference.rst b/docs/protocol/reference.rst index 26d722be..341b8392 100644 --- a/docs/protocol/reference.rst +++ b/docs/protocol/reference.rst @@ -173,34 +173,10 @@ Return Type: void Invoke the bootloader. -scheduler.total -------------------------------------------------------------------- - -ID: 14 -Type: uint32 - - -Total processor cycles in a single PWM cycle. - - - - -scheduler.busy -------------------------------------------------------------------- - -ID: 15 -Type: uint32 - - -Busy processor cycles in a single PWM cycle. - - - - scheduler.errors ------------------------------------------------------------------- -ID: 16 +ID: 14 Type: uint8 @@ -213,7 +189,7 @@ Flags: controller.state ------------------------------------------------------------------- -ID: 17 +ID: 15 Type: uint8 @@ -225,7 +201,7 @@ The state of the controller. controller.mode ------------------------------------------------------------------- -ID: 18 +ID: 16 Type: uint8 @@ -237,7 +213,7 @@ The control mode of the controller. controller.warnings ------------------------------------------------------------------- -ID: 19 +ID: 17 Type: uint8 @@ -252,7 +228,7 @@ Flags: controller.errors ------------------------------------------------------------------- -ID: 20 +ID: 18 Type: uint8 @@ -265,7 +241,7 @@ Flags: controller.position.setpoint ------------------------------------------------------------------- -ID: 21 +ID: 19 Type: float Units: tick @@ -277,7 +253,7 @@ The position setpoint. controller.position.p_gain ------------------------------------------------------------------- -ID: 22 +ID: 20 Type: float @@ -289,7 +265,7 @@ The proportional gain of the position controller. controller.velocity.setpoint ------------------------------------------------------------------- -ID: 23 +ID: 21 Type: float Units: tick / second @@ -301,7 +277,7 @@ The velocity setpoint. controller.velocity.limit ------------------------------------------------------------------- -ID: 24 +ID: 22 Type: float Units: tick / second @@ -313,7 +289,7 @@ The velocity limit. controller.velocity.p_gain ------------------------------------------------------------------- -ID: 25 +ID: 23 Type: float @@ -325,7 +301,7 @@ The proportional gain of the velocity controller. controller.velocity.i_gain ------------------------------------------------------------------- -ID: 26 +ID: 24 Type: float @@ -339,7 +315,7 @@ The integral gain of the velocity controller. controller.velocity.deadband ------------------------------------------------------------------- -ID: 27 +ID: 25 Type: float Units: tick @@ -351,7 +327,7 @@ The deadband of the velocity integrator. A region around the position setpoint w controller.velocity.increment ------------------------------------------------------------------- -ID: 28 +ID: 26 Type: float @@ -363,7 +339,7 @@ Max velocity setpoint increment (ramping) rate. Set to 0 to disable. controller.current.Iq_setpoint ------------------------------------------------------------------- -ID: 29 +ID: 27 Type: float Units: ampere @@ -375,7 +351,7 @@ The Iq setpoint. controller.current.Id_setpoint ------------------------------------------------------------------- -ID: 30 +ID: 28 Type: float Units: ampere @@ -387,7 +363,7 @@ The Id setpoint. controller.current.Iq_limit ------------------------------------------------------------------- -ID: 31 +ID: 29 Type: float Units: ampere @@ -399,7 +375,7 @@ The Iq limit. controller.current.Iq_estimate ------------------------------------------------------------------- -ID: 32 +ID: 30 Type: float Units: ampere @@ -411,7 +387,7 @@ The Iq estimate. controller.current.bandwidth ------------------------------------------------------------------- -ID: 33 +ID: 31 Type: float Units: hertz @@ -423,7 +399,7 @@ The current controller bandwidth. controller.current.Iq_p_gain ------------------------------------------------------------------- -ID: 34 +ID: 32 Type: float @@ -435,7 +411,7 @@ The current controller proportional gain. controller.current.max_Ibus_regen ------------------------------------------------------------------- -ID: 35 +ID: 33 Type: float Units: ampere @@ -447,7 +423,7 @@ The max current allowed to be fed back to the power source before flux braking a controller.current.max_Ibrake ------------------------------------------------------------------- -ID: 36 +ID: 34 Type: float Units: ampere @@ -459,7 +435,7 @@ The max current allowed to be dumped to the motor windings during flux braking. controller.voltage.Vq_setpoint ------------------------------------------------------------------- -ID: 37 +ID: 35 Type: float Units: volt @@ -471,7 +447,7 @@ The Vq setpoint. calibrate() -> void ------------------------------------------------------------------- -ID: 38 +ID: 36 Return Type: void @@ -481,7 +457,7 @@ Calibrate the device. idle() -> void ------------------------------------------------------------------- -ID: 39 +ID: 37 Return Type: void @@ -491,7 +467,7 @@ Set idle mode, disabling the driver. position_mode() -> void ------------------------------------------------------------------- -ID: 40 +ID: 38 Return Type: void @@ -501,7 +477,7 @@ Set position control mode. velocity_mode() -> void ------------------------------------------------------------------- -ID: 41 +ID: 39 Return Type: void @@ -511,7 +487,7 @@ Set velocity control mode. current_mode() -> void ------------------------------------------------------------------- -ID: 42 +ID: 40 Return Type: void @@ -521,7 +497,7 @@ Set current control mode. set_pos_vel_setpoints(pos_setpoint, vel_setpoint) -> float ------------------------------------------------------------------- -ID: 43 +ID: 41 Return Type: float @@ -533,7 +509,7 @@ Set the position and velocity setpoints in one go, and retrieve the position est comms.can.rate ------------------------------------------------------------------- -ID: 44 +ID: 42 Type: uint32 @@ -545,7 +521,7 @@ The baud rate of the CAN interface. comms.can.id ------------------------------------------------------------------- -ID: 45 +ID: 43 Type: uint32 @@ -557,7 +533,7 @@ The ID of the CAN interface. motor.R ------------------------------------------------------------------- -ID: 46 +ID: 44 Type: float Units: ohm @@ -569,7 +545,7 @@ The motor Resistance value. motor.L ------------------------------------------------------------------- -ID: 47 +ID: 45 Type: float Units: henry @@ -581,7 +557,7 @@ The motor Inductance value. motor.pole_pairs ------------------------------------------------------------------- -ID: 48 +ID: 46 Type: uint8 @@ -593,7 +569,7 @@ The motor pole pair count. motor.type ------------------------------------------------------------------- -ID: 49 +ID: 47 Type: uint8 @@ -607,7 +583,7 @@ Options: motor.offset ------------------------------------------------------------------- -ID: 50 +ID: 48 Type: float @@ -619,7 +595,7 @@ User-defined offset of the motor. motor.direction ------------------------------------------------------------------- -ID: 51 +ID: 49 Type: int8 @@ -631,7 +607,7 @@ User-defined direction of the motor. motor.calibrated ------------------------------------------------------------------- -ID: 52 +ID: 50 Type: bool @@ -643,7 +619,7 @@ Whether the motor has been calibrated. motor.I_cal ------------------------------------------------------------------- -ID: 53 +ID: 51 Type: float Units: ampere @@ -655,7 +631,7 @@ The calibration current. motor.errors ------------------------------------------------------------------- -ID: 54 +ID: 52 Type: uint8 @@ -670,7 +646,7 @@ Flags: encoder.position_estimate ------------------------------------------------------------------- -ID: 55 +ID: 53 Type: float Units: tick @@ -682,7 +658,7 @@ The filtered encoder position estimate. encoder.velocity_estimate ------------------------------------------------------------------- -ID: 56 +ID: 54 Type: float Units: tick / second @@ -694,7 +670,7 @@ The filtered encoder velocity estimate. encoder.type ------------------------------------------------------------------- -ID: 57 +ID: 55 Type: uint8 @@ -708,7 +684,7 @@ Options: encoder.bandwidth ------------------------------------------------------------------- -ID: 58 +ID: 56 Type: float Units: hertz @@ -720,7 +696,7 @@ The encoder observer bandwidth. encoder.calibrated ------------------------------------------------------------------- -ID: 59 +ID: 57 Type: bool @@ -732,7 +708,7 @@ Whether the encoder has been calibrated. encoder.errors ------------------------------------------------------------------- -ID: 60 +ID: 58 Type: uint8 @@ -746,7 +722,7 @@ Flags: traj_planner.max_accel ------------------------------------------------------------------- -ID: 61 +ID: 59 Type: float Units: tick / second @@ -758,7 +734,7 @@ The max allowed acceleration of the generated trajectory. traj_planner.max_decel ------------------------------------------------------------------- -ID: 62 +ID: 60 Type: float Units: tick / second ** 2 @@ -770,7 +746,7 @@ The max allowed deceleration of the generated trajectory. traj_planner.max_vel ------------------------------------------------------------------- -ID: 63 +ID: 61 Type: float Units: tick / second @@ -782,7 +758,7 @@ The max allowed cruise velocity of the generated trajectory. traj_planner.t_accel ------------------------------------------------------------------- -ID: 64 +ID: 62 Type: float Units: second @@ -794,7 +770,7 @@ In time mode, the acceleration time of the generated trajectory. traj_planner.t_decel ------------------------------------------------------------------- -ID: 65 +ID: 63 Type: float Units: second @@ -806,7 +782,7 @@ In time mode, the deceleration time of the generated trajectory. traj_planner.t_total ------------------------------------------------------------------- -ID: 66 +ID: 64 Type: float Units: second @@ -818,7 +794,7 @@ In time mode, the total time of the generated trajectory. move_to(pos_setpoint) -> void ------------------------------------------------------------------- -ID: 67 +ID: 65 Return Type: void @@ -828,7 +804,7 @@ Move to target position respecting velocity and acceleration limits. move_to_tlimit(pos_setpoint) -> void ------------------------------------------------------------------- -ID: 68 +ID: 66 Return Type: void @@ -838,7 +814,7 @@ Move to target position respecting time limits for each sector. traj_planner.errors ------------------------------------------------------------------- -ID: 69 +ID: 67 Type: uint8 @@ -852,7 +828,7 @@ Flags: homing.velocity ------------------------------------------------------------------- -ID: 70 +ID: 68 Type: float Units: tick / second @@ -864,7 +840,7 @@ The velocity at which the motor performs homing. homing.max_homing_t ------------------------------------------------------------------- -ID: 71 +ID: 69 Type: float Units: second @@ -876,7 +852,7 @@ The maximum time the motor is allowed to travel before homing times out and abor homing.retract_dist ------------------------------------------------------------------- -ID: 72 +ID: 70 Type: float Units: tick @@ -888,7 +864,7 @@ The retraction distance the motor travels after the endstop has been found. homing.warnings ------------------------------------------------------------------- -ID: 73 +ID: 71 Type: uint8 @@ -901,7 +877,7 @@ Flags: homing.stall_detect.velocity ------------------------------------------------------------------- -ID: 74 +ID: 72 Type: float Units: tick / second @@ -913,7 +889,7 @@ The velocity below which (and together with `stall_detect.delta_pos`) stall dete homing.stall_detect.delta_pos ------------------------------------------------------------------- -ID: 75 +ID: 73 Type: float Units: tick @@ -925,7 +901,7 @@ The velocity below which (and together with `stall_detect.delta_pos`) stall dete homing.stall_detect.t ------------------------------------------------------------------- -ID: 76 +ID: 74 Type: float Units: second @@ -937,7 +913,7 @@ The time to remain in stall detection mode before the motor is considered stalle home() -> void ------------------------------------------------------------------- -ID: 77 +ID: 75 Return Type: void @@ -947,7 +923,7 @@ Perform the homing operation. watchdog.enabled ------------------------------------------------------------------- -ID: 78 +ID: 76 Type: bool @@ -959,7 +935,7 @@ Whether the watchdog is enabled or not. watchdog.triggered ------------------------------------------------------------------- -ID: 79 +ID: 77 Type: bool @@ -971,7 +947,7 @@ Whether the watchdog has been triggered or not. watchdog.timeout ------------------------------------------------------------------- -ID: 80 +ID: 78 Type: float Units: second diff --git a/firmware/src/can/can_endpoints.c b/firmware/src/can/can_endpoints.c index 6773e418..92f2edd6 100644 --- a/firmware/src/can/can_endpoints.c +++ b/firmware/src/can/can_endpoints.c @@ -18,8 +18,8 @@ #include -uint8_t (*avlos_endpoints[81])(uint8_t * buffer, uint8_t * buffer_len, Avlos_Command cmd) = {&avlos_protocol_hash, &avlos_uid, &avlos_fw_version, &avlos_hw_revision, &avlos_Vbus, &avlos_Ibus, &avlos_power, &avlos_temp, &avlos_calibrated, &avlos_errors, &avlos_save_config, &avlos_erase_config, &avlos_reset, &avlos_invoke_bootloader, &avlos_scheduler_total, &avlos_scheduler_busy, &avlos_scheduler_errors, &avlos_controller_state, &avlos_controller_mode, &avlos_controller_warnings, &avlos_controller_errors, &avlos_controller_position_setpoint, &avlos_controller_position_p_gain, &avlos_controller_velocity_setpoint, &avlos_controller_velocity_limit, &avlos_controller_velocity_p_gain, &avlos_controller_velocity_i_gain, &avlos_controller_velocity_deadband, &avlos_controller_velocity_increment, &avlos_controller_current_Iq_setpoint, &avlos_controller_current_Id_setpoint, &avlos_controller_current_Iq_limit, &avlos_controller_current_Iq_estimate, &avlos_controller_current_bandwidth, &avlos_controller_current_Iq_p_gain, &avlos_controller_current_max_Ibus_regen, &avlos_controller_current_max_Ibrake, &avlos_controller_voltage_Vq_setpoint, &avlos_controller_calibrate, &avlos_controller_idle, &avlos_controller_position_mode, &avlos_controller_velocity_mode, &avlos_controller_current_mode, &avlos_controller_set_pos_vel_setpoints, &avlos_comms_can_rate, &avlos_comms_can_id, &avlos_motor_R, &avlos_motor_L, &avlos_motor_pole_pairs, &avlos_motor_type, &avlos_motor_offset, &avlos_motor_direction, &avlos_motor_calibrated, &avlos_motor_I_cal, &avlos_motor_errors, &avlos_encoder_position_estimate, &avlos_encoder_velocity_estimate, &avlos_encoder_type, &avlos_encoder_bandwidth, &avlos_encoder_calibrated, &avlos_encoder_errors, &avlos_traj_planner_max_accel, &avlos_traj_planner_max_decel, &avlos_traj_planner_max_vel, &avlos_traj_planner_t_accel, &avlos_traj_planner_t_decel, &avlos_traj_planner_t_total, &avlos_traj_planner_move_to, &avlos_traj_planner_move_to_tlimit, &avlos_traj_planner_errors, &avlos_homing_velocity, &avlos_homing_max_homing_t, &avlos_homing_retract_dist, &avlos_homing_warnings, &avlos_homing_stall_detect_velocity, &avlos_homing_stall_detect_delta_pos, &avlos_homing_stall_detect_t, &avlos_homing_home, &avlos_watchdog_enabled, &avlos_watchdog_triggered, &avlos_watchdog_timeout }; -uint32_t avlos_proto_hash = 2762144808; +uint8_t (*avlos_endpoints[79])(uint8_t * buffer, uint8_t * buffer_len, Avlos_Command cmd) = {&avlos_protocol_hash, &avlos_uid, &avlos_fw_version, &avlos_hw_revision, &avlos_Vbus, &avlos_Ibus, &avlos_power, &avlos_temp, &avlos_calibrated, &avlos_errors, &avlos_save_config, &avlos_erase_config, &avlos_reset, &avlos_invoke_bootloader, &avlos_scheduler_errors, &avlos_controller_state, &avlos_controller_mode, &avlos_controller_warnings, &avlos_controller_errors, &avlos_controller_position_setpoint, &avlos_controller_position_p_gain, &avlos_controller_velocity_setpoint, &avlos_controller_velocity_limit, &avlos_controller_velocity_p_gain, &avlos_controller_velocity_i_gain, &avlos_controller_velocity_deadband, &avlos_controller_velocity_increment, &avlos_controller_current_Iq_setpoint, &avlos_controller_current_Id_setpoint, &avlos_controller_current_Iq_limit, &avlos_controller_current_Iq_estimate, &avlos_controller_current_bandwidth, &avlos_controller_current_Iq_p_gain, &avlos_controller_current_max_Ibus_regen, &avlos_controller_current_max_Ibrake, &avlos_controller_voltage_Vq_setpoint, &avlos_controller_calibrate, &avlos_controller_idle, &avlos_controller_position_mode, &avlos_controller_velocity_mode, &avlos_controller_current_mode, &avlos_controller_set_pos_vel_setpoints, &avlos_comms_can_rate, &avlos_comms_can_id, &avlos_motor_R, &avlos_motor_L, &avlos_motor_pole_pairs, &avlos_motor_type, &avlos_motor_offset, &avlos_motor_direction, &avlos_motor_calibrated, &avlos_motor_I_cal, &avlos_motor_errors, &avlos_encoder_position_estimate, &avlos_encoder_velocity_estimate, &avlos_encoder_type, &avlos_encoder_bandwidth, &avlos_encoder_calibrated, &avlos_encoder_errors, &avlos_traj_planner_max_accel, &avlos_traj_planner_max_decel, &avlos_traj_planner_max_vel, &avlos_traj_planner_t_accel, &avlos_traj_planner_t_decel, &avlos_traj_planner_t_total, &avlos_traj_planner_move_to, &avlos_traj_planner_move_to_tlimit, &avlos_traj_planner_errors, &avlos_homing_velocity, &avlos_homing_max_homing_t, &avlos_homing_retract_dist, &avlos_homing_warnings, &avlos_homing_stall_detect_velocity, &avlos_homing_stall_detect_delta_pos, &avlos_homing_stall_detect_t, &avlos_homing_home, &avlos_watchdog_enabled, &avlos_watchdog_triggered, &avlos_watchdog_timeout }; +uint32_t avlos_proto_hash = 838807697; uint32_t _avlos_get_proto_hash(void) { @@ -171,35 +171,11 @@ uint8_t avlos_invoke_bootloader(uint8_t * buffer, uint8_t * buffer_len, Avlos_Co return AVLOS_RET_CALL; } -uint8_t avlos_scheduler_total(uint8_t * buffer, uint8_t * buffer_len, Avlos_Command cmd) -{ -if (AVLOS_CMD_READ == cmd) { - uint32_t v; - v = Scheduler_GetTotalCycles(); - *buffer_len = sizeof(v); - memcpy(buffer, &v, sizeof(v)); - return AVLOS_RET_READ; - } - return AVLOS_RET_NOACTION; -} - -uint8_t avlos_scheduler_busy(uint8_t * buffer, uint8_t * buffer_len, Avlos_Command cmd) -{ -if (AVLOS_CMD_READ == cmd) { - uint32_t v; - v = Scheduler_GetBusyCycles(); - *buffer_len = sizeof(v); - memcpy(buffer, &v, sizeof(v)); - return AVLOS_RET_READ; - } - return AVLOS_RET_NOACTION; -} - uint8_t avlos_scheduler_errors(uint8_t * buffer, uint8_t * buffer_len, Avlos_Command cmd) { if (AVLOS_CMD_READ == cmd) { uint8_t v; - v = controller_get_errors(); + v = scheduler_get_errors(); *buffer_len = sizeof(v); memcpy(buffer, &v, sizeof(v)); return AVLOS_RET_READ; diff --git a/firmware/src/can/can_endpoints.h b/firmware/src/can/can_endpoints.h index 2384168f..ed380ed2 100644 --- a/firmware/src/can/can_endpoints.h +++ b/firmware/src/can/can_endpoints.h @@ -96,7 +96,7 @@ typedef enum } encoder_type_options; extern uint32_t avlos_proto_hash; -extern uint8_t (*avlos_endpoints[81])(uint8_t * buffer, uint8_t * buffer_len, Avlos_Command cmd); +extern uint8_t (*avlos_endpoints[79])(uint8_t * buffer, uint8_t * buffer_len, Avlos_Command cmd); extern uint32_t _avlos_get_proto_hash(void); /* @@ -239,26 +239,6 @@ uint8_t avlos_reset(uint8_t * buffer, uint8_t * buffer_len, Avlos_Command cmd); */ uint8_t avlos_invoke_bootloader(uint8_t * buffer, uint8_t * buffer_len, Avlos_Command cmd); -/* -* avlos_scheduler_total -* -* Total processor cycles in a single PWM cycle. -* -* @param buffer -* @param buffer_len -*/ -uint8_t avlos_scheduler_total(uint8_t * buffer, uint8_t * buffer_len, Avlos_Command cmd); - -/* -* avlos_scheduler_busy -* -* Busy processor cycles in a single PWM cycle. -* -* @param buffer -* @param buffer_len -*/ -uint8_t avlos_scheduler_busy(uint8_t * buffer, uint8_t * buffer_len, Avlos_Command cmd); - /* * avlos_scheduler_errors * diff --git a/firmware/src/scheduler/scheduler.c b/firmware/src/scheduler/scheduler.c index 5914979b..6082b1a5 100644 --- a/firmware/src/scheduler/scheduler.c +++ b/firmware/src/scheduler/scheduler.c @@ -63,7 +63,6 @@ void WaitForControlLoopInterrupt(void) else { state.busy = false; - state.busy_cycles = DWT->CYCCNT - state.busy_loop_start; // Go back to sleep __DSB(); __ISB(); @@ -72,7 +71,6 @@ void WaitForControlLoopInterrupt(void) } state.busy = true; state.adc_interrupt = false; - state.busy_loop_start = DWT->CYCCNT; // We have to service the control loop by updating // current measurements and encoder estimates. if (ENCODER_MA7XX == encoder_get_type()) @@ -103,10 +101,6 @@ void ADC_IRQHandler(void) { state.adc_interrupt = true; } - - const uint32_t current_timestamp = DWT->CYCCNT; - state.total_cycles = current_timestamp - state.total_loop_start; - state.total_loop_start = current_timestamp; } void CAN_IRQHandler(void) @@ -135,16 +129,6 @@ void Wdt_IRQHandler(void) PAC55XX_WWDT->WWDTFLAG.IF = 1; } -TM_RAMFUNC uint32_t Scheduler_GetTotalCycles(void) -{ - return state.total_cycles; -} - -TM_RAMFUNC uint32_t Scheduler_GetBusyCycles(void) -{ - return state.busy_cycles; -} - TM_RAMFUNC uint8_t scheduler_get_errors(void) { return state.errors; diff --git a/firmware/src/scheduler/scheduler.h b/firmware/src/scheduler/scheduler.h index 542d86e3..e4af643d 100644 --- a/firmware/src/scheduler/scheduler.h +++ b/firmware/src/scheduler/scheduler.h @@ -26,15 +26,8 @@ typedef struct bool busy; uint8_t errors; - uint32_t busy_cycles; - uint32_t total_cycles; - uint32_t busy_loop_start; - uint32_t total_loop_start; } SchedulerState; void WaitForControlLoopInterrupt(void); -uint32_t Scheduler_GetTotalCycles(void); -uint32_t Scheduler_GetBusyCycles(void); - uint8_t scheduler_get_errors(void); diff --git a/firmware/src/system/system.c b/firmware/src/system/system.c index 04be95ca..273123bc 100644 --- a/firmware/src/system/system.c +++ b/firmware/src/system/system.c @@ -85,11 +85,6 @@ void system_init(void) // Ensure ADC GP0 register is zero, to bypass bootloader on next boot pac5xxx_tile_register_write(ADDR_GP0, 0); - // Configure reporting of mcu cycles - CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; - DWT->CYCCNT = 0; - DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; - // Configure error handling SCB->CCR |= 0x10; diff --git a/studio/Python/tests/test_board.py b/studio/Python/tests/test_board.py index 589d6243..16464edb 100644 --- a/studio/Python/tests/test_board.py +++ b/studio/Python/tests/test_board.py @@ -191,13 +191,13 @@ def test_g_limits(self): self.tm.controller.velocity.setpoint = 0 time.sleep(0.5) - def test_h_timings(self): - """ - Test DWT busy/total cycle timings - """ - self.assertGreater(self.tm.scheduler.total, 0) - self.assertGreater(self.tm.scheduler.busy, 0) - self.assertLess(self.tm.scheduler.busy, 3000) + # def test_h_timings(self): + # """ + # Test DWT busy/total cycle timings + # """ + # self.assertGreater(self.tm.scheduler.total, 0) + # self.assertGreater(self.tm.scheduler.busy, 0) + # self.assertLess(self.tm.scheduler.busy, 3000) def test_i_states(self): """ diff --git a/studio/Python/tinymovr/config/device.yaml b/studio/Python/tinymovr/config/device.yaml index 8247e8e1..4314f2ff 100644 --- a/studio/Python/tinymovr/config/device.yaml +++ b/studio/Python/tinymovr/config/device.yaml @@ -76,20 +76,10 @@ remote_attributes: meta: {reload_data: True} - name: scheduler remote_attributes: - - name: total - dtype: uint32 - meta: {dynamic: True} - getter_name: Scheduler_GetTotalCycles - summary: Total processor cycles in a single PWM cycle. - - name: busy - dtype: uint32 - meta: {dynamic: True} - getter_name: Scheduler_GetBusyCycles - summary: Busy processor cycles in a single PWM cycle. - name: errors flags: [CONTROL_BLOCK_REENTERED] meta: {dynamic: True} - getter_name: controller_get_errors + getter_name: scheduler_get_errors summary: Any scheduler errors, as a bitmask - name: controller remote_attributes: From 0ef8d803344228941fef29c2bc23ad895c99c610 Mon Sep 17 00:00:00 2001 From: Yannis Chatzikonstantinou Date: Thu, 31 Aug 2023 15:24:53 +0300 Subject: [PATCH 09/19] add adc offset calibration step --- firmware/src/controller/controller.c | 4 ++-- firmware/src/motor/calibration.c | 8 ++++++++ firmware/src/motor/calibration.h | 1 + 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/firmware/src/controller/controller.c b/firmware/src/controller/controller.c index 7a671884..20853127 100644 --- a/firmware/src/controller/controller.c +++ b/firmware/src/controller/controller.c @@ -124,11 +124,11 @@ void Controller_ControlLoop(void) reset_calibration(); if (ENCODER_MA7XX == encoder_get_type()) { - (void)((CalibrateResistance() && CalibrateInductance()) && CalibrateDirectionAndPolePairs() && calibrate_offset_and_rectification()); + (void)((CalibrateADCOffset() && CalibrateResistance() && CalibrateInductance()) && CalibrateDirectionAndPolePairs() && calibrate_offset_and_rectification()); } else if (ENCODER_HALL == encoder_get_type()) { - (void)((CalibrateResistance() && CalibrateInductance()) && calibrate_hall_sequence()); + (void)((CalibrateADCOffset() && CalibrateResistance() && CalibrateInductance()) && calibrate_hall_sequence()); } state.is_calibrating = false; controller_set_state(STATE_IDLE); diff --git a/firmware/src/motor/calibration.c b/firmware/src/motor/calibration.c index eee8b20d..e1249f28 100644 --- a/firmware/src/motor/calibration.c +++ b/firmware/src/motor/calibration.c @@ -30,6 +30,14 @@ static inline void set_epos_and_wait(float angle, float I_setpoint); static inline void wait_a_while(void); +bool CalibrateADCOffset(void) +{ + // We only need to wait here, the ADC loop will + // perform the offset calibration automatically + wait_a_while(); + return true; +} + bool CalibrateResistance(void) { if (!motor_get_is_gimbal()) diff --git a/firmware/src/motor/calibration.h b/firmware/src/motor/calibration.h index 23be4c27..7b442b4d 100644 --- a/firmware/src/motor/calibration.h +++ b/firmware/src/motor/calibration.h @@ -34,6 +34,7 @@ #define CAL_V_INDUCTANCE (5.0f) #endif +bool CalibrateADCOffset(void); bool CalibrateResistance(void); bool CalibrateInductance(void); bool CalibrateDirectionAndPolePairs(void); From 04cfce17cd1c7db235236054638d793a8c57a442 Mon Sep 17 00:00:00 2001 From: Yannis Chatzikonstantinou Date: Thu, 31 Aug 2023 15:25:11 +0300 Subject: [PATCH 10/19] ignore cp_stat error --- firmware/src/system/system.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/firmware/src/system/system.c b/firmware/src/system/system.c index 273123bc..239f4070 100644 --- a/firmware/src/system/system.c +++ b/firmware/src/system/system.c @@ -113,7 +113,9 @@ TM_RAMFUNC void system_update(void) const uint8_t drv_fault = pac5xxx_tile_register_read(ADDR_DRV_FLT); if (drv_fault > 0) { - state.errors |= ((drv_fault & 0x7) << 1); + // We use 0x5 mask because we ignore CHARGE_PUMP_FAULT_STAT + // for the time being, as it seems to always be set. + state.errors |= ((drv_fault & 0x5) << 1); } } From 615d258fcce269370f3368b5ae817046fa73bed8 Mon Sep 17 00:00:00 2001 From: Yannis Chatzikonstantinou Date: Thu, 31 Aug 2023 20:03:30 +0300 Subject: [PATCH 11/19] fix dynamic attribute getter to support enums and bitmasks --- studio/Python/tinymovr/gui/helpers.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/studio/Python/tinymovr/gui/helpers.py b/studio/Python/tinymovr/gui/helpers.py index 8bb3cdfb..c908474f 100644 --- a/studio/Python/tinymovr/gui/helpers.py +++ b/studio/Python/tinymovr/gui/helpers.py @@ -516,10 +516,13 @@ def get_dynamic_attrs(attr_dict): Get the attributes that are marked as dynamic in the spec. """ dynamic_attrs = [] - for _, attr in attr_dict.items(): - if isinstance(attr, RemoteAttribute): - if "dynamic" in attr.meta and attr.meta["dynamic"] == True: - dynamic_attrs.append(attr) + + for attr in attr_dict.values(): + if isinstance( + attr, (RemoteAttribute, RemoteEnum, RemoteBitmask) + ) and attr.meta.get("dynamic"): + dynamic_attrs.append(attr) elif hasattr(attr, "remote_attributes"): dynamic_attrs.extend(get_dynamic_attrs(attr.remote_attributes)) + return dynamic_attrs From 65de081c2c6ad06bdeab66f35dc195e1d71ea5ea Mon Sep 17 00:00:00 2001 From: Yannis Chatzikonstantinou Date: Thu, 31 Aug 2023 20:03:48 +0300 Subject: [PATCH 12/19] formatting using black --- studio/Python/tinymovr/gui/helpers.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/studio/Python/tinymovr/gui/helpers.py b/studio/Python/tinymovr/gui/helpers.py index c908474f..2cd79adb 100644 --- a/studio/Python/tinymovr/gui/helpers.py +++ b/studio/Python/tinymovr/gui/helpers.py @@ -22,7 +22,7 @@ from PySide6 import QtGui from PySide6.QtGui import QGuiApplication, QPalette from PySide6.QtWidgets import QMessageBox, QFileDialog -from avlos.definitions import RemoteAttribute +from avlos.definitions import RemoteAttribute, RemoteEnum, RemoteBitmask import tinymovr @@ -345,11 +345,15 @@ def format_value(value, include_unit=True): return "{0:.6g}".format(value) return str(value) + def bitmask_string_representation(bitmask_value): - labels_in_bitmask = [label.name for label in type(bitmask_value) if label & bitmask_value] - return ', '.join(labels_in_bitmask) + labels_in_bitmask = [ + label.name for label in type(bitmask_value) if label & bitmask_value + ] + return ", ".join(labels_in_bitmask) + -def load_pixmap(filename, dark_mode_suffix='_dark', high_dpi_suffix='@2x'): +def load_pixmap(filename, dark_mode_suffix="_dark", high_dpi_suffix="@2x"): """ Load an image from a file and return it as a QPixmap. Load appropriate variants based on pixel ratio and @@ -359,12 +363,12 @@ def load_pixmap(filename, dark_mode_suffix='_dark', high_dpi_suffix='@2x'): pixel_ratio = QtGui.QGuiApplication.primaryScreen().devicePixelRatio() # Prepare the filename based on the conditions - parts = filename.split('.') + parts = filename.split(".") if is_dark_mode(): parts[0] += dark_mode_suffix if pixel_ratio > 1: parts[0] += high_dpi_suffix - adjusted_filename = '.'.join(parts) + adjusted_filename = ".".join(parts) file_path = os.path.join( os.path.dirname(tinymovr.__file__), "resources", "icons", adjusted_filename From 1cbf740a35ce69d32bf650014cbe1a2fd6aeafb4 Mon Sep 17 00:00:00 2001 From: Yannis Chatzikonstantinou Date: Fri, 1 Sep 2023 17:02:10 +0300 Subject: [PATCH 13/19] improve handling of comm timeouts --- studio/Python/tinymovr/gui/gui.py | 3 ++- studio/Python/tinymovr/gui/helpers.py | 16 ++++++---------- studio/Python/tinymovr/gui/window.py | 12 +++++++++++- studio/Python/tinymovr/gui/worker.py | 14 ++++++++++---- 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/studio/Python/tinymovr/gui/gui.py b/studio/Python/tinymovr/gui/gui.py index a11c57af..0d1902ca 100644 --- a/studio/Python/tinymovr/gui/gui.py +++ b/studio/Python/tinymovr/gui/gui.py @@ -1,7 +1,7 @@ """Tinymovr Studio GUI Usage: - tinymovr [--bus=] [--chan=] [--bitrate=] + tinymovr [--bus=] [--chan=] [--bitrate=] [--max-timeouts=] tinymovr -h | --help tinymovr --version @@ -9,6 +9,7 @@ --bus= One or more interfaces to use, first available is used [default: canine,slcan_disco]. --chan= The bus device "channel". --bitrate= CAN bitrate [default: 1000000]. + --max-timeouts= Max timeouts before nodes are rescanned [default: 5]. """ import sys diff --git a/studio/Python/tinymovr/gui/helpers.py b/studio/Python/tinymovr/gui/helpers.py index 2cd79adb..d138b566 100644 --- a/studio/Python/tinymovr/gui/helpers.py +++ b/studio/Python/tinymovr/gui/helpers.py @@ -421,19 +421,15 @@ class TimedGetter: information for the getter function """ - def __init__(self, error_handler): - self.error_handler = error_handler + def __init__(self): self.dt = 0 def get_value(self, getter): - try: - get_start_time = time.time() - val = getter() - get_dt = time.time() - get_start_time - self.dt = self.dt * 0.99 + get_dt * 0.01 - return val - except Exception as e: - self.error_handler(e) + get_start_time = time.time() + val = getter() + get_dt = time.time() - get_start_time + self.dt = self.dt * 0.99 + get_dt * 0.01 + return val class RateLimitedFunction: diff --git a/studio/Python/tinymovr/gui/window.py b/studio/Python/tinymovr/gui/window.py index a45145ba..1700ab1d 100644 --- a/studio/Python/tinymovr/gui/window.py +++ b/studio/Python/tinymovr/gui/window.py @@ -134,9 +134,12 @@ def __init__(self, app, arguments): main_widget.setMinimumHeight(600) self.setCentralWidget(main_widget) + self.timeout_count = 0 + buses = arguments["--bus"].rsplit(sep=",") channel = arguments["--chan"] bitrate = int(arguments["--bitrate"]) + self.max_timeouts = int(arguments["--max-timeouts"]) if channel == None: params = get_bus_config(buses) @@ -164,7 +167,14 @@ def about_to_quit(self): @QtCore.Slot() def handle_worker_error(self, e): if isinstance(e, ChannelResponseError): - self.logger.warn("Timeout occured") + if self.timeout_count > self.max_timeouts: + self.timeout_count = 0 + self.logger.warn("Max timeouts exceeded. Triggering rescan...") + self.worker.reset() + else: + self.logger.warn("Timeout while getting value.") + self.timeout_count += 1 + else: raise e diff --git a/studio/Python/tinymovr/gui/worker.py b/studio/Python/tinymovr/gui/worker.py index a31af7a9..a9013472 100644 --- a/studio/Python/tinymovr/gui/worker.py +++ b/studio/Python/tinymovr/gui/worker.py @@ -43,7 +43,7 @@ def __init__(self, busparams, logger): init_tee(can.Bus(**busparams)) self._init_containers() self.dsc = Discovery(self._node_appeared, self._node_disappeared, self.logger) - self.timed_getter = TimedGetter(lambda e: self.handle_error.emit(e)) + self.timed_getter = TimedGetter() self._rate_limited_update = RateLimitedFunction(lambda: self._update(), 0.040) self.running = True @@ -78,7 +78,10 @@ def update_active_attrs(self, d): def _get_attr_values(self): vals = {} for attr in self.active_attrs: - vals[attr.full_name] = self.timed_getter.get_value(attr.get_value) + try: + vals[attr.full_name] = self.timed_getter.get_value(attr.get_value) + except Exception as e: + self.handle_error.emit(e) start_time = time.time() self.dynamic_attrs.sort( key=lambda attr: self.dynamic_attrs_last_update[attr.full_name] @@ -92,8 +95,11 @@ def _get_attr_values(self): else 0 ) if (attr.full_name not in vals) and (start_time - t > 0.5): - vals[attr.full_name] = self.timed_getter.get_value(attr.get_value) - self.dynamic_attrs_last_update[attr.full_name] = start_time + try: + vals[attr.full_name] = self.timed_getter.get_value(attr.get_value) + self.dynamic_attrs_last_update[attr.full_name] = start_time + except Exception as e: + self.handle_error.emit(e) break return vals From 5999f87ec6ed0fe6941f2da46710d9d19f550d49 Mon Sep 17 00:00:00 2001 From: Yannis Chatzikonstantinou Date: Sat, 2 Sep 2023 03:00:57 +0300 Subject: [PATCH 14/19] use term DFU instead of bootloader where the mode is implied --- docs/protocol/reference.rst | 4 ++-- firmware/src/can/can_endpoints.c | 8 ++++---- firmware/src/can/can_endpoints.h | 6 +++--- firmware/src/system/system.c | 4 ++-- firmware/src/system/system.h | 2 +- .../tests/{test_bootloader.py => test_dfu.py} | 15 +++++++-------- 6 files changed, 19 insertions(+), 20 deletions(-) rename studio/Python/tests/{test_bootloader.py => test_dfu.py} (81%) diff --git a/docs/protocol/reference.rst b/docs/protocol/reference.rst index 341b8392..d24de64f 100644 --- a/docs/protocol/reference.rst +++ b/docs/protocol/reference.rst @@ -163,14 +163,14 @@ Return Type: void Reset the device. -invoke_bootloader() -> void +enter_dfu() -> void ------------------------------------------------------------------- ID: 13 Return Type: void -Invoke the bootloader. +Enter DFU mode. scheduler.errors diff --git a/firmware/src/can/can_endpoints.c b/firmware/src/can/can_endpoints.c index 92f2edd6..58e478dc 100644 --- a/firmware/src/can/can_endpoints.c +++ b/firmware/src/can/can_endpoints.c @@ -18,8 +18,8 @@ #include -uint8_t (*avlos_endpoints[79])(uint8_t * buffer, uint8_t * buffer_len, Avlos_Command cmd) = {&avlos_protocol_hash, &avlos_uid, &avlos_fw_version, &avlos_hw_revision, &avlos_Vbus, &avlos_Ibus, &avlos_power, &avlos_temp, &avlos_calibrated, &avlos_errors, &avlos_save_config, &avlos_erase_config, &avlos_reset, &avlos_invoke_bootloader, &avlos_scheduler_errors, &avlos_controller_state, &avlos_controller_mode, &avlos_controller_warnings, &avlos_controller_errors, &avlos_controller_position_setpoint, &avlos_controller_position_p_gain, &avlos_controller_velocity_setpoint, &avlos_controller_velocity_limit, &avlos_controller_velocity_p_gain, &avlos_controller_velocity_i_gain, &avlos_controller_velocity_deadband, &avlos_controller_velocity_increment, &avlos_controller_current_Iq_setpoint, &avlos_controller_current_Id_setpoint, &avlos_controller_current_Iq_limit, &avlos_controller_current_Iq_estimate, &avlos_controller_current_bandwidth, &avlos_controller_current_Iq_p_gain, &avlos_controller_current_max_Ibus_regen, &avlos_controller_current_max_Ibrake, &avlos_controller_voltage_Vq_setpoint, &avlos_controller_calibrate, &avlos_controller_idle, &avlos_controller_position_mode, &avlos_controller_velocity_mode, &avlos_controller_current_mode, &avlos_controller_set_pos_vel_setpoints, &avlos_comms_can_rate, &avlos_comms_can_id, &avlos_motor_R, &avlos_motor_L, &avlos_motor_pole_pairs, &avlos_motor_type, &avlos_motor_offset, &avlos_motor_direction, &avlos_motor_calibrated, &avlos_motor_I_cal, &avlos_motor_errors, &avlos_encoder_position_estimate, &avlos_encoder_velocity_estimate, &avlos_encoder_type, &avlos_encoder_bandwidth, &avlos_encoder_calibrated, &avlos_encoder_errors, &avlos_traj_planner_max_accel, &avlos_traj_planner_max_decel, &avlos_traj_planner_max_vel, &avlos_traj_planner_t_accel, &avlos_traj_planner_t_decel, &avlos_traj_planner_t_total, &avlos_traj_planner_move_to, &avlos_traj_planner_move_to_tlimit, &avlos_traj_planner_errors, &avlos_homing_velocity, &avlos_homing_max_homing_t, &avlos_homing_retract_dist, &avlos_homing_warnings, &avlos_homing_stall_detect_velocity, &avlos_homing_stall_detect_delta_pos, &avlos_homing_stall_detect_t, &avlos_homing_home, &avlos_watchdog_enabled, &avlos_watchdog_triggered, &avlos_watchdog_timeout }; -uint32_t avlos_proto_hash = 838807697; +uint8_t (*avlos_endpoints[79])(uint8_t * buffer, uint8_t * buffer_len, Avlos_Command cmd) = {&avlos_protocol_hash, &avlos_uid, &avlos_fw_version, &avlos_hw_revision, &avlos_Vbus, &avlos_Ibus, &avlos_power, &avlos_temp, &avlos_calibrated, &avlos_errors, &avlos_save_config, &avlos_erase_config, &avlos_reset, &avlos_enter_dfu, &avlos_scheduler_errors, &avlos_controller_state, &avlos_controller_mode, &avlos_controller_warnings, &avlos_controller_errors, &avlos_controller_position_setpoint, &avlos_controller_position_p_gain, &avlos_controller_velocity_setpoint, &avlos_controller_velocity_limit, &avlos_controller_velocity_p_gain, &avlos_controller_velocity_i_gain, &avlos_controller_velocity_deadband, &avlos_controller_velocity_increment, &avlos_controller_current_Iq_setpoint, &avlos_controller_current_Id_setpoint, &avlos_controller_current_Iq_limit, &avlos_controller_current_Iq_estimate, &avlos_controller_current_bandwidth, &avlos_controller_current_Iq_p_gain, &avlos_controller_current_max_Ibus_regen, &avlos_controller_current_max_Ibrake, &avlos_controller_voltage_Vq_setpoint, &avlos_controller_calibrate, &avlos_controller_idle, &avlos_controller_position_mode, &avlos_controller_velocity_mode, &avlos_controller_current_mode, &avlos_controller_set_pos_vel_setpoints, &avlos_comms_can_rate, &avlos_comms_can_id, &avlos_motor_R, &avlos_motor_L, &avlos_motor_pole_pairs, &avlos_motor_type, &avlos_motor_offset, &avlos_motor_direction, &avlos_motor_calibrated, &avlos_motor_I_cal, &avlos_motor_errors, &avlos_encoder_position_estimate, &avlos_encoder_velocity_estimate, &avlos_encoder_type, &avlos_encoder_bandwidth, &avlos_encoder_calibrated, &avlos_encoder_errors, &avlos_traj_planner_max_accel, &avlos_traj_planner_max_decel, &avlos_traj_planner_max_vel, &avlos_traj_planner_t_accel, &avlos_traj_planner_t_decel, &avlos_traj_planner_t_total, &avlos_traj_planner_move_to, &avlos_traj_planner_move_to_tlimit, &avlos_traj_planner_errors, &avlos_homing_velocity, &avlos_homing_max_homing_t, &avlos_homing_retract_dist, &avlos_homing_warnings, &avlos_homing_stall_detect_velocity, &avlos_homing_stall_detect_delta_pos, &avlos_homing_stall_detect_t, &avlos_homing_home, &avlos_watchdog_enabled, &avlos_watchdog_triggered, &avlos_watchdog_timeout }; +uint32_t avlos_proto_hash = 4118115615; uint32_t _avlos_get_proto_hash(void) { @@ -164,9 +164,9 @@ uint8_t avlos_reset(uint8_t * buffer, uint8_t * buffer_len, Avlos_Command cmd) return AVLOS_RET_CALL; } -uint8_t avlos_invoke_bootloader(uint8_t * buffer, uint8_t * buffer_len, Avlos_Command cmd) +uint8_t avlos_enter_dfu(uint8_t * buffer, uint8_t * buffer_len, Avlos_Command cmd) { - system_invoke_bootloader(); + system_enter_dfu(); return AVLOS_RET_CALL; } diff --git a/firmware/src/can/can_endpoints.h b/firmware/src/can/can_endpoints.h index ed380ed2..0f773a13 100644 --- a/firmware/src/can/can_endpoints.h +++ b/firmware/src/can/can_endpoints.h @@ -230,14 +230,14 @@ uint8_t avlos_erase_config(uint8_t * buffer, uint8_t * buffer_len, Avlos_Command uint8_t avlos_reset(uint8_t * buffer, uint8_t * buffer_len, Avlos_Command cmd); /* -* avlos_invoke_bootloader +* avlos_enter_dfu * -* Invoke the bootloader. +* Enter DFU mode. * * @param buffer * @param buffer_len */ -uint8_t avlos_invoke_bootloader(uint8_t * buffer, uint8_t * buffer_len, Avlos_Command cmd); +uint8_t avlos_enter_dfu(uint8_t * buffer, uint8_t * buffer_len, Avlos_Command cmd); /* * avlos_scheduler_errors diff --git a/firmware/src/system/system.c b/firmware/src/system/system.c index 239f4070..4f7ad078 100644 --- a/firmware/src/system/system.c +++ b/firmware/src/system/system.c @@ -82,7 +82,7 @@ void system_init(void) // Vp = 10V , 440mA-540mA, Charge Pump Enable pac5xxx_tile_register_write(ADDR_SYSCONF, 0x01); - // Ensure ADC GP0 register is zero, to bypass bootloader on next boot + // Ensure ADC GP0 register is zero, to bypass DFU mode on next boot pac5xxx_tile_register_write(ADDR_GP0, 0); // Configure error handling @@ -125,7 +125,7 @@ void system_reset(void) NVIC_SystemReset(); } -void system_invoke_bootloader(void) +void system_enter_dfu(void) { pac5xxx_tile_register_write(ADDR_GP0, BTL_TRIGGER_PATTERN); NVIC_SystemReset(); diff --git a/firmware/src/system/system.h b/firmware/src/system/system.h index 598ad7c4..91bf0497 100644 --- a/firmware/src/system/system.h +++ b/firmware/src/system/system.h @@ -36,7 +36,7 @@ typedef struct { void system_init(void); void system_update(void); void system_reset(void); -void system_invoke_bootloader(void); +void system_enter_dfu(void); inline uint8_t system_get_fw_version_string(char *buffer) { diff --git a/studio/Python/tests/test_bootloader.py b/studio/Python/tests/test_dfu.py similarity index 81% rename from studio/Python/tests/test_bootloader.py rename to studio/Python/tests/test_dfu.py index e62f34c3..19a4567e 100644 --- a/studio/Python/tests/test_bootloader.py +++ b/studio/Python/tests/test_dfu.py @@ -1,5 +1,5 @@ """ -Tinymovr Bootloader Test Class +Tinymovr DFU Test Class Copyright Ioannis Chatzikonstantinou 2020-2023 Implements convenience functionality. @@ -23,8 +23,7 @@ from tinymovr.config import ( get_bus_config, create_device, - tinymovr_definition, - bl_definition, + definitions ) import unittest @@ -38,17 +37,17 @@ def setUp(cls): params["bitrate"] = 1000000 cls.can_bus = can.Bus(**params) - def test_bootloader(self, node_id=1): + def test_dfu(self, node_id=1): init_tee(self.can_bus) - tm = create_device(node_id=node_id, device_definition=tinymovr_definition) + tm = create_device(node_id=node_id) tm_hash = tm.protocol_hash - tm.invoke_bootloader() + tm.enter_dfu() time.sleep(1) - bl = create_device(node_id=node_id, device_definition=bl_definition) + bl = create_device(node_id=node_id) bl_hash = bl.protocol_hash bl.reset() time.sleep(0.1) - tm = create_device(node_id=node_id, device_definition=tinymovr_definition) + tm = create_device(node_id=node_id) tm_hash2 = tm.protocol_hash tm.reset() time.sleep(0.1) From 5171c915da1c2f2d72890ad599b7412c7a770311 Mon Sep 17 00:00:00 2001 From: Yannis Chatzikonstantinou Date: Sat, 2 Sep 2023 03:01:13 +0300 Subject: [PATCH 15/19] move yaml files to own dir --- studio/Python/tinymovr/{config => specs}/device.yaml | 6 +++--- studio/Python/tinymovr/{config/bl.yaml => specs/dfu.yaml} | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) rename studio/Python/tinymovr/{config => specs}/device.yaml (99%) rename studio/Python/tinymovr/{config/bl.yaml => specs/dfu.yaml} (96%) diff --git a/studio/Python/tinymovr/config/device.yaml b/studio/Python/tinymovr/specs/device.yaml similarity index 99% rename from studio/Python/tinymovr/config/device.yaml rename to studio/Python/tinymovr/specs/device.yaml index 4314f2ff..1e7d93cd 100644 --- a/studio/Python/tinymovr/config/device.yaml +++ b/studio/Python/tinymovr/specs/device.yaml @@ -68,9 +68,9 @@ remote_attributes: dtype: void arguments: [] meta: {reload_data: True} - - name: invoke_bootloader - summary: Invoke the bootloader. - caller_name: system_invoke_bootloader + - name: enter_dfu + summary: Enter DFU mode. + caller_name: system_enter_dfu dtype: void arguments: [] meta: {reload_data: True} diff --git a/studio/Python/tinymovr/config/bl.yaml b/studio/Python/tinymovr/specs/dfu.yaml similarity index 96% rename from studio/Python/tinymovr/config/bl.yaml rename to studio/Python/tinymovr/specs/dfu.yaml index b906b79a..4b2bdaae 100644 --- a/studio/Python/tinymovr/config/bl.yaml +++ b/studio/Python/tinymovr/specs/dfu.yaml @@ -1,5 +1,5 @@ -name: tm_bl +name: tm_dfu remote_attributes: - name: protocol_hash dtype: uint32 @@ -26,7 +26,7 @@ remote_attributes: - name: error options: [NONE, START_EXECUTION_STACK_POINTER_OUT_OF_RANGE, START_EXECUTION_ADDRESS_OUT_OF_RANGE, START_EXECUTION_ADDRESS_LSB_NOT_SET] getter_name: system_get_error - summary: The last error encountered by the bootloader + summary: The last error encountered in DFU - name: read_flash_32 summary: Read a 32 bit value from the flash caller_name: nvm_read_flash_32 From 0112fcf9ee6300286ad7fdabc6e293344df70f64 Mon Sep 17 00:00:00 2001 From: Yannis Chatzikonstantinou Date: Sat, 2 Sep 2023 03:02:05 +0300 Subject: [PATCH 16/19] fix file locations --- studio/Python/Manifest.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/studio/Python/Manifest.in b/studio/Python/Manifest.in index 97299015..95c364bd 100644 --- a/studio/Python/Manifest.in +++ b/studio/Python/Manifest.in @@ -7,4 +7,5 @@ include tinymovr/resources/icons/empty.png include tinymovr/resources/icons/empty@2x.png include tinymovr/resources/icons/empty_dark.png include tinymovr/resources/icons/empty_dark@2x.png -include tinymovr/config/device.yaml +include tinymovr/specs/device.yaml +include tinymovr/specs/dfu.yaml From c90aae2d3274023d443d6c7f80e409a486c1c881 Mon Sep 17 00:00:00 2001 From: Yannis Chatzikonstantinou Date: Sat, 2 Sep 2023 03:02:51 +0300 Subject: [PATCH 17/19] enable working with multiple device specs --- studio/Python/tinymovr/cli.py | 12 ++--- studio/Python/tinymovr/config/__init__.py | 3 +- studio/Python/tinymovr/config/config.py | 56 +++++++++++++++-------- studio/Python/tinymovr/gui/window.py | 7 ++- studio/Python/tinymovr/gui/worker.py | 36 ++++++++------- 5 files changed, 66 insertions(+), 48 deletions(-) diff --git a/studio/Python/tinymovr/cli.py b/studio/Python/tinymovr/cli.py index 21821142..df5f3303 100644 --- a/studio/Python/tinymovr/cli.py +++ b/studio/Python/tinymovr/cli.py @@ -65,16 +65,16 @@ def spawn(): user_ns["tms"] = tms def node_appeared(node, node_id): - node_name = "{}{}".format(base_node_name, node_id) - print("Found {} with device id {}".format(node_name, node.uid)) + display_name = "{}{}".format(node.name, node_id) + print("Found {} with device uid {}".format(display_name, node.uid)) tms[node_id] = node - user_ns[node_name] = node + user_ns[display_name] = node def node_disappeared(node_id): - node_name = "{}{}".format(base_node_name, node_id) - print("Lost {}".format(node_name)) + display_name = "{}{}".format(tms[node_id].name, node_id) + print("Lost {}".format(display_name)) + del user_ns[display_name] del tms[node_id] - del user_ns[node_name] print(app_name + " " + str(version)) diff --git a/studio/Python/tinymovr/config/__init__.py b/studio/Python/tinymovr/config/__init__.py index 8a642ab6..f48375b6 100644 --- a/studio/Python/tinymovr/config/__init__.py +++ b/studio/Python/tinymovr/config/__init__.py @@ -1,8 +1,7 @@ from tinymovr.config.config import ( get_bus_config, configure_logging, - tinymovr_definition, - bl_definition, + definitions, create_device, create_device_with_hash_msg, ProtocolVersionError, diff --git a/studio/Python/tinymovr/config/config.py b/studio/Python/tinymovr/config/config.py index 87bdbeec..91dc61d0 100644 --- a/studio/Python/tinymovr/config/config.py +++ b/studio/Python/tinymovr/config/config.py @@ -16,6 +16,7 @@ """ import yaml +from pathlib import Path import logging from importlib_resources import files import can @@ -24,14 +25,14 @@ from tinymovr.codec import DataType from tinymovr.channel import CANChannel -tinymovr_definition = None -bl_definition = None +definitions = {"hash_uint32": {}, "name": {}} -with open(str(files("tinymovr").joinpath("config/device.yaml"))) as def_raw: - tinymovr_definition = yaml.safe_load(def_raw) - -with open(str(files("tinymovr").joinpath("config/bl.yaml"))) as def_raw: - bl_definition = yaml.safe_load(def_raw) +for yaml_file in Path(files("tinymovr").joinpath("specs/")).glob("*.yaml"): + with open(str(yaml_file)) as def_raw: + definition = yaml.safe_load(def_raw) + tmp_node = deserialize(definition) + definitions["hash_uint32"][tmp_node.hash_uint32] = definition + definitions["name"][definition["name"]] = definition class ProtocolVersionError(Exception): @@ -62,39 +63,56 @@ def get_bus_config(suggested_types=None): raise can.CanInitializationError("No active interface found") from exc -def create_device(node_id, device_definition=tinymovr_definition): +def create_device(node_id): """ Create a device with the defined ID. The hash value will be retrieved from the remote. """ chan = CANChannel(node_id) + + # Temporarily using a default definition to get the protocol_hash + # This assumes that `protocol_hash` is standard across different definitions + # Get the first definition as a temp + tmp_definition = list(definitions["hash_uint32"].values())[0] + node = deserialize(tmp_definition) + node._channel = chan + + # Check for the correct definition using the remote hash + protocol_hash = node.protocol_hash + device_definition = definitions["hash_uint32"].get(protocol_hash) + + if not device_definition: + raise ValueError(f"No device definition found for hash {protocol_hash}.") + node = deserialize(device_definition) - # We use the generated node to retrieve the hash from - # the remote. This is ok as long as we know that the - # hash endpoint will always be the 0th one. If there - # is a hash mismatch, we raise an exception, otherwise - # we return the device node as is. node._channel = chan - # hash_uint32 is local, proto_hash is remote - if node.hash_uint32 != node.protocol_hash: + if node.hash_uint32 != protocol_hash: raise ProtocolVersionError(node_id, "") + return node -def create_device_with_hash_msg(heartbeat_msg, device_definition=tinymovr_definition): +def create_device_with_hash_msg(heartbeat_msg): """ Create a device, the heartbeat msg will be used - to decode the actual hash value and id + to decode the actual hash value and id. """ node_id = heartbeat_msg.arbitration_id & 0x3F chan = CANChannel(node_id) - node = deserialize(device_definition) + hash, *_ = chan.serializer.deserialize(heartbeat_msg.data[:4], DataType.UINT32) - if node.hash_uint32 != hash: # hash_uint32 is local, hash is remote + device_definition = definitions["hash_uint32"].get(hash) + + if not device_definition: + raise ValueError(f"No device definition found for hash {hash}.") + + node = deserialize(device_definition) + if node.hash_uint32 != hash: version_str = "".join([chr(n) for n in heartbeat_msg.data[4:]]) if not version_str.strip(): version_str = "1.3.1" raise ProtocolVersionError(node_id, version_str) + node._channel = chan return node diff --git a/studio/Python/tinymovr/gui/window.py b/studio/Python/tinymovr/gui/window.py index 1700ab1d..03fc42c1 100644 --- a/studio/Python/tinymovr/gui/window.py +++ b/studio/Python/tinymovr/gui/window.py @@ -70,7 +70,6 @@ def __init__(self, app, arguments): self.start_time = time.time() self.logger = configure_logging() - bitrate = int(arguments["--bitrate"]) self.attr_widgets_by_id = {} self.graphs_by_id = {} @@ -204,7 +203,7 @@ def add_graph_for_attr(self, attr): self.right_layout.addWidget(graph_widget) @QtCore.Slot() - def regen_tree(self, tms_by_id): + def regen_tree(self, devices_by_name): """ Regenerate the attribute tree """ @@ -213,8 +212,8 @@ def regen_tree(self, tms_by_id): self.tree_widget.clear() self.tree_widget.setEnabled(False) all_items = [] - for name, node in tms_by_id.items(): - widget, items_list = self.parse_node(node, name) + for name, device in devices_by_name.items(): + widget, items_list = self.parse_node(device, name) self.tree_widget.addTopLevelItem(widget) all_items.extend(items_list) for item in all_items: diff --git a/studio/Python/tinymovr/gui/worker.py b/studio/Python/tinymovr/gui/worker.py index a9013472..29611452 100644 --- a/studio/Python/tinymovr/gui/worker.py +++ b/studio/Python/tinymovr/gui/worker.py @@ -18,7 +18,6 @@ import time import can -from canine import CANineBus from PySide6 import QtCore from PySide6.QtCore import QObject from PySide6.QtWidgets import ( @@ -42,7 +41,7 @@ def __init__(self, busparams, logger): self.mutx = QtCore.QMutex() init_tee(can.Bus(**busparams)) self._init_containers() - self.dsc = Discovery(self._node_appeared, self._node_disappeared, self.logger) + self.dsc = Discovery(self._device_appeared, self._device_disappeared, self.logger) self.timed_getter = TimedGetter() self._rate_limited_update = RateLimitedFunction(lambda: self._update(), 0.040) self.running = True @@ -58,14 +57,14 @@ def stop(self): def force_regen(self): self.mutx.lock() - self.regen.emit(dict(self.tms_by_id)) + self.regen.emit(dict(self.devices_by_name)) self.mutx.unlock() def reset(self): self.mutx.lock() self.dsc.reset() self._init_containers() - self.regen.emit(dict(self.tms_by_id)) + self.regen.emit(dict(self.devices_by_name)) self.mutx.unlock() @QtCore.Slot(dict) @@ -106,7 +105,8 @@ def _get_attr_values(self): def _init_containers(self): self.active_attrs = set() self.dynamic_attrs = [] - self.tms_by_id = {} + self.devices_by_name = {} + self.names_by_id = {} self.dynamic_attrs_last_update = {} def _update(self): @@ -117,20 +117,22 @@ def _update(self): self.mutx.unlock() QApplication.processEvents() - def _node_appeared(self, node, name): + def _device_appeared(self, device, node_id): self.mutx.lock() - node_name = "{}{}".format(base_node_name, name) - self.tms_by_id[node_name] = node - node.name = node_name - node.include_base_name = True - self.dynamic_attrs = get_dynamic_attrs(self.tms_by_id) - self.regen.emit(dict(self.tms_by_id)) + display_name = "{}{}".format(device.name, node_id) + self.devices_by_name[display_name] = device + self.names_by_id[node_id] = display_name + device.name = display_name + device.include_base_name = True + self.dynamic_attrs = get_dynamic_attrs(self.devices_by_name) + self.regen.emit(dict(self.devices_by_name)) self.mutx.unlock() - def _node_disappeared(self, name): + def _device_disappeared(self, node_id): self.mutx.lock() - node_name = "{}{}".format(base_node_name, name) - del self.tms_by_id[node_name] - self.dynamic_attrs = get_dynamic_attrs(self.tms_by_id) - self.regen.emit(dict(self.tms_by_id)) + display_name = "{}{}".format(self.names_by_id[node_id], node_id) + del self.devices_by_name[display_name] + del self.names_by_id[node_id] + self.dynamic_attrs = get_dynamic_attrs(self.devices_by_name) + self.regen.emit(dict(self.devices_by_name)) self.mutx.unlock() From aa78288d1a82fddee68cde19d188a7d21d4e21bd Mon Sep 17 00:00:00 2001 From: Yannis Chatzikonstantinou Date: Sat, 2 Sep 2023 03:03:08 +0300 Subject: [PATCH 18/19] only use the dfu util for fw upgrades --- studio/Python/tinymovr/dfu.py | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/studio/Python/tinymovr/dfu.py b/studio/Python/tinymovr/dfu.py index 39e7f45f..5920444c 100644 --- a/studio/Python/tinymovr/dfu.py +++ b/studio/Python/tinymovr/dfu.py @@ -1,9 +1,9 @@ """ Usage: - dfu.py --node_id=ID [--bin=PATH] [--no-reset] + dfu.py --node_id=ID --bin=PATH [--no-reset] Options: - --node_id=ID The CAN Node id of the bootloader to address. + --node_id=ID The CAN Node ID of the device in DFU mode. --bin=PATH The path of the .bin file to upload. --no-reset Do not perform a reset following successful flashing. """ @@ -22,8 +22,7 @@ from tinymovr.config import ( get_bus_config, create_device, - tinymovr_definition, - bl_definition, + definitions ) """ @@ -117,10 +116,13 @@ def spawn(): params = get_bus_config(["canine", "slcan_disco"]) params["bitrate"] = 1000000 init_tee(can.Bus(**params), timeout=1.0) - device = create_device(node_id=node_id, device_definition=bl_definition) + device = create_device(node_id=node_id) + + if not bin_path: + raise FileNotFoundError(f"No bin file specified!") # If a non-existing .bin file is specified, raise error - if bin_path and not Path(bin_path).is_file(): + elif bin_path and not Path(bin_path).is_file(): raise FileNotFoundError(f"Bin file {bin_path} not found!") # If an existing .bin file is specified, upload it to the device @@ -133,14 +135,6 @@ def spawn(): if not args["--no-reset"]: print("Resetting device...") device.reset() - - # If no bin file specified, enter the iPython CLI - else: - user_ns = {} - user_ns["device"] = device - c = Config() - c.TerminalIPythonApp.display_banner = False - IPython.start_ipython(argv=[], config=c, user_ns=user_ns) destroy_tee() From 41cafb2c6734406b8966c8d625484649035cbe2a Mon Sep 17 00:00:00 2001 From: Yannis Chatzikonstantinou Date: Sat, 2 Sep 2023 03:05:53 +0300 Subject: [PATCH 19/19] update bootloader binaries --- firmware/bootloader/bootloader_M51.bin | Bin 3572 -> 3580 bytes firmware/bootloader/bootloader_R32.bin | Bin 3596 -> 3604 bytes firmware/bootloader/bootloader_R33.bin | Bin 3596 -> 3604 bytes firmware/bootloader/bootloader_R50.bin | Bin 3556 -> 3564 bytes firmware/bootloader/bootloader_R51.bin | Bin 3556 -> 3564 bytes firmware/bootloader/bootloader_R52.bin | Bin 3572 -> 3580 bytes 6 files changed, 0 insertions(+), 0 deletions(-) diff --git a/firmware/bootloader/bootloader_M51.bin b/firmware/bootloader/bootloader_M51.bin index c559ca3d2e2ef23166f78eeeb54a66e5a2fc81a2..b99bde8a7b4c1e70945e50cfa5c16fdfc3351c6c 100755 GIT binary patch delta 529 zcmew&{YSc9f|EgECmRF9Y9L+<#Or~0BM@%}Vsx+-No+fi{gj1)VI`2J09%oy`6#l5 z6L(rOzMS~Al=0l;Y(`ba{>c*=B^fVGUd^b@STgxKV>F}NWMigS#>JB-G6^#-pS+Yw zKeO|vNr6Uzf?L5}29@8>Ew-|_F=X(%F?@LYi$z%>LA!ui!D27R)(bxv1sEzAKAif+ ztiZ7stf~T}>J*YHgx<|4qO5K_K$Rya+cN(bPW}1exdJPL0s{k=1IJc11%?kAll@sl z88s)TvZylJP3~rq6yN>>=mw2X7cCV*@=U)p+zf&G&rIIUV$EsfW8}R!K{>-{@_!a> z#&46gS@juZCP%Yc%2fU|bkhc^@BPW+#p4;A>HI-}IXKb(!vp2W#K|jI6*w5)GCX+i z$;7bv0xJunF}FWMigS#`%*cG6^#-p1hPv zKeP3xNr6Uzf?L5}29@8>Ew-|_F=X(%F?@LWi$z%>LA!ui!D27R)(bxv1sEzAJ{KKwLgx>WiqO5K_K$S-)+cN(bPW<`dxdJPL0s{k=1IJc11%?kQll@sl z8C55zvZyjzP3~rq6yN*<=mw2X7cCV*^8bEnxETWVpP0Ox#hTN=$H04Wf^vqz4*&oF diff --git a/firmware/bootloader/bootloader_R32.bin b/firmware/bootloader/bootloader_R32.bin index 4c5eb57e0efef1512d9bcb2bbbfecb743e41f31f..064c691dcfb9cb3af735ddace0ca9ba4f26816ce 100755 GIT binary patch delta 528 zcmeB?nIcm!!O5U-m5qVnI1rx%;?qEU7KqOSF*>-2Bz76dW@KexI0~dGz*Zz_e#nAk z*~FcJjISnhGnO-6nB2^$$=Ex2Eu$pkrOC$`wHb>he`btkbeZhW6f3&;CyTOifkuLY zTftrimEX@fwlaKJKKUS%K4a(Pk4)m~uYa*9D<=A@R2crN(1;d9EznB#` z_F8OZabu|9bp!Gz>obdrZbVXRv6a=02PkuVawPMA&D5VCo-432C@?T^IdE)MQ(*X@ z_RCU(^*%)yENA08-2CQd%Ws=&eUmf^vBPbP-VZ&+Cv8P87s Z$R^JCV>2iFYetsU*PSvq|KJc|1ppb3o{9hf delta 537 zcmbOt(<4(a!O5U-mW_d7KM)@T;=@3E6o`)lF*-PjBz79eW@Kex*bAg7z*Zz_e#nAk z*~FcJjL#->GnO-+ncU2%$=Er0Eu$pkxyi>FwHfm!e`btkbeQbV6e~LaCyTOifkuLY zTftrimEX@fwlaKJJozA#K4a_Tk4)m~&wsHfD<=A@R2crN(1;d9UznB#` z_F8OZabu|9bp!Gz>obdru0>L7v6a=02PkuRawPMA&BUJ{o-432C@?T^IdE)MQ(*X@ z^vhC%-2Bz76dW@KexI0~dGz*Zz_e#nAk z*~FcJjISnhGnO-6nB2^$$=Ex2Eu$pkrOC$`wHb>he`btkbeZhW6f3&;CyTOifkuLY zTftrimEX@fwlaKJKKUS%K4a(Pk4)m~uYa*9D<=A@R2crN(1;d9EznB#` z_F8OZabu|9bp!Gz>obdrZbVXRv6a=02PkuVawPMA&D5VCo-432C@?T^IdE)MQ(*X@ z_RCU(^*%)yENA08-2CQd%Ws=&eUmf^vBPbP-VZ&+Cv8P87s Z$R^JCV>2iFYetsU*PSvq|KJc|1ppb3o{9hf delta 537 zcmbOt(<4(a!O5U-mW_d7KM)@T;=@3E6o`)lF*-PjBz79eW@Kex*bAg7z*Zz_e#nAk z*~FcJjL#->GnO-+ncU2%$=Er0Eu$pkxyi>FwHfm!e`btkbeQbV6e~LaCyTOifkuLY zTftrimEX@fwlaKJJozA#K4a_Tk4)m~&wsHfD<=A@R2crN(1;d9UznB#` z_F8OZabu|9bp!Gz>obdru0>L7v6a=02PkuRawPMA&BUJ{o-432C@?T^IdE)MQ(*X@ z^vhC%hDul8l!o&t}wSESY?qF`ChBvNBUF)kf3>my`3?JV9Vo_E|&@NzBu-MD7^}-KE0fq{O52t=H zD{$-utEvF0I)$VPp?5QiD61O}Q02+Vy3GHDQ-6MVuE5Hmz`(%ez_C?Lf#HM3WP27- zM$O5gEUJulldD-I#kcv{@IW~-aq)kf3>my`3?E+pVo_E|&@NzBu-MD7^}-KE0fq{O566Bn zD{$-utEvF0I)nlf79jMM{4fx@iN|cmDMM@IaZhDul8l!o&t}wSESY?qF`ChBvNBUF)kf3>my`3?JV9Vo_E|&@NzBu-MD7^}-KE0fq{O52t=H zD{$-utEvF0I)$VPp?5QiD61O}Q02+Vy3GHDQ-6MVuE5Hmz`(%ez_C?Lf#HM3WP27- zM$O5gEUJulldD-I#kcv{@IW~-aq)kf3>my`3?E+pVo_E|&@NzBu-MD7^}-KE0fq{O566Bn zD{$-utEvF0I)nlf79jMM{4fx@iN|cmDMM@IaZc*=B^fVGUd^b@STgxKV>F}NWMigS#>JB-G6^#-pS+Yw zKeO|vNr6Uzf?L5}29@8>Ew-|_F=X(%F?@LYi$z%>LA!ui!D27R)(bxv1sEzAKAif+ ztiZ7stf~T}>J*YHgx<|4qO5K_K$Rya+cN(bPW}1exdJPL0s{k=1IJc11%?kAll@sl z88s)TvZylJP3~rq6yN>>=mw2X7cCV*@=U)p+zf&G&rIIUV$EsfW8}R!K{>-{@_!a> z#&46gS@juZCP%Yc%2fU|bkhc^@BPW+#p4;A>HI-}IXKb(!vp2W#K|jI6*w5)GCX+i z$;7bv0xJunF}FWMigS#`%*cG6^#-p1hPv zKeP3xNr6Uzf?L5}29@8>Ew-|_F=X(%F?@LWi$z%>LA!ui!D27R)(bxv1sEzAJ{KKwLgx>WiqO5K_K$S-)+cN(bPW<`dxdJPL0s{k=1IJc11%?kQll@sl z8C55zvZyjzP3~rq6yN*<=mw2X7cCV*^8bEnxETWVpP0Ox#hTN=$H04Wf^vqz4*&oF