From 141d1edd35e3c54c79b209570172809061c1c5fd Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 12 May 2020 01:30:40 -0400 Subject: [PATCH 1/3] Change UART baudrate via fibre --- CHANGELOG.md | 1 + Firmware/MotorControl/main.cpp | 7 ++++++- Firmware/MotorControl/odrive_main.h | 1 + Firmware/communication/communication.cpp | 1 + docs/interfaces.md | 2 +- 5 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f37e0555..e2b4f6be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ Please add a note of your changes below this heading if you make a Pull Request. * Added support for Flylint VSCode Extension for static code analysis * Using an STM32F405 .svd file allows CortexDebug to view registers during debugging * Added scripts for building via docker. +* Added ability to change uart baudrate via fibre ### Changed * Changed ratiometric `motor.config.current_lim_tolerance` to absolute `motor.config.current_lim_margin` diff --git a/Firmware/MotorControl/main.cpp b/Firmware/MotorControl/main.cpp index f49d02d6..d3864ed0 100644 --- a/Firmware/MotorControl/main.cpp +++ b/Firmware/MotorControl/main.cpp @@ -3,6 +3,7 @@ #include "odrive_main.h" #include "nvm_config.hpp" +#include "usart.h" #include "freertos_vars.h" #include #include @@ -123,7 +124,7 @@ void enter_dfu_mode() { } extern "C" int construct_objects(){ - #if HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR >= 3 +#if HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR >= 3 if (board_config.enable_i2c_instead_of_can) { // Set up the direction GPIO as input GPIO_InitTypeDef GPIO_InitStruct; @@ -147,6 +148,10 @@ extern "C" int construct_objects(){ #endif MX_CAN1_Init(); + HAL_UART_DeInit(&huart4); + huart4.Init.BaudRate = board_config.uart_baudrate; + HAL_UART_Init(&huart4); + // Init general user ADC on some GPIOs. GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; diff --git a/Firmware/MotorControl/odrive_main.h b/Firmware/MotorControl/odrive_main.h index 2dbb82a6..b1c30de2 100644 --- a/Firmware/MotorControl/odrive_main.h +++ b/Firmware/MotorControl/odrive_main.h @@ -122,6 +122,7 @@ struct BoardConfig_t { float dc_max_negative_current = -0.000001f; // Max current [A] the power supply can sink. You most likely want a non-positive value here. Set to -INFINITY to disable. PWMMapping_t pwm_mappings[GPIO_COUNT]; PWMMapping_t analog_mappings[GPIO_COUNT]; + uint32_t uart_baudrate = 115200; }; extern BoardConfig_t board_config; extern bool user_config_loaded_; diff --git a/Firmware/communication/communication.cpp b/Firmware/communication/communication.cpp index fb033bdd..c318040b 100644 --- a/Firmware/communication/communication.cpp +++ b/Firmware/communication/communication.cpp @@ -164,6 +164,7 @@ static inline auto make_obj_tree() { make_protocol_property("max_regen_current", &board_config.max_regen_current), // TODO: changing this currently requires a reboot - fix this make_protocol_property("enable_uart", &board_config.enable_uart), + make_protocol_property("uart_baudrate", &board_config.uart_baudrate), // requires a reboot make_protocol_property("enable_i2c_instead_of_can" , &board_config.enable_i2c_instead_of_can), // requires a reboot make_protocol_property("enable_ascii_protocol_on_usb", &board_config.enable_ascii_protocol_on_usb), make_protocol_property("dc_bus_undervoltage_trip_level", &board_config.dc_bus_undervoltage_trip_level), diff --git a/docs/interfaces.md b/docs/interfaces.md index 13dccec4..01173e93 100644 --- a/docs/interfaces.md +++ b/docs/interfaces.md @@ -164,7 +164,7 @@ The endpoint pairs `0x01, 0x81` and `0x03, 0x83` behave exactly identical, only If you plan to access the USB endpoints directly it is recommended that you use interface 2. The other interfaces (the ones associated with the CDC device) are usually claimed by the CDC driver of the host OS, so their endpoints cannot be used without first detaching the CDC driver. ### UART -Baud rate: 115200 +Baud rate: 115200 by default. See `odrv0.config.uart_baudrate` to change value. Requires a restart. Pinout: * GPIO 1: Tx (connect to Rx of other device) * GPIO 2: Rx (connect to Tx of other device) From 08f5045ace23c8ed28175a275bc265ddea22bf8e Mon Sep 17 00:00:00 2001 From: Samuel Sadok Date: Wed, 13 May 2020 11:22:20 +0200 Subject: [PATCH 2/3] add documentation for `uart_baudrate` --- Firmware/MotorControl/odrive_main.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Firmware/MotorControl/odrive_main.h b/Firmware/MotorControl/odrive_main.h index b1c30de2..d2a56896 100644 --- a/Firmware/MotorControl/odrive_main.h +++ b/Firmware/MotorControl/odrive_main.h @@ -122,6 +122,31 @@ struct BoardConfig_t { float dc_max_negative_current = -0.000001f; // Max current [A] the power supply can sink. You most likely want a non-positive value here. Set to -INFINITY to disable. PWMMapping_t pwm_mappings[GPIO_COUNT]; PWMMapping_t analog_mappings[GPIO_COUNT]; + + /** + * Defines the baudrate used on the UART interface. + * Some baudrates will have a small timing error due to hardware limitations. + * + * Here's an (incomplete) list of baudrates for ODrive v3.x: + * + * Configured | Actual | Error [%] + * -------------|---------------|----------- + * 1.2 KBps | 1.2 KBps | 0 + * 2.4 KBps | 2.4 KBps | 0 + * 9.6 KBps | 9.6 KBps | 0 + * 19.2 KBps | 19.195 KBps | 0.02 + * 38.4 KBps | 38.391 KBps | 0.02 + * 57.6 KBps | 57.613 KBps | 0.02 + * 115.2 KBps | 115.068 KBps | 0.11 + * 230.4 KBps | 230.769 KBps | 0.16 + * 460.8 KBps | 461.538 KBps | 0.16 + * 921.6 KBps | 913.043 KBps | 0.93 + * 1.792 MBps | 1.826 MBps | 1.9 + * 1.8432 MBps | 1.826 MBps | 0.93 + * + * For more information refer to Section 30.3.4 and Table 142 (the column with f_PCLK = 42 MHz) in the STM datasheet: + * https://www.st.com/content/ccc/resource/technical/document/reference_manual/3d/6d/5a/66/b4/99/40/d4/DM00031020.pdf/files/DM00031020.pdf/jcr:content/translations/en.DM00031020.pdf + */ uint32_t uart_baudrate = 115200; }; extern BoardConfig_t board_config; From 312180fc3116dd269d1b75cf089ebb044af7ac6e Mon Sep 17 00:00:00 2001 From: Samuel Sadok Date: Wed, 13 May 2020 11:24:38 +0200 Subject: [PATCH 3/3] add test for `uart_baudrate` setting --- docs/testing.md | 2 +- tools/odrive/tests/uart_ascii_test.py | 65 ++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 12 deletions(-) diff --git a/docs/testing.md b/docs/testing.md index 771d4e44..ae01361a 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -113,7 +113,7 @@ To flash and start remote debugging: To run a test: - rsync -avh -e ssh /path/to/ODriveFirmware odrv:/opt/odrivetest --exclude="Firmware/build" --exclude="Firmware/.tup" --exclude=".git" --delete + rsync -avh -e ssh /path/to/ODriveFirmware/ odrv:/opt/odrivetest --exclude="Firmware/build" --exclude="Firmware/.tup" --exclude=".git" --delete ssh odrv > cd /opt/odrivetest/tools/odrive/tests/ diff --git a/tools/odrive/tests/uart_ascii_test.py b/tools/odrive/tests/uart_ascii_test.py index 86b2f4ab..91d61709 100644 --- a/tools/odrive/tests/uart_ascii_test.py +++ b/tools/odrive/tests/uart_ascii_test.py @@ -31,6 +31,10 @@ def reset_state(ser): ser.flushInput() # discard response class TestUartAscii(): + """ + Tests the most important functions of the ASCII protocol. + """ + def get_test_cases(self, testrig: TestRig): for odrive in testrig.get_components(ODriveComponent): ports = list(testrig.get_connected_components({ @@ -40,10 +44,6 @@ class TestUartAscii(): yield (odrive, ports) def run_test(self, odrive: ODriveComponent, port: SerialPortComponent, logger: Logger): - """ - Tests the most important functions of the ASCII protocol. - """ - logger.debug('Enabling UART...') # GPIOs might be in use by something other than UART and some components # might be configured so that they would fail in the later test. @@ -138,7 +138,11 @@ class TestUartAscii(): # TODO: test cases for 't', 'ss', 'se', 'sr' commands -class TestUartBurnIn(): +class TestUartBaudrate(): + """ + Tests if the UART baudrate setting works as intended. + """ + def get_test_cases(self, testrig: TestRig): for odrive in testrig.get_components(ODriveComponent): ports = list(testrig.get_connected_components({ @@ -148,10 +152,47 @@ class TestUartBurnIn(): yield (odrive, ports) def run_test(self, odrive: ODriveComponent, port: SerialPortComponent, logger: Logger): - """ - Tests if the ASCII protocol can handle 64kB of random data being thrown at it. - """ + odrive.handle.axis0.config.enable_step_dir = False + odrive.handle.config.enable_uart = True + odrive.handle.config.uart_baudrate = 9600 + odrive.save_config_and_reboot() + + # Control test: talk to the ODrive with the wrong baudrate + with port.open(115200) as ser: + # reset port to known state + reset_state(ser) + + ser.write(b'r vbus_voltage\n') + test_assert_eq(ser.readline().strip(), b'') + + with port.open(9600) as ser: + # reset port to known state + reset_state(ser) + + # Check if protocol works + ser.write(b'r vbus_voltage\n') + response = float(ser.readline().strip()) + test_assert_eq(response, odrive.handle.vbus_voltage, accuracy=0.1) + + odrive.handle.config.uart_baudrate = 115200 + odrive.save_config_and_reboot() + + +class TestUartBurnIn(): + """ + Tests if the ASCII protocol can handle 64kB of random data being thrown at it. + """ + + def get_test_cases(self, testrig: TestRig): + for odrive in testrig.get_components(ODriveComponent): + ports = list(testrig.get_connected_components({ + 'rx': (odrive.gpio1, True), + 'tx': (odrive.gpio2, False) + }, SerialPortComponent)) + yield (odrive, ports) + + def run_test(self, odrive: ODriveComponent, port: SerialPortComponent, logger: Logger): odrive.handle.axis0.config.enable_step_dir = False odrive.handle.config.enable_uart = True @@ -170,6 +211,10 @@ class TestUartBurnIn(): class TestUartNoise(): + """ + Tests if the UART can handle invalid signals. + """ + def get_test_cases(self, testrig: TestRig): for odrive in testrig.get_components(ODriveComponent): # For every ODrive, find a connected serial port which has a teensy @@ -200,9 +245,6 @@ class TestUartNoise(): yield (odrive, ports) def run_test(self, odrive: ODriveComponent, port: SerialPortComponent, noise_enable: LinuxGpioComponent, logger: Logger): - """ - Tests if the UART can handle invalid signals. - """ noise_enable.config(output=True) noise_enable.write(False) time.sleep(0.1) @@ -244,6 +286,7 @@ class TestUartNoise(): if __name__ == '__main__': test_runner.run([ TestUartAscii(), + TestUartBaudrate(), TestUartBurnIn(), TestUartNoise(), ])