0

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

I need to forward the data incoming on USART1 to UART5 and back.

Current MCU is STM32F107VCT7.

The main reason I want to do that is to update a device over UART, which is connected to my MCU. The MCU is connected to a PC.

PC --- STM32 --- Other Device

dda
  • 6,030
  • 2
  • 25
  • 34
guenthernagel
  • 73
  • 1
  • 3
  • 14

3 Answers3

2

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. E.g. 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
  • Thanks. I feared that the simple copy dont work at all. Will check with the circular buffer, i read about it before. – guenthernagel Jun 22 '19 at 10:11
  • @berendi No if there are gaps (more than 1 char) between those 1000 bytes. Then the counter starts from the begining – 0___________ Jun 22 '19 at 12:36
  • @P__J__ With +/- 2% HSI accuracy at both ends, it could break down at the 25th byte – followed Monica to Codidact Jun 22 '19 at 14:45
  • Depending on the stm32 model and even for some silicon version. Some of the uarts compensate the clock deviations. For example f303 on internal clock just tested 1M speed DMA circular random data from flash. No errors after 4 hours – 0___________ Jun 22 '19 at 14:51
  • @P__J__ That's exactly the problem here. The receiving UART would tolerate speed deviations up to 5%, but the other one won't transmit the data any faster than the programmed baudrate. Buffers would be filled up, fast. – followed Monica to Codidact Jun 22 '19 at 19:19
  • 1
    @guenthernagel If you can have either hardware or XON/XOFF flow control, a simple copy will work. – tonypdmtr Jun 22 '19 at 23:05
1

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.

  • @guenthernagel I added a snippet of what I would expect it to be like. – Matthew Robinson Jun 21 '19 at 00:09
  • Tried but the registers dont match. In the tutorial you refered they use the same. I use HAL_Libray for communicate with USART. Any Ideas how to adopt? – guenthernagel Jun 21 '19 at 14:11
  • To learn how to communicate from the PC to the STM and back, simply write a test program for the STM and check it with some terminal emulator on the PC side. If you have done this, you know how to use your library, and you can implement the other channel. The main part of your "transport" is then quite simple. – the busybee Jun 21 '19 at 16:31
  • @MatthewRobinson do not use this tutorial. What is `USART5_DR` ? Use modern CMSIS definitions, BTW article is very very poor. – 0___________ Jun 22 '19 at 12:38
0

Here's a simple two-way communication method, assuming the same speed of 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];
    }
}
dda
  • 6,030
  • 2
  • 25
  • 34
0___________
  • 60,014
  • 4
  • 34
  • 74