diff --git a/README.md b/README.md
index a2c2acc7..78c873b6 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
![Docs Build](https://github.com/yconst/tinymovr/workflows/Tinymovr%20Docs%20Build/badge.svg)
[![Discord](https://img.shields.io/discord/742400176664084535)](https://discord.gg/CzcCaXbU)
-[Tinymovr is an affordable motor controller](https://tinymovr.com) for precise control of 3-phase brushless motors. Tinymovr works with up to 38V input voltage, drives motors up to 40A continuous phase current, integrates an absolute angle encoder (MPS MA702) and features rich connectivity.
+[Tinymovr is an affordable motor controller](https://tinymovr.com) with integrated encoder and CAN bus for precise control of 3-phase brushless motors (PMSMs).
This repository holds the open source firmware, client library, hardware designs and documentation source.
diff --git a/docs/hardware/overview.rst b/docs/hardware/overview.rst
index ebab8b87..c127ca44 100644
--- a/docs/hardware/overview.rst
+++ b/docs/hardware/overview.rst
@@ -47,15 +47,15 @@ M5.x
Tinymovr M5.x is is our specialized driver for gimbal motors and light robotic joints. It features a very compact footprint and 5A max drive.
-Board Dimensions (M5.1)
-#######################
+Board Dimensions (M5.1, M5.2)
+#############################
.. image:: dimensions_m5.png
:width: 800
:alt: Tinymovr M5 dimensions
-Connectivity (M5.1)
-###################
+Connectivity (M5.1, M5.2)
+#########################
.. image:: connectors_m5.png
:width: 800
diff --git a/docs/studio/usage.rst b/docs/studio/usage.rst
index 805ed6ec..537af8a5 100644
--- a/docs/studio/usage.rst
+++ b/docs/studio/usage.rst
@@ -120,6 +120,8 @@ In order for multiple Tinymovr instances to coexist in the same CAN network, the
:width: 400
:alt: Change CAN bus node ID using the GUI
+The board will be discovered with the new ID. Studio GUI will rescan, discover the new node, and remove the old instance.
+
2. |cli| Change the ID
.. code-block:: python
@@ -128,21 +130,21 @@ In order for multiple Tinymovr instances to coexist in the same CAN network, the
where x is the desired ID. You can assign IDs in the range 1-1024.
-3. Relaunch Studio. The board will be discovered with the new ID.
+The board will be discovered with the new ID. Relaunch Studio CLI to remove the old board instance.
-4. |gui| Save configuration.
+3. |gui| Save configuration.
.. image:: save_config.png
:width: 400
:alt: Save configuration using the GUI
-4. |cli| Save configuration.
+3. |cli| Save configuration.
.. code-block:: python
tm1.save_config()
-5. Power down or reset the board. Tinymovr is now ready to use with the new ID.
+4. Power down or reset the board. Tinymovr is now ready to use with the new ID.
.. _command-line-options:
diff --git a/docs/upgrade/upgrade.rst b/docs/upgrade/upgrade.rst
index fa1b6f73..09d867ce 100644
--- a/docs/upgrade/upgrade.rst
+++ b/docs/upgrade/upgrade.rst
@@ -29,8 +29,8 @@ R5.0, R5.1
:width: 800
:alt: Tinymovr R5.0 and R5.1 connectors and pinouts
-M5.1
-====
+M5.1, M5.2
+==========
.. image:: connectors_m5.png
:width: 800
diff --git a/firmware/Makefile b/firmware/Makefile
index 137a646e..ea9c2846 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -104,7 +104,7 @@ all: release
debug: CFLAGS += -DDEBUG -g2 -O1
debug: CPPFLAGS += -DDEBUG -g2 -O1
debug: LDFLAGS += -O1
-debug: OBJECTS += $(BUILDDIR)/bootloader_$(REV).o
+debug: OBJECTS += $(BUILDDIR)/bootloader-$(REV).o
debug: binary
# Upgrade target
@@ -114,11 +114,11 @@ upgrade: LDFLAGS += -O3
upgrade: binary
# Release target
-release: OBJECTS += $(BUILDDIR)/bootloader_$(REV).o
+release: OBJECTS += $(BUILDDIR)/bootloader-$(REV).o
release: upgrade
# Binary target
-binary: print_board_rev $(HEX) $(BIN) $(ELF)
+binary: print_board_info $(HEX) $(BIN) $(ELF)
# Objcopy to HEX
$(HEX): $(ELF)
@@ -131,7 +131,7 @@ $(BIN): $(ELF)
# Link
$(ELF): $(OBJECTS)
- - $(OBJCOPY) -I binary -O elf32-littlearm -B arm --rename-section .data=.bl_section,alloc,load,readonly,data,contents $(PROJECTDIR)/bootloader/bootloader_$(REV).bin $(BUILDDIR)/bootloader_$(REV).o
+ - $(OBJCOPY) -I binary -O elf32-littlearm -B arm --rename-section .data=.bl_section,alloc,load,readonly,data,contents $(PROJECTDIR)/bootloader/bootloader-$(REV).bin $(BUILDDIR)/bootloader-$(REV).o
$(LD) $(LDFLAGS) $(OBJECTS) -o $(ELF)
$(SIZE_EX) --format=berkeley $(ELF)
@@ -151,8 +151,9 @@ clean :
- $(rmdir_cmd) "$(BUILDDIR)"
# Print board revision
-.PHONY: print_board_rev
-print_board_rev:
- @echo "===Building Tinymovr==="
+.PHONY: print_board_info
+print_board_info:
+ @echo "===Building Tinymovr Bootloader==="
@echo "Board revision is $(REV)"
- @echo "======================="
+ @echo "Fw version is $(GIT_VERSION)"
+ @echo "=================================="
diff --git a/firmware/bootloader/bootloader-M51.bin b/firmware/bootloader/bootloader-M51.bin
new file mode 100755
index 00000000..0945a943
Binary files /dev/null and b/firmware/bootloader/bootloader-M51.bin differ
diff --git a/firmware/bootloader/bootloader-R32.bin b/firmware/bootloader/bootloader-R32.bin
new file mode 100755
index 00000000..8409f60e
Binary files /dev/null and b/firmware/bootloader/bootloader-R32.bin differ
diff --git a/firmware/bootloader/bootloader-R33.bin b/firmware/bootloader/bootloader-R33.bin
new file mode 100755
index 00000000..f407b4d0
Binary files /dev/null and b/firmware/bootloader/bootloader-R33.bin differ
diff --git a/firmware/bootloader/bootloader-R50.bin b/firmware/bootloader/bootloader-R50.bin
new file mode 100755
index 00000000..5dc7410c
Binary files /dev/null and b/firmware/bootloader/bootloader-R50.bin differ
diff --git a/firmware/bootloader/bootloader-R51.bin b/firmware/bootloader/bootloader-R51.bin
new file mode 100755
index 00000000..936228a3
Binary files /dev/null and b/firmware/bootloader/bootloader-R51.bin differ
diff --git a/firmware/bootloader/bootloader-R52.bin b/firmware/bootloader/bootloader-R52.bin
new file mode 100755
index 00000000..73ecce31
Binary files /dev/null and b/firmware/bootloader/bootloader-R52.bin differ
diff --git a/firmware/bootloader/bootloader_M51.bin b/firmware/bootloader/bootloader_M51.bin
deleted file mode 100755
index 9ea49f0d..00000000
Binary files a/firmware/bootloader/bootloader_M51.bin and /dev/null differ
diff --git a/firmware/bootloader/bootloader_R32.bin b/firmware/bootloader/bootloader_R32.bin
deleted file mode 100755
index aab86464..00000000
Binary files a/firmware/bootloader/bootloader_R32.bin and /dev/null differ
diff --git a/firmware/bootloader/bootloader_R33.bin b/firmware/bootloader/bootloader_R33.bin
deleted file mode 100755
index 227098ab..00000000
Binary files a/firmware/bootloader/bootloader_R33.bin and /dev/null differ
diff --git a/firmware/bootloader/bootloader_R50.bin b/firmware/bootloader/bootloader_R50.bin
deleted file mode 100755
index ecdfd3c8..00000000
Binary files a/firmware/bootloader/bootloader_R50.bin and /dev/null differ
diff --git a/firmware/bootloader/bootloader_R51.bin b/firmware/bootloader/bootloader_R51.bin
deleted file mode 100755
index 74deae9b..00000000
Binary files a/firmware/bootloader/bootloader_R51.bin and /dev/null differ
diff --git a/firmware/bootloader/bootloader_R52.bin b/firmware/bootloader/bootloader_R52.bin
deleted file mode 100755
index b6601332..00000000
Binary files a/firmware/bootloader/bootloader_R52.bin and /dev/null differ
diff --git a/firmware/src/can/can.c b/firmware/src/can/can.c
index 512f5212..d48ce0f7 100644
--- a/firmware/src/can/can.c
+++ b/firmware/src/can/can.c
@@ -39,6 +39,9 @@ static CANState state ={0};
extern volatile uint32_t msTicks;
+const uint8_t avlos_proto_hash_8 = (uint8_t)(avlos_proto_hash & 0xFF);
+const size_t endpoint_count = sizeof(avlos_endpoints) / sizeof(avlos_endpoints[0]);
+
void CAN_init(void)
{
#if defined(BOARD_REV_R52)
@@ -135,7 +138,8 @@ void CAN_process_interrupt(void)
{
can_process_extended();
- if (sizeof(avlos_endpoints) / sizeof(avlos_endpoints[0]) > can_ep_id)
+ if ((endpoint_count > can_ep_id) &&
+ ((can_frame_hash == avlos_proto_hash_8) || (can_frame_hash == 0)))
{
uint8_t (*callback)(uint8_t buffer[], uint8_t * buffer_length, Avlos_Command cmd) = avlos_endpoints[can_ep_id];
uint8_t can_msg_buffer[8];
diff --git a/firmware/src/can/can_endpoints.c b/firmware/src/can/can_endpoints.c
index 5280c9fd..f9b6ec0f 100644
--- a/firmware/src/can/can_endpoints.c
+++ b/firmware/src/can/can_endpoints.c
@@ -19,7 +19,6 @@
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 = 3526126264;
uint32_t _avlos_get_proto_hash(void)
{
diff --git a/firmware/src/can/can_endpoints.h b/firmware/src/can/can_endpoints.h
index 0f773a13..11fbdf12 100644
--- a/firmware/src/can/can_endpoints.h
+++ b/firmware/src/can/can_endpoints.h
@@ -95,7 +95,7 @@ typedef enum
ENCODER_TYPE_HALL = 1
} encoder_type_options;
-extern uint32_t avlos_proto_hash;
+static const uint32_t avlos_proto_hash = 3526126264;
extern uint8_t (*avlos_endpoints[79])(uint8_t * buffer, uint8_t * buffer_len, Avlos_Command cmd);
extern uint32_t _avlos_get_proto_hash(void);
diff --git a/firmware/src/can/can_func.c b/firmware/src/can/can_func.c
index 05265c80..e279722f 100644
--- a/firmware/src/can/can_func.c
+++ b/firmware/src/can/can_func.c
@@ -22,7 +22,7 @@ uint8_t data_length;
uint32_t rx_id;
bool rtr;
uint32_t can_ep_id;
-uint32_t can_seq_id;
+uint32_t can_frame_hash;
// * The function "can_io_config" is part of the Tinymovr-Firmware distribution
// * (https://github.com/yconst/tinymovr-firmware).
@@ -169,256 +169,5 @@ void can_baud(CAN_BAUD_TYPE baud)
}
}
-TM_RAMFUNC void can_process_standard(void)
-{
- uint32_t buffer = PAC55XX_CAN->RXBUF; // read RX buffer, RX buffer bit order same as TX buffer
-
- data_length = buffer & 0x0F;
- rx_id = ((buffer & 0xE00000) >> 21) | ((buffer & 0xFF00) >> 5);
-
- can_ep_id = rx_id & 0x3F;
- rtr = ((buffer >> 6) & 0x1) == 0x1;
- rx_data[0] = buffer >> 24; // data0
- if (data_length > 1u)
- {
- buffer = PAC55XX_CAN->RXBUF; // buffer contains data1..data4
- rx_data[1] = buffer;
- rx_data[2] = buffer >> 8;
- rx_data[3] = buffer >> 16;
- rx_data[4] = buffer >> 24;
- if (data_length > 5u)
- {
- buffer = PAC55XX_CAN->RXBUF; // buffer contains data7..data5
- rx_data[5] = buffer;
- rx_data[6] = buffer >> 8;
- rx_data[7] = buffer >> 16;
- }
- }
-}
-
-// * The function "can_process_extended" is part of the Tinymovr-Firmware distribution
-// * (https://github.com/yconst/tinymovr-firmware).
-// * Copyright (c) 2022 Ioannis Chatzikonstantinou.
-// *
-// * This program is free software: you can redistribute it and/or modify
-// * it under the terms of the GNU General Public License as published by
-// * the Free Software Foundation, version 3.
-// *
-// * This program is distributed in the hope that it will be useful, but
-// * WITHOUT ANY WARRANTY; without even the implied warranty of
-// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// * General Public License for more details.
-// *
-// * You should have received a copy of the GNU General Public License
-// * along with this program. If not, see .
-
-TM_RAMFUNC void can_process_extended(void)
-{
- uint32_t buffer = PAC55XX_CAN->RXBUF; // read RX buffer, RX buffer bit order same as TX buffer
-
- data_length = buffer & 0x0F;
- rtr = ((buffer >> 6) & 0x1) == 0x1;
- rx_id = ((buffer & 0xFF000000) >> 19) | ((buffer & 0x00FF0000) >> 3) | ((buffer & 0x0000FF00) << 13);
-
- buffer = PAC55XX_CAN->RXBUF;
-
- rx_id |= (buffer & 0xFF) >> 3;
-
- ids_from_arbitration(rx_id, &can_ep_id, &can_seq_id);
-
- rx_data[0] = (buffer >> 8) & 0xFF; // data0
- rx_data[1] = (buffer >> 16) & 0xFF; // data1
- rx_data[2] = (buffer >> 24) & 0xFF; // data2
- if (data_length > 3u)
- {
- buffer = PAC55XX_CAN->RXBUF; // buffer contains data3..data6
- rx_data[3] = buffer & 0xFF;
- rx_data[4] = (buffer >> 8) & 0xFF;
- rx_data[5] = (buffer >> 16) & 0xFF;
- rx_data[6] = (buffer >> 24) & 0xFF;
- if (data_length > 7u)
- {
- buffer = PAC55XX_CAN->RXBUF; // buffer contains data7
- rx_data[7] = buffer & 0xFF;
- }
- }
-}
-
-TM_RAMFUNC void can_transmit_standard(uint8_t dataLen, uint16_t id, const uint8_t * data)
-{
- while (PAC55XX_CAN->SR.TBS == 0) {}; // wait for TX buffer free
- PAC55XX_CAN->TXBUF = (dataLen << 0) | // DLC - Data Length Code
- (0u << 6) | // RTR = 0 Data Frame
- (0u << 7) | // FF - Format Frame; 0=Std Frame
- ((id>>3 & 0xFF) << 8) | // ID 10:3
- ((id&0x07u) << 21) | // ID 2:0
- (data[0] << 24); // Data 0
-
- if (dataLen > 1u)
- {
- PAC55XX_CAN->TXBUF = (data[1] << 0) | // Data 1
- (data[2] << 8) | // Data 2
- (data[3] << 16) | // Data 3
- (data[4] << 24); // Data 4
- }
- if (dataLen > 5u)
- {
- PAC55XX_CAN->TXBUF = (data[5] << 0) | // Data 5
- (data[6] << 8) | // Data 6
- (data[7] << 16); // Data 7
-
- }
-
- PAC55XX_CAN->CMR.TR = 1; // Request transmit
-}
-
-// * The function "can_transmit_extended" is part of the Tinymovr-Firmware distribution
-// * (https://github.com/yconst/tinymovr-firmware).
-// * Copyright (c) 2022 Ioannis Chatzikonstantinou.
-// *
-// * This program is free software: you can redistribute it and/or modify
-// * it under the terms of the GNU General Public License as published by
-// * the Free Software Foundation, version 3.
-// *
-// * This program is distributed in the hope that it will be useful, but
-// * WITHOUT ANY WARRANTY; without even the implied warranty of
-// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// * General Public License for more details.
-// *
-// * You should have received a copy of the GNU General Public License
-// * along with this program. If not, see .
-
-TM_RAMFUNC void can_transmit_extended(uint8_t dataLen, uint32_t id, const uint8_t * data)
-{
- while (PAC55XX_CAN->SR.TBS == 0) {}; // wait for TX buffer free
- PAC55XX_CAN->TXBUF = (dataLen << 0) | // DLC - Data Length Code
- (0u << 6) | // RTR = 0 Data Frame
- (1u << 7) | // FF - Format Frame; 1=Ext Frame
- ((id&0x1FE00000u) >> (21-8)) |
- ((id&0x001FE000u) << (16-13)) |
- ((id&0x00001FE0u) << (24-5));
-
- PAC55XX_CAN->TXBUF = ((id & 0x1F) << 3) |
- ((data[0] & 0xFF) << 8) |
- ((data[1] & 0xFF) << 16) |
- ((data[2] & 0xFF) << 24);
-
- if (dataLen > 3u)
- {
- PAC55XX_CAN->TXBUF = ((data[3] & 0xFF) << 0) | // Data 3
- ((data[4] & 0xFF) << 8) | // Data 4
- ((data[5] & 0xFF) << 16) | // Data 5
- ((data[6] & 0xFF) << 24); // Data 6
- }
- if (dataLen > 7u)
- {
- PAC55XX_CAN->TXBUF = ((data[7] & 0xFF) << 0); // Data 7
- }
- PAC55XX_CAN->CMR.TR = 1; // Request transmit
-}
-
-uint16_t CAN_BaudTypeToInt(CAN_BAUD_TYPE type)
-{
- uint16_t ret = 0u;
- switch(type)
- {
- case CAN_BAUD_50KHz:
- ret = 50u;
- break;
-
- case CAN_BAUD_100KHz:
- ret = 100u;
- break;
-
- case CAN_BAUD_125KHz:
- ret = 125u;
- break;
-
- case CAN_BAUD_200KHz:
- ret = 200u;
- break;
-
- case CAN_BAUD_250KHz:
- ret = 250u;
- break;
-
- case CAN_BAUD_400KHz:
- ret = 400u;
- break;
-
- case CAN_BAUD_500KHz:
- ret = 500u;
- break;
-
- case CAN_BAUD_800KHz:
- ret = 800u;
- break;
-
- case CAN_BAUD_1000KHz:
- ret = 1000u;
- break;
-
- default:
- // ret already set
- break;
- }
- return ret;
-}
-CAN_BAUD_TYPE CAN_IntToBaudType(uint16_t baud)
-{
- CAN_BAUD_TYPE ret = CAN_BAUD_250KHz;
- switch(baud)
- {
- case 50u:
- ret = CAN_BAUD_50KHz;
- break;
-
- case 100u:
- ret = CAN_BAUD_100KHz;
- break;
-
- case 125u:
- ret = CAN_BAUD_125KHz;
- break;
-
- case 200u:
- ret = CAN_BAUD_200KHz;
- break;
-
- // 250 handled in default
-
- case 400u:
- ret = CAN_BAUD_400KHz;
- break;
-
- case 500u:
- ret = CAN_BAUD_500KHz;
- break;
-
- case 800u:
- ret = CAN_BAUD_800KHz;
- break;
-
- case 1000u:
- ret = CAN_BAUD_1000KHz;
- break;
-
- default:
- // ret already set
- break;
- }
- return ret;
-}
-
-inline void ids_from_arbitration(uint32_t arb_id, uint32_t* ep_id, uint32_t* seq_id)
-{
- *ep_id = arb_id & CAN_EP_MASK;
- *seq_id = (arb_id & CAN_SEQ_MASK) >> CAN_EP_SIZE;
-}
-
-inline void arbitration_from_ids(uint32_t* arb_id, uint32_t ep_id, uint32_t seq_id, uint32_t node_id)
-{
- *arb_id = (ep_id & CAN_EP_MASK) | ((seq_id << CAN_EP_SIZE) & CAN_SEQ_MASK) | ((node_id << (CAN_EP_SIZE + CAN_SEQ_SIZE)) & CAN_DEV_MASK);
-}
diff --git a/firmware/src/can/can_func.h b/firmware/src/can/can_func.h
index 597080ba..5637ee3c 100644
--- a/firmware/src/can/can_func.h
+++ b/firmware/src/can/can_func.h
@@ -20,10 +20,10 @@
#define CAN_EP_SIZE 12
#define CAN_EP_MASK ((1 << CAN_EP_SIZE) - 1)
-#define CAN_SEQ_SIZE 9
-#define CAN_SEQ_MASK (((1 << CAN_SEQ_SIZE) - 1) << CAN_EP_SIZE)
+#define CAN_HASH_SIZE 9
+#define CAN_HASH_MASK (((1 << CAN_HASH_SIZE) - 1) << CAN_EP_SIZE)
#define CAN_DEV_SIZE 8
-#define CAN_DEV_MASK (((1 << CAN_DEV_SIZE) - 1) << (CAN_EP_SIZE + CAN_SEQ_SIZE))
+#define CAN_DEV_MASK (((1 << CAN_DEV_SIZE) - 1) << (CAN_EP_SIZE + CAN_HASH_SIZE))
// #define CAN_SJW_1tq ((uint8_t)0x00) /*!< 1 time quantum */
// #define CAN_SJW_2tq ((uint8_t)0x01) /*!< 2 time quantum */
@@ -77,17 +77,261 @@ extern uint8_t data_length;
extern uint32_t rx_id;
extern bool rtr;
extern uint32_t can_ep_id;
-extern uint32_t can_seq_id;
+extern uint32_t can_frame_hash;
void can_baud(CAN_BAUD_TYPE baud);
void can_io_config(void);
-void can_process_standard(void);
-void can_process_extended(void);
-void can_transmit_standard(uint8_t dataLen, uint16_t id, const uint8_t * data);
-void can_transmit_extended(uint8_t dataLen, uint32_t id, const uint8_t * data);
-uint16_t CAN_BaudTypeToInt(CAN_BAUD_TYPE type);
-CAN_BAUD_TYPE CAN_IntToBaudType(uint16_t baud);
+static inline void ids_from_arbitration(uint32_t arb_id, uint32_t* ep_id, uint32_t* hash)
+{
+ *ep_id = arb_id & CAN_EP_MASK;
+ *hash = (arb_id & CAN_HASH_MASK) >> CAN_EP_SIZE;
+}
+
+static inline void arbitration_from_ids(uint32_t* arb_id, uint32_t ep_id, uint32_t hash, uint32_t node_id)
+{
+ *arb_id = (ep_id & CAN_EP_MASK) | ((hash << CAN_EP_SIZE) & CAN_HASH_MASK) | ((node_id << (CAN_EP_SIZE + CAN_HASH_SIZE)) & CAN_DEV_MASK);
+}
+
+static inline void can_process_standard(void)
+{
+ uint32_t buffer = PAC55XX_CAN->RXBUF; // read RX buffer, RX buffer bit order same as TX buffer
+
+ data_length = buffer & 0x0F;
+ rx_id = ((buffer & 0xE00000) >> 21) | ((buffer & 0xFF00) >> 5);
+
+ can_ep_id = rx_id & 0x3F;
+ rtr = ((buffer >> 6) & 0x1) == 0x1;
+ rx_data[0] = buffer >> 24; // data0
+ if (data_length > 1u)
+ {
+ buffer = PAC55XX_CAN->RXBUF; // buffer contains data1..data4
+ rx_data[1] = buffer;
+ rx_data[2] = buffer >> 8;
+ rx_data[3] = buffer >> 16;
+ rx_data[4] = buffer >> 24;
+ if (data_length > 5u)
+ {
+ buffer = PAC55XX_CAN->RXBUF; // buffer contains data7..data5
+ rx_data[5] = buffer;
+ rx_data[6] = buffer >> 8;
+ rx_data[7] = buffer >> 16;
+ }
+ }
+}
+
+// * The function "can_process_extended" is part of the Tinymovr-Firmware distribution
+// * (https://github.com/yconst/tinymovr-firmware).
+// * Copyright (c) 2022 Ioannis Chatzikonstantinou.
+// *
+// * This program is free software: you can redistribute it and/or modify
+// * it under the terms of the GNU General Public License as published by
+// * the Free Software Foundation, version 3.
+// *
+// * This program is distributed in the hope that it will be useful, but
+// * WITHOUT ANY WARRANTY; without even the implied warranty of
+// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// * General Public License for more details.
+// *
+// * You should have received a copy of the GNU General Public License
+// * along with this program. If not, see .
+
+static inline void can_process_extended(void)
+{
+ uint32_t buffer = PAC55XX_CAN->RXBUF; // read RX buffer, RX buffer bit order same as TX buffer
+
+ data_length = buffer & 0x0F;
+ rtr = ((buffer >> 6) & 0x1) == 0x1;
+ rx_id = ((buffer & 0xFF000000) >> 19) | ((buffer & 0x00FF0000) >> 3) | ((buffer & 0x0000FF00) << 13);
+
+ buffer = PAC55XX_CAN->RXBUF;
+
+ rx_id |= (buffer & 0xFF) >> 3;
+
+ ids_from_arbitration(rx_id, &can_ep_id, &can_frame_hash);
+
+ rx_data[0] = (buffer >> 8) & 0xFF; // data0
+ rx_data[1] = (buffer >> 16) & 0xFF; // data1
+ rx_data[2] = (buffer >> 24) & 0xFF; // data2
+ if (data_length > 3u)
+ {
+ buffer = PAC55XX_CAN->RXBUF; // buffer contains data3..data6
+ rx_data[3] = buffer & 0xFF;
+ rx_data[4] = (buffer >> 8) & 0xFF;
+ rx_data[5] = (buffer >> 16) & 0xFF;
+ rx_data[6] = (buffer >> 24) & 0xFF;
+ if (data_length > 7u)
+ {
+ buffer = PAC55XX_CAN->RXBUF; // buffer contains data7
+ rx_data[7] = buffer & 0xFF;
+ }
+ }
+}
+
+static inline void can_transmit_standard(uint8_t dataLen, uint16_t id, const uint8_t * data)
+{
+ while (PAC55XX_CAN->SR.TBS == 0) {}; // wait for TX buffer free
+ PAC55XX_CAN->TXBUF = (dataLen << 0) | // DLC - Data Length Code
+ (0u << 6) | // RTR = 0 Data Frame
+ (0u << 7) | // FF - Format Frame; 0=Std Frame
+ ((id>>3 & 0xFF) << 8) | // ID 10:3
+ ((id&0x07u) << 21) | // ID 2:0
+ (data[0] << 24); // Data 0
+
+ if (dataLen > 1u)
+ {
+ PAC55XX_CAN->TXBUF = (data[1] << 0) | // Data 1
+ (data[2] << 8) | // Data 2
+ (data[3] << 16) | // Data 3
+ (data[4] << 24); // Data 4
+ }
+ if (dataLen > 5u)
+ {
+ PAC55XX_CAN->TXBUF = (data[5] << 0) | // Data 5
+ (data[6] << 8) | // Data 6
+ (data[7] << 16); // Data 7
+
+ }
+
+ PAC55XX_CAN->CMR.TR = 1; // Request transmit
+}
+
+// * The function "can_transmit_extended" is part of the Tinymovr-Firmware distribution
+// * (https://github.com/yconst/tinymovr-firmware).
+// * Copyright (c) 2022 Ioannis Chatzikonstantinou.
+// *
+// * This program is free software: you can redistribute it and/or modify
+// * it under the terms of the GNU General Public License as published by
+// * the Free Software Foundation, version 3.
+// *
+// * This program is distributed in the hope that it will be useful, but
+// * WITHOUT ANY WARRANTY; without even the implied warranty of
+// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// * General Public License for more details.
+// *
+// * You should have received a copy of the GNU General Public License
+// * along with this program. If not, see .
+
+static inline void can_transmit_extended(uint8_t dataLen, uint32_t id, const uint8_t * data)
+{
+ while (PAC55XX_CAN->SR.TBS == 0) {}; // wait for TX buffer free
+ PAC55XX_CAN->TXBUF = (dataLen << 0) | // DLC - Data Length Code
+ (0u << 6) | // RTR = 0 Data Frame
+ (1u << 7) | // FF - Format Frame; 1=Ext Frame
+ ((id&0x1FE00000u) >> (21-8)) |
+ ((id&0x001FE000u) << (16-13)) |
+ ((id&0x00001FE0u) << (24-5));
+
+ PAC55XX_CAN->TXBUF = ((id & 0x1F) << 3) |
+ ((data[0] & 0xFF) << 8) |
+ ((data[1] & 0xFF) << 16) |
+ ((data[2] & 0xFF) << 24);
+
+ if (dataLen > 3u)
+ {
+ PAC55XX_CAN->TXBUF = ((data[3] & 0xFF) << 0) | // Data 3
+ ((data[4] & 0xFF) << 8) | // Data 4
+ ((data[5] & 0xFF) << 16) | // Data 5
+ ((data[6] & 0xFF) << 24); // Data 6
+ }
+ if (dataLen > 7u)
+ {
+ PAC55XX_CAN->TXBUF = ((data[7] & 0xFF) << 0); // Data 7
+ }
+
+ PAC55XX_CAN->CMR.TR = 1; // Request transmit
+}
+
+static inline uint16_t CAN_BaudTypeToInt(CAN_BAUD_TYPE type)
+{
+ uint16_t ret = 0u;
+ switch(type)
+ {
+ case CAN_BAUD_50KHz:
+ ret = 50u;
+ break;
+
+ case CAN_BAUD_100KHz:
+ ret = 100u;
+ break;
+
+ case CAN_BAUD_125KHz:
+ ret = 125u;
+ break;
+
+ case CAN_BAUD_200KHz:
+ ret = 200u;
+ break;
+
+ case CAN_BAUD_250KHz:
+ ret = 250u;
+ break;
+
+ case CAN_BAUD_400KHz:
+ ret = 400u;
+ break;
+
+ case CAN_BAUD_500KHz:
+ ret = 500u;
+ break;
+
+ case CAN_BAUD_800KHz:
+ ret = 800u;
+ break;
+
+ case CAN_BAUD_1000KHz:
+ ret = 1000u;
+ break;
+
+ default:
+ // ret already set
+ break;
+ }
+ return ret;
+}
+
+static inline CAN_BAUD_TYPE CAN_IntToBaudType(uint16_t baud)
+{
+ CAN_BAUD_TYPE ret = CAN_BAUD_250KHz;
+ switch(baud)
+ {
+ case 50u:
+ ret = CAN_BAUD_50KHz;
+ break;
+
+ case 100u:
+ ret = CAN_BAUD_100KHz;
+ break;
+
+ case 125u:
+ ret = CAN_BAUD_125KHz;
+ break;
+
+ case 200u:
+ ret = CAN_BAUD_200KHz;
+ break;
+
+ // 250 handled in default
+
+ case 400u:
+ ret = CAN_BAUD_400KHz;
+ break;
+
+ case 500u:
+ ret = CAN_BAUD_500KHz;
+ break;
+
+ case 800u:
+ ret = CAN_BAUD_800KHz;
+ break;
+
+ case 1000u:
+ ret = CAN_BAUD_1000KHz;
+ break;
-void ids_from_arbitration(uint32_t arb_id, uint32_t* can_ep_id, uint32_t* can_seq_id);
-void arbitration_from_ids(uint32_t* arb_id, uint32_t ep_id, uint32_t seq_id, uint32_t node_id);
\ No newline at end of file
+ default:
+ // ret already set
+ break;
+ }
+ return ret;
+}
diff --git a/firmware/src/system/system.h b/firmware/src/system/system.h
index 91bf0497..5ddf404b 100644
--- a/firmware/src/system/system.h
+++ b/firmware/src/system/system.h
@@ -38,10 +38,11 @@ void system_update(void);
void system_reset(void);
void system_enter_dfu(void);
-inline uint8_t system_get_fw_version_string(char *buffer)
+static inline uint8_t system_get_fw_version_string(char *buffer)
{
- memcpy(buffer, GIT_VERSION, 4);
- return 4;
+ const uint8_t size = fminf(sizeof(GIT_VERSION), 8);
+ memcpy(buffer, GIT_VERSION, size);
+ return size;
}
inline uint32_t system_get_uid(void)
diff --git a/studio/Python/tests/test_dfu.py b/studio/Python/tests/test_dfu.py
index c560b576..031626b7 100644
--- a/studio/Python/tests/test_dfu.py
+++ b/studio/Python/tests/test_dfu.py
@@ -39,24 +39,26 @@ def setUp(cls):
def test_dfu(self, node_id=1):
init_tee(self.can_bus)
time.sleep(0.5)
- tm = create_device(node_id=node_id)
- tm_hash = tm.protocol_hash
- tm.enter_dfu()
- time.sleep(0.5)
- bl = create_device(node_id=node_id)
- bl_hash = bl.protocol_hash
- bl.reset()
- time.sleep(0.2)
- tm = create_device(node_id=node_id)
- tm_hash2 = tm.protocol_hash
- tm.reset()
- time.sleep(0.2)
- tm_hash3 = tm.protocol_hash
- self.assertNotEqual(tm_hash, 0)
- self.assertEqual(tm_hash, tm_hash2)
- self.assertEqual(tm_hash, tm_hash3)
- self.assertNotEqual(tm_hash, bl_hash)
- time.sleep(0.2)
+ for i in range(10):
+ print("Testing DFU iteration ", i+1)
+ tm = create_device(node_id=node_id)
+ tm_hash = tm.protocol_hash
+ tm.enter_dfu()
+ time.sleep(0.5)
+ bl = create_device(node_id=node_id)
+ bl_hash = bl.protocol_hash
+ bl.reset()
+ time.sleep(0.2)
+ tm = create_device(node_id=node_id)
+ tm_hash2 = tm.protocol_hash
+ tm.reset()
+ time.sleep(0.2)
+ tm_hash3 = tm.protocol_hash
+ self.assertNotEqual(tm_hash, 0)
+ self.assertEqual(tm_hash, tm_hash2)
+ self.assertEqual(tm_hash, tm_hash3)
+ self.assertNotEqual(tm_hash, bl_hash)
+ time.sleep(0.2)
@classmethod
def tearDownClass(cls):
diff --git a/studio/Python/tinymovr/channel.py b/studio/Python/tinymovr/channel.py
index aa088194..42cb07fc 100644
--- a/studio/Python/tinymovr/channel.py
+++ b/studio/Python/tinymovr/channel.py
@@ -24,30 +24,29 @@
CAN_DEV_MASK,
CAN_EP_SIZE,
CAN_EP_MASK,
- CAN_SEQ_SIZE,
- CAN_SEQ_MASK,
+ CAN_HASH_SIZE,
+ CAN_HASH_MASK,
)
from tinymovr.codec import MultibyteCodec
class ResponseError(Exception):
- def __init__(self, kw, *args, **kwargs):
- msg = "Node {} did not respond".format(kw)
- super().__init__(msg, *args, **kwargs)
- self.kw = kw
+ def __init__(self, node_id):
+ super().__init__(f"Node {node_id} did not respond")
+ self.node_id = node_id
class CANChannel(BaseChannel):
- def __init__(self, node_id):
+ def __init__(self, node_id, compare_hash = 0):
self.node_id = node_id
- get_tee().add(
- lambda frame: frame.is_remote_frame == False
- and ids_from_arbitration(frame.arbitration_id)[2] == node_id,
- self._recv_cb,
- )
+ self.compare_hash = compare_hash
self.queue = []
self.lock = Lock()
self.evt = Event()
+ get_tee().add(self._filter_frame, self._recv_cb)
+
+ def _filter_frame(self, frame):
+ return not frame.is_remote_frame and ids_from_arbitration(frame.arbitration_id)[2] == self.node_id
def _recv_cb(self, frame):
"""
@@ -76,12 +75,11 @@ def recv(self, ep_id, timeout=1.0):
with self.lock:
self.evt.wait(timeout=timeout)
self.evt.clear()
- frame_id = arbitration_from_ids(ep_id, 0, self.node_id)
- index = 0
- while index < len(self.queue):
- if self.queue[index].arbitration_id == frame_id:
- return self.queue.pop(index).data
- index += 1
+ for frame in self.queue:
+ inc_ep_id, inc_hash, _ = ids_from_arbitration(frame.arbitration_id)
+ if inc_ep_id == ep_id and (inc_hash == self.compare_hash or inc_hash == 0):
+ self.queue.remove(frame)
+ return frame.data
raise ResponseError(self.node_id)
def create_frame(self, endpoint_id, rtr=False, payload=None):
@@ -89,7 +87,7 @@ def create_frame(self, endpoint_id, rtr=False, payload=None):
Generate a CAN frame using python-can Message class
"""
return can.Message(
- arbitration_id=arbitration_from_ids(endpoint_id, 0, self.node_id),
+ arbitration_id=arbitration_from_ids(endpoint_id, self.compare_hash, self.node_id),
is_extended_id=True,
is_remote_frame=rtr,
data=payload,
@@ -103,22 +101,22 @@ def serializer(self):
# TODO: Implement unit test for these functions
def ids_from_arbitration(arbitration_id):
"""
- Generate endpoint, message sequence and node ids
+ Generate endpoint, hash value and node ids
from a CAN arbitration id
"""
- node_id = (arbitration_id & CAN_DEV_MASK) >> (CAN_EP_SIZE + CAN_SEQ_SIZE)
- seq_id = (arbitration_id & CAN_SEQ_MASK) >> CAN_EP_SIZE
+ node_id = (arbitration_id & CAN_DEV_MASK) >> (CAN_EP_SIZE + CAN_HASH_SIZE)
+ hash = (arbitration_id & CAN_HASH_MASK) >> CAN_EP_SIZE
ep_id = arbitration_id & CAN_EP_MASK
- return ep_id, seq_id, node_id
+ return ep_id, hash, node_id
-def arbitration_from_ids(ep_id, seq_id, node_id):
+def arbitration_from_ids(ep_id, hash, node_id):
"""
Generate a CAN arbitration id from endpoint,
- message sequence and node ids
+ hash value and node ids
"""
return (
ep_id & CAN_EP_MASK
- | ((seq_id << CAN_EP_SIZE) & CAN_SEQ_MASK)
- | ((node_id << (CAN_EP_SIZE + CAN_SEQ_SIZE)) & CAN_DEV_MASK)
+ | ((hash << CAN_EP_SIZE) & CAN_HASH_MASK)
+ | ((node_id << (CAN_EP_SIZE + CAN_HASH_SIZE)) & CAN_DEV_MASK)
)
diff --git a/studio/Python/tinymovr/config/config.py b/studio/Python/tinymovr/config/config.py
index 28ab4698..6f72b1a9 100644
--- a/studio/Python/tinymovr/config/config.py
+++ b/studio/Python/tinymovr/config/config.py
@@ -69,18 +69,20 @@ 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 spec to get the protocol_hash
# This assumes that `protocol_hash` is standard across different specs
# Get the first spec as a temp
- tmp_spec = list(specs["hash_uint32"].values())[0]
+ tmp_hash = list(specs["hash_uint32"].keys())[0]
+ tmp_spec = specs["hash_uint32"][tmp_hash]
node = deserialize(tmp_spec)
+ chan = CANChannel(node_id, 0)
node._channel = chan
# Check for the correct spec using the remote hash
protocol_hash = node.protocol_hash
device_spec = specs["hash_uint32"].get(protocol_hash)
+ chan.compare_hash = protocol_hash & 0xFF
if not device_spec:
raise ValueError(f"No device spec found for hash {protocol_hash}.")
@@ -101,6 +103,7 @@ def create_device_with_hash_msg(heartbeat_msg):
hash, *_ = chan.serializer.deserialize(heartbeat_msg.data[:4], DataType.UINT32)
device_spec = specs["hash_uint32"].get(hash)
+ chan.compare_hash = hash & 0xFF
if not device_spec:
raise ValueError(f"No device spec found for hash {hash}.")
diff --git a/studio/Python/tinymovr/constants.py b/studio/Python/tinymovr/constants.py
index de5d58fb..f2f07674 100644
--- a/studio/Python/tinymovr/constants.py
+++ b/studio/Python/tinymovr/constants.py
@@ -25,8 +25,8 @@
CAN_EP_SIZE = 12
CAN_EP_MASK = (1 << CAN_EP_SIZE) - 1
-CAN_SEQ_SIZE = 9
-CAN_SEQ_MASK = ((1 << CAN_SEQ_SIZE) - 1) << CAN_EP_SIZE
+CAN_HASH_SIZE = 9
+CAN_HASH_MASK = ((1 << CAN_HASH_SIZE) - 1) << CAN_EP_SIZE
CAN_DEV_SIZE = 8
-CAN_DEV_MASK = ((1 << CAN_DEV_SIZE) - 1) << (CAN_EP_SIZE + CAN_SEQ_SIZE)
+CAN_DEV_MASK = ((1 << CAN_DEV_SIZE) - 1) << (CAN_EP_SIZE + CAN_HASH_SIZE)
diff --git a/studio/Python/tinymovr/dfu.py b/studio/Python/tinymovr/dfu.py
index 4b1c8d3e..299bbaf6 100644
--- a/studio/Python/tinymovr/dfu.py
+++ b/studio/Python/tinymovr/dfu.py
@@ -15,6 +15,7 @@
import sys
import os
import time
+import inspect
from pathlib import Path
import can
import yaml
@@ -89,7 +90,12 @@ def upload_bin(device, bin_path):
total_size = os.path.getsize(bin_path) # Get the total size of .bin file
uploaded_size = 0
print("\nErasing flash...")
- result = device.erase_all()
+ try:
+ # Assume device.erase_all can take hash_validation and attempt to call it
+ result = device.erase_all(device.hash_uint32)
+ except TypeError:
+ # Fallback to calling erase_all without hash_validation if TypeError is raised
+ result = device.erase_all()
if result != 0:
print("\nError while erasing!")
return
@@ -110,7 +116,12 @@ def upload_bin(device, bin_path):
time.sleep(1e-5)
# Commit the data in scratchpad to flash memory and get checksum
- device_checksum = device.commit(flash_addr)
+ try:
+ # Assume device.commit can take hash_validation and attempt to call it
+ device_checksum = device.commit(flash_addr, device.hash_uint32)
+ except TypeError:
+ # Fallback to calling commit without hash_validation if TypeError is raised
+ device_checksum = device.commit(flash_addr)
local_checksum = calculate_local_checksum(chunk)
diff --git a/studio/Python/tinymovr/gui/widgets.py b/studio/Python/tinymovr/gui/widgets.py
index 6914b827..21f5d225 100644
--- a/studio/Python/tinymovr/gui/widgets.py
+++ b/studio/Python/tinymovr/gui/widgets.py
@@ -131,6 +131,7 @@ def __init__(self, name, node, *args, **kwargs):
self.text_editor.editingFinished.connect(self._on_editor_text_changed)
else:
self.text_editor = QLineEdit(format_value(node.get_value()))
+ self.text_editor.editingFinished.connect(self._on_editor_text_changed)
if not editable:
self.text_editor.setReadOnly(True)
self._checked = False
@@ -153,7 +154,7 @@ def _on_editor_text_changed(self):
except UndefinedUnitError:
attr.set_value(text)
if "reload_data" in attr.meta and attr.meta["reload_data"]:
- self.worker.reset()
+ self.treeWidget().window().worker.reset()
return
else:
self.text_editor.setText(format_value(attr.get_value()))
diff --git a/studio/Python/tinymovr/specs/dfu.yaml b/studio/Python/tinymovr/specs/dfu_1_0_x.yaml
similarity index 100%
rename from studio/Python/tinymovr/specs/dfu.yaml
rename to studio/Python/tinymovr/specs/dfu_1_0_x.yaml
diff --git a/studio/Python/tinymovr/specs/dfu_1_1_x.yaml b/studio/Python/tinymovr/specs/dfu_1_1_x.yaml
new file mode 100644
index 00000000..1cef75e1
--- /dev/null
+++ b/studio/Python/tinymovr/specs/dfu_1_1_x.yaml
@@ -0,0 +1,72 @@
+
+name: tm_dfu
+remote_attributes:
+ - name: protocol_hash
+ dtype: uint32
+ getter_name: _system_get_proto_hash_and_trigger_dfu
+ summary: The Avlos protocol hash.
+ - name: uid
+ dtype: uint32
+ getter_name: system_get_uid
+ summary: The unique device ID, unique to each PAC55xx chip produced.
+ - name: fw_version
+ dtype: string
+ getter_name: system_get_fw_version_string
+ summary: The bootloader firmware version.
+ - name: hw_revision
+ dtype: uint32
+ getter_name: system_get_hw_revision
+ summary: The hardware revision.
+ - name: reset
+ summary: Reset the device.
+ caller_name: system_reset
+ dtype: void
+ arguments: []
+ meta: {reload_data: True}
+ - name: node_id
+ summary: The node id
+ getter_name: CAN_get_ID
+ dtype: uint8
+ - 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 in DFU
+ - name: read_flash_32
+ summary: Read a 32 bit value from the flash
+ caller_name: nvm_read_flash_32
+ dtype: uint32
+ arguments:
+ - name: address
+ dtype: uint32
+ - name: write_scratch_32
+ summary: Write a 32 bit value to the scratchpad
+ caller_name: nvm_write_scratch_32
+ dtype: void
+ arguments:
+ - name: offset_word32
+ dtype: uint8
+ - name: value
+ dtype: uint32
+ - name: read_scratch_32
+ summary: Read a 32 bit value from the scratchpad
+ caller_name: nvm_read_scratch_32
+ dtype: uint32
+ arguments:
+ - name: offset_word32
+ dtype: uint8
+ - name: commit
+ summary: Commit the 128 bit scratchpad to the specified flash address. Pass the current protocol hash for validation.
+ caller_name: nvm_commit
+ dtype: uint32
+ arguments:
+ - name: address
+ dtype: uint32
+ - name: hash_validation
+ dtype: uint32
+ - name: erase_all
+ summary: Erase all flash. Pass the current protocol hash for validation.
+ caller_name: nvm_erase_all
+ dtype: uint32
+ arguments:
+ - name: hash_validation
+ dtype: uint32