2020-01-18 12:22 PM
Hello:
Problems with the USART1 receive call on this device. Or is it me? I hope not.
I have a serial decode option on my scope. I can see what I send out, and what comes back, every byte. This is my call to receive:
rxChar[50];
HAL_UART_Receive_IT(&huart1, (uint8_t*)rxChar, 16);
I call it before main to set it up, then in the handler HAL_UART_RxCpltCallback, it is called at the end of the handler
void HAL_UART_RxCpltCallback(UART_HandleTypeDef* uartHandle)
{
//...do stuff
HAL_UART_Receive_IT(&huart1, (uint8_t*)rxChar, 16);
}
After using HAL_UART_Transmit to send the byte string to the device, it responds back in about 10ms, with exactly 16 bytes. And the 16 bytes are correct, what I should get back, as confirmed on the scope serial decode. However, the HAL_UART_RxCpltCallback is behaving badly.
It is important to note that the device I am sending to may NOT respond to every request - it only responds if the device is active at that address. So, I have it set up that if I get no response in 100ms, I move on to the next query/transmit.
First, I set up the request to transmit at a known good address where it will respond. It receives back the 16 bytes, but the first 2 bytes are not correct, and not anything I see on the scope. It comes back with rxChar[0] = 0xFF, and rxChar[1] = 0x0.
Bytes 2 to 15 are correct, BUT: the last 2 bytes are missing! If I set my receive size to 18 in the call to HAL_UART_Receive_IT, run it again and then check bytes 16 and 17, the correct byes are there. So, even though my scope shows no trace of anything other than the exact correct byte data coming back, the UART handler feels otherwise.
After pushing reset on the development board, it will behave the same way and produce the same result every time. So it's consistently producing the same junk, not the random kind.
Now I try this.
I don't change the number of bytes on the call to HAL_UART_Receive_IT (leave at 18)
Instead of sending first to a known good address, I send to an address where I know I'll get no response. And I get back a string of "FF" and "0".
Next, I send to the know GOOD address, and this time it does not return good data, but rather, and bunch of random FF and 0. However - further up in the array - starting at around byte 16 - I see the correct preamble bytes. So odd. In summary, when the good address is sent first, the data is "semi-correct", and when the good address I sent second, the data is not correct. The devices never send back junk or bad bytes that I see on the scope.
I'm using IAR compiler, generating code with CubeMX (5.4). I thought I might try using LL instead of HAL. So, I set Cube up in advanced options to generate LL code for the UART, but when I try to compile, the copiler faults with: "Build error: Multiple tools write to the same file." A far and wide search with gewGul provided no solid answer on how to fix this odd error, and left me wondering if the nice folks at ST ever test their software produced by Cube for the target tool. Indeed, this is the kobayashi maru, a no-win scenario.
My questions:
Why is the UART (USART1) handler behaving badly? Why the 2 bytes of garbage that are definitely not seen on the scope?
How can I fix the compile error when using LL ? (no answer expected, this is really for ST)
Thanks - appreciate your help.
2020-01-18 01:49 PM
> I can see what I send out, and what comes back
Do you observe it *directly* on the Rx pin?
JW
2020-01-18 01:59 PM
Yes, on the NUCLEO-L433 board the scope is attached channel 1 pin to transmit(PA9) , channel 2 to receive (PA10)
2020-01-18 04:07 PM
Can anyone else think of something or anything as to what is going on?
2020-01-19 12:43 AM
Anything can go wrong with CubeMX and HAL. Use the register interface.
Set up / check GPIOA registers (alternate function, push-pull etc) for PA9 and PA10.
Remove every single HAL function call related to USART1 from your code, except the line where the RCC clock is enabled.
Initialize USART1
USART1->BRR = divisor;
USART1->CR1 =
USART_CR1_TE | // Transmitter enable
USART_CR1_RE | // receiver enable
USART_CR1_UE | // USART enable
0;
where divisor is the APB clock frequency divided by the baudrate.
Now you can use the UART, first without interrupts
while(1) {
uint32_t sr = USART1->SR;
if(sr & USART_SR_TXE) {
if(there is data to transmit)
USART1->TDR = data_to_transmit;
}
if(sr & USART_SR_RXNE) {
data_received = USART1->RDR;
// store received data
}
}
if that's working, enable USART_CR1_RXNEIE and move the receive code to the interrupt handler. See the USRAT functional description and register documentation in the reference manual.
2020-01-19 03:28 AM
I despise Cube/HAL myself, but this sounds to me more like a hardware problem.
Depending on type of oscilloscope, some "event" on Rx could be overlooked, if it is then succeeded by the genuine transfer after a sufficiently long time. Can you use please single-shot triggering on the scope and look again?
You appear to use some sort of a bus between master and slaves? Isn't there some - possibly unwanted - connection between Tx and Rx, on this bus? If you in software only transmit, isn't it some traffic on Rx as viewed on oscilloscope/doesn't appear something also in the Rx buffer?
On the Nucleo-433P board, according to UM2206, PA10 can be connected to the STLINK_RX (named confusingly as it's actually STLINK's TX - ST tried very incorrectly to bow to the novices who don't know that in UARTs the common usage/marking is to connect Rx to Tx), through SB32 - isn't it connected? Also, PA 10 can be connected to PA3, through SB75. Also, by default, it's present on two pins on the CN6 connector - can't there be some inadvertent short?
JW
2020-01-19 02:11 PM
jan, berendi1, thanks for the replies.
All jumpers seem correct for PA9/10 for USART1. According to table 10, SB32,Sb34, SB60, and SB73 are OFF. If you check the "By Default" notes, it indicates that "Communication between target STM32 and Arduino and ST morpho connector is enabled on USART1". In this case, everything appears OK.
The NUCLEO is connected to an outboard Sparkfun RS485 transceiver board, then that is tied to the device. Internally the device is bused, but there is no termination required at the interface point, because it's a "drop point", thus the RS485 and the scope presents a high impedance and should not be loading the bus. Internally the bus is terminated at the endpoints. However - I discovered that the scope seemed to be "loading" the Rx line going into the L433. It's an Agilent DSO, with a 10x probe. Very little possibility it can be this very expensive and new instrument, never seen this before. Since it's on the UART side of the RS485, I'd say it's the NUCLEO board. So, I would say there is something funky going on. I may need to cast the device onto a temporary proto board with an RS485 device to get a better feel for what's going on.
Also - I switched from IRQ to DMA. This helped. I set the DMA receive to the expected number of bytes. Since the response is invoked by a query, I can resend if the preamble bytes are incorrect (error) or check the CRC. If I don't get back the response for the HAL_UART_RxCpltCallback flag after 30ms, I reset and restart the UART. Unfortunately, the ugliness of HAL forces one to do things by brute force.
What floors me about HAL, is the follies of ST and how they deploy this silliness. They give you a tool - CubeMX - that they try to convince you to use as it makes your task so much easier (right, got that) That said, at the HW development stage of a project, it is a good and fast tool.
Then - they provide a bunch of examples that were NOT generated by CubeMX, rather, made by a line of monkey coders. And then they do not give you the CubeMX ".ioc" file. You really need to see how it was configured, see what they added to make the solution work, and that would give you some real meat and potatoes as to how the system works. So just how can we correlate back the examples to CubeMX. A bit of a joke for sure.