
; --------------------------------------------------------------------------------
;  Wuseldraht or Scurry Wire in English is a field bus over a single twisted pair
; --------------------------------------------------------------------------------

Wuseldraht is a reference implementation released under GPL3 of my own field bus system which uses two wires - one for Ground and one for Power/Data. It can handle very long wires and capacitances on the bus, and supplies an useful amount of power. This time it is limited for simplicity by current drive capabilities of Launchpad, but on my real-world implementation I use a MOSFET to inject power - and this bus can supply a lot of current per design !

Have a look at the images to get a first idea what the nodes could look like.

Basically, this is a wired-or with a passive 4.7 kOhms pulldown resistor on the bus. Green alligator clip is GND, yellow clip connects to P2.3 of Launchpad.

Each node is equipped with:

- MSP430F201x
- 100uF power supply capacitor
- 1N4148 silicon diode for power supply
- 220 Ohms resistor for bus sensing and pulling line high actively
- 15 kOhms Reset resistor
- Blue LED 

The 100 uF capacitor is connected between VCC and GND of microcontroller. The 1N4148 diode is connected to scurry bus line (anode) and to VCC of microcontroller (cathode). The 220 Ohms resistor is connected between scurry bus line and P1.0. GND is connected to GND bus line. The 15 kOhms resistor is connected between VCC and Reset, the blue LED is on P1.2 (anode) and P1.3 (cathode).


Time to describe what actually happens:

In silence - nothing to transmit - the bus line is driven high to distribute current into all nodes capacitors. Clamping diodes are rated for about 1.5 mA to 2 mA, if your node is lucky with 1 mA only, you can drop the 220 Ohms resistor and diode of that node and directly connect the bus line to port pin. I tried this, MSP430F2012 + 100uF capacitor is enough to have a temperature sensor node. Nodes fresh from Reset have released their bus line into high impedance state and wait.

If all nodes including the chief node release the line, then it is passively pulled low. There is only one pulldown resistor for the whole bus line. The time to reach low is determined by the ratio of line capacitance and pulldown resistor and can be as long as you wish - the nodes wait for the line to reach low. The chief waits, too, as other nodes could still hold the line - signaling busy state. Note that on this point, all nodes are synchronized on the passive high-to-low flank. The time the line stays low determines what is transmitted.

There are three different "low times": N, 0 and 1. N is longest, 0 is in the middle, 1 is shortest. As this is a wired-OR line, 0 can overwrite N; 1 can overwrite both 0 and N. Nodes not involved in the current transaction or idling always send N.
After the time needed for N, 0 or 1, the node pulls the line up again with charge from their capacitor. As capacitor voltage is 0.7V less than bus voltage, the node pulling the bus back high only needs few current as its minus-0.7V-through-diode-voltage is not suifficient to charge the other capacitors. (BTW: This is a "passive hardware watchdog" feature - if a node fails while blocking the line high, the bus voltage will drop over time and drain the supply capacitor of the failing node soon causing a brownout Reset in it.) The one with the shortest desired pulse duration is the one that determines the pulse seen on the bus - all the others pull up the line later, too. After the time needed for N pulse, ALL nodes are actively pulling the line high together. The active rise time is determined by line capacitance and current drive capabilities - the bus base time has to be longer that this rise. I set the values in reference implementation to VERY conservative values, it will b
e slow, but should work without flaws under most circumstances.

After processing the current pulse and being ready to receive the next, they release the bus line again. This way there are few timing dependencies on the nodes.

Now we have the waveform and the synchronisation. Fine to this stage ?


This is the protocol:

N means "New transmission", is used for idling or denotes "no response" in some cases. If a N is seen on the bus, all nodes quit current transactions (if any) and watch for upcoming bits in their protocol logic.

I will write the transaction the way that N, 0, 1 is what is seen on bus, (N) (1) (0) is what the chief transmitted. Ok ? 1(N) means that chief send an N and sees an electrical 1 on bus.

Addresses are transmitted MSB first, address length can vary as long as the addresses in use are prefix-free - you cannot have the first bits of a long address identical to a short one. Nodes respond as soon as their address bit stream has been compared successfully.

N-0-Address-1(N) is to select an individual node which achknowledges its presence by overwritting the chief-N with 1.

N-N-N-N-N-0-1-0-1-1(N)... is the begin of a transaction to node 101.
N-0-1-1-0-N... is a call for 110, which is currently nonexistent.

N-1-1-1(N) is to select all nodes at once. All nodes respond to N-1-1, so if you see N-1-1-N on the bus, there are no nodes available.

Communication is done synchronously by transmitting individual bits on the line, N never occours in regular transactions. If you receive, then you can either send 0 and get 0 or 1(0), or you can send N and get 0(N) or 1(N) if you want to make sure that you get an electrical answer. Each node can have another bit protocol for communication, but I implemented a simple "exchange 16 bits" routine that handles all individual communications.

N-1-0... selects nodes with feedback. This is used for a node search algorithms and could be for regular addressing, but it is slower.

Search algorithm sends this pattern: N-1-0-[-a(N)-b(N)-0/1]. The nodes answer with a=1 b=0 if they have an one in that bit place of the address, with a=0 and b=1 if they have a zero in that bit place of the address. This way the chief sees 1(N)-0(N) if there are only ones in the current address bit of all nodes, 0(N)-1(N) if only zeros, 1(N)-1(N) if there are both ones and zeros, 1(N)-N if a nodes address is exhausted and solely selected and N-N if there are no more nodes responding. After that, the chief chooses one more bit of the address and repeats.

This is more tricky, I will describe this with examples:

Consider that there are four nodes with addresses 000, 011, 100, 101 on the bus:

N-1-0- Start search
[-1(N)-1(N)-0] Current address "": First address bits are both 0 and 1. Select 0:
[-1(N)-1(N)-0] Current address "0": Second address bits are both 0 and 1. Select 0:
[-0(N)-1(N)-0] Current address "00": Third address bit available is 0. Select 0:
[-1(N)-N] Current address "000": Node is selected and acknowledges. Found node 000.

-1-0- Restart search, N has already been on the bus
[-1(N)-1(N)-0] Current address "": First address bits are both 0 and 1. Select 0:
[-1(N)-1(N)-1] Current address "0": Second address bits are both 0 and 1. Select 1:
[-1(N)-0(N)-1] Current address "01": Third address bit available is 1. Select 1:
[-1(N)-N] Current address "011": Node is selected and acknowledges. Found node 011.

-1-0- Restart search, N has already been on the bus
[-1(N)-1(N)-0] Current address "": First address bits are both 0 and 1. Select 1:
[-0(N)-1(N)-0] Current address "1": Second address bit available is 0. Select 0:
[-1(N)-1(N)-0] Current address "10": Third address bits are both 0 and 1. Select 0:
[-1(N)-N] Current address "100": Node is selected and acknowledges. Found node 100.

-1-0- Restart search, N has already been on the bus
[-1(N)-1(N)-0] Current address "": First address bits are both 0 and 1. Select 1:
[-0(N)-1(N)-0] Current address "1": Second address bit available is 0. Select 0:
[-1(N)-1(N)-1] Current address "10": Third address bits are both 0 and 1. Select 1:
[-1(N)-N] Current address "101": Node is selected and acknowledges. Found node 101.

Of course, this is a resursive algorithm that branches in two on every -1(N)-1(N)- bud.

I hope now it is clear that you could add a node 0101 ("010" is not recognized by any existing node) to the bus, but not an additional node with 1010 (prefix 101 already exists!). This way you can start with short addresses, leave some "pre-dials" free and add more nodes with longer addresses later. Of course, you can have all nodes with same address length, too, just as you wish.

The example nodes have the 3 bit address range exhausted and have commands to try for Led-on, Led-off and memory inspection: c@ @ c! !

I invented this for use in greenhouses. A long twisted pair wire running between plants... For exact measurement timings, it is easy to implement a circular buffer for measurement results. Send measurement commands and parameters with N-1-1 addressing for capturing in perfect synchrony, and read out buffered results individually one after the other. Note that the Forth implementation is not generating MOSFET drive signals, but you can add this by enabling your power injection transistor at the same time when the bus line is pulled high in Forth code.

You can start with a single node connected to a Launchpad, the node code should in theory work in a G2452 or others, too. It is a good idea to hook an oscilloscope to bus line for grasping the idea !

Matthias Koch
Summer 2013
