RS-Bus Software

There are two software versions:

  1. Version 2: an Arduino library
    This version runs on standard Arduino processors, such as the MEGA328 and MEGA2560, as wll as DIP-40 "mighty-core" processors, such as the MEGA8535, 16A, 32A, 164, 324 and 644.

  2. Version 1: C-code written before Arduino. This version runs only on MEGA8535, 16A, 32A, 164, 324 and 644 processors.

Version 1: the Arduino library

The RS-bus supports a maximum of 128 feedback addresses, numbered 1 to 128. The master polls all 128 addresses in a sequential order to ask if they have data to send. Per address 8 bits of feedback data can be send; individual feedback messages carry only 4 of these bits (a nibble), so 2 messages are needed to send all 8 bits. Note that this library supports multiple RS-bus addresses per decoder. For each address a separate RS-Bus connection should be established.

If no feedback module sends information, one complete polling cyclus takes 33,1 ms. On the other hand, if all feedback modules send information, one polling cyclus takes 33,1 + 128 * 1,875 = 273,1 ms. Since feedback modules can only send half of their data (one nibble) during one polling cyclus, roughly 550 ms may be needed to send 8 bits.

Used hardware and software:

  • INTx (an interrupt pin): used to receive RS-bus polling pulses from the command station

  • TXD/TXDx (the/an USART): used to send RS-bus messages to the command station

  • the Arduino micros() function

The RSbusHardware class

The RSbusHardware class initialises the USART for sending the RS-bus messages, and the Interrupt Service Routine (ISR) used for receiving the RS-bus pulses send by the master to poll each decoder if it has data to send. Most AVRs have a single USART, but the ATMega 162, 164 and 644 have two, while the 1280 and 2560 have four USARTs. By specifying the tx_pin, the choice which USART will be used is made implicitly.

  • attach()

Should be called at the start of the program to connect the TX pin to the USART and the RX pin to the RS-bus Interrupt Service Routine (ISR).

  • detach()

Should be called in case of a (soft)reset of the decoder, to stop the ISR

  • checkPolling()

Should be called as often as possible from the program's main loop. The RS-bus master sequentially polls each decoder. After all decoders have been polled, a new polling cyclus will start. checkPolling() maintains the polling status.

  • masterIsSynchronised

A flag maintained by checkPolling() and used by objects from the RSbusConnection class to determine if the start of the (first) polling cyclus has been detected and the master is ready to receive feedback data.

The RSbusConnection class

For each address this decoder will use, a dedicated RSbusConnection object should be created by the main program. To connect to the master station, each RSbusConnection object should start with sending all 8 feedback bits to the master. Since RS_bus messages carry only 4 bits of user data (a nibble), the 8 bits will be split in 4 low and 4 high bits and send in two consequetive messages.

  • address

The address used by this RS-bus connection object. Valid values are: 1..128

  • needConnect

A flag indicating to the user that a connection should be established to the master station. If this flag is set, the main program should react with calling send8bits(), to tell the master the value of all 8 feedback bits. Note that this flag may be ignored if we always use send8bits() and send all 8 feedback bits, and never use send4bits() for sending only part of our feedback bits.

  • type

A variable that specifies the type of decoder. The default value is Switch, but this may be changed to Feedback. Note that RS-bus messages do contain two bits to specify this decoder type, but there is no evidence that these bits are actually being used by the master. Therefore the "type" can be set via this library for completeness, but an incorrect value will (most likely) not lead to any negative effect.

  • send4bits()

Sends a single 4 bit message (nibble) to the master station. We have to specify whether the high or low order bits are being send. Note that the data will not immediately be send, but first be stored in an internal FIFO buffer until the address that belongs to this object is called by the master.

  • send8bits()

Sends two 4 bit messages (nibbles) to the master station. Note that the data will not immediately be send, but first be stored (as two nibbles) in an internal FIFO buffer until the address that belongs to this object is called by the master.

  • checkConnection()

Should be called as often as possible from the program's main loop. It maintains the connection logic and checks if data is waiting in the FIFO buffer. If data is waiting, it checks if the USART and RS-bus ISR are able to accept that data. The RS-bus ISR waits till its address is being polled by the master, and once it gets polled sends the RS-bus message (carrying 4 bits of feedback data) to the master.

Details

enum Decoder_t { Switch, Feedback };

enum Nibble_t { HighBits, LowBits };


class RSbusHardware {

public:

uint8_t masterIsSynchronised;

RSbusHardware();

void attach(int tx_pin, int rx_pin);

void detach(void);

void checkPolling(void);

}



class RSbusConnection {

public:

uint8_t address;

uint8_t needConnect;

Decoder_t type;


RSbusConnection();

void send4bits(Nibble_t nibble, uint8_t value);

void send8bits(uint8_t value);

void checkConnection(void);

}

Download

The software for this Arduino library can be downloaded from GitHub .

Version2: Traditional C-code

The software consist of two parts:

  • Layer 1, which is described in the file rs_bus_hardware.c.

  • Layer 2, which is described in the file rs_bus_messages.c (orrs_bus / rs_bus_port.c, depending on the decoder).

Layer 1 takes care of all physical layer aspects, as well as the access control. Layer 2 takes care of initialization and formatting of the data bytes.

Overall operation

The interaction between both layers is illustrated in the figure below (note: although the figure shows some names specific for the Emergency-stop decoder, all decoders use a similar set-up).

Diagram to show interaction between both RS-bus layers

The top-part of the figure shows the variables and (function) calls specific for connecting the decoder to the RS-bus; the bottom-part shows the variables and calls specific for sending data bytes over the RS-bus.

To connect, three variables are used: RS_Layer_1_active, RS_Layer_2_connected and T_Feedback.

  • The RS_Layer_1_active flag is set whenever the hardware detects a valid signal (transition) on the RS-bus. If there is no signal (transition) for a period longer than 4 msec, the RS_Layer_1_active flag is cleared. This flag is checked by layer 2 before initialization / data transmission.

  • The RS_Layer_2_connected flag is set by layer 2 after it has established a "connection" to the master station. Connection establishment basically means that the RS-bus slave (the decoder) has transmitted the low and high order nibbles in two consecutive data bytes. The flag is cleared by layer 1 after 200 ms of silence on the RS-bus.

  • The T_Feedback timer is incremented by layer 1 every ms. It can be used by layer 2 for various purposes, for example to read the actual switch positions once every 30 ms.

Also for sending data three variables are used: RS_bus_address, RS_data2send_flag and RS_data2send.

  • The RS_bus_address variable is set by layer 2 and derived from the switch address / CV value. It is used by layer 1 while counting the number of access control pulses.

  • The RS_data2send_flag is set by layer 2 after to indicate that is has a data byte waiting in the RS_data2send variable.

  • The RS_data2send variable holds the data byte to be transmitted over the RS-bus. The byte holds a feedback nibble, and was formatted by layer 2.

Layer 1 operation

An interrupt (INT0) is raised at every transition of the RS-bus. If the master is polling, such interrupt occurs every 200 micro-seconds. One complete polling cycle consists of 130 interrupts. At each interrupt, the RS_address_polled variable gets incremented by the INT0-ISR. Once all feedback modules are polled, the master is idle for 7 ms. Such waiting period allows all feedback modules to synchronize (which means, in our case, the RS_address_polled variable is reset to zero). To detect this idle timer, a timer of roughly 1 ms is running. The ISR of this timer maintains a counter (T_RS_Idle), which is reset (by the INT0-ISR) every time a transition is detected at the RS-bus. If the counter exceeds 4, we know the master station has been idle for more than 4 ms. The timer ISR sets, next to resetting the RS_address_polled variable, also theRS_Layer_1_active flag, to indicate a valid (or invalid) RS-bus signal is received. In addition, it increments the T_Feedback counter, which is used in rs_bus_port.c to determine the interval between successive feedback samples.

Feedback modules may send information back to the master once their address is called. The length of such information is 9 bits, and takes around 1,875 ms (4800 baud). During that period no RS-bus transitions will occur, which means that the T_RS_Idle counter will not be resetted. Therefore the length of the timing interval to detect if the master is idle, should be between 1,875 ms and 7 ms. A value of 4 ms therefore seems save.

To send information back to the master, the process that uses these basic RS-bus routines initializes the RS_bus_address variable, assembles the data byte (RS_data2send) and, once ready, sets the RS_data2send flag. Using a flag which the AVR can set within a single instruction, has as advantage that either all or none of the data will be send; it is not possible that the hardware starts sending data while the data byte is still being modified. The flag is tested, and the actual data transfer is performed, by the RS-bus ISR (INT0-ISR). By initiating the actual data transfer from within this ISR, we ensure that: 1) data is send immediately after the feedback module gets its turn, and 2) it is not possible that more than one byte is send per cycle.

Layer 2 operation

After the decoder is switched on, the init_RS routine within the layer 2 software has to first initialize the RS-bus hardware. The init_RS routine therefore first reads the address of this decoder from its EEPROM, and checks whether this address does not exceed the maximum RS-bus address (the maximum decoder address is 256, the maximum RS-bus address is 128). Since feedback decoders should not send feedback information of multiple switches in a single nibble, the skip_even_addresses flag can be set if needed, as well as a variable telling how often feedback data should be retransmitted (RS_tranmissions). Eventually the init_RS routine calls the layer 1 routines: init_rs_usart, init_rs_input_interrupt and init_timer2.

Every time the decoder's main software loop calls the send_RS routine, the RS_Layer_2_connected flag is checked to determine if the decoder should first connect to the master station. If that is the case, the RS_connect routine is called, which establishes the connection by sending the low and high order nibble in 2 consecutive cycles.

If feedback data is available, the send_RS routine calls the send_feedbacks routine, which fills in the four feedback bits (nibble). On its turn, the send_feedbacks routine calls the format_and_send_RS_data_nibble routine, to formats the data byte (RS_data2send) in accordance to the RS-bus specification (the parity, TT-bits, and nibble identifier).

Note that in case none of the feedback modules sends information, one complete polling cycle takes 33,1 ms. On the other hand, if all feedback modules send information, one polling cyclus takes 33,1 + 128 * 1,875 = 273,1 ms. Since feedback modules can only send half of their data (one nibble) during one polling cycle, roughly 550 ms are needed to send all changes.

Download

The software for the C-code can be downloaded via the RS-Bus downloads page.