mirror of
https://github.com/odriverobotics/ODrive.git
synced 2026-09-21 15:34:33 +08:00
Add support for UART1
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
Please add a note of your changes below this heading if you make a Pull Request.
|
||||
### Added
|
||||
* [Mechanical brake support](docs/mechanical-brakes.md)
|
||||
* Support for UART1 on GPIO3 and GPIO4. UART0 (on GPIO1/2) and UART1 can currently not be enabled at the same time.
|
||||
|
||||
### Changed
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ Stm32SpiArbiter spi3_arbiter{&hspi3};
|
||||
Stm32SpiArbiter& ext_spi_arbiter = spi3_arbiter;
|
||||
|
||||
UART_HandleTypeDef* uart0 = &huart4;
|
||||
UART_HandleTypeDef* uart1 = nullptr; // TODO: this could be supported in ODrive v3.6 (or similar) using STM32's USART2
|
||||
UART_HandleTypeDef* uart1 = &huart2; // TODO: this could be supported in ODrive v3.6 (or similar) using STM32's USART2
|
||||
UART_HandleTypeDef* uart2 = nullptr;
|
||||
|
||||
Drv8301 m0_gate_driver{
|
||||
@@ -219,14 +219,14 @@ std::array<GpioFunction, 3> alternate_functions[GPIO_COUNT] = {
|
||||
#if HW_VERSION_MINOR >= 3
|
||||
/* GPIO1: */ {{{ODrive::GPIO_MODE_UART0, GPIO_AF8_UART4}, {ODrive::GPIO_MODE_PWM0, GPIO_AF2_TIM5}}},
|
||||
/* GPIO2: */ {{{ODrive::GPIO_MODE_UART0, GPIO_AF8_UART4}, {ODrive::GPIO_MODE_PWM0, GPIO_AF2_TIM5}}},
|
||||
/* GPIO3: */ {{{ODrive::GPIO_MODE_PWM0, GPIO_AF2_TIM5}}},
|
||||
/* GPIO3: */ {{{ODrive::GPIO_MODE_UART1, GPIO_AF7_USART2}, {ODrive::GPIO_MODE_PWM0, GPIO_AF2_TIM5}}},
|
||||
#else
|
||||
/* GPIO1: */ {{}},
|
||||
/* GPIO2: */ {{}},
|
||||
/* GPIO3: */ {{}},
|
||||
#endif
|
||||
|
||||
/* GPIO4: */ {{{ODrive::GPIO_MODE_PWM0, GPIO_AF2_TIM5}}},
|
||||
/* GPIO4: */ {{{ODrive::GPIO_MODE_UART1, GPIO_AF7_USART2}, {ODrive::GPIO_MODE_PWM0, GPIO_AF2_TIM5}}},
|
||||
/* GPIO5: */ {{}},
|
||||
/* GPIO6: */ {{}},
|
||||
/* GPIO7: */ {{}},
|
||||
@@ -273,13 +273,18 @@ bool board_init() {
|
||||
MX_SPI3_Init();
|
||||
MX_ADC3_Init();
|
||||
MX_TIM2_Init();
|
||||
MX_UART4_Init();
|
||||
MX_TIM5_Init();
|
||||
MX_TIM13_Init();
|
||||
|
||||
HAL_UART_DeInit(uart0);
|
||||
uart0->Init.BaudRate = odrv.config_.uart0_baudrate;
|
||||
HAL_UART_Init(uart0);
|
||||
if (odrv.config_.enable_uart0) {
|
||||
uart0->Init.BaudRate = odrv.config_.uart0_baudrate;
|
||||
MX_UART4_Init();
|
||||
}
|
||||
|
||||
if (odrv.config_.enable_uart1) {
|
||||
uart1->Init.BaudRate = odrv.config_.uart1_baudrate;
|
||||
MX_USART2_UART_Init();
|
||||
}
|
||||
|
||||
if (odrv.config_.enable_i2c0) {
|
||||
// Set up the direction GPIO as input
|
||||
|
||||
@@ -41,8 +41,15 @@ size_t oscilloscope_pos = 0;
|
||||
void init_communication(void) {
|
||||
printf("hi!\r\n");
|
||||
|
||||
// Dual UART operation not supported yet
|
||||
if (odrv.config_.enable_uart0 && odrv.config_.enable_uart1) {
|
||||
odrv.misconfigured_ = true;
|
||||
}
|
||||
|
||||
if (odrv.config_.enable_uart0 && uart0) {
|
||||
start_uart_server();
|
||||
start_uart_server(uart0);
|
||||
} else if (odrv.config_.enable_uart1 && uart1) {
|
||||
start_uart_server(uart1);
|
||||
}
|
||||
|
||||
start_usb_server();
|
||||
|
||||
@@ -22,8 +22,7 @@ static uint32_t dma_last_rcv_idx;
|
||||
// static thread_local uint32_t deadline_ms = 0;
|
||||
|
||||
osThreadId uart_thread = 0;
|
||||
extern UART_HandleTypeDef* uart0;
|
||||
static UART_HandleTypeDef* huart_ = uart0; // defined in board.cpp.
|
||||
static UART_HandleTypeDef* huart_ = nullptr;
|
||||
const uint32_t stack_size_uart_thread = 4096; // Bytes
|
||||
|
||||
|
||||
@@ -102,7 +101,9 @@ static void uart_server_thread(void * ctx) {
|
||||
}
|
||||
|
||||
// TODO: allow multiple UART server instances
|
||||
void start_uart_server() {
|
||||
void start_uart_server(UART_HandleTypeDef* huart) {
|
||||
huart_ = huart;
|
||||
|
||||
// DMA is set up to receive in a circular buffer forever.
|
||||
// We dont use interrupts to fetch the data, instead we periodically read
|
||||
// data out of the circular buffer into a parse buffer, controlled by a state machine
|
||||
|
||||
@@ -9,11 +9,12 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#include <cmsis_os.h>
|
||||
#include "usart.h"
|
||||
|
||||
extern osThreadId uart_thread;
|
||||
extern const uint32_t stack_size_uart_thread;
|
||||
|
||||
void start_uart_server(void);
|
||||
void start_uart_server(UART_HandleTypeDef* huart);
|
||||
void uart_poll(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -99,13 +99,24 @@ interfaces:
|
||||
|
||||
enable_uart0:
|
||||
type: bool
|
||||
doc: Enables/disables UART0. You also need to set the corresponding GPIOs to GPIO_MODE_UART0. Changing this requires a reboot.
|
||||
enable_uart1: {type: bool, doc: Not supported on ODrive v3.x.}
|
||||
brief: Enables/disables UART0.
|
||||
doc: |
|
||||
You also need to set the corresponding GPIOs to GPIO_MODE_UART0.
|
||||
Refer to [interfaces](interfaces.md) to see which pins support UART0.
|
||||
Changing this requires a reboot.
|
||||
enable_uart0:
|
||||
type: bool
|
||||
brief: Enables/disables UART1.
|
||||
doc: |
|
||||
You also need to set the corresponding GPIOs to GPIO_MODE_UART1.
|
||||
Refer to [interfaces](interfaces.md) to see which pins support UART1.
|
||||
Changing this requires a reboot.
|
||||
enable_uart2: {type: bool, doc: Not supported on ODrive v3.x.}
|
||||
uart0_baudrate:
|
||||
type: uint32
|
||||
unit: baud/s
|
||||
brief: Defines the baudrate used on the UART interface.
|
||||
doc: |
|
||||
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:
|
||||
@@ -127,7 +138,11 @@ interfaces:
|
||||
|
||||
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).
|
||||
uart1_baudrate: {type: uint32, doc: Not supported on ODrive v3.x.}
|
||||
uart1_baudrate:
|
||||
type: uint32
|
||||
unit: baud/s
|
||||
brief: Defines the baudrate used on the UART interface.
|
||||
doc: See `uart0_baudrate` for details.
|
||||
uart2_baudrate: {type: uint32, doc: Not supported on ODrive v3.x.}
|
||||
enable_can0:
|
||||
type: bool
|
||||
|
||||
+20
-19
@@ -18,25 +18,25 @@ The ODrive can be controlled over various ports and protocols. If you're comfort
|
||||
|
||||
## Pinout
|
||||
|
||||
| # | Label | `GPIO_MODE_DIGITAL` | `GPIO_MODE_ANALOG_IN` | `GPIO_MODE_UART0` | `GPIO_MODE_PWM0` | `GPIO_MODE_CAN0` | `GPIO_MODE_I2C0` | `GPIO_MODE_ENC0` | `GPIO_MODE_ENC1` | `GPIO_MODE_MECH_BRAKE` |
|
||||
|----|---------------|------------------------|-----------------------|-------------------|------------------|------------------|------------------|------------------|------------------|------------------------|
|
||||
| 0 | _not a pin_ | | | | | | | | | |
|
||||
| 1 | GPIO1 (+) | general purpose | analog input | **UART0.TX** | PWM0.0 | | | | | mechanical brake |
|
||||
| 2 | GPIO2 (+) | general purpose | analog input | **UART0.RX** | PWM0.1 | | | | | mechanical brake |
|
||||
| 3 | GPIO3 | general purpose | **analog input** | | PWM0.2 | | | | | mechanical brake |
|
||||
| 4 | GPIO4 | general purpose | **analog input** | | PWM0.3 | | | | | mechanical brake |
|
||||
| 5 | GPIO5 | general purpose | **analog input** (*) | | | | | | | mechanical brake |
|
||||
| 6 | GPIO6 (*) (+) | **general purpose** | | | | | | | | mechanical brake |
|
||||
| 7 | GPIO7 (*) (+) | **general purpose** | | | | | | | | mechanical brake |
|
||||
| 8 | GPIO8 (*) (+) | **general purpose** | | | | | | | | mechanical brake |
|
||||
| 9 | M0.A | general purpose | | | | | | **ENC0.A** | | |
|
||||
| 10 | M0.B | general purpose | | | | | | **ENC0.B** | | |
|
||||
| 11 | M0.Z | **general purpose** | | | | | | | | |
|
||||
| 12 | M1.A | general purpose | | | | | I2C.SCL | | **ENC1.A** | |
|
||||
| 13 | M1.B | general purpose | | | | | I2C.SDA | | **ENC1.B** | |
|
||||
| 14 | M1.Z | **general purpose** | | | | | | | | |
|
||||
| 15 | _not exposed_ | general purpose | | | | **CAN0.RX** | I2C.SCL | | | |
|
||||
| 16 | _not exposed_ | general purpose | | | | **CAN0.TX** | I2C.SDA | | | |
|
||||
| # | Label | `GPIO_MODE_DIGITAL` | `GPIO_MODE_ANALOG_IN` | `GPIO_MODE_UART0` | `GPIO_MODE_UART1` | `GPIO_MODE_PWM0` | `GPIO_MODE_CAN0` | `GPIO_MODE_I2C0` | `GPIO_MODE_ENC0` | `GPIO_MODE_ENC1` | `GPIO_MODE_MECH_BRAKE` |
|
||||
|----|---------------|------------------------|-----------------------|-------------------|-------------------|------------------|------------------|------------------|------------------|------------------|------------------------|
|
||||
| 0 | _not a pin_ | | | | | | | | | | |
|
||||
| 1 | GPIO1 (+) | general purpose | analog input | **UART0.TX** | | PWM0.0 | | | | | mechanical brake |
|
||||
| 2 | GPIO2 (+) | general purpose | analog input | **UART0.RX** | | PWM0.1 | | | | | mechanical brake |
|
||||
| 3 | GPIO3 | general purpose | **analog input** | | **UART1.TX** | PWM0.2 | | | | | mechanical brake |
|
||||
| 4 | GPIO4 | general purpose | **analog input** | | **UART1.RX** | PWM0.3 | | | | | mechanical brake |
|
||||
| 5 | GPIO5 | general purpose | **analog input** (*) | | | | | | | | mechanical brake |
|
||||
| 6 | GPIO6 (*) (+) | **general purpose** | | | | | | | | | mechanical brake |
|
||||
| 7 | GPIO7 (*) (+) | **general purpose** | | | | | | | | | mechanical brake |
|
||||
| 8 | GPIO8 (*) (+) | **general purpose** | | | | | | | | | mechanical brake |
|
||||
| 9 | M0.A | general purpose | | | | | | | **ENC0.A** | | |
|
||||
| 10 | M0.B | general purpose | | | | | | | **ENC0.B** | | |
|
||||
| 11 | M0.Z | **general purpose** | | | | | | | | | |
|
||||
| 12 | M1.A | general purpose | | | | | | I2C.SCL | | **ENC1.A** | |
|
||||
| 13 | M1.B | general purpose | | | | | | I2C.SDA | | **ENC1.B** | |
|
||||
| 14 | M1.Z | **general purpose** | | | | | | | | | |
|
||||
| 15 | _not exposed_ | general purpose | | | | | **CAN0.RX** | I2C.SCL | | | |
|
||||
| 16 | _not exposed_ | general purpose | | | | | **CAN0.TX** | I2C.SDA | | | |
|
||||
|
||||
|
||||
(*) ODrive v3.5 and later <br>
|
||||
@@ -50,6 +50,7 @@ Notes:
|
||||
* Digital mode is a general purpose mode that can be used for these functions: step, dir, enable, encoder index, hall effect encoder, SPI encoder nCS.
|
||||
* You must also connect GND between ODrive and your other board.
|
||||
* ODrive v3.3 and onward have 5V tolerant GPIO pins.
|
||||
* Simultaneous operation of UART0 and UART1 is currently not supported.
|
||||
|
||||
## Native Protocol
|
||||
|
||||
|
||||
+6
-1
@@ -21,14 +21,17 @@ Most information in this file can be reproduced by running `dump_interrupts(odrv
|
||||
| 13 | DMA1_Stream2_IRQn | 5 |
|
||||
| 15 | DMA1_Stream4_IRQn | 5 |
|
||||
| 16 | DMA1_Stream5_IRQn | 5 |
|
||||
| 17 | DMA1_Stream6_IRQn | 5 |
|
||||
| 18 | ADC_IRQn | 5 |
|
||||
| 19 | CAN1_TX_IRQn | 6 |
|
||||
| 20 | CAN1_RX0_IRQn | 6 |
|
||||
| 21 | CAN1_RX1_IRQn | 6 |
|
||||
| 22 | CAN1_SCE_IRQn | 6 |
|
||||
| 25 | TIM1_UP_TIM10_IRQn | 0 |
|
||||
| 38 | USART2_IRQn | 5 |
|
||||
| 44 | TIM8_UP_TIM13_IRQn | 0 |
|
||||
| 45 | TIM8_TRG_COM_TIM14_IRQn | 0 |
|
||||
| 47 | DMA1_Stream7_IRQn | 5 |
|
||||
| 50 | TIM5_IRQn | 5 |
|
||||
| 51 | SPI3_IRQn | 5 |
|
||||
| 52 | UART4_IRQn | 5 |
|
||||
@@ -44,6 +47,8 @@ Most information in this file can be reproduced by running `dump_interrupts(odrv
|
||||
| DMA1_Stream0 | 1 | 0 (SPI3_RX) | SPI |
|
||||
| DMA1_Stream2 | 0 | 4 (UART4_RX) | UART0 |
|
||||
| DMA1_Stream4 | 0 | 4 (UART4_TX) | UART0 |
|
||||
| DMA1_Stream5 | 1 | 0 (SPI3_TX) | SPI |
|
||||
| DMA1_Stream5 | 0 | 4 (USART2_RX) | UART1 |
|
||||
| DMA1_Stream6 | 0 | 4 (USART2_TX) | UART1 |
|
||||
| DMA1_Stream7 | 1 | 0 (SPI3_TX) | SPI |
|
||||
| DMA2_Stream0 | 0 | 0 (ADC1) | freerunning ADC |
|
||||
|
||||
|
||||
@@ -41,16 +41,40 @@ class TestUartAscii():
|
||||
'rx': (odrive.gpio1, True),
|
||||
'tx': (odrive.gpio2, False)
|
||||
}, SerialPortComponent))
|
||||
yield (odrive, ports)
|
||||
yield (odrive, 0, ports)
|
||||
|
||||
def run_test(self, odrive: ODriveComponent, port: SerialPortComponent, logger: Logger):
|
||||
logger.debug('Enabling UART...')
|
||||
# Enable the line below to manually test UART1. For this you need
|
||||
# to manually move to the wires go to GPIO1/2 to GPIO3/4. The ones
|
||||
# that normally go to GPIO3/4 have a low pass filter.
|
||||
#yield (odrive, 1, ports)
|
||||
|
||||
def run_test(self, odrive: ODriveComponent, uart_num: int, port: SerialPortComponent, logger: Logger):
|
||||
logger.debug('Enabling UART {}...'.format(uart_num))
|
||||
|
||||
# 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.
|
||||
odrive.erase_config_and_reboot()
|
||||
odrive.handle.config.enable_uart0 = True
|
||||
odrive.handle.config.gpio1_mode = GPIO_MODE_UART0
|
||||
odrive.handle.config.gpio2_mode = GPIO_MODE_UART0
|
||||
odrive.disable_mappings()
|
||||
odrive.handle.config.enable_uart0 = False
|
||||
odrive.handle.config.uart0_baudrate = 115200
|
||||
odrive.handle.config.enable_uart1 = False
|
||||
odrive.handle.config.uart1_baudrate = 115200
|
||||
odrive.handle.config.enable_uart2 = False
|
||||
odrive.handle.config.uart2_baudrate = 115200
|
||||
|
||||
if uart_num == 0:
|
||||
odrive.handle.config.enable_uart0 = True
|
||||
odrive.handle.config.gpio1_mode = GPIO_MODE_UART0
|
||||
odrive.handle.config.gpio2_mode = GPIO_MODE_UART0
|
||||
odrive.handle.config.gpio3_mode = GPIO_MODE_ANALOG_IN
|
||||
odrive.handle.config.gpio4_mode = GPIO_MODE_ANALOG_IN
|
||||
else:
|
||||
odrive.handle.config.enable_uart1 = True
|
||||
odrive.handle.config.gpio1_mode = GPIO_MODE_ANALOG_IN
|
||||
odrive.handle.config.gpio2_mode = GPIO_MODE_ANALOG_IN
|
||||
odrive.handle.config.gpio3_mode = GPIO_MODE_UART1
|
||||
odrive.handle.config.gpio4_mode = GPIO_MODE_UART1
|
||||
|
||||
odrive.save_config_and_reboot()
|
||||
|
||||
with port.open(115200) as ser:
|
||||
# reset port to known state
|
||||
|
||||
Reference in New Issue
Block a user