Go Down

Topic: Idle thinking about SPI daisy chains. (Read 584 times) previous topic - next topic

GoForSmoke

Nov 09, 2017, 06:19 pm Last Edit: Nov 09, 2017, 06:25 pm by GoForSmoke
I could put a few controllers on an SPI bus using CS to address one to all, which is neat.

I was thinking about controllers daisy-chained like shift registers. Each would get a data stream off the one before and pass a data stream to the next though at/most times the data may be NULL and the chain may be circular.
Data could be addressed and passed on through (after any outgoing message is sent, per node) fairly quickly, flags and responses sent not passed on after use -- the serial traffic never mixing message contents.

What do the controllers do? I would hope, track and respond to the real world when 1 controller is not enough.
This is just about a way to connect them.

Consider non-blocking tasks written inside of loop(). This is like that for multi-processors, one after the other in the serial sense they pass data along rather than executing in sequence.

Please don't ask why or what it's for. Why are there compilers? What are they for? 

Come to think of it, this might work with serial RX and TX.
Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

Qdeathstar

Mmm, nothing sexier than some spi in daisy chains.

And that is all I have to add.
A creaking creeping shadow
stiff against the freezing fog
glares at a tickless watch.

Time has failed him -- all things shall pass.

Henry_Best

I could put a few controllers on an SPI bus using CS to address one to all, which is neat.

I was thinking about controllers daisy-chained like shift registers. Each would get a data stream off the one before and pass a data stream to the next though at/most times the data may be NULL and the chain may be circular.
If the chain is circular you will have to give your data stream a 'time to live', else it will continue circulating for ever.

GoForSmoke

I might want "a trigger" to loop around until a task is done and the trigger would not get passed on.

If not looped, it could be a bit like command line pipes with the controllers running the commands.
Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

travis_farmer

what about a master controller, setup like a network switch? seems like it would be more efficient than a ring. maybe with some multiplexing/demultiplexing to handle the switching.

I think i had a working ring a while back for serial UART. though it was subject to runaway data from time to time. ;)

~Travis
Current Obsession: My server rack cooler, and my CNC Router
Check out my website, i have my own under-used forum on my hobby server.

GoForSmoke

I could put a few controllers on an SPI bus using CS to address one to all, which is neat.
Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

TomGeorge

"daisy chains"
its Spring here! Australia.

So why in the norther hemisphere, Fall or Autumn, did  you start thinking of "daisy chains"?

Either you are not taking enough water with it.
OR
Like most of us, need our medication adjusted.

I might want "a trigger" to loop around until a task is done and the trigger would not get passed on.

If not looped, it could be a bit like command line pipes with the controllers running the commands.
Sounds like Token Ring Topology.
what about a master controller, setup like a network switch? seems like it would be more efficient than a ring. maybe with some multiplexing/demultiplexing to handle the switching.

That's Star Topology.
See ya learned sumfink every day.

Everything runs on smoke, let the smoke out, it stops running....

GoForSmoke

#7
Nov 11, 2017, 09:54 am Last Edit: Nov 11, 2017, 10:10 am by GoForSmoke
Those terms were new to me back in the 70's. And then there's all the ways they get applied, always something new.

Daisy chaining is what people do to shift registers on SPI, data out from one connects to data in on the next, etc, daisy chain.

We probably have different views here where the flowers don't have deadly spiders hiding under.

I'm also thinking that serial links might be better for this, no SPI clock to keep with but fast enough to be useful. At 115200 baud the rate is > 11000 chars/sec and the load is whatever is on all the wires, the trickle-through speed won't be great but doesn't have to be slow either, depending on what processing is done. Main advantages are flexibility and simplicity, any system has to be put in by the programmer so there's none to get in the way.





Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

travis_farmer

I'm also thinking that serial links might be better for this, no SPI clock to keep with but fast enough to be useful. At 115200 baud the rate is > 11000 chars/sec and the load is whatever is on all the wires, the trickle-through speed won't be great but doesn't have to be slow either, depending on what processing is done. Main advantages are flexibility and simplicity, any system has to be put in by the programmer so there's none to get in the way.
the copy of my "Serial ring" that i found was heavy on the use of the String object. i had a working version at some point that transferred bytes, but i can't find it.
essentially, it was a leading byte to identify the start of a block, a byte for the sender address, then the receiver address, followed by the data, and a terminator byte. it worked great, if all the Arduinos booted at the exact same time. i didn't have any error correction built in, or even a checksum.

though, in thinking now on it, i may revisit the idea, simply out of curiosity if i can improve it.

~Travis
Current Obsession: My server rack cooler, and my CNC Router
Check out my website, i have my own under-used forum on my hobby server.

GoForSmoke

the copy of my "Serial ring" that i found was heavy on the use of the String object. i had a working version at some point that transferred bytes, but i can't find it.
essentially, it was a leading byte to identify the start of a block, a byte for the sender address, then the receiver address, followed by the data, and a terminator byte. it worked great, if all the Arduinos booted at the exact same time. i didn't have any error correction built in, or even a checksum.

though, in thinking now on it, i may revisit the idea, simply out of curiosity if i can improve it.

~Travis
Start by ditching the use of String and use char array instead. Arduino Serial has 64 byte input and output buffers already so you don't need to replicate those, just read and write to Serial but never let a buffer fill!

At 115200 baud you have 1388 cpu cycles between arriving chars. The more you can process your data char by char as it comes in, the faster the process will be done. It may be done before the next char arrives.
If you buffer then process, 'then' doesn't start until the last char arrives and there may be times when it has to be that way but I find it often is not.

I have a keyword match system that uses small code and RAM but could use a big chunk of flash if the keywords are long. It's fast enough to keep up with 250000 baud but it's a bit complicated to use, there's a sketch that takes a word list and generates Arduino source to make tables in flash for the new sketch that uses the match() function to parse text commands.

Still it shows that an Uno can read a serial char and trace down if it matches any of the choices in the list links and print debug text before the next char shows up in 40 microseconds (640 cpu cycles) --- my test pushed that hard btw --- it shows that you can do a good bit of processing in between serial arrivals if you put your head to it and do a bit of trial and error coding.


The whole thing seems beyond most people here. I could make something that stores the list and offsets in EEPROM but that would limit the list severely to 256 chars including null terminators. With short words, maybe 40 or so.
Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

travis_farmer

I threw together a rough example of what i was thinking. i haven't tested it for function, but it does pass verify. I will have to play with it a bit to debug, if needed, as i just now had my first cup of coffee for the morning.

if i put into code, what was running through my head, correctly, it has 16bit source and target addressing, as well as the data length.

feel free to use as you like. if it works, i may even write it into a library, and toss it up on my GitHub.

Code: [Select]
/**
Serial Ring example
prepared by Travis Farmer (travis_farmer on the Arduino Forum)
this is open source, use as you wish, as long as it remains open source.
------------
serial block structure: startByte, target Uint, sender Uint, length Uint, dataBytes, endByte

*/

#define SerialRing Serial // change to the UART port you will be using
#define StartBlock 0xff
#define EndBlock 0x00
#define MyAddr 1

char procArray[50];
bool BlockStarted = false;

void ProcData(unsigned int targetAddr, unsigned int sourceAddr, unsigned int dataLength)
{
  // do something with the contents of procArray[]
 
}

void setup() {
  SerialRing.begin(115200);

}

void loop() {
  unsigned int CurTarget;
  unsigned int CurSource;
  unsigned int CurLength;
 
  while (SerialRing.available()) {
    byte inByte = SerialRing.read();
    // if the incoming character is a newline, send it to the ProcRing function
    if (inByte == StartBlock && BlockStarted == false) {
      BlockStarted = true;
    }
    else if (BlockStarted == true && inByte != EndBlock)
    {
      CurTarget = ((inByte << 8) + SerialRing.read());
      CurSource = ((inByte << 8) + SerialRing.read());
      CurLength = ((inByte << 8) + SerialRing.read());
      if (CurTarget != MyAddr && CurSource != MyAddr)
      {
        SerialRing.write(StartBlock);
        SerialRing.write(CurTarget >> 8);
        SerialRing.write(CurTarget & 0xff);
        SerialRing.write(CurSource >> 8);
        SerialRing.write(CurSource & 0xff);
        SerialRing.write(CurLength >> 8);
        SerialRing.write(CurLength & 0x00);
        byte inByte2 = 0x00;
        while (inByte != EndBlock)
        {
          inByte2 = SerialRing.read();
          SerialRing.write(inByte2);
        }
        SerialRing.write(EndBlock);
        BlockStarted = false;
      }
      else if (CurTarget == MyAddr)
      {
        byte inByte2 = 0x00;
        unsigned int bytCounter = 0;
        while (inByte != EndBlock)
        {
          inByte2 = SerialRing.read();
          procArray[bytCounter] = char(inByte2);
          bytCounter++;
        }
        ProcData(CurTarget, CurSource, CurLength);
        BlockStarted = false;
      }
    }
  }
}


~Travis
Current Obsession: My server rack cooler, and my CNC Router
Check out my website, i have my own under-used forum on my hobby server.

GoForSmoke

That is buffer then process, you need the end marker to verify the binary data message.
You don't need to shift the data bits. Store as an array of bytes then address it with int pointers.

Each node has to determine if a message applies to it and pass the message along if it applies to other nodes (a message addressed to all would do both). If the message applies to the node, the node needs to act on the message which may include sending another message along.

Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

travis_farmer

That is buffer then process, you need the end marker to verify the binary data message.
You don't need to shift the data bits. Store as an array of bytes then address it with int pointers.
then i guess i am not sure how to process inline, without buffering. i had it coded so it would buffer the header data, and if not for itself, pass it along as it arrived. the start and end markers were there in case the data got read out of context.

Quote
Each node has to determine if a message applies to it and pass the message along if it applies to other nodes (a message addressed to all would do both). If the message applies to the node, the node needs to act on the message which may include sending another message along.
i usually use address 0 as the "all" address, but i forgot to put it into the example.

that was just a rough example, BTW ;)

~Travis
Current Obsession: My server rack cooler, and my CNC Router
Check out my website, i have my own under-used forum on my hobby server.

GoForSmoke

Serial (including SPI) has no guarantee that every byte gets through. However there is usually some baud rate that any connection will run "rock solid" and 10,000,000 chars tests shouldn't be hard to run until found hopefully > 28800.

I like text, it makes the data log easier to read. Text transmission errors generally produce non-text, easy to spot where with binary data it's all the same only different -- binary data needs CRC.








 
Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

Go Up