Two-wires RS485 and the driver enable problem

I have a multi-drop two-wires RS485 bus. One node is the master and all the others are slaves. The master is the only node that is authorized to initiate a transmission, addressing one slave. The addressed slave usually answers to the master.

The bus is half-duplex, so every node disables the driver. Only THE node that transmits data on the bus enables the driver and disables it as soon as it can, just after the last byte. An interrupt (transmit complete) usually triggers when the last byte is totally shifted out, so the driver can be disabled immediately.

Of course, other interrupts can be triggered. What happens when interrupt X (whatever) triggers just before the "transmit complete" interrupt? The result is the ISR X is called, postponing the execution of "transmit complete" ISR. The RS485 driver will be disabled with a certain amount of delay. In the worst case, the driver could be disabled with a delay that is the sum of the duration of all ISRs that could trigger. [In this scenario, I think of ISRs that can't be interrupted by a higher priority interrupt.]

If a node on the bus is very fast and starts transmitting (the master) or answering (one slave) immediately after receving the last byte, but when the previous transmitting node is executing other ISRs, the final result is a corrupted transmission.

What is the solution? I think the only solution is to define, at the design time, a minimum interval between the receiving of the last byte from one node and the transmission of the first byte. This interval could be in the range of 100 microseconds and should be calibrated on the sum of duration of *all* ISRs of *all* nodes on the bus. It isn't a simple calculation.

Moreover, implementing a short "software" delay in the range of some microseconds isn't a simple task. An empty loop on a decreasing volatile variable is a solution, but the final delay isn't simple to calculate at the design time, and it could depend on the compiler, compiler settings, clock frequency and so on. Use an hw timer only for this pause?

How do you solve this problem?

[I know there are some microcontrollers that automatically (at the hw-level) toggle an output pin when the last byte is totally shifted out, but I'm not using one of the them and they aren't so common.]
Reply to
pozzugno
Loading thread data ...

pozzugno schreef op 13-Oct-14 1:58 PM:

The minimum delay that you calculated is just that: a minimum. Apart from performance, there no problem in waiting somewhat longer. IMO you must come up with two figures: the minimum respond time (determined by the maximum driver turn-off delay) and the maximum respond time (determined by the time you can afford to loose with the bus idling bewteen request and response).

As for the delay: My experience is that I need delays all over the place. One approach is to have a free-running 64 bit counter (which will roll over long after you are dead) and wait for it to exceed start+delay.

Wouter

Reply to
Wouter van Ooijen

Il 13/10/2014 14:29, Wouter van Ooijen ha scritto:

Ok, so you're confirming the solution is a delay.

I usually use this approach for longer delays (milliseconds or seconds), so I can increment the counter in a ISR that trigger every millisecond. I don't like to fire a trigger every 100us.

64-bit appears to me too wide. Everytime I need to read it and compare with the time, I have to disable interrupts.
Reply to
pozzugno

You don't have to use the sum of all ISR's on all nodes as your minimum time. You have to use the largest value of delay that could occur on any one of the nodes, which is certainly not the same thing.

If possible, you can make the "transmission complete" interrupt a high priority interrupt - if your microcontroller supports some sort of nested interrupt scheme, then this will greatly reduce the latency of the transmission complete interrupt and therefore the bus disable.

But the key point is that interrupt functions, or other areas of code during which interrupts are disabled, should be as short, fast and deterministic as possible. Don't do any "work" during interrupt functions - or if you do, re-enable global interrupts first. Then it makes little difference if an interrupt function is running when the "transmission complete" triggers because the function will be complete in a few microseconds.

Reply to
David Brown

Il 13/10/2014 14:47, David Brown ha scritto:

Yes, I wanted to write the same thing, but my English isn't very good.

I wanted to stress I have to *add all the ISRs execution time* that could trigger in a single slave and take the maximum value. One slave could use just a single interrupt, but another could use 10 interrupts (ADC, serial ports, I2C, timers, ...)

I'm using AVR8 and SAMD20 from Atmel. In AVR8 there is a "hard wired" priority scheme that can't be changed and the TXC (transmit complete interrupt) priority is very low. Anyway an ISR can't be never interrupted, even by a higher priority interrupt event (the priority is used only if there are more than one interrupt requests at the same time).

I know, I know.

Someone considers the practice to enable interrupts inside an ISR as The Devil :-)

formatting link

Reply to
pozzugno

Yes, the best solution is to make it happen in hardware, but I understand it isn't always available.

As you commented, the key is to define the maximum period after transmission is complete that a unit is allowed to drive the line, and thus the minimum time another unit must wait to respond.

By defining a maximum time that a unit can drive the bus, you have now introduced a "Hard Real Time" requirement to the system. That normally means that you need to be careful what is done in interrupt routines, so no interrupt can mask off other interrupts for an extended time.

A second question is how much data is being sent and how fast do responses need to be. It may be possible to define the minimum reply delay long enough that you don't really need to worry about "small" delays in the transmitter.

A third question is can the protocol be made "fail-safe" so that if on an occasional unlucky combination of delays, and the beginning of the response is garbled by a slow disable, that the system can detect this and cause a retransmission (This is often good to handle other types of errors too), or otherwise tolerate an occasional missing response. In this case you just need to make sure that the responding unit takes long enough to build its response (maybe with an added delay to make sure) for the transmitter to normally get off the bus. Unless you have vastly differing speed of units, this often will just happen to be true as the receiving unit, especially if set to verify the "stop bit", won't begin to parse the message which is normally a longer task than the sending units "shut off the driver" operation.

Reply to
Richard Damon

pozzugno schreef op 13-Oct-14 2:38 PM:

With a 64 bit counter that ticks at 1 ns you have a rollover after 585 years, so you can use it for all delays. If you don't have a hardware 64 bit counter you can use a 32 bit counter + rollover interrupt.

If you don't want to disable interrupts:

h1 = read_high(); l1 = read_low(); h2 = read_high(); l2 = read_low(); if h1 == h2 return ( h1, l1 ) else return ( h2, l2 )

This makes the reasonable assumption that only one carry from low to high can occur during the execution of this code fragment.

Wouter van Ooijen

Reply to
Wouter van Ooijen

No, you only have to include the ISR's that could occur during that time

- not all the ISR's in your system. That means you either have to know which ones might occur (for example, you may be confident that I2C interrupts could not happen at that point, and therefore discount them), or you may perhaps choose to disable some of them temporarily on the transmission of the last character, and re-enable them within the transmission complete ISR.

You also have to consider things from a point of view of the chance of something going wrong, and the consequences of that error. In most communication systems, you already have a method of checking telegram correctness (CRC, checksum, etc.) and of re-trying in the case of error. Suppose - through calculation or testing - you figure out that a latency of more than 20 us occurs one telegram out of 10000. Then if your bus-turnaround delay is set to 20 us, then one out of every 10000 replies could be lost or corrupted. If that is within the level of acceptable error rates, a 20 us delay is good enough.

(Note that you will not damage your drivers by having two drivers enabled at the same time - decent RS-485 drivers have protection against that.)

Of course, it is highly application-dependent whether such a statistical test is good enough - it is likely to be fine for a temperature measurement system, but frowned upon for a car brake control.

The "priorities" here are of minor relevance, since they only affect which interrupt vector is used on simultaneous interrupts. The point is that you don't have a microcontroller that supports nested interrupts (other than by simply re-enabling global interrupts).

Apply that principle seriously, and you should not have a problem here.

Also avoid using interrupts unnecessarily. It is often tempting to have lots of interrupts on SPI, I2C, ADC, etc., when they are actually unnecessary - and may be slower than a simple polling loop.

People always have opinions and their own ideas of general rules. In embedded development, general rules are often wrong - there are always exceptions.

You do have to be careful about re-enabling interrupts inside an ISR, however. A typical usage is for a long-running ISR on a timer interrupt. First, acknowledge the timer interrupt. Then disable the timer interrupt to avoid recursion, then re-enable global interrupts. Reverse the process at the end of the timer ISR. But be even more careful than usual about shared data and race conditions!

Reply to
David Brown

You can skip the second read of the "low"; if the highs differ, you can assume the low takes on the value *at* rollover (depends on down count vs. up count).

E.g., if counter increments (decimal):

X 90 X 91

Reply to
Don Y

Correct. But that requires a little more knowledge of the hardware. Which you will need anyway if it is about up versus down counting.

But the main point was that you don't have to disable interrupts if you don't want to. An IIRC disabling interrupts doesn't help much.

Wouter

Reply to
Wouter van Ooijen

If you can't use hardware to control the driver enable signal, then perhaps you can use hardware to control your time out. Rather than worry about software reading timers and messing with your interrupt priorities, etc... use the UART as a timer to delay the first enabled character being transmitted.

Before a device transmits on the bus, send a character to the UART without enabling the RS-485 driver. Wait for the transmitter shift register to be empty ("transmit complete" by your terminology). Then enable the bus driver and start sending the packet data. This will provide 1 character transmission time delay.

You still need to calculate the worst case delay needed. If it turns out to be longer than 1 character transmission time then you may need to pad with more than 1 dummy character.

--

Rick
Reply to
rickman

Il 13/10/2014 15:28, Wouter van Ooijen ha scritto:

On 8-bit microcontrollers, it's difficult to have a 32 bit counter :-)

Again, you are supposing you have a 32-bits hardware counter available.

Even if I don't have 32-bits hardware counters, thank you for sharing this approach.

Reply to
pozzugno

Correct. Disabling interrupts *forces* an atomic operation -- when there often isn't the need for one. E.g., in this case, you are trying to emulate two *concurrent* reads (Hi,Lo). As long as the result that you get "makes sense" given the approach you've taken for implementation, it's (almost) as good as any other!

[E.g., (X,99) and (Y,00) are different from each other, but more correct than, for example, (Y,17)]
Reply to
Don Y

Il 13/10/2014 16:53, rickman ha scritto:

Good suggestion to avoid using another hardware peripheral for implementing the delay. Thank you.

Reply to
pozzugno

No, what you are most concerned with is ensuring every ISR manages to terminate before it can be reinvoked.

So, ISR1 can be interrupted by ISR3 which can be interrupted by ISR7 which can be interrupted by ISR2, etc. AS LONG AS ISR1 can't reassert itself while ANY instance of ISR1 is still "active".

(Ditto for every ISR in the system)

Even this "rule" can be bent -- if you know the worst case nesting of ISR's on themselves (and ensure you have adequate stack to cover that level of penetration)

Reply to
Don Y

All you need is a wide enough counter to span the maximum delay you want to measure "comfortably". You need to design such that your "most sluggish" activity happens often enough to be captured in one counter rollover period (i.e., counter can't roll over more than once between observations)

Reply to
Don Y
[bus acquisition in the face of possible contention]

First, you need to *know* that it is *you* that has been granted access to the bus/resource. If this requires you to perform some analysis of the ENTIRE MESSAGE (to verify that the "address field" is, in fact, intact!), then you probably DON'T want to try to ride the coat-tails of the message, directly.

As the front end of a message (including yours) is more likely to be corrupted (by a collision on the bus -- someone jabbering too long or too soon), you might consider designing a packet format that has one checksum on the address field "early" in the packet (before the payload) and another that handles the balance of the message.

This allows you to capture the address information and it's closely following checksum, verify that it is *you* that are being addressed and prepare for your acquisition of the bus before the message has completely arrived.

You can also arrange to access the bus in "timeslots" referenced to some easily recognizable event (e.g., a beacon sent by the master). So, you do all of your timing off of that single event (see "some special point" in the beacon, start timer, wait to transmit until "your slot").

Note this also works if you just assume the "next slot" after the master's message is the slot you should use (you just limit the length of the master's message so it fits in that fixed delay). Similarly, the master can "know" that your reply will never exceed a fixed duration so it won't issue another beacon/request until that has expired.

Hopefully, this makes sense. Sorry, I'm off for a pro bono day so no time here... :-/

Reply to
Don Y

... so that you don't erroneously acquire the bus only to discover that it was intended for someone else (and you've just made things worse)

Reply to
Don Y

Or put a some disposable preamble bytes on the front of messages. This is pretty common when using half-duplex modems: the padding bytes give the modems time to "turn-around" and get carrier established, PLLs locked, etc.

--
Grant Edwards               grant.b.edwards        Yow! Here I am in the 
                                  at               POSTERIOR OLFACTORY LOBULE 
 Click to see the full signature
Reply to
Grant Edwards

pozzugno schreef op 13-Oct-14 4:59 PM:

You can use the same technique, but with a 16-bit counter and some more bytes updated by the overflow ISR. The 8-bittters I know have 16-bit counters with a mechanism to do an atomic 16-bit read. The total number of bits you need depends on the resolution and the required run time of the application.

But at least on the 8-bitters I know (PIC 12 and 14 bit cores) instruction timing is totally predictable, so it is easy to make a busy delay subroutine that is accurate.

Wouter van Ooijen

Reply to
Wouter van Ooijen

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.