Forums

Two-wires RS485 single master multi slaves: how to define the receiving buffer

Started by pozz May 28, 2013
On Thu, 30 May 2013 23:59:38 +0200, pozz <pozzugno@gmail.com> wrote:

>Il 29/05/2013 09:02, upsidedown@downunder.com ha scritto: > > > > [...] > > >> If the slave address is corrupted producing an (incorrect) address >> match, the whole message will be processed, but any higher level >> routine would reject the message due to CRC error. > >Do you think it's better to discard a packet with a bad CRC or to answer >with a "bad CRC" message to the master? In the latter scenario, the >retransmission is speeded up (the master will not wait for the timeout), >but I'm in doubt if it is correct to answer to a corrupted packet (even >the destination address could be wrong). >
Unless you have a separate CRC for the header, responding to a message with overall CRC, could cause quite a lot of problems. If the master and slave(s) are out of synch for some reason, having a timeout is a good thing, during the silent period every device will end into a known state.
>Il 29/05/2013 09:02, upsidedown@downunder.com ha scritto: >My implementation uses an array buf[] to store the packet, starting from >buf[0]. The SLIP decoding is performed inside the ISR thanks to a >simple state machine. If the first byte of the packet (destination >address) matches the slave address, the remaining bytes of the packet >are saved in the buffer, otherwise they are discarded and the buffer >pointer reset. > >When the END character is received during reception of a packet for us, >the rx interrupt is disabled to let the CPU process it. After >transmitting the answer, the interrupt is enabled again and buffer >pointer reset. > >I have just one problem with this implementation: there are some >messages or destionation addresses (broadcast addresses) that doesn't >want any answer from the slaves. >The master could send a new packet just after a broadcast packet: >there's no need to wait for some time if no answer will be received. > >In this case my implementation doesn't work, because I stop receiving at >the end of the first packet until the CPU will process it. There's a >concrete risk some bytes of the second packet will be lost. > >One solution is to delay the transmission of a packet after one packet >that doesn't want an answer. I don't like this solution, the delay >depends on the speed of the slaves (if they are supercomputers or >smallish 8-bit microcontrollers). > >So I'm thinking to change my implementation and move from a simple >buffer/array to a more complex FIFO/array, without stopping anymore the >rx interrupt at the end of a packet for us (a second packet could appear >immediately after). However, this new approach brings other problems >with it. > >Now the packets are pushed in the FIFO one after the other, so I loose >the separation between them (remember that SLIP decoding is performed in >the ISR, because I have to check the destination address to discard >packets that are for other slaves). In other words, I loose the packet >length info. >One solution is to add a new byte at the beginning of the packet that is >the packet length in bytes. I don't like it, because I'm solving a >problem related to the physical layer modifying the upper MAC layer. >But it's just a philosophical argument.
How about using a ring buffer to store the decoded packet data (what you are calling your FIFO) but have a separate FIFO to carry the details for each received message - i.e. at the end of your RX ISR you push the last byte of the message into the 'data' ring buffer and then push {pointer, length} onto the 'control' FIFO. Of course, you will have to protect the ring buffer from overflow. --------------------------------------- Posted through http://www.EmbeddedRelated.com
In comp.arch.embedded,
pozz <pozzugno@gmail.com> wrote:
> > I have just one problem with this implementation: there are some > messages or destionation addresses (broadcast addresses) that doesn't > want any answer from the slaves. > The master could send a new packet just after a broadcast packet: > there's no need to wait for some time if no answer will be received. > > In this case my implementation doesn't work, because I stop receiving at > the end of the first packet until the CPU will process it. There's a > concrete risk some bytes of the second packet will be lost. > > One solution is to delay the transmission of a packet after one packet > that doesn't want an answer. I don't like this solution, the delay > depends on the speed of the slaves (if they are supercomputers or > smallish 8-bit microcontrollers). > > So I'm thinking to change my implementation and move from a simple > buffer/array to a more complex FIFO/array, without stopping anymore the > rx interrupt at the end of a packet for us (a second packet could appear > immediately after). However, this new approach brings other problems > with it. > > Now the packets are pushed in the FIFO one after the other, so I loose > the separation between them (remember that SLIP decoding is performed in > the ISR, because I have to check the destination address to discard > packets that are for other slaves). In other words, I loose the packet > length info. > One solution is to add a new byte at the beginning of the packet that is > the packet length in bytes. I don't like it, because I'm solving a > problem related to the physical layer modifying the upper MAC layer. > But it's just a philosophical argument. > > With this FIFO/array implementation, a single packet could be stored in > part at the end and in part at the beginning of the FIFO/array. So I > need a new array where to copy all the bytes of the packet in order, > starting from the first. The memory/RAM requirements increase respect > the buffer/array implementation. > > > Other suggestions?
Instead of inserting a length character in the buffer, you can build a FIFO of receive buffers, each with it's length and other info. If the processing is guaranteed to be shorter than the transmission time of the next message, a simple 'flip buffer' will work. Just have two receive buffers with an RxCount and 'ready' status. On reception of a complete and OK message, set the lenght, mark 'ready' and start filling the next buffer while your application processes the just received message. -- Stef (remove caps, dashes and .invalid from e-mail address to reply by mail) To generalize is to be an idiot. -- William Blake
On Thu, 30 May 2013 23:59:38 +0200, pozz <pozzugno@gmail.com> wrote:

>I have just one problem with this implementation: there are some >messages or destionation addresses (broadcast addresses) that doesn't >want any answer from the slaves. >The master could send a new packet just after a broadcast packet: >there's no need to wait for some time if no answer will be received. > >In this case my implementation doesn't work, because I stop receiving at >the end of the first packet until the CPU will process it. There's a >concrete risk some bytes of the second packet will be lost. > >One solution is to delay the transmission of a packet after one packet >that doesn't want an answer. I don't like this solution, the delay >depends on the speed of the slaves (if they are supercomputers or >smallish 8-bit microcontrollers).
What do you intend to use those broadcasts ? Of course it is nice for clock synchronization, but what else in practice ? For clock setting/synchronization, the master should cease communication for a while, in order to any buffered traffic has died out, then generate the time message from master clock. This message will then go immediately for transmission and can be handled immediately by the slaves at the frame (no messages in the FIFO), thus, there is a well defined time difference between the master and slave clocks and hence easily correctable. Sending an unspecified broadcast messages back to back is a bad idea, since even a device with large buffers but slow responses might overflow. For this reason, silent gaps should be added around broadcast frames. if you insist to use broadcasts with both fast and slow devices, instead of one broadcast address, Why not use several multicast addresses for slaves with small buffers, but fast processing time, one for small buffers with long processing time and one for huge buffers slow processing time etc. Anyway, I do not see the point of using the same protocol for short messages with short response times and big computer with large transfer requirements on the same RS-485 bus. It might be a better idea to let the big slaves communicate directly over ethernet and install some eth/RS485 converters for the smaller devices.
On 2013-05-30, pozz <pozzugno@gmail.com> wrote:
> Il 29/05/2013 09:02, upsidedown@downunder.com ha scritto: > > > > [...] > > >> If the slave address is corrupted producing an (incorrect) address >> match, the whole message will be processed, but any higher level >> routine would reject the message due to CRC error. > > Do you think it's better to discard a packet with a bad CRC or to answer > with a "bad CRC" message to the master? In the latter scenario, the > retransmission is speeded up (the master will not wait for the timeout), > but I'm in doubt if it is correct to answer to a corrupted packet (even > the destination address could be wrong).
If the CRC is bad, you don't know the address is valid. If you don't know the address is valid, how do you know which unit should respond? -- Grant Edwards grant.b.edwards Yow! Thousands of days of at civilians ... have produced gmail.com a ... feeling for the aesthetic modules --
On 05/30/13 21:59, pozz wrote:

> > Other suggestions?
I wrote code for a project (Traffic led signs) that used rs485, half duplex at 9600 bauds. The protocol had been designed years ago, used stx / etx frame delimiters and had a crc included to detect errors. It too was master slave and comms was only ever initiated by the master. It was fully interrupt driven with fifo buffers for both tx and rx. Each slave has a unique address, but there was also a broadcast facility, with no reply, for things like clear display, usually followed by round robin status enquiry to check all that all the slaves had received the broadcast. The low level code was classic lower half interrupt handler, with upper half called from the application code and fifo buffers in between. For portability, the lower layers were designed to be transparent to data. That is, everything received went into the fifo and the protocol decode handled by the layers above. There is a module with a set of functions to control the uarts and another module to do protocol decode etc, which is just a simple state machine. The top level calls functions in the fifo module that search for frame delimiters and if found, the frame is handed over to the protocol handler. There was no real time exec on this project, and the mainloop is a state machine that scans the two rs485 interfaces for traffic, then calls a command processor when a valid frame is received. While there is quite a bit of traffic on the interfaces, the frames are short and quite small buffers (512 bytes rx, less for tx) were found to be more than enough. There are up to 12 slave nodes in a system, so 11 out of 12 frames may be discarded by any slave, but the system had more than enough performance, even when output of display data was via software. Modern micros are very fast :-)... Regards, Chris