cancel
Showing results for 
Search instead for 
Did you mean: 

Configure STM32 U585 UART in single-wire half duplex mode

Neharika
Associate II

I am trying to configure the LPUART1 on STM32U585 in single-wire half duplex mode. As I understand, in half-duplex mode, only one pin is configured which is used to send and receive data. I need the half-duplex mode for self-test in my code letting me know that the hardware pin itself is operational. I do not want to use DMA or interrupts for transmit or receive. I am configuring the GPIO Pin as follows - 

I am only configuring PC1 as both the TX and RX pin.

 

 

    GPIO_HI (UART_PORT, IPC_UART_TX_PIN); //UART PORT = PORT C, IPC_UART_TX_PIN = Pin 1
    GPIO_SET_MODE (UART_PORT, IPC_UART_TX_PIN, GPIO_MODE_ALT_FUNC);
    GPIO_SET_OUT_TYPE (UART_PORT, IPC_UART_TX_PIN, GPIO_OTYPE_OPENDRAIN);
    GPIO_SET_SPEED (UART_PORT, IPC_UART_TX_PIN, GPIO_SPEED_LO__10MHZ);
    GPIO_SET_PULL_UPDN(UART_PORT, IPC_UART_TX_PIN, GPIO_PUPD_PULLUP);
    GPIO_SET_ALT_FUNC (UART_PORT, IPC_UART_TX_PIN, GPIO_AFN_LPUART1);

 

 

 I enable the half-duplex mode when doing self-test by doing the following - 

 

 

void enable_halfduplex(USART_TypeDef * p_uart_handle)
  {
      // Single-wire Half-duplex mode is selected by setting
      // the HDSEL bit in the LPUART_CR3 register.
      // disable usart controller.
      // this is needed for changes
      // to usart setting.

      p_uart_handle->CR1 &= ~(USART_CR1_UE);
      p_uart_handle->CR1 &= ~(USART_CR1_TE);
      p_uart_handle->CR1 &= ~(USART_CR1_RE);
      p_uart_handle->CR3 |= USART_CR3_HDSEL;

      // enable  usart controller.
      p_uart_handle->CR1 |= (USART_CR1_UE);
      p_uart_handle->CR1 |= (USART_CR1_TE);
      p_uart_handle->CR1 |= (USART_CR1_RE);    
      }

 

 

As I understand, HAL_HalfDuplex_EnableTrasmitter() and HAL_HalfDuplex_EnableReceiver() needs to be called everytime we transmit or receive data. I created my versions of these two functions since I am not using the HAL library - 

 

 

void uart_half_duplex_enable_transmitter(USART_TypeDef * p_uart_handle)
{
    p_uart_handle->CR1 &= ~(USART_CR1_UE);
    /* Clear TE and RE bits */
    p_uart_handle->CR1 &= ~((uint32_t)(USART_CR1_TE | USART_CR1_RE));
    
     p_uart_handle->CR1 |= (USART_CR1_UE);
    /* Enable the USART's transmit interface by setting the TE bit in the USART CR1 register */
     SET_BIT(p_uart_handle->CR1, USART_CR1_TE) ;
}

void uart_half_duplex_enable_receiver(USART_TypeDef * p_uart_handle)
{
    p_uart_handle->CR1 &= ~(USART_CR1_UE);
    
    /* Clear TE and RE bits */
    p_uart_handle->CR1 &= ~((uint32_t)(USART_CR1_TE | USART_CR1_RE));
    
    p_uart_handle->CR1 |= (USART_CR1_UE);
    
    /* Enable the USART's transmit interface by setting the TE bit in the USART CR1 register */
    SET_BIT(p_uart_handle->CR1, USART_CR1_RE) ;
}

 

 

I transmit and receive as follows- 

 

 

 int uart_tx(const uint8_t c, USART_TypeDef * p_uart_handle)
{
    uint32_t reg;
    do
    {
        reg = p_uart_handle->ISR;
    } while ((reg & USART_ISR_TXE) == 0);

    p_uart_handle->TDR = c;

    return 1;
}
int uart_rx(uint8_t *c, USART_TypeDef * p_uart_handle)
{
    volatile uint32_t reg = p_uart_handle->ISR;
    if ((reg & USART_ISR_RXNE) != 0)
    {
        reg = p_uart_handle->RDR;
        *c = (uint8_t)(reg & 0xFF);
        return 1;
    }
   
    return 0;
}  
void test_half_duplex(USART_TypeDef * p_uart_handle)
{
uint8_t tbuffer[] = USART_TEST_STRING;
for (chars = 0; chars < USART_TEST_STRING_SIZE; chars++)
    {
        uart_half_duplex_enable_transmitter(p_session->p_uart_handle);
        
        (void)uart_tx((uint8_t)tbuffer[chars], p_session->p_uart_handle);
        
        uart_half_duplex_enable_receiver(p_session->p_uart_handle);
        
        uart_rx(&rbuffer[chars], p_session->p_uart_handle);
    }
}

 

 

When I do this, I see the data being transmitted and see it in the TDR register but I never receive it in the RDR register. I am configuring the PC1 GPIO as in open drain and pull up mode? Is this pull-up sufficient for me to be able to receive the sent data or do I need to add an external pull-up? I am really confused as to why I cannot receive the sent data on the same pin. Any help in the right direction is really appreciated. Thank you!

 

6 REPLIES 6
TDK
Guru

An external pullup would be best, but if your baud rate is low enough, such as with 9600, the internal pullup can suffice.

Take a look at the reference manual to understand how single-wire mode works. You do not need to disable the transmitter/receiver every time to switch. In particular read "67.4.12 LPUART single-wire Half-duplex communication"

In your code, you are not waiting at all for characters to be able to come in. You check if they're there (which since you just sent a character, they won't be), and then you just return.

A logic analyzer on the line would be informative and would show if characters are being sent and received. I suspect that neither are happening since you disable the peripheral immediately after sending a byte, before it has a chance to be sent out on the line.

If you feel a post has answered your question, please click "Accept as Solution".

Hi Guru, thank you so much for your answer, it really helped a lot!!! I reduced the baud rate to 9600 and removed the calls to the following functions that was disabling the peripheral immediately - 

uart_half_duplex_enable_transmitter(p_session->p_uart_handle);
uart_half_duplex_enable_receiver(p_session->p_uart_handle);

 I can now see data in both TDR and RDR registers. However, there is another issue that I am facing. Let me try and explain the issue -

I have two processors, that communicate with each other over UART. They communicate with each other in full-duplex mode and everything works great. There are no issues there. 

 

However, I want to perform a self-test on each of the TX and RX pins of both the MCUs, to verify that they are operational and hence I want to put them in half-duplex mode and independently test them each. The weird thing that I see in half-duplex mode for STM32U585 Tx is that the co-processor(STM32L4) also receives whatever was sent by the STM32U585 Tx pin. When I send the string "test" in half-duplex mode on the STM32U585 Tx pin, I also receive "test" on the STM32L4 Rx pin. This is a normal behavior in full duplex mode and I am confused if this should be happening in the half-duplex mode as well. 

Neharika_0-1707773268277.png

Please help me understand if this behavior is expected. Your support is really appreciated!! Thank you so much!!

Best,

Neharika

 

TDK
Guru

> When I send the string "test" in half-duplex mode on the STM32U585 Tx pin, I also receive "test" on the STM32L4 Rx pin. This is a normal behavior in full duplex mode and I am confused if this should be happening in the half-duplex mode as well. 

If the STM32U585 TX pin is connected to the STM32L4 RX pin, of course the latter is going to receive the characters you send out.

The example is a little confusing. In half-duplex mode, only a single pin is used (the TX pin). In your figure, both the TX and RX pins are shown and are connected separately.

 

If you feel a post has answered your question, please click "Accept as Solution".
Neharika
Associate II

Sorry about the confusion. I just wanted to show that even if I have the STM32U585 TX pin(just one pin) configured in single-wire half-duplex mode, the physical connection b/w the STM32U585 TX pin and STM32L4 RX pin still exists.

> If the STM32U585 TX pin is connected to the STM32L4 RX pin, of course the latter is going to receive the characters you send out.

So this is true even when the STM32U585 TX pin is configured in single-wire half-duplex mode? I just want to make sure that the two co-processors are independent of each other in the half-duplex mode. 

Hope this was clearer.

Thanks,

Neharika

 

 

Pavel A.
Evangelist III

If both MCUs work in single wire mode, they both use TX pin, so TX of one connects to TX of the other. Note that you can swap TX and RX pins on one side by software, in USART_CR2 register bit 15, so you don't have to solder.

> So this is true even when the STM32U585 TX pin is configured in single-wire half-duplex mode? I just want to make sure that the two co-processors are independent of each other in the half-duplex mode. 

Yes.

It's not very clear why you need to test the pins in single wire mode, but yes it seems to be behaving as expected given that scenario.

If you feel a post has answered your question, please click "Accept as Solution".