Author Topic: uart echo code outputs alternate characters. What's wrong with the code?  (Read 4986 times)

0 Members and 1 Guest are viewing this topic.

Offline helpmeTopic starter

  • Newbie
  • Posts: 3
  • Country: hk
I am using stm32f0 MCU.

I would like to transmit every single byte received from the uart out of the uart. I am enabling an interrupt on every byte received from uart.

My code is quite simple.

uint8_t Rx_data[5];

Code: [Select]
//Interrupt callback routine
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart->Instance == USART1)  //current UART
    {
        HAL_UART_Transmit(&huart1, &Rx_data[0], 1, 100);       
        HAL_UART_Receive_IT(&huart1, Rx_data, 1);   //activate UART receive interrupt every time on receiving 1 byte
    }
}

My PC transmits ASCII 12345678 to stm32. If things work as expected, the PC should be receiving 12345678 back. However, the PC receives 1357 instead. What is wrong with the code?
 

Online rstofer

  • Super Contributor
  • ***
  • Posts: 9890
  • Country: us
From the code, I can't determine if the actual device driver waits for the transmit buffer to be empty before sending a char.  Same with the receive function.   Does it wait for a char to be received?  All that would come from the documentation of the HAL.

I really HATE the STM HAL.  I have no idea what those mysterious functions do and I have to go read yet another document to find out.

So, I stay away from the STM devices and use stuff from NXP where it is easy to play with the registers directly.  I am perfectly capable of writing a device driver without having to resort to someone else's HAL.

Let' assume the transmit function is blocking.  In this case, the function won't return until the char is loaded into an output buffer.  But what about the receive function.  If it isn't blocking, it will skip over the char still being clocked in and your code goes right back to the transmit function.  This type of situation occurs because there are buffers of at least 1 char in both the transmit and receive hardware.

You might try putting a small time delay between the transmit and receive functions.  Maybe 1 char worth of delay.  9600 baud is about 1 mS per char.

« Last Edit: May 19, 2016, 03:34:32 am by rstofer »
 

Offline obiwanjacobi

  • Frequent Contributor
  • **
  • Posts: 988
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Looks like its skipping every other character.
The HAL_UART_Receive_IT call looks weird. I don't know the HAL API but it just looks weird. What if that call removes one character...? That would explain it, wouldn't it?

[2c]
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
1) Chalk up another vote against HAL.  What convoluted code aimed at achieving ... I don't know what.  It certainly doesn't look like it would be much help in implementing the "standard" UART APIs that I'm used to (like a ring buffer.)  It sorta looks like the _IT (non-blocking, interrupt driven) functions are a copy of the DMA functions.  I guess that's OK, except that DMA is problematic for sporadic devices like UARTs, and I'd rather the DMA functions worked hard to duplicate the functionality of non-DMA functions.

2) In any case, using Receive_IT with a count of 1 seems like a bad idea; that means swapping buffer pointers around, disabling and enabling interrupts, and a bunch of other overhead for EVERY character received.

3) Calling the blocking Transmit() function from an ISR callback seems like a bad idea.  If the UART HW buffer is full, the transmit could end up taking a full character time (with rx interrupts turned off.)  I can't quite see how this would explain the behavior you're seeing for the test case you describe, but I can see similar things happening...

4) Normally I'd do echoing at user/process level (or perhaps "tty driver" level) rather than in the receive interrupt (or callback.)  Largely because of reentrancy issues (like (3)), but also because I'll normally want echoing to be smarter (visual rubout, not echoing control characters, etc.)  Since you're currently "reading" the characters just to echo them, I don't see how you'll be able to do something more useful with them as well.
 

Offline andersm

  • Super Contributor
  • ***
  • Posts: 1198
  • Country: fi
Is the transmit register double-buffered? If not, you're probably still transmitting the previous character when the next one arrives. Check the status of the TE bit before writing to the transmit register.

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Quote
My code is quite simple.

Is the transmission (to the mcu) continuous? if so, some form of collision detection is needed.

If the transmission is discontinuous - large gaps in between individual characters - the logic is likely slightly different from what you have:

Code: [Select]
  in RX isr:
    clear the flag - if it is not automatically done
    save the rx data to a buffer;
    transmit the buffer;  //only works if transmission has sufficient gaps in between data

To simplify it, you may want to receive / transmit on different uarts.
================================
https://dannyelectronics.wordpress.com/
 

Offline Tom45

  • Frequent Contributor
  • **
  • Posts: 556
  • Country: us
How are you sending and receiving the characters on the PC?

Perhaps there is an unintentional mixture of 8 bit characters and 16 bit double byte characters between the two systems.
 

Offline xygor

  • Regular Contributor
  • *
  • Posts: 227
  • Country: us
Parity error maybe?
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Quote
       HAL_UART_Transmit(&huart1, &Rx_data[0], 1, 100);       
       HAL_UART_Receive_IT(&huart1, Rx_data, 1);   //activate UART receive interrupt every time on receiving 1 byte

I'll not that both of these functions do return a status code.  Perhaps that should be looked at!
 

Offline helpmeTopic starter

  • Newbie
  • Posts: 3
  • Country: hk

Thanks for all the replies. I found the answer. The solution is to use "HAL_UART_Transmit(&huart1, &Rx_data[0], 1, 0);" such that the timeout is set to 0. For some reason, HAL_UART_Transmit() is taking too long when timeout was set to 100.
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
For some reason, HAL_UART_Transmit() is taking too long when timeout was set to 100.
Perhaps that's why they call it 'blocking mode'? ST's documentation is pathetic.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf