简体   繁体   中英

UART to UART Bridge STM32

is there a simple way to "bridge" 2 U(S)ART Lines (USART1 & UART5 on STM32F107) by software?

I need to forward the data which are incoming at USART1 to the UART5 and reverse.

Current MCU is STM32F107VCT7

Main reason why I want to do that is to update a Device over UART which is connected to my MCU. The MCU is connected to PC.

PC --- STM32 --- Other Device

Could you just write the data the data to the appropriate usart registers? That is, if you have a byte come through on the usart1 line and it is stored in the usart1 data register, read it and write it to the usart5 data register and set the bit to let the chip know it is ready transfer the byte. Do the same for the usart5 to usart1 bridge.

If you are concerned about reading/writing multiple bytes consider adding transmit and receive buffers to handle this.

If we were to do a polling method, the code would look something like (note: I mainly deal with AVR so I may be off with my register names but the method should be along these lines):



// Check to see if data has been written to usart1 and transfer it usart5.
if(USART1_CR1&(1 << USART1_SR_RXNE))
{
    // May want to avoid race conditions, so disable interrupts.
    // Write the data in usart1 to usart5
    USART5_DR = USART1_DR;

    // Set the data ready bit on the usart5 control register.
    USART5_CR1 |= (1 << USART_SR_RXNE);
    // Enable interrupts.
}

I used this tutorial for STM32 language. Not the point about disabling interrupts. You may also want to write to a buffer.

Simply copying bytes from one UART to the other will not work.

If the sending side (PC serial adapter) is just by 0.1% faster than the MCU, it will start dropping bytes after the 1000th byte. The frequency accuracy of the STM32F107 internal clock is given as -1.1% to +1.8% at room temperature in the datasheet, so it might as well happen earlier, and the other two participants might not be perfectly accurate either.

Dropping bytes in the middle of a firmware update to an otherwise inaccessible part is not going to be funny.

You need circular (FIFO) buffers both ways

The size of the buffer is determined by the size of the data packets, and the sum of the frequency inaccuracies in the participating devices. Eg if there is 64 kB data in one block, and both devices have +/- 2% frequency accuracy, then you'd need at least 65536*0.04 ~ 2622 bytes buffer.

Do this in an endless loop,

  • check for RXNE in USART1->SR
  • if set, read the data from USART1->DR and put it at the head of the buffer (complain loudly if the buffer is full)
  • check for TXE in UART5->SR`
  • if set, AND the buffer is not empty, write the byte at the tail of the buffer into UART5->DR
  • do the same for the other direction

Simple both way communication method assuming the same speed of the both UARTs.

volatile uint8_t data[2];

void USART1_IRQHandler(void)
{
    if(USART1 -> SR & USART_SR_RXNE)
    {
        data[0] = USART1 -> DR;
        USART5 -> CR1 |= USART_CR1_TXEIE;
    }

    if( (USART1 -> CR1 & USART_CR_TXEIE) && (USART1 -> SR & USART_SR_TXE))
    {
        USART1 -> CR1 &= ~USART_CR1_TXEIE;
        USART1 -> DR = data[1];
    }
}

void USART5_IRQHandler(void)
{
    if(USART5 -> SR & USART_SR_RXNE)
    {
        data[1] = USART5 -> DR;
        USART1 -> CR1 |= USART_CR1_TXEIE;
    }

    if( (USART5 -> CR1 & USART_CR_TXEIE) && (USART5 -> SR & USART_SR_TXE))
    {
        USART5 -> CR1 &= ~USART_CR1_TXEIE;
        USART5 -> DR = data[0];
    }
}

I tried the answer from above with small changes:

/**
  * @brief This function handles USART1 global interrupt.
  */
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */

  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */
  if(USART1 -> SR & USART_SR_RXNE)
     {
         data[0] = USART1 -> DR;
         UART5 -> CR1 |= USART_CR1_TXEIE;
     }

     if( (USART1 -> CR1 & USART_CR1_TXEIE) && (USART1 -> SR & USART_SR_TXE))
     {
         USART1 -> CR1 &= ~USART_CR1_TXEIE;
         USART1 -> DR = data[1];
     }
  /* USER CODE END USART1_IRQn 1 */
}




/**
  * @brief This function handles UART5 global interrupt.
  */
void UART5_IRQHandler(void)
{
  /* USER CODE BEGIN UART5_IRQn 0 */

  /* USER CODE END UART5_IRQn 0 */
  HAL_UART_IRQHandler(&huart5);
  /* USER CODE BEGIN UART5_IRQn 1 */

  if(UART5 -> SR & USART_SR_RXNE)
     {
         data[1] = UART5 -> DR;
         USART1 -> CR1 |= USART_CR1_TXEIE;
     }

     if( (UART5 -> CR1 & USART_CR1_TXEIE) && (UART5 -> SR & USART_SR_TXE))
     {
         UART5 -> CR1 &= ~USART_CR1_TXEIE;
         UART5 -> DR = data[0];
     }

  /* USER CODE END UART5_IRQn 1 */
}

But no communication beween both UART Lines.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM