Go Down

Topic: SPI multi master (Read 4002 times) previous topic - next topic

TomS

Hello Arduino friends!

I am working on a project that requires multiple masters to send their data to one slave on a shared bus.
Since speed is an issue I need to use SPI and not I2C / TWI etc.

The big question now is how to properly synchronize the masters so only one is sending data at a time.

Since there is only one central slave I don't really need the SS line. Would it be possible to connect all the SS lines of the masters and use it as a "busy" line?
I.e. if a master wants to send data he first checks the SS line if it's busy, if not he sets it to busy, sends his data and then resets the line.
Would this be possible or would we face possible race condition problems here?

What about SCLK, how could I ensure the right CLK signal arrives at the slave?

And last but not least, how can I prevent a master from "starving" i.e. he wants to send data but the line is always busy?


Thanks a lot in advance for any ideas, I appreciate the help very much!
Have a nice day! :)
Tom

Graynomad

Quote
The big question now is how to properly synchronize the masters

That is indeed the big question.

I can't think of a simple way to do this straight away.

What is the slave device? Smart or dumb? And how much data does it need?

______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

TomS

Slave device is a microcontroller but data transfer has to be initiated by the master devices (i.e. no polling by the slave).

There is a lot of data to process, the combined dataflow from all the masters will probably be around 1 Mb/s.

Now you see why I'm having a problem ;)

Graynomad

OK, what is the nature of the data, are the masters reading sensors and the slave has to consolidate the readings or something.

Would all masters normally have data to send?

Also, what is the slave going to do with all this data? I gather it's not an Arduino.

______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

TomS

Exactly, the masters sample large sensor arrays at a high rate and the slave has to gather all this data at a central place to either forward it to a PC or if it has sufficient resources left process the data first and then send the results to a PC.

The slave hasn't been implemented yet, so there hasn't been a decision on what microprocessor it will be.

TeslaFan

Why are you assuming the data collectors have to be masters? Since they can only transmit one at a time to the 'slave' anyway it's really the 'masters' that are subservient to the 'slave' in this.

Might as well just make it official and call the data collectors the slaves and the collection point the master.

If the data collectors know in advance that they will be polled at high speed already, they can have the first byte of a message preloaded into the shift register, then load in the subsequent bytes under interrupt control. As soon as the data is sent, they go get more data and be ready for the next polling cycle. The speed at which they can transmit messages is determined by the number of slaves, the size of the message,  and the clock speed. The Sensor Array has to be set up to not exceed this rate.
Linux and Arduino, two great things that go great together!
http://www.roboticcore.com

TomS

There is a reason why I would like the communication to be initiated by the master modules and not polling by the collector.

The uCs are pretty much working to capacity when sampling the sensors.
But there is a few microseconds dead time while waiting for an AD-conversion. If I could utilize this time to send the previously sampled data, the overall performance of the system would not be affected by the communication procedure whereas the performance would go down when working with interrupts and polling.

If I can't find a solution for multi master SPI, I will eventually have to go with a version similar to what you proposed and find a way to make up for the communication delay (faster uC or external ADC possibly).

But maybe there is a way to use the existing hardware and find a way to synchronize the SPI masters.

What about the approach I proposed earlier, using the SS line as a "busy" line to synchronize, couldn't we maybe get this to work?

Thanks for your ideas!
Tom

Graynomad

#7
Apr 29, 2011, 03:00 pm Last Edit: Apr 29, 2011, 05:55 pm by Graynomad Reason: 1
If it's that tight you'll have to get creative.

Any form of multi-master needs arbitration and without extra hardware that will take time and get complicated.

The SPI hardware is really just a fancy shift register.

To use SS or any pin as an interrupt or input to tell the slaves (sorry I have to think multiple slaves and one master) to load the data will I think be too slow.

I'm thinking the other way around, the slaves load the data into the SPI register unless told not to.

Use a pin as a load enable (we'll call it EN), ie during the brief inter-ADC reading period the slaves load 8 bits of data into the SPDR reg unless EN is high, in which case the reading may be discarded or not depending on if you really need every one.

So on the slave chips the code is like this

Code: [Select]
read ADC
if EN == LOW
   write value to SPDR


All slaves are daisy chained so the master does the following

Code: [Select]
raise EN
for (n = 0; n < number_of_slaves; n++)
    SPI.transfer
lower EN


This of course means that for ( slaves * 8 ) bit times the slaves are effectively disabled from updating their ADC reading. This may or may not matter depending on the number of slaves and the importance of getting every reading.

You can maybe speed this up by reading say 8 slaves in parallel. Run all the slave MISO pins to digital inputs of the master. So assuming <= 8 slaves

Code: [Select]
   raise EN
   pulse clock pin
   bits0 = PORTD;
   pulse clock pin
   bits1 = PORTD;
   pulse clock pin
   bits2 = PORTD;
   pulse clock pin
   bits3 = PORTD;
   pulse clock pin
   bits4 = PORTD;
   pulse clock pin
   bits5 = PORTD;
   pulse clock pin
   bits6 = PORTD;
   pulse clock pin
   bits7 = PORTD;
   lower EN


It looks bad but might be faster than getting 64 bits bytes via the SPI. Of course the bytes have to be reconstructed but that can be done later.

If you need all 10 ADC bits then I guess the above has to be duplicated (but only two more pulses needed) and the slaves are once again disabled for the duration of the transfer.

If you absolutely can't afford to lose a reading and need 10 bits I think you'll have to throw hardware at the problem.

_____
Rob
Rob Gray aka the GRAYnomad www.robgray.com

CrossRoads

I think your idea of the masters polling the SS line is good.
Use 2 pins to do it tho - one that is the SS output, have it drive an open collector driver that goes low out to the slave, and connect the open collector output to another input that you poll to see if it is free.
The open collector can just be a simple NPN transistor, drive the base high, pullup resistor for the high signal.  You will then drive SS high from the Arduino to start your transmission, and low to end, the slave will see that as the regular low & high.
Then you will not have to switch modes on the pin to see if the line is free. Either use a good fast transistor, or an IC equivalent such as 74LS06
http://focus.ti.com/lit/ds/symlink/sn74ls06.pdf

As to how to keep more than one master from starting at the same time- can the masters talk to each other directly?
Then you could make a ring of comm's - 1 pulls SS low to start, and is connected to 2, pulling a line low to let 2 know it has started and stopped. 2 does the same to 3, which does the same to 4, etc, all way around until 10 gets back to 1 to start the process over. And maybe that line is just the pre-buffered SS line.  On power up, all would have to wait until 1 was ready to go to begin.
How far apart are the masters and slave?
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

TomS

Thanks to the two of you for your ideas and help!

Interesting idea Graynomand to disable sending instead of enabling it, I will think about that!

CrossRoads, thanks for the advice as well.
Do I understand this right, you propose to set the SS line high with a pull up resistor and connect it to the collector of an NPN transistor which has its emitter connected to ground and its base to the SS out pin on the uC.
An additional in pin is also connected to the SS line to check it.
Is this the design you meant?

The ring topology to synchronize the uCs is also a very interesting idea, I'll try that as well.

Thanks again & have a great weekend!
Tom

CrossRoads

Yes, along these lines for idea 1:
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

TomS

Ok thanks, then I understood you right.

I guess it is time to order a few more Arduinos and see if a race condition is going to be a problem.

Graynomad

#12
Apr 30, 2011, 11:41 am Last Edit: Apr 30, 2011, 11:43 am by Graynomad Reason: 1
In any multi-master test-then-do arrangement race conditions are a potential issue.

CrossRoads scheme gets around this I think but will cost you some time.

You still haven't said if you can afford to miss a reading or two and if readings from every chip have to be aligned, for example if this is a logic analyser front end you can't miss a single reading, however if you're looking at batteries discharging (OK unlikely given the speeds you've mentioned :)) it doesn't matter.

Knowing the application might help as well.

______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

Nick Gammon

Use another couple of wires for I2C. That supports multiple masters. Then the "master" that wants to send information sends a single byte to the "slave" with its address saying "I am ready".

A couple of microseconds later the slave then addresses that master using SPI to download the data. Meanwhile other sensors (masters) can be queuing up additional requests which the slave can address when it is ready. This incoming I2C data can be serviced by an interrupt so this should work OK.

If timing is really critical I don't think it can be solved. For example, what if two sensors need to send 1Mb of data right now?

One will miss out, won't it?

I think the idea of lots of masters and one slave is getting things backwards. You really want one master and lots of slaves, and work out a neat way of having the master address the slaves in a reasonable way. All this talk about race conditions just shows that the other design is only going to work under perfect circumstances anyway, which won't happen.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

CrossRoads

#14
Apr 30, 2011, 07:10 pm Last Edit: Apr 30, 2011, 07:13 pm by CrossRoads Reason: 1
I think my idea of the masters passing along a clear to send signal would work.
Unit 1 asserts its SS line, unit 2 sees and has to wait until it is deasserted before asserting its own SS, unit3 sees it and has wait, etc.
All the masters need the control lines buffered so they can all drive them without interfering, like this:

(notes are a little off, should say  "2 sees 1", "3 sees 2",  "4 sees 3", "1 sees 4")



Otherwise, Nick's method of swapping roles and having the master tell each slave "report in" would work, with MISO needing buffering between slaves to avoid interference. Slave in that case can't say "not ready" tho, so if not ready to send the line just gets read as FF coming back (or 00, depending on how buffering is set up).
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

Go Up