I tried to make single-wire half-duplex communication with a UART using the STM32F103C8 controller. In single-wire half-duplex communication, a TX pin is used for transmitting and receiving the data.

I had configured the pins and register with the help of a datasheet (reference manual for STM32F103C8). So I tried to transmit the data from one bluepill board (STM32F103C8) and to receive the data in another bluepill board (STM32F103C8). But I am not able to transmit and receive data. I have enclosed my code. Can anyone help me to solve it? I have used the register for the code.

Communication: USART3

Pins: PB10-TX

STM32 reference manual

enter image description here enter image description here

Here is my code for UART3 single-wire half-duplex communication


char receive;
void USART3_init(void)
    USART3->BRR = 0x0EA6;  //0x1D4C //0x0EA6
    USART3->CR1 |= USART_CR1_RE ;
    USART3->CR1 |= USART_CR1_TE ;
    USART3->CR1 |= USART_CR1_UE;
int main()
    GPIOB->CRH = 0x00000F00;
       USART3->DR = data;
       while (!(USART3->SR & (1<<6)));
  • \$\begingroup\$ Your code has no transmitting and no receiving statements. Please edit your question and add it. -- A while loop inside an ISR is most of the time plain wrong. \$\endgroup\$ Feb 2, 2023 at 6:42
  • \$\begingroup\$ @thebusybee thanks for the response while loop is to Wait for TC to SET. This indicates that the data has been transmitted \$\endgroup\$ Feb 2, 2023 at 7:40
  • \$\begingroup\$ GPIOB->CRH = 0x00000F00; - port is set in open-drain mode. Do you have externall pull-up resistor? \$\endgroup\$
    – Flexz
    Feb 2, 2023 at 8:10
  • 1
    \$\begingroup\$ Yeah, I know that you want to wait for the completion. However, this is not how interrupt-driven transmission is supposed to be used. Anyway, you change the code. -- How do you know that there is no transmission? Did you measure the line with an oscilloscope? -- There is still no receiving source. How do you know that there is no reception? -- You did not add a statement concerning the necessary pull-up resistor. \$\endgroup\$ Feb 2, 2023 at 9:38
  • 1
    \$\begingroup\$ Please add such important information to your question by editing. -- To be clear: Your logic analyzer does not show any transmission. Is this correct? What level does it show? -- "Open drain" is not a synonym for "pull-up". Actually, an open-drain output has no pull-up according to the reference manual. You need to provide an extra pull-up. Please add a resistor and repeat, post the result in the question as advised above. \$\endgroup\$ Feb 2, 2023 at 13:27

1 Answer 1


I was having a similar issue getting a USART single-wire half-duplex to work on a STM32 microcontroller using ST's Cube MX IDE.

I believe their IDE has a bug in it's code-generation for half-duplex support. I'm running version v1.2.0 from early 2020, so perhaps its fixed in newer versions, but this is how I got it to work.

What I'm sharing is the difference between going from (a working) full-duplex two-wire UART/USART to a 1-wire half-duplex. In this particular case, I got it working in "tx-only" instead of rx/tx. I'll share that difference below.

So this is how I'm configuring the pin in the "Device Configuration Tool":

enter image description here

And here is the other configuration for the peripheral:

enter image description here

Next, these are the code changes that you'll need to make to stm32l4xx_hal_msp.c. I found that the STM32 Cube MX tool completely removed the calls to HAL_GPIO_Init() in its generated code which is wrong.

So again, these are the changes I needed to make between a working full-duplex and my new half-duplex configuration in stm32l4xx_hal_msp.c. I found all the other generated code to be correct:

    @@ -557,7 +492,6 @@ void HAL_UART_MspInit(UART_HandleTypeDef* huart)
     /**USART2 GPIO Configuration
     PA2     ------> USART2_TX
-    PA15 (JTDI)     ------> USART2_RX
     GPIO_InitStruct.Pin = VCP_TX_Pin;
     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
@@ -566,13 +500,6 @@ void HAL_UART_MspInit(UART_HandleTypeDef* huart)
     GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
     HAL_GPIO_Init(VCP_TX_GPIO_Port, &GPIO_InitStruct);

-    GPIO_InitStruct.Pin = VCP_RX_Pin;
-    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
-    GPIO_InitStruct.Pull = GPIO_NOPULL;
-    GPIO_InitStruct.Alternate = GPIO_AF3_USART2;
-    HAL_GPIO_Init(VCP_RX_GPIO_Port, &GPIO_InitStruct);
   /* USER CODE BEGIN USART2_MspInit 1 */

   /* USER CODE END USART2_MspInit 1 */
@@ -600,7 +527,7 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
     PA2     ------> USART2_TX
     PA15 (JTDI)     ------> USART2_RX
+    HAL_GPIO_DeInit(GPIOA, VCP_TX_Pin);^M

   /* USER CODE BEGIN USART2_MspDeInit 1 */

And here is a graphical screenshot from gitk in case you prefer its presentation:

enter image description here


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.