From 5cadb2f51a0df64ff67c41ad6a23e25c30ed3ea3 Mon Sep 17 00:00:00 2001 From: Philipp Erhardt Date: Thu, 26 Mar 2026 15:30:53 +0000 Subject: [PATCH 1/2] Support more UARTs --- machine/arm/stm32l4xx/interface/uart.c | 103 ++++++++++++++++--------- options.toml | 2 +- 2 files changed, 68 insertions(+), 37 deletions(-) diff --git a/machine/arm/stm32l4xx/interface/uart.c b/machine/arm/stm32l4xx/interface/uart.c index abf4621..acf65d7 100644 --- a/machine/arm/stm32l4xx/interface/uart.c +++ b/machine/arm/stm32l4xx/interface/uart.c @@ -29,56 +29,87 @@ int write_debug_uart(const char *buf, int len) { if (HAL_UART_Transmit(&HDBG_UART, (uint8_t *)buf, len, 100) != HAL_OK) { return -1; } - return len; // Return number of bytes written + return len; } void HAL_UART_MspInit(UART_HandleTypeDef *huart) { - if (huart->Instance == LPUART1) { - - RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; - PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LPUART1; - PeriphClkInit.Lpuart1ClockSelection = RCC_LPUART1CLKSOURCE_PCLK1; - - if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { - return; - } - - __HAL_RCC_LPUART1_CLK_ENABLE(); + RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; + GPIO_InitTypeDef GPIO_InitStruct = {0}; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + + if (huart->Instance == USART1) { + // TX: PA9 (AF7), RX: PA10 (AF7) — Nucleo CN12 pins 21, 33 + PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1; + PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) return; + __HAL_RCC_USART1_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + GPIO_InitStruct.Alternate = GPIO_AF7_USART1; + GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + } else if (huart->Instance == USART2) { + // TX: PA2 (AF7), RX: PA3 (AF7) — Nucleo CN12 pins 35, 37 + PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART2; + PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) return; + __HAL_RCC_USART2_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + GPIO_InitStruct.Alternate = GPIO_AF7_USART2; + GPIO_InitStruct.Pin = GPIO_PIN_2 | GPIO_PIN_3; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + } else if (huart->Instance == USART3) { + // TX: PC10 (AF7), RX: PC11 (AF7) — Nucleo CN11 pins 1, 2 + PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART3; + PeriphClkInit.Usart3ClockSelection = RCC_USART3CLKSOURCE_PCLK1; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) return; + __HAL_RCC_USART3_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + GPIO_InitStruct.Alternate = GPIO_AF7_USART3; + GPIO_InitStruct.Pin = GPIO_PIN_10 | GPIO_PIN_11; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); - GPIO_InitTypeDef GPIO_InitStruct = {0}; - GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7; // LPUART1_TX, LPUART1_RX - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF8_LPUART1; + } else if (huart->Instance == UART4) { + // TX: PA0 (AF8), RX: PA1 (AF8) — Nucleo CN11 pins 28, 30 + // Note: PA0 is also connected to user button B1 via SB197; cut SB197 to use UART4 TX + PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_UART4; + PeriphClkInit.Uart4ClockSelection = RCC_UART4CLKSOURCE_PCLK1; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) return; + __HAL_RCC_UART4_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + GPIO_InitStruct.Alternate = GPIO_AF8_UART4; + GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - HAL_PWREx_EnableVddIO2(); - __HAL_RCC_GPIOG_CLK_ENABLE(); - HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); } else if (huart->Instance == UART5) { - - RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; + // TX: PC12 (AF8), RX: PD2 (AF8) — Nucleo CN11 pins 3, 4 PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_UART5; PeriphClkInit.Uart5ClockSelection = RCC_UART5CLKSOURCE_PCLK1; - if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { - return; - } - + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) return; __HAL_RCC_UART5_CLK_ENABLE(); - - // Enable GPIO clocks - HAL_PWREx_EnableVddIO2(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); - - GPIO_InitTypeDef GPIO_InitStruct = {0}; - GPIO_InitStruct.Pin = GPIO_PIN_12; // PC12 == UART5_TX - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF8_UART5; + GPIO_InitStruct.Pin = GPIO_PIN_12; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); - // PD2 == UART5_RX GPIO_InitStruct.Pin = GPIO_PIN_2; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); + + } else if (huart->Instance == LPUART1) { + // TX: PG7 (AF8), RX: PG8 (AF8) — Nucleo CN12 pins 67, 66 + // Note: SB130/SB131 connect PG7/PG8 to the ST-LINK VCP by default; + // cut them to route LPUART1 to external pins instead. + PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LPUART1; + PeriphClkInit.Lpuart1ClockSelection = RCC_LPUART1CLKSOURCE_PCLK1; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) return; + __HAL_RCC_LPUART1_CLK_ENABLE(); + HAL_PWREx_EnableVddIO2(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + GPIO_InitStruct.Alternate = GPIO_AF8_LPUART1; + GPIO_InitStruct.Pin = GPIO_PIN_7 | GPIO_PIN_8; + HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); } } diff --git a/options.toml b/options.toml index 985e288..58f3392 100644 --- a/options.toml +++ b/options.toml @@ -13,7 +13,7 @@ type = "Boolean" [debug.uart] name = "Debug UART" description = "Select the UART peripheral to use for debug output." -type = { type = "String", allowed_values = ["LPUART1", "UART5"] } +type = { type = "String", allowed_values = ["USART1", "USART2", "USART3", "UART4", "UART5", "LPUART1"] } default = "LPUART1" [tuning] From f0c1e6538c118a819549ae55d66a46a240678a6d Mon Sep 17 00:00:00 2001 From: xarantolus Date: Thu, 26 Mar 2026 17:58:45 +0000 Subject: [PATCH 2/2] Cleanup --- machine/arm/stm32l4xx/interface/uart.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/machine/arm/stm32l4xx/interface/uart.c b/machine/arm/stm32l4xx/interface/uart.c index acf65d7..34e42f5 100644 --- a/machine/arm/stm32l4xx/interface/uart.c +++ b/machine/arm/stm32l4xx/interface/uart.c @@ -29,7 +29,7 @@ int write_debug_uart(const char *buf, int len) { if (HAL_UART_Transmit(&HDBG_UART, (uint8_t *)buf, len, 100) != HAL_OK) { return -1; } - return len; + return len; // Return number of bytes written } void HAL_UART_MspInit(UART_HandleTypeDef *huart) { @@ -40,7 +40,7 @@ void HAL_UART_MspInit(UART_HandleTypeDef *huart) { GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; if (huart->Instance == USART1) { - // TX: PA9 (AF7), RX: PA10 (AF7) — Nucleo CN12 pins 21, 33 + // TX: PA9 (AF7), RX: PA10 (AF7) PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1; PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) return; @@ -51,7 +51,7 @@ void HAL_UART_MspInit(UART_HandleTypeDef *huart) { HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } else if (huart->Instance == USART2) { - // TX: PA2 (AF7), RX: PA3 (AF7) — Nucleo CN12 pins 35, 37 + // TX: PA2 (AF7), RX: PA3 (AF7) PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART2; PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) return; @@ -62,7 +62,7 @@ void HAL_UART_MspInit(UART_HandleTypeDef *huart) { HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } else if (huart->Instance == USART3) { - // TX: PC10 (AF7), RX: PC11 (AF7) — Nucleo CN11 pins 1, 2 + // TX: PC10 (AF7), RX: PC11 (AF7) PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART3; PeriphClkInit.Usart3ClockSelection = RCC_USART3CLKSOURCE_PCLK1; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) return; @@ -73,8 +73,7 @@ void HAL_UART_MspInit(UART_HandleTypeDef *huart) { HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); } else if (huart->Instance == UART4) { - // TX: PA0 (AF8), RX: PA1 (AF8) — Nucleo CN11 pins 28, 30 - // Note: PA0 is also connected to user button B1 via SB197; cut SB197 to use UART4 TX + // TX: PA0 (AF8), RX: PA1 (AF8) PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_UART4; PeriphClkInit.Uart4ClockSelection = RCC_UART4CLKSOURCE_PCLK1; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) return; @@ -85,7 +84,7 @@ void HAL_UART_MspInit(UART_HandleTypeDef *huart) { HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } else if (huart->Instance == UART5) { - // TX: PC12 (AF8), RX: PD2 (AF8) — Nucleo CN11 pins 3, 4 + // TX: PC12 (AF8), RX: PD2 (AF8) PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_UART5; PeriphClkInit.Uart5ClockSelection = RCC_UART5CLKSOURCE_PCLK1; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) return; @@ -99,9 +98,7 @@ void HAL_UART_MspInit(UART_HandleTypeDef *huart) { HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); } else if (huart->Instance == LPUART1) { - // TX: PG7 (AF8), RX: PG8 (AF8) — Nucleo CN12 pins 67, 66 - // Note: SB130/SB131 connect PG7/PG8 to the ST-LINK VCP by default; - // cut them to route LPUART1 to external pins instead. + // TX: PG7 (AF8), RX: PG8 (AF8) PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LPUART1; PeriphClkInit.Lpuart1ClockSelection = RCC_LPUART1CLKSOURCE_PCLK1; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) return;