SPI comms between 2 MCUs

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

SPI comms between 2 MCUs

918 Views
woohoo
Contributor I

Hi,

 

I am attempting to establish SPI communication between 2 GT16a MCUs, where one is the slave and the other the master. I am able to send data from the master to the slave, but am receiving rubbish when trying to get data sent from the slave to the master. Any idea as to what could be the problem.

 

// For the Master MCU  void laserComm(char Data[]) {    if (Data[0] == 'X')PTCD_PTCD6 = 0; //Pull low to select correct slave   if (Data[0] == 'Y')PTCD_PTCD5 = 0; //Pull low to select correct slave   if (Data[0] == 'Z')PTCD_PTCD4 = 0; //Pull low to select correct slave    for(laserCommCount=0; laserCommCount <= dataSize ; laserCommCount++)        SPIdataIn[laserCommCount] = SPItransfer(Data[laserCommCount]);    PTCD_PTCD6 = 1; // Pull high after data transfer   PTCD_PTCD5 = 1;   PTCD_PTCD4 = 1; }  byte SPItransfer (byte val) {   // First send, then receive   while(!SPIS_SPTEF);   SPID = val;   while(!SPIS_SPRF);   return SPID; }  // For the slave MCU interrupt 15 void receiveSPI (void) {         SPIdataIn[SPIReceiveIndex] = SPItransfer(Packet1[SPIReceiveIndex]);         if (SPIReceiveIndex == dataSize)         {             SPIdataReceived = 1;             // Indicate the data has been received                  SPIReceiveIndex = 0; // Reset receive index             }        else SPIReceiveIndex++; }

 

all the data is an array of chars.

 

Thanks!

 

Labels (1)
0 Kudos
3 Replies

640 Views
bigmac
Specialist III

Hello,

As has already been mentioned, the SPItransfer() function is unsuited to slave use, and particularly so when using an interrupt for the slave process.

  1. Any data to be returned by the slave needs to be pre-loaded to the slave buffer prior to SS from the master becoming active.  This data will then be shifted out to the master, as the next byte from the master is shifted in by the slave.
  2. It is also possible to make use of the double buffering capability of the SPI module, where the first two return bytes would be preloaded to the buffer.  In this instance, it would not matter whether the new return data were loaded to the buffer prior to, or following the processing of the received byte, within the ISR.
  3. When appropriately using the SPI interrupt for the slave end, the ISR should handle only a single byte at a time, and then exit.
  4. The send process by the master may need to be suitably "paced" so that there is sufficient time for the slave ISR to complete execution, prior to the next byte being sent.  This will also need to take into account the processing of any other interrupts that may be enabled within the slave.
  5. The master may also need to send an extra dummy byte so that the final slave byte can be returned from the SPI buffer.

// Global variables:
byte SPIdataIn[BUF_SIZE];
byte Packet1[BUF_SIZE];

byte dataSize;

byte SPIdataReceived;

static byte *Recv_buf;
static byte *Send_buf;
static byte byte_count;

...

  // Initialise pointers

  Recv_buf = SPIdataIn;
  Send_buf = Packet1;
  byte_count = 0;

  SPIdataReceived = 0;

...

interrupt 15 
void receiveSPI (void)  
{   
  (void)SPIS;            // Part of flag clearing
  *Recv_buf++ = SPID;    // Receive current byte
  SPID = *Send_buf++;    // Load next byte to buffer
  byte_count++;

  if (byte_count == dataSize)  {  
    SPIdataReceived = 1; // Flag data received   
    byte_count = 0;      // Reset counter  
  }
}

Regards,

Mac

640 Views
woohoo
Contributor I

Thanks for the reply.

I just want to confirm that my code for the master to receive is valid, also is shown my modified code for the slave.

// Master

byte SPItransfer (byte val)

{

  // First send, then receive

  while(!SPIS_SPTEF);

  SPID = val;

  while(!SPIS_SPRF);

  return SPID;

}

/////////////////////////////////////////////////////////////////////////////////////

//Master

void laserComm(char Data[])

{

  if (Data[0] == 'X')PTCD_PTCD6 = 0; //Pull low to select correct slave

  if (Data[0] == 'Y')PTCD_PTCD5 = 0; //Pull low to select correct slave

  if (Data[0] == 'Z')PTCD_PTCD4 = 0; //Pull low to select correct slave

  for(laserCommCount=0; laserCommCount <= dataSize ; laserCommCount++)

  SPIdataIn[laserCommCount] = SPItransfer(Data[laserCommCount]);

  PTCD_PTCD6 = 1; // Pull high after data transfer

  PTCD_PTCD5 = 1;

  PTCD_PTCD4 = 1;

}

/////////////////////////////////////////////////////////////////////////////////////

//Slave receive function

interrupt 15  // SPI receive interrupt

void receiveSPI (void)

{

  (void)SPIS; // Clear flags

  SPIdataIn[SPIReceiveIndex] = SPID; // Receive byte

  SPID = Packet1[SPIReceiveIndex]; // Load byte to send

  if (SPIReceiveIndex == dataSize)

  {

  SPIdataReceived = 1;             // Indicate the data has been received

  SPIReceiveIndex = 0; // Reset receive index

  }

  else SPIReceiveIndex++;

}

Also I still don't seem to be receiving the data I expect. Are there any timing considerations?

0 Kudos

640 Views
yanam
Contributor II

In the slave code, I would have checked the SPRF and read the data, followed by stuffing of byte to be sent... something like this

  1. byte SPItransfer_ForSlave (byte val) 
  2. {
  3.   byte return_data; 
  4.   // First receive, then keep the register updated with val
  5.   while(!SPIS_SPRF); 
  6.   return_data = SPID;
  7.   SPID = val; 
  8.   return return_data
  9. }