Best way to route an input to 7 possible outputs?

Hi, how do I take a data signal (for NeoPixels) and route it to one of 7 possible destinations?

For context: I'm working on a lighting project involving lots of separate Arduino circuits, each functioning as its own module. They're all hexagons that can connect to each other and communicate via serial (initially wanted to use that for lighting data but it's not nearly fast enough), with 1 NeoPixel per side, with all 6 permanently arranged in one "sub-strip", meaning the input from any side could go back to any one of the sides OR to that sub-strip (total of 7 possibilities), and then the end of the sub-strip can go to any side. Then I have one "source" module (triangular with only one active side) which controls all the LEDs. I already have an algorithm that automatically figures out what the whole assembly looks like using serial between the modules.

What I want to do is have each module kind of "dynamically route" the data wire for those NeoPixels, so that no matter what the assembly looks like, the source can treat it as one big LED strip. This means, a cell needs to route input from whichever side has data coming to it from the previous cell, to any of the 7 destinations I listed.

My question is, what would be the best way to do this? Should I just use a ton of npn transistors? Is there a cheap 8-channel multiplexer that will do what I want? I don't think shift registers would work but maybe? I'd like the solution to be as small and cheap as possible, since if this works I'll be using dozens of the modules and that adds up quick!

A analog multiplexer can also be used for digital signals: https://www.gammon.com.au/forum/?id=11976.

Is there a way to identify a hexagon ?
Are there solar cells in the hexagons ?

A sketch can keep certain sections with leds off if the ledstrip is one big long ledstrip.
A Arduino can also have eight ledstrips connected to eight different pins.
I'm lost when you talked about triangular the active side. Can you make a drawing ?

I'm very new to electronics, so wherever possible I try to overcome difficulties in software.

Are you sure serial is too slow? On a Nano I get 50 FPS for 256 LEDs at 1Mbaud without doing anything special. 2Mbaud can be done too, but needs direct register access because HardwareSerial can't keep up.

If I were trying to create this, I would tie all the hexes' serial RXs to the TX of the triangle. Perhaps this might need a signal re-shaper on each hex, I don't know. So every cell receives the entire layout's LED data. Then, each cell uses its own ID to select the relevant 6 LEDs' data, and sends only that to the local 6-LED strip.

edited to add: I think the highest frequency component of 1Mbaud serial is 2MHz. I think the highest for WS2812 protocol is 20MHz. If this is right, serial may be much easier to get to work through all the interconnections in the layout.


Picture? Sure, here's a marked up screenshot of a simulation for this project I've been working on in Processing. The source module keeps track of each cell's location/orientation in the assembly, theoretically I could have it assign an ID to a hex as soon as it's added to the assembly but I don't have a reason to yet. No solar cells or anything, the source would have wall power or battery and the rest of the modules would be on a power bus when connected.

I had my eye on that analog multiplexer, sounds like it'd work. However, stav's comment has me interested: how on earth did you get 1Mbaud over serial?? And what is this "dierect register access" you speak of? I was under the impression the max rate was 115200 baud, but if I can get speeds like that it'd definitely be easier and a lot cheaper!

Currently I'm planning to use either SoftwareSerial or a serial expander chip so each module has one local serial port per side, in addition to a serial "bus" so any module can read/write to all other modules. The per-side is used for detecting the assembly, bus would be used for global messages and LED frames. I MIGHT be able to replace the per-side serial with a simple GPIO and use the global serial for everything which would save the multiple ports, not sure yet.

As I said, I didn't do anything special to get 1Mbaud to work. I asked for it with Serial.begin(1000000); and it worked.

I have seen many sources suggest that nothing faster than 115,200 works. Perhaps it doesn't work on genuine boards, which I believe use the FTDI USB serial chip. I have various clone Nanos, Unos and a Mega. They all use the CH340G instead, and every one works flawlessly at 2Mbaud.

By "direct register access" I mean banging on the AVR's internal registers manually, rather than using a library to drive the UART. The code isn't much more complicated, but it is quite a lot faster. Of course, it only works on AVR8, so I included a fallback for other architectures.

The description makes no sense to me, unless there is an Arduino or MCU chip in each hexagon? Are these chips communicating via UARTs? Chips cannot communicate to each other using the serial protocol used with ws2812 LEDs, that is only for use from an MCU to a ws2812 or between ws2812s.

Although we call them both "serial", UART and ws2812 protocols are quite different. The WS2812 protocol runs at 800KHz. As mentioned, UART can go up to 1MHz or even 2MHz if using hardware UART. If using the SoftwareSerial library, a much lower maximum speed can be achieved.

So assuming I'm right and each hexagon contains an Arduino or MCU of some kind, then yes, an analog multiplexer could be used to direct the TX signal from a UART to one of the neighbouring hexagons. But what about receiving that data? Another multiplexer could be used to allow the MCU to listen to any one of its neighbours, but not all of them at once, so inevitably, the data will be lost on most occasions. The only way I can think of to make this reliable would be to use MCU with 6 hardware UART ports. I can't think of any that have that.

So how does this communication between the hexagons work, exactly?

1 Like

Whaddya know, 1Mbaud does work out of the box! Guess it's just the USB terminal window that's limited to 115200. (Edit: never mind, even got it working there too)

Paul, you're correct each module would have a separate Arduino. They'd communicate with each other over serial, and I figured it'd be fastest to have them use an analog multiplexer or something to trick the source module into thinking it's controlling one giant LED strip, by "routing" the path of the data wire on the fly. However, it's looking like it may be easier and adequately fast to just send the data over serial, and have each module translate that to its own local strip of 6.

I would recommend using a digital multiplexer or demultiplexer for routing digital signals. The TI-SN74A(L)S151 to select one input out of 8 and the OnSemi MC74HC238A one-of-eight decoder/demultiplexer to select one of eight outputs for the one input.

1 Like

Thanks all, I'll try with serial first and if I run into problems I'll look into using one of those muxers. This whole thing is a big side project for fun/learning and I don't actually have many components yet (just using a few Nano clones I have lying around), but this is a big help!

Generally speaking, there is no need to use a multiplexer to distribute outputs because you are using "intelligent" systems which should examine each of the inputs (in turn) and choose which one of them it needs to use as its source.

The others are then simply ignored and it is up to your overall protocol to arrange this initial handshake and any necessary later re-routing.

If you're talking about reading the actual NeoPixel data and distributing that, that was actually my initial thought but I don't think it's fast enough to handle that 800KHz, at least certainly not with digitalRead...

You are replying to me?

You can certainly distribute the NeoPixel data itself using multiplexers but you would generally need to do that purely using logic gates, not through the Arduino itself.

You would then require a separate communication system as a side channel, to allow the Arduinos to organise the multiplexing of the NeoPixel data.

1 Like

Oh yeah, I think that's what we were getting at with the muxers.. I must've misunderstood your post, what did you mean?

Ok update: experimenting further with high speed serial, I found that I can actually do 2Mbaud without complications and it's quite reliable, but now my issue is the input buffer fills up before I can read it. I can send long messages (tested with >256 bytes) from Arduino to the terminal window no problem, but when I try to write back... It starts skipping data just a few bytes after 64 (the buffer limit).

My code for reading incoming data is:

while(!Serial.available()); // Wait for something
char msg[1023]; // Storage for incoming data
long c = 0;
unsigned long timer = millis();
while(millis() < timer + 2){ // Loop until it's been 2ms since the last byte was received
  while(Serial.available()){
    char cc = Serial.read();
    if(cc != '\n'){ // Get rid of automatic newline from serial terminal
      msg[c] = cc;
      c++;
      timer = millis(); // Reset timeout
    }
  }
}
Serial.write(msg); // Send a receipt for analysis

In addition to buffer problems, when it sends its receipt for some reason it also outputs a bunch of jibberish (amount is roughly proportional to the size of msg) after the actual data and I can't for the life of me figure out why...

That could be because you didn't terminate the string before you printed it.

msg[c] = '\0';
Serial.write(msg); // Send a receipt for analysis

Also you could try using micros() instead of millis() because millis() is only accurate to 1ms and you are timing a period of 2ms, so your timing could be 50% out.

unsigned long timer = micros();
while(micros() < timer + 2000){ // Loop until it's been 2ms since the last byte was received

Nailed that on the head, no more jibberish!

Changed that, probably a good idea

So now I just have the buffer issue. Is Serial.read() too slow? When I knock it down to lower baud rates (<= 115200) it works fine, but I really need those higher speeds. Surely there has to be a better way to read it?

Edit: also, for some reason strcmp() isn't returning what I expect. If I type "test" into the console, the receipt reads "test" but strcmp(msg, "test") doesn't return 0 as I'd expect - regardless of if \0 is there or not.

Edit to the edit: strcmp still doesn't work but I wrote my own method

bool msgCmp(char msg1[], char msg2[], long len1, long len2){
  if(len1 != len2) return false;
  for(long i = 0; i < len1; i++){
    if(msg1[i] != msg2[i]) return false;
  }
  return true;
}

and that works as expected.

So yeah, I've even got it working directly Arduino-to-Arduino and if I keep the data under 64 bytes it's rock solid, but the reading starts getting inconsistent after just ~70 bytes at 2Mbaud.

Maybe, yes, on slower Arduino like Uno/Nano. I seem to remember someone in the forum saying just that and having to access the AVR hardware registers directly instead of using Serial.read(). If that's the problem, maybe you should consider something faster than a classic Arduino. There are many cheap options these days, such as Teensy LC from PJRC, Arduino Zero clones or even RPi 2040.

strcmp() should work fine if your strings are properly null-terminated. Maybe you could post your entire code? Or a complete code that's just enough to demonstrate the problem?

Yeah, I may look into that. Or might get one of those other boards. Realistically a lower baud rate will work fine for small-scale testing, just thinking about if I were to have 50 or 100 cells in an assembly, * 6 LEDs * 3 for RGB, that'd be 1 or 2 KB of data for a single frame.

Ahh those pesky null terminators again. I've been neglecting to include those since the "strings" I'm using are just for testing - ultimately it'll just be bytes whose value from 0-255 directly represents the color component value.

Currently I've broken things pretty badly with various experiments so my code is in a complete mess :sweat_smile: I think I'd better set this project aside for a bit and come back to it later. Thanks for all the help though!

I agree. You started out with an idea for a project, which you never fully explained to the forum: what it would do, how it would operate from the users point of view. You then started to come up with a solution and, probably due to insufficient experience, almost immediately started going down some strange roads, where you needed to route data between multiple nodes, each of which is an Arduino, combined with some complex data routing circuits that for some reason needs to send serial data at the absolute limit of what Arduino can achieve. You fell into the "X-Y problem" trap, asking the forum to help you solve those complex issues (the "X") when what you really need was help with coming up with a simple and effective solution to implement your original idea (the "Y").

True. I did explain most of what I'm trying to do in the first couple messages, but for more context: I've already designed a new sort of storage system for small things like pencils and cables, made up of 3D printed hexagonal "cells" with slots on each side so you can put them together in any arrangement. This works pretty well and is cool as is, but then I thought... What if I used clear filament and had a PCB with lights on the back of each cell??

My goal with that is for each cell to have 1 LED per side, offset from center so when put together it acts as 2 LEDs per joined edge (see picture in previous post). All of them would be powered and controlled by a single, smaller "source" cell, which can send updates to the lights for custom animations on the whole assembly. One that I really want to see is some perlin noise in one color across the whole thing, with a chaser in a different color running along just the outer edges. Lots of other ideas but that's my favorite. Another cool thing could be if the source could keep track of what was stored in each cell, and highlight certain cells on command, though that'd be a whole other can of worms with smart-home compatibility etc so I'm only considering the animation aspect for now.

In addition to lighting updates, I also have an algorithm that works in a simulated environment (just a Processing sketch with each cell as an object running its loop in a separate thread) which detects the position and orientation of all cells relative to the source cell, only by sending messages to adjacent cells. I want this to be as user-friendly as possible, so someone could just attach or remove cell(s) at any time and boom, it re-calculates the model, updates the animation, and starts sending frames again, all automatically.

The core issue with this is I need a solution that can

  1. provide full control over each LED for totally custom frames
  2. support up to ~100 cells, meaning ~600 LEDs so about 2KB per frame (it sounds unnecessary, but I could see situations needing almost that much... Of course then I have to work on power issues too :sweat_smile: one thing at a time haha)
  3. get up to 30FPS with that many cells
  4. be affordable... This is the kicker, with modular stuff like this it adds up FAST and every dollar per unit counts

Like I said this whole thing is a giant side project and at this point I'm mostly using it to learn about some of the areas I'm less experienced with. I have been working with Arduino and related tech on and off for several years (not exactly a vet but I wouldn't call myself a noob either), I just haven't done much with the nitty-gritty of how it works under the hood.