I am working on a project which requires communication from a central controller and multiple peripheral sensors. Each sensor can push out data at a rate of 4-5KB/s(kilobytes/sec). There are 25-30 of these sensors which need to be connected to the central controller. These sensors are not a single board as the central controller and are connected via twisted pair wires. The overall length of the bus is approx 60cm(From controller to the last sensor). Working on a 3.3V voltage range. All sensors can stream potentially together at the same time. All sensors have data and I was hoping to poll each of them fast enough to get the data out. (Yes this would mean that sensor can have memory to store).

What can be a potential architecture for such a system? UART is not considered because I can't do one to one connection between sensor and controller. I cant use SPI because I can't have 25-30 select pins running in the bus for each sensor. I need to minimise the number of wires running from the controller to the peripherals.

My ideal choice is an I2C bus on high-speed mode(3.4Mbps(Megabits/sec)) which can satisfy my data rates(Theoretically at 425KB/s). For the speeds I require and the bus length at 60cm, I am doubtful about the signal quality. Is there any way to estimate whether this setup will work without physically building and testing it? I can consider putting an i2c bus extender between the SDA, SCL lines on the controller and the sensor inputs. But TBH, I am still on the lookout for high-speed extender ICs which work at 3.4Mbps. Can't seem to find any.

Is there any other alternative communication protocol that I can use?

Any suggestions for the above-mentioned issues are welcome.

  • \$\begingroup\$ Comments are not for extended discussion; this conversation has been moved to chat. \$\endgroup\$
    – Voltage Spike
    Commented Mar 17, 2022 at 5:46

3 Answers 3


Dumb idea: connect every sensor with USB. There are some pretty cheap fullspeed USB micros around. Cables are cheap. You'll need hubs, but they're cheap too. USB frame timing gives you synchronization, and you can use interrupt transfers for low latency.

OK, no USB.

30x 5kB/s = 150 kB/s = 1.2Mbps without overhead, which is a bit expensive for an UART.

Here's an idea:

The 4-wire cable:

  • Clock twisted with GND
  • Data twisted with VCC

So we have two single-ended twisted pair lines in the 4 wire cable. There shouldn't be any need for differential over a short length like 60cm, if I read the question correctly, and 60cm is the total length, and you don't have thirty 60cm cables...

Let's use SPI without chip selects.

You need a sensor micro that has a SPI peripheral with MISO and MOSI connected to both ends of the shift register, so when it is configured as slave, bits come in MISO, travel through the shift register, then exit on MOSI, to be sent to the next sensor in the chain, and finally to the master micro.

So, let's make a protocol.

Clock line is connected to all the sensor micro SPI clock inputs, but on any decent micro, that pin is also a GPIO. So we'll use the clock line to communicate from the master to the slaves. If the micro has a pinmux that can turn this pin into an UART RX, then a simple serial protocol can be used, otherwise, bitbanged UART.

The master can send commands to all the slaves, for example "identify" and "transmit data".

Then, the slaves load the requested data into their SPI shift registers, configure the SPI peripheral as output, and switch the Clock pin from GPIO/UART input to SPI SCK input. Master pulses the clock lines enough times, the shift registers do their job, and all the data is shifted and received by the master.

Since the slaves are daisy-chained, no extra data is required to identify which slave sent which byte. This is determined by the position in the bit stream.

Once all the slaves have shifted their data, they should switch SCK back to GPIO or UART input, and wait for a new command.

These commands handle synchronization automatically since all the slaves receive them at the same time.

Now, each slave will have to send the same number of bytes as the others, since they're all read at the same time. I guess you could come up with a simple protocol to solve that issue, for example a value representing "I have nothing to send" or something like that.

In this case, there isn't even a need for a command to request the slaves to send data. You just need the slave to set a timeout on the clock pin (with a timer), for example the timer is reset if the pin is 1, and when it stays at 0 for a while, the timer fires an interrupt. So when the clock stops pulsing for a certain time, the slaves reload a value in their registers, and then the master sends another sequence of clock pulses to shift out all the values.

I think that's the cheapest solution...

With this, the sensors can even know their own position in the chain: suppose the one at the end of the chain has a pulldown on MISO. The master sends "enumerate" command, and all slaves load a value like "1" in their shift register. Then the master sends 8 clocks, shifting all the registers from one sensor to the next. The first sensor, having MISO pulled low, reads a zero, so it knows it's first. Then the master sends 8 more cycles, and the zero reaches the second sensor, so it knows it's second. Etc. When the zero reaches the master, it knows the number of sensors in the chain is equal to the number of 8-pulses it sent.

  • 1
    \$\begingroup\$ This is nothing short of brilliant if this can work. I have to go through this in detail before responding. Its late here and I will take a look at this with fresh eyes to if this can be even done. I was wondering how one might do SPI without CS pins. BTW, 60cm is the overall length of the bus. Just confirming. \$\endgroup\$
    – dev_000
    Commented Mar 16, 2022 at 15:14
  • \$\begingroup\$ I think it'll work. I've never daisy chained SPI but I hear it's a common thing. \$\endgroup\$
    – bobflux
    Commented Mar 16, 2022 at 17:16
  • \$\begingroup\$ I went through this in detail, I think its possible to do this. This protocol is a mix of UART + SPI where master to peripheral communication is via the SCLK line asynchronously with an address byte header mentioning whom its for. It will be similar to broadcasting. A command can be sent to the sensor to be ready and load data to its SPI buffer. Then SCLK is switched to a CLK sequence to clock out the data via daisy chained SPI. \$\endgroup\$
    – dev_000
    Commented Mar 17, 2022 at 7:49
  • \$\begingroup\$ I think there will be 5 lines for this custom mode. (Pwr, GND, SCLK/UART, MOSI, MISO) Also, I am not sure how to calculate the theoretically data rate for peripheral to master transfer to see if this indeed can be better. Collision of data won't be there in this case though. \$\endgroup\$
    – dev_000
    Commented Mar 17, 2022 at 7:49
  • \$\begingroup\$ 5 lines, but the clock is dual use, so 4 wires. Note, if you make a loop by connecting the first and last modules to the master, then the master can receive MOSI output from the last node, but it can also send to MISO input of the first node, so it can send data to all the shift registers in the chain. In this case you no longer need the dual use clock/uart line since the micro can send data to all the sensors. \$\endgroup\$
    – bobflux
    Commented Mar 17, 2022 at 7:58

The problem with i2c is that it only takes a single false edge and the data acquisition process can grind to a halt, with no indication where the problem is; you'd have to guarantee that the interface is 100% interference-free, which is difficult to do in the real world.

There are various ways you can get the sensor units to respond in an orderly manner, without having to supply the individual chip-selects of SPI. For example, they could be daisy-chained using something as simple as an asynchronous serial link; this could be 1 Mbaud or faster, since the distances are short. The controller uses its UART transmit line to send a data trigger byte to the first sensor unit, which adds its data on and passes the whole block (trigger plus data) to the second unit, which transmits all that plus any new data to the third unit, and so on. Having gone through all the daisy-chained units, the complete data set (trigger plus several data blocks) arrives back at the receive pin of the UART that sent the trigger.

Each sensor unit will directly copy byte-for-byte the data from its serial input to output, until it detects the end of the incoming data, then it appends its own data. This ensures the minimum of delay in passing the data on. You just need some recognisable begin/end flags in the messages; maybe control characters, if the data is in plain text, or base64 encoded binary.

Async daisy-chain diagram

The key advantage is that this scheme is self-organising, you can just add sensors at will, without the risk of lengthening & overloading a shared bus, but of course the failure of a single sensor could cause the whole system to fail. So you could split the sensors into, say, 4 groups, driven by 4 UARTs on the controller, which would reduce the effect of a sensor failure, and reduce the required baud rate for each group. The software in the controller is really simple (just send a trigger, and wait for the data blocks) so running several simultaneous daisy-chains won't be at all difficult.

You mention twisted-pair wiring, and this scheme would work really well with 5V or 3.3V twisted-pair links, using cheap RS485 transceivers as permanently-enabled drivers and receivers.

Alternatively, you could just use a simple token-passing scheme with an RS485 bus; each unit listens to the bus before transmitting, so as to avoid collisions, and ensure the data emerges as an ordered stream However I do think the daisy-chained scheme would be quicker to create and easier to debug - no need to worry about addressing or collisions.

The reason for suggesting asynchronous serial is that it is simpler and more interference-resistant than i2c; a single glitch will at worst corrupt one message, and serial traffic is really easy to monitor for debugging purposes.

If that is unsuitable, then you could use CAN, it is just a question of whether your data structures lend themselves to being broken up into small frames - sometimes the overhead of tracking the individual fragments means that the overall data rate becomes quite low.

  • \$\begingroup\$ Thanks for the detailed response. I am not sure if asynchronous serial link can work because it will be adding data blocks serially and lets say we have 30 sensors it will add up quickly. So I am not sure if we can hit a limit of approx 1Mbps of data transfer rate. Regarding the RS485 scheme with each node checking before sending that might be a better solution(if you can do collision handling yourselves). But wouldnt the data rates of RS485 be limited by your microcontrollers UART(Which usually maxes out at 1Mbps)? Is there any workaround for these? Bitbanging a pin in software? \$\endgroup\$
    – dev_000
    Commented Mar 17, 2022 at 7:59
  • \$\begingroup\$ CAN is a solution but will be expensive because of transceivers. I would prefer RS485 over CAN for price reasons if RS485 can reach the required data rates. \$\endgroup\$
    – dev_000
    Commented Mar 17, 2022 at 8:01
  • \$\begingroup\$ Yes, PC async serial ports are normally limited to 921600 baud, but on embedded systems they can run faster, or you could run multiple daisy-chains so each is under 1 Mbits/. As a networking enthusiast, I'd normally push a multidrop RS485 solution, but I also know how much time can be consumed when creating and debugging a do-it-yourself network protocol; in my opinion, an asynchronous daisy-chain would be the quickest to create and easiest to debug - no need to worry about addressing or collisions. \$\endgroup\$
    – jayben
    Commented Mar 17, 2022 at 9:41
  • \$\begingroup\$ Thanks for the inputs. I am still unclear on the Async daisy chain which you are mentioning. How will that work? Is it the way you have mentioned in your answer wherein each sensor data passes through the other and the last one transmits it back to the master? If possible can you be a bit elaborate on that in your answer? The issue I see with that is that baud rate will be low as you are transmitting data through each sensor. I have exhausted all other options and understood the pros and cons of each except for the async serial you are mentioning. \$\endgroup\$
    – dev_000
    Commented Mar 17, 2022 at 15:02
  • \$\begingroup\$ I've added yet more explanatory text to my response - think I've done enough now... \$\endgroup\$
    – jayben
    Commented Mar 17, 2022 at 18:49

One idea: daisy-chained SPI. TI app note

Diagram on Wikipedia (SVG file will not embed)

All CS and SCK lines are connected in parallel. MOSI/MISO (easier to call them SDI/SDO in this arrangement) are daisy-chained from the host, to the first device, then the second, etc, and then back to the host at the end.

With a single SPI device, the device contains a shift register. You would shift in data, activate the device (which replaces the contents of the shift register with some output data), then shift out data. With daisy-chained SPI, all of the devices form a single long shift register. You would shift in data for every device in sequence, activate them all at once, and then shift out data for every device in sequence. This seems particularly well-suited when you are sending the similar commands to every device.

4 data lines are needed to support a large number of devices.

I have used this scheme in the past with 4 devices (motor drivers), and a similar concept is used in addressable LED strips.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.