Multi processor project

Thread Starter

KansaiRobot

Joined Jan 15, 2010
324
Hello and thanks for your help.

I am thinking in rather general terms about my next project. (Which I have to propose in a couple of days) and I was thinking:
so far I have programmed the PIC18F2550 to control LEDs, Steppers, DC etc.

What if I want to have several of these PICs as modules controlling a particular process and I want them to communicate with each other ?(In which fashion, master slave or different I dont know yet)

What to use? SPI, I2C, CAN??? what do you guys recommend?

This is still a rather general topic so any idea or comment will be greatly welcomed
 

kubeek

Joined Sep 20, 2005
5,793
All that will pretty much depend on what the process is. Some will be more suited for a master-slave model, and some for a peer-peer model. Do you have any particular process in mind?
 

DickCappels

Joined Aug 21, 2008
10,140
If you want to keep it highly achievable have one master that runs the application program and set up the others as slave peripheral processors that do little more respond to commands from the host. The peripheral processors can have their own "smarts" but only with respect to their assigned tasks. Peer-to-peer might greatly complicate the picture, so it would be best to avoid it, at least at the start.

If the system only has a few processors on the same PCB or in close proximity to one-another I2C or SPI should work fine. SPI is particularly good for high data rates. You don't have to rule out using multiple types of interfaces in your system. Can't comment on CAN.
 

RJohnson

Joined May 29, 2011
21
Agree with Dick here. A single Master and multiple slaves is easier to implement.
I have done this with longer distances using an RS-485 bus (2 wire) and Com Ports. All devices share the same bus but only one
talker at a time controlled by a Master.
For short distances use SPI or I2C.
 

Thread Starter

KansaiRobot

Joined Jan 15, 2010
324
All that will pretty much depend on what the process is. Some will be more suited for a master-slave model, and some for a peer-peer model. Do you have any particular process in mind?
Well, I haven't decided yet, but say which is better for master-slave and which for peer to peer?
Frankly I agree with Dick that master slave would be preferable, a master and some slaves doing their own thing.

If the system only has a few processors on the same PCB or in close proximity to one-another I2C or SPI should work fine. SPI is particularly good for high data rates. You don't have to rule out using multiple types of interfaces in your system. Can't comment on CAN.
Thank you for your insight. One thing to clarify: So I2C and SPI are only recommended for close proximity??
Right now I was thinking of having each processor in its own board and connected with wires but I think that would not work right?
On the other hand it can be as you say, several processors on a single board and the actuators they control in different positions and the ones connected with cables

Agree with Dick here. A single Master and multiple slaves is easier to implement.
I have done this with longer distances using an RS-485 bus (2 wire) and Com Ports. All devices share the same bus but only one
talker at a time controlled by a Master.
For short distances use SPI or I2C.
RS-485? I ll look into it... So again SPI and I2C are not recommended for say wires right?
 

DickCappels

Joined Aug 21, 2008
10,140
You can go a couple of meters with I2C -Philips proposed it as a standard computer peripheral interface less than a year before the USB was introduced. The greater the distance between devices the more chance for signal quality issues.
 

kubeek

Joined Sep 20, 2005
5,793
Well, I haven't decided yet, but say which is better for master-slave and which for peer to peer?
Frankly I agree with Dick that master slave would be preferable, a master and some slaves doing their own thing.
Let´say your slave processors are monitoring some inputs upon which the master processor needs to act. With a master-slave bus arrangement such as I2C or SPI the slaves cannot send a message on their own, but need to wait for the master to ask them. If you have lots of slaves then it will take considerable time between the input happening and the master cpu knowing about it.
In a multi-master bus such as CAN any device can send a message on their own, so whenever the event happens the slave cpu will send a message on its own and the information will get to the master cpu much quicker.

Now, this was about the bus architecture. For the actual relation between the cpus, there are other things to keep in mind. Lets say the cpus are doing some long computation, for example searching for a solution to some problem. In the beginning the master distributes parts of the space to be searched between the worker cpus. However there will be times where the worker cpu decides that there cannot be any more solutions in the workload it received, so it asks for another part of the job to work on.

In a master-slave relation the master decides who of the slaves gives some of its work to the empty one.
In a peer to peer relation the empty one asks its peers and they collectively decide who gives the work to the empty one. This could be done by some parallel computation and might be faster than in the master-slave model.
 

Thread Starter

KansaiRobot

Joined Jan 15, 2010
324
Let´say your slave processors are monitoring some inputs upon which the master processor needs to act. With a master-slave bus arrangement such as I2C or SPI the slaves cannot send a message on their own, but need to wait for the master to ask them. If you have lots of slaves then it will take considerable time between the input happening and the master cpu knowing about it.
In a multi-master bus such as CAN any device can send a message on their own, so whenever the event happens the slave cpu will send a message on its own and the information will get to the master cpu much quicker.

Now, this was about the bus architecture. For the actual relation between the cpus, there are other things to keep in mind. Lets say the cpus are doing some long computation, for example searching for a solution to some problem. In the beginning the master distributes parts of the space to be searched between the worker cpus. However there will be times where the worker cpu decides that there cannot be any more solutions in the workload it received, so it asks for another part of the job to work on.

In a master-slave relation the master decides who of the slaves gives some of its work to the empty one.
In a peer to peer relation the empty one asks its peers and they collectively decide who gives the work to the empty one. This could be done by some parallel computation and might be faster than in the master-slave model.

Very interesting. I have done some CAN communications in the past but using a ARM cortex A processor.
But times passes and I forget things (I had to read SPI and I2C again to remember the concepts)

So, CAN is interesting as an option. now the question is Can PICs handle CAN??
 

nsaspook

Joined Aug 27, 2009
12,998
With SPI slaves you can also use interrupts to signal the master it needs to be serviced. The slave cannot initiate the data transfer but it can alert the master that it has data ready using an external interrupt, so the master can query the slave in response.

Here is a simple prototype board that uses a PIC32MX250 (That handles data logging to a fat32 formatted SD-card and other functions on one SPI link) as the master with a PIC18F45K80 as the slave on the other SPI link for ADC inputs and serial data via light-links. The PIC18 can send interrupts to the PIC32 to quickly service SPI when serial or other data is ready for it to receive or it can poll in a timed loop.
 
Last edited:

nsaspook

Joined Aug 27, 2009
12,998
With a PIC32 the external interrupt from the slave can be assigned using PPS (pin 10 in this simple example)
C32 2.02 plib
Code:
....
setup an ISR vector for the interrupt

void __ISR(_EXTERNAL_1_VECTOR, ipl2) External_Interrupt_1(void)
{
   blink_led(RED_LED, LED_OFF, FALSE);
   blink_led(GREEN_LED, LED_ON, TRUE);
   spi_flag=1;
   mINT1ClearIntFlag();
}
....
config the pin to receive INT1

   PORTSetPinsDigitalIn(IOPORT_A, BIT_3); // for SPI 2 slave interrupt input
   PPSInput(4, INT1, RPA3); // EXT Interrupt #1 Port A bit 3, chip pin 10
   ConfigINT1(EXT_INT_PRI_2 | FALLING_EDGE_INT | EXT_INT_ENABLE);
   SetSubPriorityINT1(EXT_INT_SUB_PRI_3);
   mINT1ClearIntFlag(); // clear before enable
....
  // Enable multi-vectored interrupts
   INTEnableSystemMultiVectoredInt();

Monitoring the spi_flag in the debugger for a write when pin 10 goes to ground (with a jumper here)
ICD3 with a AC164110 RJ12 (6P6C) to ICSP adapter


Linux MPLAB®X 3.05: http://www.microchip.com/pagehandler/en-us/family/mplabx/
 
Last edited:

Thread Starter

KansaiRobot

Joined Jan 15, 2010
324
Well, after a couple of months I ve returned to this.
I ve implemented successfully a 2 PIC system that communicates through SPI. It is rather simple, the slave just transmit what the master sends to it.
I have several questions on this.

1) First, in my implemented project there is always one delay from what the master sends to what it receives. Say the master sends (one by one) "HELLO WORLD", the slave would bump back "%HELLO WORL" (with % being garbage the first time, and on reset being 'D' the last letter of the previous message. I wonder why is this so...

2) The slave can only transmit on a master command right? so if I want to implement a master controlling a slave process, the slave can do its work , put the results on some variable and then when asked by the master reply.
I am reading your posts on the slave notifying the master through interruptions. Can you tell me more about this?
What kind of interruptions?? I am guessing (and I can be totally wrong), some cable from the slave to the master so that the master gets an interruption from the I/O pins... is this so??

Any comment or advice will be greatly appreciated

Btw, if any of you have any comment, or observation on SPI, not even related to the above two questions, I would like to hear them as well thanks :)
 

ErnieM

Joined Apr 24, 2011
8,377
The interrupt referred to is the traditional external interrupt caused by an input line that forces an interrupt call in the code. To implement this you need one line per slave. Since you are using SPI you thus need two lines per slave plus two lines for clock and data. Example: 5 slaves need 5 x 2 + 2 = 12 lines.

The time I needed a master controlling multiple (10 total) slaves I did it all with 2 wires over an I2C bus. After giving the GO command to each slave the master would then loop and frequently ask each slave was it done.
 

Thread Starter

KansaiRobot

Joined Jan 15, 2010
324
Thank you for your replies. I understand your assertion that it would need 2 lines per slave for the implementation. However I have been advised of a way to use only one line per slave (but the number of slaves is limited to four). I will explain this here and would appreciate your comments.

The trick is to use as CS pins the IOC pins of the master (in my case RB4~RB7). Instead of setting these pins as outputs we set them as inputs (high impedance).
Now, whenever the master wants to select a slave, it sets the corresponding CS as output, clears it (therefore notifying the slave to start SPI) and transmit. Once it is finished, sets the CS and then tristate it by making it an input again.

Now, when the slave finish what is doing, and wants to notify the master it sets this line (SS) to 1 therefore changing the state of the IOC pins of the master, therefore generating an interrupt.

This interrupt in the master will again start SPI communication with the corresponding slave.

It seems like a good idea (did I explain the idea well??) but the only thing that puzzles me is: yeah we can change the CS input/output direction but can we do that with the slave SS if we have set SSPM3~0 as 0100?? Or do I have to use SSPM3=0 as 0101?? but then if there is no SS control enabled how the slave recognize it is the one being called to transmit??
 

ErnieM

Joined Apr 24, 2011
8,377
If yoy use SPI you need a way to control the chip select. Final answer.

If you try to use that line as an input then you have nothing holding the slaves off.
 

nsaspook

Joined Aug 27, 2009
12,998
You can 'fake' a tri-state multi-directional one-wire line on a PIC to (many) PIC(s) by using a pull-up on the line. All ports to the line are inputs to keep it HIGH until a port pin pulls it LOW to send a signal with a TRIS to make it a output with the latch set LOW to control the line from it's side (then switch back to a input to bring the line back HIGH) to send a signal to another or (better) to a master interrupt to poll slaves. You could do this with the CS line but then there would be a window where the slave could have a collision unless it was coded to dump data during this CS back to master time with open-drain and all HIGH bits idle state in its SPI buffer. IMO more trouble than it's worth to implement.
 
Last edited:

nsaspook

Joined Aug 27, 2009
12,998
A external interrupt from the slave example using the board in this thread: PIC32 master/PIC18 slave
You can use polling and delays but this method gives max throughput (~108us per sample with overhead) and is decoupled from the slaves exact timing.

Top to bottom traces
SRQ Service request line from PIC18 to PIC32
SDI
SCK clocks for each transmission of a byte
SDO


The PIC32 input pin is configured to INT1 set to trigger on a negative edge sent from a output pin from the PIC18.
32 sends request for ADC data to 18 via SPI then waits for SRQ or timeouts out
18 sets the SRQ line HIGH when the ADC request is received and starts the conversion
18 completes the conversion (39.1 us), loads the ADC data into the SPI buffer then sets the SRQ line low
SRQ negative edge triggers the 32 ISR routine to set the spi_flag TRUE in the wait routine and it exits
32 then talks to the 18 slave to receive the data in the buffer (~10us from SRQ received)

PIC32 SPI wait routine
C:
/*
* branch macros for MIPS
*/
#define likely(x)      __builtin_expect(!!(x), 1)
#define unlikely(x)    __builtin_expect(!!(x), 0)
...
/*
*  delay a short time after spi command or exit on slave SRQ signal if srq is true
*  flag will always be unset to low on exit
*/

static void DelaySPI(WORD delay, int srq)
{
    unsigned int int_status;

    while (delay--) {
        if (likely(srq & spi_flag)) // make the instruction cache preload the exit code
            goto DelaySPI_exit;
        int_status = INTDisableInterrupts();
        OpenCoreTimer(500000 / 2000);
        INTRestoreInterrupts(int_status);
        mCTClearIntFlag();
        while (!mCTGetIntFlag());
    }
DelaySPI_exit:
    mCTClearIntFlag();
    spi_flag = LOW;
}
...
int SpiADCRead(unsigned char channel)
{
    V.adc_count++;
    xmit_spi_bus(CMD_DUMMY_CFG, 1);
    spi_flag = HIGH;
    cmd_response_port = xmit_spi_bus(CMD_ADC_GO_H | (channel & 0x0f), 1);
    DelaySPI(50, HIGH); // delay for adc conversion time and look for SRQ signal
    cmd_data[0] = xmit_spi_bus(CMD_ADC_DATA, 1);
    cmd_data[1] = xmit_spi_bus(CMD_DUMMY_CFG, 1);
    return(short int) (cmd_data[0] | (cmd_data[1] << 8));
}
...
/*-----------------------------------------------------------------------*/
/* Transmit a byte via SPI2  (Platform dependent)                  */

/*-----------------------------------------------------------------------*/

unsigned char xmit_spi_bus(unsigned char dat, WORD pace)
{
    unsigned char rec_buffer;

    V.spi_count++;
    SpiChnPutC(BUS_CHAN, dat); // Send data on the master channel, SPI2
    while (SpiChnIsBusy(BUS_CHAN));
    rec_buffer = SpiChnGetC(BUS_CHAN); // Get the received data
    DelaySPI(pace, LOW);
    return rec_buffer; // Get the received data
}
The Likely Macro in the delay function uses branch prediction hints (GCC __builtin_expect) to tell the compiler (if it's a good compiler) to generate code for the CPU pipeline to order the exit code inline instead of the timer code to optimize speed. Most of the time the delay function is called without checking for the flag so the prediction would be unlikely to just exit. Making exit likely reorders the code to directly exit without jumps and moves jumps/flushes into the delay code where it doesn't matter much.

http://kernelnewbies.org/FAQ/LikelyUnlikely

I could easily expand the use of SRQ for every master/slave SPI transmission instead of just ADC conversions to reduce fixed delays needed for the PIC18 to process data in its ISR but the time gained vs overhead is small as the PIC18 ISR is quick.
 
Last edited:
Top