mirror of
https://github.com/odriverobotics/ODrive.git
synced 2026-08-18 09:29:03 +08:00
Merge branch 'devel' into control-loop-refactor
This commit is contained in:
@@ -3,6 +3,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)
|
||||
* Added periodic sending of encoder position on CAN
|
||||
* Support for UART1 on GPIO3 and GPIO4. UART0 (on GPIO1/2) and UART1 can currently not be enabled at the same time.
|
||||
|
||||
### Changed
|
||||
* Modified encoder offset calibration to work correctly when calib_scan_distance is not a multiple of 4pi
|
||||
|
||||
@@ -43,8 +43,8 @@
|
||||
|
||||
#define DEFAULT_GPIO_MODES \
|
||||
ODriveIntf::GPIO_MODE_DIGITAL, \
|
||||
ODriveIntf::GPIO_MODE_UART0, \
|
||||
ODriveIntf::GPIO_MODE_UART0, \
|
||||
ODriveIntf::GPIO_MODE_UART_A, \
|
||||
ODriveIntf::GPIO_MODE_UART_A, \
|
||||
ODriveIntf::GPIO_MODE_ANALOG_IN, \
|
||||
ODriveIntf::GPIO_MODE_ANALOG_IN, \
|
||||
ODriveIntf::GPIO_MODE_ANALOG_IN, \
|
||||
@@ -57,8 +57,8 @@
|
||||
ODriveIntf::GPIO_MODE_ENC1, \
|
||||
ODriveIntf::GPIO_MODE_ENC1, \
|
||||
ODriveIntf::GPIO_MODE_DIGITAL_PULL_DOWN, \
|
||||
ODriveIntf::GPIO_MODE_CAN0, \
|
||||
ODriveIntf::GPIO_MODE_CAN0,
|
||||
ODriveIntf::GPIO_MODE_CAN_A, \
|
||||
ODriveIntf::GPIO_MODE_CAN_A,
|
||||
|
||||
#define TIM_TIME_BASE TIM14
|
||||
|
||||
@@ -97,9 +97,9 @@ extern USBD_HandleTypeDef& usb_dev_handle;
|
||||
|
||||
extern Stm32SpiArbiter& ext_spi_arbiter;
|
||||
|
||||
extern UART_HandleTypeDef* uart0;
|
||||
extern UART_HandleTypeDef* uart1;
|
||||
extern UART_HandleTypeDef* uart2;
|
||||
extern UART_HandleTypeDef* uart_a;
|
||||
extern UART_HandleTypeDef* uart_b;
|
||||
extern UART_HandleTypeDef* uart_c;
|
||||
|
||||
extern PwmInput pwm0_input;
|
||||
#endif
|
||||
|
||||
@@ -58,11 +58,14 @@ void DMA1_Stream0_IRQHandler(void);
|
||||
void DMA1_Stream2_IRQHandler(void);
|
||||
void DMA1_Stream4_IRQHandler(void);
|
||||
void DMA1_Stream5_IRQHandler(void);
|
||||
void DMA1_Stream6_IRQHandler(void);
|
||||
void DMA1_Stream7_IRQHandler(void);
|
||||
//void ADC_IRQHandler(void);
|
||||
void CAN1_TX_IRQHandler(void);
|
||||
void CAN1_RX0_IRQHandler(void);
|
||||
void CAN1_RX1_IRQHandler(void);
|
||||
void CAN1_SCE_IRQHandler(void);
|
||||
void USART2_IRQHandler(void);
|
||||
void TIM8_TRG_COM_TIM14_IRQHandler(void);
|
||||
void TIM5_IRQHandler(void);
|
||||
void SPI3_IRQHandler(void);
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
/* USER CODE END Includes */
|
||||
|
||||
extern UART_HandleTypeDef huart4;
|
||||
extern UART_HandleTypeDef huart2;
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
|
||||
@@ -70,6 +71,7 @@ extern UART_HandleTypeDef huart4;
|
||||
extern void _Error_Handler(char *, int);
|
||||
|
||||
void MX_UART4_Init(void);
|
||||
void MX_USART2_UART_Init(void);
|
||||
|
||||
/* USER CODE BEGIN Prototypes */
|
||||
|
||||
|
||||
@@ -82,9 +82,15 @@ void MX_DMA_Init(void)
|
||||
HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 10, 0);
|
||||
HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
|
||||
/* DMA1_Stream5_IRQn interrupt configuration */
|
||||
HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 3, 0); // SPI TX - must have higher priority than SPI RX
|
||||
HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 10, 0); // SPI TX - must have higher priority than SPI RX
|
||||
// and higher priority than the control loop handler
|
||||
HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
|
||||
/* DMA1_Stream6_IRQn interrupt configuration */
|
||||
HAL_NVIC_SetPriority(DMA1_Stream6_IRQn, 10, 0);
|
||||
HAL_NVIC_EnableIRQ(DMA1_Stream6_IRQn);
|
||||
/* DMA1_Stream7_IRQn interrupt configuration */
|
||||
HAL_NVIC_SetPriority(DMA1_Stream7_IRQn, 3, 0);
|
||||
HAL_NVIC_EnableIRQ(DMA1_Stream7_IRQn);
|
||||
/* DMA2_Stream0_IRQn interrupt configuration */
|
||||
// Dear STM, no we _don't_ want to fire an interrupt for this DMA
|
||||
// (it's not possible to deselect this in CubeMX)
|
||||
|
||||
@@ -110,7 +110,7 @@ void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
|
||||
|
||||
/* SPI3 DMA Init */
|
||||
/* SPI3_TX Init */
|
||||
hdma_spi3_tx.Instance = DMA1_Stream5;
|
||||
hdma_spi3_tx.Instance = DMA1_Stream7;
|
||||
hdma_spi3_tx.Init.Channel = DMA_CHANNEL_0;
|
||||
hdma_spi3_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
|
||||
hdma_spi3_tx.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
|
||||
@@ -54,7 +54,10 @@ extern TIM_HandleTypeDef htim5;
|
||||
extern TIM_HandleTypeDef htim8;
|
||||
extern DMA_HandleTypeDef hdma_uart4_rx;
|
||||
extern DMA_HandleTypeDef hdma_uart4_tx;
|
||||
extern DMA_HandleTypeDef hdma_usart2_rx;
|
||||
extern DMA_HandleTypeDef hdma_usart2_tx;
|
||||
extern UART_HandleTypeDef huart4;
|
||||
extern UART_HandleTypeDef huart2;
|
||||
|
||||
extern TIM_HandleTypeDef htim14;
|
||||
|
||||
@@ -251,12 +254,40 @@ void DMA1_Stream5_IRQHandler(void)
|
||||
/* USER CODE BEGIN DMA1_Stream5_IRQn 0 */
|
||||
COUNT_IRQ(DMA1_Stream5_IRQn);
|
||||
/* USER CODE END DMA1_Stream5_IRQn 0 */
|
||||
HAL_DMA_IRQHandler(&hdma_spi3_tx);
|
||||
HAL_DMA_IRQHandler(&hdma_usart2_rx);
|
||||
/* USER CODE BEGIN DMA1_Stream5_IRQn 1 */
|
||||
|
||||
/* USER CODE END DMA1_Stream5_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles DMA1 stream6 global interrupt.
|
||||
*/
|
||||
void DMA1_Stream6_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN DMA1_Stream6_IRQn 0 */
|
||||
COUNT_IRQ(DMA1_Stream6_IRQn);
|
||||
/* USER CODE END DMA1_Stream6_IRQn 0 */
|
||||
HAL_DMA_IRQHandler(&hdma_usart2_tx);
|
||||
/* USER CODE BEGIN DMA1_Stream6_IRQn 1 */
|
||||
|
||||
/* USER CODE END DMA1_Stream6_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles DMA1 stream7 global interrupt.
|
||||
*/
|
||||
void DMA1_Stream7_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN DMA1_Stream7_IRQn 0 */
|
||||
COUNT_IRQ(DMA1_Stream7_IRQn);
|
||||
/* USER CODE END DMA1_Stream7_IRQn 0 */
|
||||
HAL_DMA_IRQHandler(&hdma_spi3_tx);
|
||||
/* USER CODE BEGIN DMA1_Stream7_IRQn 1 */
|
||||
|
||||
/* USER CODE END DMA1_Stream7_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles CAN1 TX interrupts.
|
||||
*/
|
||||
@@ -313,6 +344,20 @@ void CAN1_SCE_IRQHandler(void)
|
||||
/* USER CODE END CAN1_SCE_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles USART2 global interrupt.
|
||||
*/
|
||||
void USART2_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN USART2_IRQn 0 */
|
||||
|
||||
/* USER CODE END USART2_IRQn 0 */
|
||||
HAL_UART_IRQHandler(&huart2);
|
||||
/* USER CODE BEGIN USART2_IRQn 1 */
|
||||
|
||||
/* USER CODE END USART2_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles TIM8 trigger and commutation interrupts and TIM14 global interrupt.
|
||||
*/
|
||||
|
||||
@@ -58,15 +58,18 @@
|
||||
/* USER CODE END 0 */
|
||||
|
||||
UART_HandleTypeDef huart4;
|
||||
UART_HandleTypeDef huart2;
|
||||
DMA_HandleTypeDef hdma_uart4_rx;
|
||||
DMA_HandleTypeDef hdma_uart4_tx;
|
||||
DMA_HandleTypeDef hdma_usart2_rx;
|
||||
DMA_HandleTypeDef hdma_usart2_tx;
|
||||
|
||||
/* UART4 init function */
|
||||
void MX_UART4_Init(void)
|
||||
{
|
||||
|
||||
huart4.Instance = UART4;
|
||||
huart4.Init.BaudRate = 115200; // Provisionally this can be changed to 921600 for faster transfers, the low power Arduinos will not keep up.
|
||||
//huart4.Init.BaudRate = 115200; // Provisionally this can be changed to 921600 for faster transfers, the low power Arduinos will not keep up.
|
||||
huart4.Init.WordLength = UART_WORDLENGTH_8B;
|
||||
huart4.Init.StopBits = UART_STOPBITS_1;
|
||||
huart4.Init.Parity = UART_PARITY_NONE;
|
||||
@@ -78,6 +81,25 @@ void MX_UART4_Init(void)
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
}
|
||||
/* USART2 init function */
|
||||
|
||||
void MX_USART2_UART_Init(void)
|
||||
{
|
||||
|
||||
huart2.Instance = USART2;
|
||||
//huart2.Init.BaudRate = 115200;
|
||||
huart2.Init.WordLength = UART_WORDLENGTH_8B;
|
||||
huart2.Init.StopBits = UART_STOPBITS_1;
|
||||
huart2.Init.Parity = UART_PARITY_NONE;
|
||||
huart2.Init.Mode = UART_MODE_TX_RX;
|
||||
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
||||
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
|
||||
if (HAL_UART_Init(&huart2) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
|
||||
@@ -135,6 +157,58 @@ void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
|
||||
|
||||
/* USER CODE END UART4_MspInit 1 */
|
||||
}
|
||||
else if(uartHandle->Instance==USART2)
|
||||
{
|
||||
/* USER CODE BEGIN USART2_MspInit 0 */
|
||||
|
||||
/* USER CODE END USART2_MspInit 0 */
|
||||
/* USART2 clock enable */
|
||||
__HAL_RCC_USART2_CLK_ENABLE();
|
||||
|
||||
/* USART2 DMA Init */
|
||||
/* USART2_RX Init */
|
||||
hdma_usart2_rx.Instance = DMA1_Stream5;
|
||||
hdma_usart2_rx.Init.Channel = DMA_CHANNEL_4;
|
||||
hdma_usart2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
|
||||
hdma_usart2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
hdma_usart2_rx.Init.MemInc = DMA_MINC_ENABLE;
|
||||
hdma_usart2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
|
||||
hdma_usart2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
|
||||
hdma_usart2_rx.Init.Mode = DMA_CIRCULAR;
|
||||
hdma_usart2_rx.Init.Priority = DMA_PRIORITY_LOW;
|
||||
hdma_usart2_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||
if (HAL_DMA_Init(&hdma_usart2_rx) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
__HAL_LINKDMA(uartHandle,hdmarx,hdma_usart2_rx);
|
||||
|
||||
/* USART2_TX Init */
|
||||
hdma_usart2_tx.Instance = DMA1_Stream6;
|
||||
hdma_usart2_tx.Init.Channel = DMA_CHANNEL_4;
|
||||
hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
|
||||
hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE;
|
||||
hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
|
||||
hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
|
||||
hdma_usart2_tx.Init.Mode = DMA_NORMAL;
|
||||
hdma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW;
|
||||
hdma_usart2_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||
if (HAL_DMA_Init(&hdma_usart2_tx) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
__HAL_LINKDMA(uartHandle,hdmatx,hdma_usart2_tx);
|
||||
|
||||
/* USART2 interrupt Init */
|
||||
HAL_NVIC_SetPriority(USART2_IRQn, 5, 0);
|
||||
HAL_NVIC_EnableIRQ(USART2_IRQn);
|
||||
/* USER CODE BEGIN USART2_MspInit 1 */
|
||||
|
||||
/* USER CODE END USART2_MspInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
|
||||
@@ -147,12 +221,6 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
|
||||
/* USER CODE END UART4_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_UART4_CLK_DISABLE();
|
||||
|
||||
/**UART4 GPIO Configuration
|
||||
PA0-WKUP ------> UART4_TX
|
||||
PA1 ------> UART4_RX
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOA, GPIO_1_Pin|GPIO_2_Pin);
|
||||
|
||||
/* UART4 DMA DeInit */
|
||||
HAL_DMA_DeInit(uartHandle->hdmarx);
|
||||
@@ -164,6 +232,24 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
|
||||
|
||||
/* USER CODE END UART4_MspDeInit 1 */
|
||||
}
|
||||
else if(uartHandle->Instance==USART2)
|
||||
{
|
||||
/* USER CODE BEGIN USART2_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END USART2_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_USART2_CLK_DISABLE();
|
||||
|
||||
/* UART4 DMA DeInit */
|
||||
HAL_DMA_DeInit(uartHandle->hdmarx);
|
||||
HAL_DMA_DeInit(uartHandle->hdmatx);
|
||||
|
||||
/* USART2 interrupt Deinit */
|
||||
HAL_NVIC_DisableIRQ(USART2_IRQn);
|
||||
/* USER CODE BEGIN USART2_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END USART2_MspDeInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
+23
-18
@@ -26,9 +26,9 @@ extern "C" void SystemClock_Config(void); // defined in main.c generated by Cube
|
||||
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* uart2 = nullptr;
|
||||
UART_HandleTypeDef* uart_a = &huart4;
|
||||
UART_HandleTypeDef* uart_b = &huart2; // TODO: this could be supported in ODrive v3.6 (or similar) using STM32's USART2
|
||||
UART_HandleTypeDef* uart_c = nullptr;
|
||||
|
||||
Drv8301 m0_gate_driver{
|
||||
&spi3_arbiter,
|
||||
@@ -224,16 +224,16 @@ std::array<GpioFunction, 3> alternate_functions[GPIO_COUNT] = {
|
||||
/* GPIO0 (inexistent): */ {{}},
|
||||
|
||||
#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}}},
|
||||
/* GPIO1: */ {{{ODrive::GPIO_MODE_UART_A, GPIO_AF8_UART4}, {ODrive::GPIO_MODE_PWM, GPIO_AF2_TIM5}}},
|
||||
/* GPIO2: */ {{{ODrive::GPIO_MODE_UART_A, GPIO_AF8_UART4}, {ODrive::GPIO_MODE_PWM, GPIO_AF2_TIM5}}},
|
||||
/* GPIO3: */ {{{ODrive::GPIO_MODE_UART_B, GPIO_AF7_USART2}, {ODrive::GPIO_MODE_PWM, GPIO_AF2_TIM5}}},
|
||||
#else
|
||||
/* GPIO1: */ {{}},
|
||||
/* GPIO2: */ {{}},
|
||||
/* GPIO3: */ {{}},
|
||||
#endif
|
||||
|
||||
/* GPIO4: */ {{{ODrive::GPIO_MODE_PWM0, GPIO_AF2_TIM5}}},
|
||||
/* GPIO4: */ {{{ODrive::GPIO_MODE_UART_B, GPIO_AF7_USART2}, {ODrive::GPIO_MODE_PWM, GPIO_AF2_TIM5}}},
|
||||
/* GPIO5: */ {{}},
|
||||
/* GPIO6: */ {{}},
|
||||
/* GPIO7: */ {{}},
|
||||
@@ -241,11 +241,11 @@ std::array<GpioFunction, 3> alternate_functions[GPIO_COUNT] = {
|
||||
/* ENC0_A: */ {{{ODrive::GPIO_MODE_ENC0, GPIO_AF2_TIM3}}},
|
||||
/* ENC0_B: */ {{{ODrive::GPIO_MODE_ENC0, GPIO_AF2_TIM3}}},
|
||||
/* ENC0_Z: */ {{}},
|
||||
/* ENC1_A: */ {{{ODrive::GPIO_MODE_I2C0, GPIO_AF4_I2C1}, {ODrive::GPIO_MODE_ENC1, GPIO_AF2_TIM4}}},
|
||||
/* ENC1_B: */ {{{ODrive::GPIO_MODE_I2C0, GPIO_AF4_I2C1}, {ODrive::GPIO_MODE_ENC1, GPIO_AF2_TIM4}}},
|
||||
/* ENC1_A: */ {{{ODrive::GPIO_MODE_I2C_A, GPIO_AF4_I2C1}, {ODrive::GPIO_MODE_ENC1, GPIO_AF2_TIM4}}},
|
||||
/* ENC1_B: */ {{{ODrive::GPIO_MODE_I2C_A, GPIO_AF4_I2C1}, {ODrive::GPIO_MODE_ENC1, GPIO_AF2_TIM4}}},
|
||||
/* ENC1_Z: */ {{}},
|
||||
/* CAN_R: */ {{{ODrive::GPIO_MODE_CAN0, GPIO_AF9_CAN1}, {ODrive::GPIO_MODE_I2C0, GPIO_AF4_I2C1}}},
|
||||
/* CAN_D: */ {{{ODrive::GPIO_MODE_CAN0, GPIO_AF9_CAN1}, {ODrive::GPIO_MODE_I2C0, GPIO_AF4_I2C1}}},
|
||||
/* CAN_R: */ {{{ODrive::GPIO_MODE_CAN_A, GPIO_AF9_CAN1}, {ODrive::GPIO_MODE_I2C_A, GPIO_AF4_I2C1}}},
|
||||
/* CAN_D: */ {{{ODrive::GPIO_MODE_CAN_A, GPIO_AF9_CAN1}, {ODrive::GPIO_MODE_I2C_A, GPIO_AF4_I2C1}}},
|
||||
};
|
||||
|
||||
#if HW_VERSION_MINOR <= 2
|
||||
@@ -278,7 +278,6 @@ bool board_init() {
|
||||
MX_SPI3_Init();
|
||||
MX_ADC3_Init();
|
||||
MX_TIM2_Init();
|
||||
MX_UART4_Init();
|
||||
MX_TIM5_Init();
|
||||
MX_TIM13_Init();
|
||||
|
||||
@@ -304,11 +303,17 @@ bool board_init() {
|
||||
HAL_NVIC_SetPriority(TIM8_UP_TIM13_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(TIM8_UP_TIM13_IRQn);
|
||||
|
||||
HAL_UART_DeInit(uart0);
|
||||
uart0->Init.BaudRate = odrv.config_.uart0_baudrate;
|
||||
HAL_UART_Init(uart0);
|
||||
if (odrv.config_.enable_uart_a) {
|
||||
uart_a->Init.BaudRate = odrv.config_.uart_a_baudrate;
|
||||
MX_UART4_Init();
|
||||
}
|
||||
|
||||
if (odrv.config_.enable_i2c0) {
|
||||
if (odrv.config_.enable_uart_b) {
|
||||
uart_b->Init.BaudRate = odrv.config_.uart_b_baudrate;
|
||||
MX_USART2_UART_Init();
|
||||
}
|
||||
|
||||
if (odrv.config_.enable_i2c_a) {
|
||||
// Set up the direction GPIO as input
|
||||
get_gpio(3).config(GPIO_MODE_INPUT, GPIO_PULLUP);
|
||||
get_gpio(4).config(GPIO_MODE_INPUT, GPIO_PULLUP);
|
||||
@@ -322,11 +327,11 @@ bool board_init() {
|
||||
MX_I2C1_Init(i2c_stats_.addr);
|
||||
}
|
||||
|
||||
if (odrv.config_.enable_can0) {
|
||||
if (odrv.config_.enable_can_a) {
|
||||
// The CAN initialization will (and must) init its own GPIOs before the
|
||||
// GPIO modes are initialized. Therefore we ensure that the later GPIO
|
||||
// mode initialization won't override the CAN mode.
|
||||
if (odrv.config_.gpio_modes[15] != ODriveIntf::GPIO_MODE_CAN0 || odrv.config_.gpio_modes[16] != ODriveIntf::GPIO_MODE_CAN0) {
|
||||
if (odrv.config_.gpio_modes[15] != ODriveIntf::GPIO_MODE_CAN_A || odrv.config_.gpio_modes[16] != ODriveIntf::GPIO_MODE_CAN_A) {
|
||||
odrv.misconfigured_ = true;
|
||||
} else {
|
||||
MX_CAN1_Init();
|
||||
|
||||
@@ -551,9 +551,9 @@ extern "C" int main(void) {
|
||||
}
|
||||
|
||||
odrv.misconfigured_ = odrv.misconfigured_
|
||||
|| (odrv.config_.enable_uart0 && !uart0)
|
||||
|| (odrv.config_.enable_uart1 && !uart1)
|
||||
|| (odrv.config_.enable_uart2 && !uart2);
|
||||
|| (odrv.config_.enable_uart_a && !uart_a)
|
||||
|| (odrv.config_.enable_uart_b && !uart_b)
|
||||
|| (odrv.config_.enable_uart_c && !uart_c);
|
||||
|
||||
// Init board-specific peripherals
|
||||
if (!board_init()) {
|
||||
@@ -611,49 +611,49 @@ extern "C" int main(void) {
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
} break;
|
||||
case ODriveIntf::GPIO_MODE_UART0: {
|
||||
case ODriveIntf::GPIO_MODE_UART_A: {
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = (i == 0) ? GPIO_PULLDOWN : GPIO_PULLUP; // this is probably swapped but imitates old behavior
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
if (!odrv.config_.enable_uart0) {
|
||||
if (!odrv.config_.enable_uart_a) {
|
||||
odrv.misconfigured_ = true;
|
||||
}
|
||||
} break;
|
||||
case ODriveIntf::GPIO_MODE_UART1: {
|
||||
case ODriveIntf::GPIO_MODE_UART_B: {
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = (i == 0) ? GPIO_PULLDOWN : GPIO_PULLUP; // this is probably swapped but imitates old behavior
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
if (!odrv.config_.enable_uart1) {
|
||||
if (!odrv.config_.enable_uart_b) {
|
||||
odrv.misconfigured_ = true;
|
||||
}
|
||||
} break;
|
||||
case ODriveIntf::GPIO_MODE_UART2: {
|
||||
case ODriveIntf::GPIO_MODE_UART_C: {
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = (i == 0) ? GPIO_PULLDOWN : GPIO_PULLUP; // this is probably swapped but imitates old behavior
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
if (!odrv.config_.enable_uart2) {
|
||||
if (!odrv.config_.enable_uart_c) {
|
||||
odrv.misconfigured_ = true;
|
||||
}
|
||||
} break;
|
||||
case ODriveIntf::GPIO_MODE_CAN0: {
|
||||
case ODriveIntf::GPIO_MODE_CAN_A: {
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
if (!odrv.config_.enable_can0) {
|
||||
if (!odrv.config_.enable_can_a) {
|
||||
odrv.misconfigured_ = true;
|
||||
}
|
||||
} break;
|
||||
case ODriveIntf::GPIO_MODE_I2C0: {
|
||||
case ODriveIntf::GPIO_MODE_I2C_A: {
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLUP;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
if (!odrv.config_.enable_i2c0) {
|
||||
if (!odrv.config_.enable_i2c_a) {
|
||||
odrv.misconfigured_ = true;
|
||||
}
|
||||
} break;
|
||||
//case ODriveIntf::GPIO_MODE_SPI0: { // TODO
|
||||
//case ODriveIntf::GPIO_MODE_SPI_A: { // TODO
|
||||
//} break;
|
||||
case ODriveIntf::GPIO_MODE_PWM0: {
|
||||
case ODriveIntf::GPIO_MODE_PWM: {
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
|
||||
@@ -63,14 +63,14 @@ struct BoardConfig_t {
|
||||
DEFAULT_GPIO_MODES
|
||||
};
|
||||
|
||||
bool enable_uart0 = true;
|
||||
bool enable_uart1 = false;
|
||||
bool enable_uart2 = false;
|
||||
uint32_t uart0_baudrate = 115200;
|
||||
uint32_t uart1_baudrate = 115200;
|
||||
uint32_t uart2_baudrate = 115200;
|
||||
bool enable_can0 = true;
|
||||
bool enable_i2c0 = false;
|
||||
bool enable_uart_a = true;
|
||||
bool enable_uart_b = false;
|
||||
bool enable_uart_c = false;
|
||||
uint32_t uart_a_baudrate = 115200;
|
||||
uint32_t uart_b_baudrate = 115200;
|
||||
uint32_t uart_c_baudrate = 115200;
|
||||
bool enable_can_a = true;
|
||||
bool enable_i2c_a = false;
|
||||
bool enable_ascii_protocol_on_usb = true;
|
||||
float max_regen_current = 0.0f;
|
||||
float brake_resistance = DEFAULT_BRAKE_RESISTANCE;
|
||||
|
||||
@@ -38,17 +38,24 @@ char serial_number_str[13]; // 12 digits + null termination
|
||||
void init_communication(void) {
|
||||
printf("hi!\r\n");
|
||||
|
||||
if (odrv.config_.enable_uart0 && uart0) {
|
||||
start_uart_server();
|
||||
// Dual UART operation not supported yet
|
||||
if (odrv.config_.enable_uart_a && odrv.config_.enable_uart_b) {
|
||||
odrv.misconfigured_ = true;
|
||||
}
|
||||
|
||||
if (odrv.config_.enable_uart_a && uart_a) {
|
||||
start_uart_server(uart_a);
|
||||
} else if (odrv.config_.enable_uart_b && uart_b) {
|
||||
start_uart_server(uart_b);
|
||||
}
|
||||
|
||||
start_usb_server();
|
||||
|
||||
if (odrv.config_.enable_i2c0) {
|
||||
if (odrv.config_.enable_i2c_a) {
|
||||
start_i2c_server();
|
||||
}
|
||||
|
||||
if (odrv.config_.enable_can0) {
|
||||
if (odrv.config_.enable_can_a) {
|
||||
odCAN->start_can_server();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,7 @@ static uint8_t dma_rx_buffer[UART_RX_BUFFER_SIZE];
|
||||
static uint32_t dma_last_rcv_idx;
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -97,7 +96,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
|
||||
|
||||
@@ -93,6 +93,8 @@ properties:
|
||||
additionalProperties: false
|
||||
"""))
|
||||
|
||||
# TODO: detect duplicate keys in yaml dictionaries
|
||||
|
||||
# Source: https://stackoverflow.com/a/53647080/3621512
|
||||
class SafeLineLoader(yaml.SafeLoader):
|
||||
pass
|
||||
|
||||
@@ -176,15 +176,26 @@ interfaces:
|
||||
gpio15_mode: {type: GpioMode, doc: Mode of GPIO15 (changes take effect after reboot), c_name: 'gpio_modes[15]'}
|
||||
gpio16_mode: {type: GpioMode, doc: Mode of GPIO16 (changes take effect after reboot), c_name: 'gpio_modes[16]'}
|
||||
|
||||
enable_uart0:
|
||||
enable_uart_a:
|
||||
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.}
|
||||
enable_uart2: {type: bool, doc: Not supported on ODrive v3.x.}
|
||||
uart0_baudrate:
|
||||
type: uint32
|
||||
brief: Enables/disables UART_A.
|
||||
doc: |
|
||||
You also need to set the corresponding GPIOs to GPIO_MODE_UART_A.
|
||||
Refer to [interfaces](interfaces.md) to see which pins support UART_A.
|
||||
Changing this requires a reboot.
|
||||
enable_uart_b:
|
||||
type: bool
|
||||
brief: Enables/disables UART_B.
|
||||
doc: |
|
||||
You also need to set the corresponding GPIOs to GPIO_MODE_UART_B.
|
||||
Refer to [interfaces](interfaces.md) to see which pins support UART_B.
|
||||
Changing this requires a reboot.
|
||||
enable_uart_c: {type: bool, doc: Not supported on ODrive v3.x.}
|
||||
uart_a_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:
|
||||
@@ -206,17 +217,21 @@ 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.}
|
||||
uart2_baudrate: {type: uint32, doc: Not supported on ODrive v3.x.}
|
||||
enable_can0:
|
||||
uart_b_baudrate:
|
||||
type: uint32
|
||||
unit: baud/s
|
||||
brief: Defines the baudrate used on the UART interface.
|
||||
doc: See `uart_a_baudrate` for details.
|
||||
uart_c_baudrate: {type: uint32, doc: Not supported on ODrive v3.x.}
|
||||
enable_can_a:
|
||||
type: bool
|
||||
doc: |
|
||||
Enables CAN. Changing this setting requires a reboot.
|
||||
enable_i2c0:
|
||||
enable_i2c_a:
|
||||
type: bool
|
||||
doc: |
|
||||
Enables I2C. The I2C pins on ODrive v3.x are in conflict with CAN.
|
||||
This setting has no effect if `enable_can0` is also true.
|
||||
This setting has no effect if `enable_can_a` is also true.
|
||||
This setting has no effect on ODrive v3.2 or earlier.
|
||||
Changing this setting requires a reboot.
|
||||
enable_ascii_protocol_on_usb: bool
|
||||
@@ -280,10 +295,10 @@ interfaces:
|
||||
brief: Max current the power supply can sink.
|
||||
doc: You most likely want a non-positive value here. Set to -INFINITY to disable.
|
||||
|
||||
gpio1_pwm_mapping: {type: Endpoint, c_name: 'pwm_mappings[0]', doc: Make sure the corresponding GPIO is in `GPIO_MODE_PWM0`.}
|
||||
gpio2_pwm_mapping: {type: Endpoint, c_name: 'pwm_mappings[1]', doc: Make sure the corresponding GPIO is in `GPIO_MODE_PWM0`.}
|
||||
gpio3_pwm_mapping: {type: Endpoint, c_name: 'pwm_mappings[2]', doc: Make sure the corresponding GPIO is in `GPIO_MODE_PWM0`.}
|
||||
gpio4_pwm_mapping: {type: Endpoint, c_name: 'pwm_mappings[3]', doc: Make sure the corresponding GPIO is in `GPIO_MODE_PWM0`.}
|
||||
gpio1_pwm_mapping: {type: Endpoint, c_name: 'pwm_mappings[0]', doc: Make sure the corresponding GPIO is in `GPIO_MODE_PWM`.}
|
||||
gpio2_pwm_mapping: {type: Endpoint, c_name: 'pwm_mappings[1]', doc: Make sure the corresponding GPIO is in `GPIO_MODE_PWM`.}
|
||||
gpio3_pwm_mapping: {type: Endpoint, c_name: 'pwm_mappings[2]', doc: Make sure the corresponding GPIO is in `GPIO_MODE_PWM`.}
|
||||
gpio4_pwm_mapping: {type: Endpoint, c_name: 'pwm_mappings[3]', doc: Make sure the corresponding GPIO is in `GPIO_MODE_PWM`.}
|
||||
gpio3_analog_mapping: {type: Endpoint, c_name: 'analog_mappings[3]', doc: Make sure the corresponding GPIO is in `GPIO_MODE_ANALOG_IN`.}
|
||||
gpio4_analog_mapping: {type: Endpoint, c_name: 'analog_mappings[4]', doc: Make sure the corresponding GPIO is in `GPIO_MODE_ANALOG_IN`.}
|
||||
user_config_loaded: readonly uint32
|
||||
@@ -299,10 +314,10 @@ interfaces:
|
||||
Possible causes:
|
||||
- A GPIO was set to a mode that it doesn't support
|
||||
- A GPIO was set to a mode for which the corresponding feature was
|
||||
not enabled. Example: `GPIO_MODE_UART0` was used without enabling
|
||||
`config.enable_uart0`.
|
||||
not enabled. Example: `GPIO_MODE_UART_A` was used without enabling
|
||||
`config.enable_uart_a`.
|
||||
- A feature was enabled which is not supported on this hardware.
|
||||
Example: `config.enable_uart2` set to true on ODrive v3.x.
|
||||
Example: `config.enable_uart_c` set to true on ODrive v3.x.
|
||||
- A GPIO was used as an interrupt input for two internal components
|
||||
or two GPIOs that are mutually exclusive in their interrupt
|
||||
capability were both used as interrupt input.
|
||||
@@ -1078,15 +1093,15 @@ valuetypes:
|
||||
doc: |
|
||||
The pin can be used for one or more of these functions:
|
||||
Sin/cos encoders, analog input, `get_adc_voltage`.
|
||||
Uart0: {doc: See `config.enable_uart0`.}
|
||||
Uart1: {doc: This mode is not supported on ODrive v3.x.}
|
||||
Uart2: {doc: This mode is not supported on ODrive v3.x.}
|
||||
Can0: {doc: See `config.enable_can0`.}
|
||||
I2c0: {doc: See `config.enable_i2c0`.}
|
||||
Spi0: {doc: Note that the SPI pins on ODrive v3.x are hardwired so they
|
||||
cannot be configured through software. Consequently, even though SPI0
|
||||
UartA: {doc: See `config.enable_uart_a`.}
|
||||
UartB: {doc: This mode is not supported on ODrive v3.x.}
|
||||
UartC: {doc: This mode is not supported on ODrive v3.x.}
|
||||
CanA: {doc: See `config.enable_can_a`.}
|
||||
I2cA: {doc: See `config.enable_i2c_a`.}
|
||||
SpiA: {doc: Note that the SPI pins on ODrive v3.x are hardwired so they
|
||||
cannot be configured through software. Consequently, even though SPI_A
|
||||
is exposed, this mode is of no use on ODrive v3.x.}
|
||||
Pwm0: {doc: See `config.gpio0_pwm_mapping`.}
|
||||
Pwm: {doc: See `config.gpio0_pwm_mapping`.}
|
||||
Enc0: {doc: The pin is used by quadrature encoder 0.}
|
||||
Enc1: {doc: The pin is used by quadrature encoder 1.}
|
||||
Enc2: {doc: This mode is not supported on ODrive v3.x.}
|
||||
|
||||
+21
-20
@@ -1,24 +1,24 @@
|
||||
# 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_UART_A` | `GPIO_MODE_UART_B` | `GPIO_MODE_PWM` | `GPIO_MODE_CAN_A` | `GPIO_MODE_I2C_A` | `GPIO_MODE_ENC0` | `GPIO_MODE_ENC1` | `GPIO_MODE_MECH_BRAKE` |
|
||||
|----|---------------|------------------------|-----------------------|--------------------|--------------------|-----------------|------------------|-------------------|------------------|------------------|------------------------|
|
||||
| 0 | _not a pin_ | | | | | | | | | | |
|
||||
| 1 | GPIO1 (+) | general purpose | analog input | **UART_A.TX** | | PWM0.0 | | | | | mechanical brake |
|
||||
| 2 | GPIO2 (+) | general purpose | analog input | **UART_A.RX** | | PWM0.1 | | | | | mechanical brake |
|
||||
| 3 | GPIO3 | general purpose | **analog input** | | **UART_B.TX** | PWM0.2 | | | | | mechanical brake |
|
||||
| 4 | GPIO4 | general purpose | **analog input** | | **UART_B.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 | | | | | **CAN_A.RX** | I2C.SCL | | | |
|
||||
| 16 | _not exposed_ | general purpose | | | | | **CAN_A.TX** | I2C.SDA | | | |
|
||||
|
||||
|
||||
(*) ODrive v3.5 and later <br>
|
||||
@@ -28,7 +28,8 @@ Notes:
|
||||
* Changes to the pin configuration only take effect after `odrv0.save_configuration()` and `odrv0.reboot()`
|
||||
* Bold font marks the default configuration.
|
||||
* If a GPIO is set to an unsupported mode it will be left uninitialized.
|
||||
* When setting a GPIO to a special purpose mode (e.g. `GPIO_MODE_UART0`) you must also enable the corresponding feature (e.g. `<odrv>.config.enable_uart`).
|
||||
* When setting a GPIO to a special purpose mode (e.g. `GPIO_MODE_UART_A`) you must also enable the corresponding feature (e.g. `<odrv>.config.enable_uart_a`).
|
||||
* 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 UART_A and UART_B is currently not supported.
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ Any of the numerical parameters that are writable from the ODrive Tool can be ho
|
||||
2. If you want to control your ODrive with the PWM input without using anything else to activate the ODrive, you can configure the ODrive such that axis 0 automatically goes operational at startup. See [here](commands.md#startup-procedure) for more information.
|
||||
3. In ODrive Tool, configure the PWM input mapping
|
||||
```
|
||||
odrv0.config.gpio4_mode = GPIO_MODE_PWM0
|
||||
odrv0.config.gpio4_mode = GPIO_MODE_PWM
|
||||
odrv0.config.gpio4_pwm_mapping.min = -2
|
||||
odrv0.config.gpio4_pwm_mapping.max = 2
|
||||
odrv0.config.gpio4_pwm_mapping.endpoint = odrv0.axis0.controller._remote_attributes['input_pos']
|
||||
|
||||
+9
-5
@@ -27,7 +27,8 @@ Take this info with a grain of salt as we might forget to update it from time to
|
||||
| 11 | DMA1_Stream0_IRQn | 4 |
|
||||
| 13 | DMA1_Stream2_IRQn | 10 |
|
||||
| 15 | DMA1_Stream4_IRQn | 10 |
|
||||
| 16 | DMA1_Stream5_IRQn | 3 |
|
||||
| 16 | DMA1_Stream5_IRQn | 10 |
|
||||
| 17 | DMA1_Stream6_IRQn | 10 |
|
||||
| 19 | CAN1_TX_IRQn | 9 |
|
||||
| 20 | CAN1_RX0_IRQn | 9 |
|
||||
| 21 | CAN1_RX1_IRQn | 9 |
|
||||
@@ -36,6 +37,7 @@ Take this info with a grain of salt as we might forget to update it from time to
|
||||
| 40 | EXTI15_10_IRQn | 1 |
|
||||
| 44 | TIM8_UP_TIM13_IRQn | 0 |
|
||||
| 45 | TIM8_TRG_COM_TIM14_IRQn | 6 |
|
||||
| 47 | DMA1_Stream7_IRQn | 3 |
|
||||
| 50 | TIM5_IRQn | 1 |
|
||||
| 52 | UART4_IRQn | 10 |
|
||||
| 67 | OTG_FS_IRQn | 6 |
|
||||
@@ -49,10 +51,12 @@ Take this info with a grain of salt as we might forget to update it from time to
|
||||
|
||||
| Name | Prio | Channel | High Level Func |
|
||||
|--------------|------|----------------------------------|-----------------|
|
||||
| DMA1_Stream0 | 1 | 0 (SPI3_RX) | SPI |
|
||||
| DMA1_Stream2 | 0 | 4 (UART4_RX) | UART0 |
|
||||
| DMA1_Stream4 | 0 | 4 (UART4_TX) | UART0 |
|
||||
| DMA1_Stream5 | 2 | 0 (SPI3_TX) | SPI |
|
||||
| DMA1_Stream0 | 1 | 0 (SPI3_RX) | SPI_A |
|
||||
| DMA1_Stream2 | 0 | 4 (UART4_RX) | UART_A |
|
||||
| DMA1_Stream4 | 0 | 4 (UART4_TX) | UART_A |
|
||||
| DMA1_Stream5 | 0 | 4 (USART2_RX) | UART_B |
|
||||
| DMA1_Stream6 | 0 | 4 (USART2_TX) | UART_B |
|
||||
| DMA1_Stream7 | 2 | 0 (SPI3_TX) | SPI_A |
|
||||
| DMA2_Stream0 | 0 | 0 (ADC1) | freerunning ADC |
|
||||
|
||||
|
||||
|
||||
+14
-2
@@ -1,6 +1,6 @@
|
||||
# UART Interface
|
||||
|
||||
The ODrive's UART0 interface is enabled by default with a baudrate of 115200 on the pins as shown in [Pinout](pinout).
|
||||
The ODrive's UART_A interface is enabled by default with a baudrate of 115200 on the pins as shown in [Pinout](pinout).
|
||||
|
||||
To use UART connect it like this:
|
||||
|
||||
@@ -10,4 +10,16 @@ To use UART connect it like this:
|
||||
|
||||
The logic level of the ODrive is 3.3V. The GPIOs are 5V tolerant.
|
||||
|
||||
You can use `odrv0.config.uart0_baudrate` to change the baudrate and `odrv0.config.enable_uart0` to disable/reenable UART0. Currently the UART port runs both the [Native Protocol](native-protocol) and the [ASCII Protocol](ascii-protocol) at the same time.
|
||||
You can use `odrv0.config.uart_a_baudrate` to change the baudrate and `odrv0.config.enable_uart_a` to disable/reenable UART_A. Currently the UART port runs both the [Native Protocol](native-protocol) and the [ASCII Protocol](ascii-protocol) at the same time.
|
||||
|
||||
### How to use UART on GPIO3/4
|
||||
|
||||
If you need GPIO1/2 for some function other than UART you can disable UART_A and instead use UART_B on GPIO3/4. Here's how you do it:
|
||||
|
||||
odrv0.config.enable_uart_a = False
|
||||
odrv0.config.gpio1_mode = GPIO_MODE_DIGITAL
|
||||
odrv0.config.gpio2_mode = GPIO_MODE_DIGITAL
|
||||
odrv0.config.enable_uart_b = True
|
||||
odrv0.config.gpio3_mode = GPIO_MODE_UART_B
|
||||
odrv0.config.gpio4_mode = GPIO_MODE_UART_B
|
||||
odrv0.reboot()
|
||||
|
||||
@@ -8,13 +8,13 @@ GPIO_MODE_DIGITAL = 0
|
||||
GPIO_MODE_DIGITAL_PULL_UP = 1
|
||||
GPIO_MODE_DIGITAL_PULL_DOWN = 2
|
||||
GPIO_MODE_ANALOG_IN = 3
|
||||
GPIO_MODE_UART0 = 4
|
||||
GPIO_MODE_UART1 = 5
|
||||
GPIO_MODE_UART2 = 6
|
||||
GPIO_MODE_CAN0 = 7
|
||||
GPIO_MODE_I2C0 = 8
|
||||
GPIO_MODE_SPI0 = 9
|
||||
GPIO_MODE_PWM0 = 10
|
||||
GPIO_MODE_UART_A = 4
|
||||
GPIO_MODE_UART_B = 5
|
||||
GPIO_MODE_UART_C = 6
|
||||
GPIO_MODE_CAN_A = 7
|
||||
GPIO_MODE_I2C_A = 8
|
||||
GPIO_MODE_SPI_A = 9
|
||||
GPIO_MODE_PWM = 10
|
||||
GPIO_MODE_ENC0 = 11
|
||||
GPIO_MODE_ENC1 = 12
|
||||
GPIO_MODE_ENC2 = 13
|
||||
|
||||
@@ -109,9 +109,9 @@ class TestSimpleCAN():
|
||||
|
||||
def run_test(self, odrive: ODriveComponent, canbus: CanInterfaceComponent, node_id: int, extended_id: bool, logger: Logger):
|
||||
odrive.disable_mappings()
|
||||
odrive.handle.config.gpio15_mode = GPIO_MODE_CAN0
|
||||
odrive.handle.config.gpio16_mode = GPIO_MODE_CAN0
|
||||
odrive.handle.config.enable_can0 = True
|
||||
odrive.handle.config.gpio15_mode = GPIO_MODE_CAN_A
|
||||
odrive.handle.config.gpio16_mode = GPIO_MODE_CAN_A
|
||||
odrive.handle.config.enable_can_a = True
|
||||
odrive.save_config_and_reboot()
|
||||
|
||||
axis = odrive.handle.axis0
|
||||
|
||||
@@ -70,7 +70,7 @@ class TestPwmInput():
|
||||
odrive.handle.config.gpio4_pwm_mapping
|
||||
][odrive_gpio_num - 1]
|
||||
|
||||
setattr(odrive.handle.config, 'gpio' + str(odrive_gpio_num) + '_mode', GPIO_MODE_PWM0)
|
||||
setattr(odrive.handle.config, 'gpio' + str(odrive_gpio_num) + '_mode', GPIO_MODE_PWM)
|
||||
pwm_mapping.endpoint = odrive.handle.axis0.controller._remote_attributes['input_pos']
|
||||
pwm_mapping.min = min_val
|
||||
pwm_mapping.max = max_val
|
||||
|
||||
@@ -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 UART_B. 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_uart_a = False
|
||||
odrive.handle.config.uart_a_baudrate = 115200
|
||||
odrive.handle.config.enable_uart_b = False
|
||||
odrive.handle.config.uart_b_baudrate = 115200
|
||||
odrive.handle.config.enable_uart_c = False
|
||||
odrive.handle.config.uart_c_baudrate = 115200
|
||||
|
||||
if uart_num == 0:
|
||||
odrive.handle.config.enable_uart_a = True
|
||||
odrive.handle.config.gpio1_mode = GPIO_MODE_UART_A
|
||||
odrive.handle.config.gpio2_mode = GPIO_MODE_UART_A
|
||||
odrive.handle.config.gpio3_mode = GPIO_MODE_ANALOG_IN
|
||||
odrive.handle.config.gpio4_mode = GPIO_MODE_ANALOG_IN
|
||||
else:
|
||||
odrive.handle.config.enable_uart_b = 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_UART_B
|
||||
odrive.handle.config.gpio4_mode = GPIO_MODE_UART_B
|
||||
|
||||
odrive.save_config_and_reboot()
|
||||
|
||||
with port.open(115200) as ser:
|
||||
# reset port to known state
|
||||
@@ -163,11 +187,11 @@ class TestUartBaudrate():
|
||||
yield (odrive, ports)
|
||||
|
||||
def run_test(self, odrive: ODriveComponent, port: SerialPortComponent, logger: Logger):
|
||||
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.enable_uart_a = True
|
||||
odrive.handle.config.gpio1_mode = GPIO_MODE_UART_A
|
||||
odrive.handle.config.gpio2_mode = GPIO_MODE_UART_A
|
||||
|
||||
odrive.handle.config.uart0_baudrate = 9600
|
||||
odrive.handle.config.uart_a_baudrate = 9600
|
||||
odrive.save_config_and_reboot()
|
||||
|
||||
# Control test: talk to the ODrive with the wrong baudrate
|
||||
@@ -187,7 +211,7 @@ class TestUartBaudrate():
|
||||
response = float(ser.readline().strip())
|
||||
test_assert_eq(response, odrive.handle.vbus_voltage, accuracy=0.1)
|
||||
|
||||
odrive.handle.config.uart0_baudrate = 115200
|
||||
odrive.handle.config.uart_a_baudrate = 115200
|
||||
odrive.save_config_and_reboot()
|
||||
|
||||
|
||||
@@ -205,9 +229,9 @@ class TestUartBurnIn():
|
||||
yield (odrive, ports)
|
||||
|
||||
def run_test(self, odrive: ODriveComponent, port: SerialPortComponent, logger: Logger):
|
||||
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.enable_uart_a = True
|
||||
odrive.handle.config.gpio1_mode = GPIO_MODE_UART_A
|
||||
odrive.handle.config.gpio2_mode = GPIO_MODE_UART_A
|
||||
|
||||
with port.open(115200) as ser:
|
||||
with open('/dev/random', 'rb') as rand:
|
||||
@@ -262,9 +286,9 @@ class TestUartNoise():
|
||||
noise_enable.write(False)
|
||||
time.sleep(0.1)
|
||||
|
||||
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.enable_uart_a = True
|
||||
odrive.handle.config.gpio1_mode = GPIO_MODE_UART_A
|
||||
odrive.handle.config.gpio2_mode = GPIO_MODE_UART_A
|
||||
|
||||
with port.open(115200) as ser:
|
||||
# reset port to known state
|
||||
|
||||
Reference in New Issue
Block a user