How are the different modules going to communicate with each other?
To make a modular sequencing system, I need to communicate several electronic devices, in such a way that real-time events can propagate fast throughout some, or many modules, while each module produce transformations to these signals. As we are speaking about communications, we will now refer a module (or music performance interface) as node. Nodes are the pseudonym for the units that run a program that lets them participate in the bus, and have the user interaction interface.
Communication between nodes in a network is very complex because of all the factors that are involved. The design and interaction of the product is also compromised in the mode of communication between nodes. As an example, if the network is point to point, then the expected interaction of the user involves patching the modules in the same way as modules are patched in an Eurorack system, mechanically. Otherwise, in a common bus network for instance, the user would be expected to virtually patch modules, as they are all already fully connected from the start.
The main challenge here is to create an algorithm to prevent data collision. Data collision is when two nodes need to send a message at the same time. A bus can’t support more than one message at a given time, and a microcontroller can’t (or has a limited capacity to) listen to more than one incoming message. This is similar to spoken communications, where we cant listen to more than one person speaking to us at the same time.
The main problems of concern are:
The idea of the point-to-point network is that each node is only aware of those nodes whose inputs are connected to it. Daily life examples of this could be neurons, manufacture and distribution chains, or the postal service. Other example is the software PureData.
It became unviable in front of the realization that a unit may need to receive signals from more than just one unit, while this protocol is intended for one to one communications only. Albeit the AtMega 2560, has four RS232 pair of pins, it would either constrain the extendability of the protocol or require a lot of hardware implementation. It also has the problem that it would require one dedicated socket for each input or output, limiting these to only four, including the possible MIDI input and output.
Is an idea of a multiplexed Rs232; where a RX pin would be connected sequentially to different multiplexor pins, theoretically allowing any quantity of outputs to a single port. This idea could theoretically work if the system has other, parallel multiplexor that distributes to the sending devices, an electric flag granting permission to transmit, as a consequence of the multiplexor being connected. I discarded this plan because it appeared another idea that would require less hardware than this.
A shared bus network consists of a single bus to which all nodes communicate. Daily life examples for this type of network are spoken conversations between more than two, an internet group chat, and the system in cars that check whether every component is working well.
Two advantages of a shared bus network are the ability to monitor the whole network by monitoring a single wire, and the possibility of optimizing the flow of events for lower latency. There are two drawbacks: one is that each node gets a portion of the bandwidth that is in inverse proportion to the amount of nodes in the network (whereas for the case of distributed, each network has a different bandwidth). The other drawback is that we loose the physical interaction of plugging and unplugging terminals manually.
Was a good candidate; it was tested by making a random pattern generator that outputs midi. To try that the bandwidth of the network is enough, I sent 24 clocks per step to the random step generator, and evaluated how much stutter and how much the common bus gets saturated from this. The conclusion was that one module can clock the other module with rates as high as 100 clocks per step, for a musical speed of 120 BPM without any noticeable stutter or latency. The problem was that 24 clocks per quarter note were already occupying the bus for most of the time; and so I couldn’t expect to be able to connect many more modules to the bus and have them sending too much information to the others. I2C would pose a low limit on the amount of modules that can be integrated to the network, and would put a low limit on how much information these modules could share. Other big problem with I2c is that there is no slave to slave communication. All data transfer needs to be actively mediated by the master, which introduces double processor use and double overhead on most device communications. To solve this, each module would need to have two active Wire objects, and operate as a point-to-point network.
RS484 is not a protocol in itself, but a standard, meaning that within this standard there are many different networking options. Most of these options are described here (https://users.ece.cmu.edu/~koopman/protsrvy/protsrvy.html). This standard suggested me that maybe I could use the Rs232 terminals in such a way, that would allow using Rs232 for a common bus protocol. This protocol could then be easily translated into the Rs484 standard if needed.
I set out to create this protocol, which I will name TBHN. The concept is the same as in a token ring, only that in this case, there is a token line, and to there is a module in charge of restarting the token every time it reaches the end.
This should allow us to make such a network that:
To achieve this, the approach is a hybrid between Token ring and master-bus polling. Token is a signal that is passed from one node to another, sequentially. The concept requires that there is only one token running for the network.
-----\ /---------------\ /---------------\ /----------> \ / \ / \ / |-TI-----TO---| |-TI-----TO---| |-TI-----TO---| | node | | node | | node | |-----COM-----| |-----COM-----| |-----COM-----| | | | -----------|-----------bus-----------|-------------------------|--------------> <-- "left or previous" "right or next"-->
TI is input with internal pull-up, and the logic is direct (not inverse) meaning that it defaults to 1
For easier commenting, in the code, modules are said to be on the left or right. This corresponds to the hierarchical connection of the ti/to. A module on the left is the one whose TOP is connected to the node’s TIP in question. A node on the right, (also refered as the next node) is the one whose TIP is connected to the node’s TOP in question.
TBHN should allow theoretically 100 messages per second, from each module in a network where there are three modules. In that case, the latency “downstream” is very low, and “upstream” is ~10ms. There is a chance I can implement a “end of line message” where the last node detects no following node, and communicates this to the bus, making the master react instantly without waiting a timeout.
To develop the protocol, I needed to follow incremental steps. Otherwise it becomes too difficult to spot the source of a problem.
Set up three arduinos, all connected to the same bus. Test that it is possible to address each individual arduino in the network by a hard coded address, and that the arduino can respond with his own ID plus a string. This is proves that there is a network, and there can be communications through it.
The arduinos are tied with the TI and TO connections. One single arduino is set to reflect in the serial all the signals that happen in the common bus. After the automatic address assignation, the arduino that is connected to the serial should be able to address individually each arduino as in the previous step
The arduinos should start their activity without input from the node that is connected to the serial. The message length is fixed. The activity can be seen in the serial output of one of the nodes.
This effect was granted automatically, because the continuity is given by the physical cable between nodes, thus removing a node becomes a complete removal from the network. Anyhow, there was a bug where newly connected nodes would assume an address 0 instantly and started creating new tokens that destroyed the network reliability. This bug seems to happen in many different cases, and they are being found and addressed one by one.
One change that I discovered that I should make to the protocol, is that the header byte goes before and not after the origin byte. This reduces the bandwidth usage, because in case of sending a “nothing to send” header, the origin byte becomes redundant. This change of order also theoretically allows each node to host multiple virtual nodes that could be addressed by the network.