How to download a file through a RS485 link
Started by 6 years ago●13 replies●latest reply 6 years ago●1743 viewsHello,
I need to download a file on an STM32 through a half-duplex RS485 link. For the moment, it is using modbus (slave) to talk with a PC, and it is working fine.
As modbus is not really efficient to transfer big amont of data, I planned to stop modbus when I need to download a file, and use Ymodem instead.
But when I try to send simple ASCII characters to my hyperterminal, most of the time I do not get what I expected, and sometimes, for an obscure reason, it is working fine.
I compared the data I receive on my computer to the ones I send on my board, and there is no obvious link between them, like bit shift or LSB first/ MSB first inversion.
I also tried to send a simple file from my computer with Ymodem protocol, but my board was unable to recognize the starting sequence.
I do not understand where I am going wrong.
Any help? Thanks a lot in advance
Since you didn't state your exact MCU, here are some general suggestions:
- 1. Figure out what's going on with the unexpected characters (if you can't send simple ASCII characters, there's absolutely no hope to put a protocol on top)
- double check your UART isn't configured for one of the "addressed modes", which effectively requires a 9th bit with rules around using it (not widely supported on the PC side)
- There's a fairly lengthy thread here about "9it RS485": https://www.embeddedrelated.com/showthread/comp.ar...
- if your modbus implementation requires the uart to decode a 9th bit to signal addressing, you'll want to modify the UART peripheral configuration before/after receiving the file
- double check your UART isn't configured for one of the "addressed modes", which effectively requires a 9th bit with rules around using it (not widely supported on the PC side)
- If you haven't already, check out this example from ST which implements YMODEM over UART:
- https://www.st.com/en/embedded-software/stsw-stm32...
- NOTE: Current versions of TeraTerm don't seem to implement YMODEM is a way that is compatible with this code, try using an older version like 4.79
luckily I am using an 8-bits modbus protocol :-) I am using the ST code your are mentionning to implement Ymodem on my board, and ExtraPutty to transfer the file. I am using a STM32F407
If it ever works fine, the problem is going to be flow control and/or timing. I'd also try to get it to full duplex. But for big data block transfers, half duplex isn't a hinderance. Check both ends for handshaking of lines like RTS / CTS and DTR / DSR / CD. It can also be in the datastream (xon / xoff), but that pretty much requires full duplex.
Check Wikipedia on "serial communication flow control". Hope your protocol was written properly with flow control supported. If not (seen it) you May be able to add it, or you have to approximate it through block size and timing. A dual trace o'scope or a data line analyzer is nearly required to do this well. It can be done without, but a Lot of baby steps and guessing is involved.
Seems like there is no flow control on my board, as I have only 2 wires connected to my computer :-(
If possible connect a scope to your system so you can see what is going on. If it's half duplex you need to be sure that the tx/tx directions of the driver chips are being set correctly.
MK
Thank you every one for your replies.
I succeeded to make the ASCII sending from my board work every time :-) The problem was due to the fact that I short-circuited UART configuration while short-circuiting modbus, so I was not using the right baudrate.
Now I need to understand why my board is only receiving 0x80 when I try a file transfer...
Silly question: If you can compile and load code onto your board, why are you trying to download a file? Why not just compile the info as needed and load it to your board?
Because during product's life, we will have to remotely update our firmware. So we need a bootloader
Hello everyone,
Next step in my adventures ;-)
Now I manage to get the first Ymodem packet (the one with the name and size of the file). But when my computer send the second one, my board sees it corrupted (CRC error).
I looked at the packet arriving at the input of my board thanks to a serial sniffer. Data is OK. But when I look at the data received by my UART, I see that bytes 144 to 147 are systematically replaced by a repeated 16-bit pattern (e.g: 0x0C 0F 0C 0F). This pattern can change between two transmissions of the same file, but always takes place in bytes 144 to 147.
I also checked the pin giving the tx direction on my board with an oscilloscope. It is set to "receive" mode during the whole transmission.
Any idea of what is going wrong? Thanks a lot in advance
PS: I also switched from ExtraPuTTy to the TeraTerm version advised by bamos to send my file
Hi,
I looked at the reception buffer I am filling in my UART Rx interrupt: data is OK in it. So the problem is happening when I am copying these data to another table in my application with the simpliest instruction:
for(i = 0; i < PACKET_SIZE; i++)
{
data[i] = Buffer[i];
}
I looked at assembly code generated by my compiler. I do not see what couldd go wrong, especially because these instructions are repeated many times, but only for this particular set of bytes, it is going wrong...
The only hypothesis that I can make is that there is a hardware bug in my microcontroller. What do you think about it?
This sounds like a software bug to me, there are no known STM32 UART flaws known to me, except that you could run into issues with modbus timing due to too high system latencies (avoided easily, when you have a hardware RS485 support).
When you copy a block in 'user space' (not inside the IRQ handler): Think of this: what happens, if an IRQ gets in between?
The best way to avoid this is:
- Design a proper FIFO queue (ring or ping-pong-buffer)
- Make sure all your FIFO head/tail variables are accessed atomically
Also: avoid copying as far as possible, push the data inside the IRQ handler where it's needed or use DMA mode.
This can all be done on the STM32 without IRQ disabling (bad practise), if I recall right.
Hi srtubi,
I removed all the modbus protocol from my code, and the problem is still there. The only way I found to remove it was to use a local table to copy data from my reception buffer instead of a pointer passed as a parameter of my user function. Then I copy data to my pointer as soon as all of them are received.
I also looked at the assembly code of my copy, all loads/stores are done atomically, so there is no risk of data corruption if an interrupt happens during it.
Hi Aina,
hard to say what's going wrong when not seeing the exact code, but: your copy loop (which is outside the IRQ handler, right?) can be interrupted. So your data buffer might be overwritten from the IRQ handler while 'user space' is copying it. You could bracket it by DISABLE_IRQ()/ENABLE_IRQ() statements (substitute by your arch-specific IRQ macros), but that's not good practise, esp. when you rely on precise timer interrupts/timing.