SPI interrupt missing transmits. What can I do?

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

SPI interrupt missing transmits. What can I do?

1,125 Views
mavericknm
Contributor I

I am using an IMx6 variant master to collect data from a MC9SC08PA32 slave over SPI. I have noticed many byte packets are being dropped. The symptom is more pronounced when the SPI frequency is increased relative to the slave's external crystal speed. The error only occurs on the the slave's write cycle. It is able to read each and every incoming byte.

 

The error sends the previous byte a second time. No information is lost but there are duplicate bytes. So if the slave was asked to send 10 bytes in increasing order from 1 to 10, an error will appear as 11 bytes with one of the bytes randomly duplicated.

Ex. 1,2,2,3,4,5,6,7,8,9,10.

 

Example:

When the slave is clocked with a 18.1 MHz crystal and the master sets a SPI speed of 60kHz, 84/5000 bytes are errors. At an SPI speed of 100kHz, 5000/5000 fail.

 

When the slave is over clocked with a 24 MHz crystal and the master sets a SPI speed of 60kHz, 0/5000 bytes are errors. At an SPI speed of 100kHz, 47/5000 fail.

 

Similar results were tested for an 11.05 MHz crystal at lower SPI speeds.

 

Data sheets tell me that a an SPI frequency between fBus/2048 and fBus/2 are acceptable. It also tells me that an external crystal must be between 4 and 20 MHz. It's nice to see that over clocking is possible but this isn't an acceptable solution to getting MHz speed SPI.

 

It's fairly clear to me that the slave (in slave mode) is unable to keep up with the master and is missing transmit opportunities. The master is simply reading whatever data already exists in the SPI buffer. I've tried disabling timer and ADC interrupts but that hasn't had any impact. What can I do? Where are my cycles going?

 

Code

volatile byte Flags;   /* Temporary variable for flags */

volatile byte Data;

ISR(SS1_Interrupt)

{

  SPITimeout = mScount + 2;

  if (SPITimeout > ROLLTIME) SPITimeout = -2;

  Flags = SPI0_S;

  Data = SPI0_D;

 

 

  switch (IOState) {

  case IOSTATE_RECV:

  if ((SPI0_S_SPRF_MASK & Flags) == SPI0_S_SPRF_MASK) {

  InpTransitBuf[receivepos] = Data;

  receivepos++;

  if (receivepos == (SPI_INP_BUF_SIZE - 1)) {

  IOState = IOSTATE_XMIT;

  transitpos = 0;

  }

  }

  break;

  case IOSTATE_XMIT:

  SPI0_C1_SPTIE = 0U;                  // Disable transmit interrupt

  if ((SPI0_S_SPTEF_MASK & Flags) == SPI0_S_SPTEF_MASK) { //is buffer empty? It better be!

  SPI0_D = OutTransitBuf[transitpos];

  transitpos++;

  if (transitpos == (SPI_OUT_BUF_SIZE - 1)) {

  IOState = IOSTATE_COMPLETE;

  }

  }

  IPC_SC_PULIPM = 1U;                  // Restore Interrupt Priority Mask

  break;

  case IOSTATE_COMPLETE:

  SS1_TransferComplete();

  Flags = SPI0_D;

  SPI0_D = 0xdd;

  IOState = IOSTATE_WAIT;

  break;

  case IOSTATE_WAIT:

  Flags = SPI0_D;

  SPI0_D = 0xcc;

  break;

  }

  //IPC_SC_PULIPM = 1U;                  // Restore Interrupt Priority Mask

}

 

Thanks for taking the time to read this.

Labels (1)
0 Kudos
1 Reply

459 Views
kef2
Senior Contributor IV

Hi,

"It's fairly clear to me that the slave (in slave mode) is unable to keep up with the master and is missing transmit opportunities."

That's right. Master has to give some time for slave to respond to SPI interrupt and fill SPI tx register. You may keep using max allowed bit rate but have to keep gaps between byte transfers longer than interrupt latency defined by your S08 app.

0 Kudos