uart echo code outputs alternate characters. What's wrong with the code? - Page 1
Forum section: electronics / general

author: helpme
author_rank: Newbie
timestamp: May 19, 2016, 02:04:06 am
content: 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;Code://Interrupt callback routinevoid HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){if (huart->Instance == USART1) //current UART{HAL_UART_Transmit(&huart1, &Rx_data, 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?

author: rstofer
author_rank: Super Contributor
timestamp: May 19, 2016, 03:31:20 am
content: 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.

author: obiwanjacobi
author_rank: Super Contributor
timestamp: May 19, 2016, 04:33:01 pm
content: 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?

author: westfw
author_rank: Super Contributor
timestamp: May 20, 2016, 12:43:08 am
content: 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.

author: andersm
author_rank: Super Contributor
timestamp: May 20, 2016, 02:38:44 pm
content: 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.

author: dannyf
author_rank: Super Contributor
timestamp: May 20, 2016, 02:54:50 pm
content: QuoteIs 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:in RX isr:clear the flag - if it is not automatically donesave the rx data to a buffer;transmit the buffer; //only works if transmission has sufficient gaps in between dataTo simplify it, you may want to receive / transmit on different uarts.

author: Tom45
author_rank: Frequent Contributor
timestamp: May 20, 2016, 03:37:29 pm
content: 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.

author: xygor
author_rank: Regular Contributor
timestamp: May 20, 2016, 04:55:56 pm
content: Parity error maybe?

author: westfw
author_rank: Super Contributor
timestamp: May 21, 2016, 12:37:37 am
content: QuoteI'll not that both of these functions do return a status code. Perhaps that should be looked at!

author: helpme
author_rank: Newbie
timestamp: May 25, 2016, 03:05:21 am
content: Thanks for all the replies. I found the answer. The solution is to use "HAL_UART_Transmit(&huart1, &Rx_data, 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.

author: Bruce Abbott
author_rank: Frequent Contributor
timestamp: May 25, 2016, 05:46:45 pm
content: Quote from: helpme on May 25, 2016, 03:05:21 amPerhaps that's why they call it 'blocking mode'? ST's documentation is pathetic.