9 years, 9 months ago.

Combination of Serial and SPI Communication

Hello, I'm trying to combine the serial usb communication and SPI communication in mbed LPC1768. But, everytime I try to run both communication, the data that is received is very unstable. I need to combine both of them because I need to make a hardware-in-the-loop simulation by using mbed, MATLAB and a flight controller board. This simulation is used for visual-tracking octorotor that I build for my thesis. Is there anyone know about the solution of this problem? Strangely enough, when I try not to combine them and run them separately, the communication runs well.

This is some of my code

void Receivedserial() // Used to receive serial data from MATLAB simulink
{
   idxserial=0;
   overflowSerial=0;
   while ((overflowSerial==0) && (idxserial<10))
          {
             temp=pc.getc();
             if ((temp=='#') && (tanda==0)) {
                 idxserial=0;
                 tanda=1;
                 }
             if ((temp=='*')&&(idxserial==9)) overflowSerial=1;
             ReceiveSerial[idxserial]=temp; 
             if (overflowSerial==1)  tanda=0;
             idxserial++;  
           } 
    
}

void communicationSPI() //Used for SPI communication between flight control board and the mbed board. 
{
    idxSPI=0;
    overflowSPI=0;
    while ((overflowSPI==0)&& (idxSPI<10))
           {
                if(device.receive()) 
                {
                   temp1 = device.read();   // Read byte from master
                   ReceiveSPI[idxSPI]=temp1;
                   if ((temp1=='#')&&(tanda1==0)) 
                   {
                       idxSPI=0;
                       tanda1=1;
                   }
                   if ((temp1=='*') &&(idxSPI==9)) overflowSPI=1;
                   device.reply(ReceiveSerial[idxSPI]);
                   if (overflowSPI==1)  tanda1=0;
                   idxSPI++;
                }
             }   
}

void sendserial() //Used for sending the data received from the flight control board to MATLAB simulink
{
   for(unsigned char i=0;i<10;i++)
                       {                        
                        pc.putc(ReceiveSPI[i]);                       
                       } 
}

Please use <<code>> and <</code>> (on seperate lines), now your code is unreadable.

posted by Erik - 07 Aug 2014

1 Answer

9 years, 9 months ago.

I'm assuming that Receivedserial() and the SPI equivalent are called by the receive interrupts rather than being polled. If not then you need to do that before you have any real hope of getting this to work. You can run a single interface without interrupts but running two of them that way is fighting a loosing battle.

With that assumption...

If it works with one section at a time then it's probably going to be some sort of timing related problem. Normally this would indicate things are overflowing due to the timings changing or values are changing when you don't expect them to.

Are all of your packets always 10 bytes long?

It looks like your receive interrupts put data into an array that I'm guessing is 10 bytes and then your transmit functions read from the same buffers and send the whole buffer no matter how much of it contains valid data. In the interrupts you only flag an overflow if the 10th byte is a * and you still increase the index counters which means they could be pointing outside of the array. c doesn't protect against that, if you try to write to byte 11 of a 10 byte array it will let you. What ends up happening is that it trashes whatever variable happens to be in the next memory location.

Do you have any protections against the data getting changed while you are sending it?

It doesn't look as if you have any protection against the buffer getting changed by an interrupt while you are sending it. If it takes longer than expected to finish sending a packet because you've been reading a new one coming in then your buffer may change during the transmit. (Obviously not an issue if you're not using interrupts but if you're not it's not going to work well for more than one input) One thing you may want to do is copy the buffer before sending it. e.g.

main() {

.. setup

char tempBuffer[10];
while (true) {
  if (SPIReadyToSend) {

    // disableInterrupts
    _disable_irq() 

    // copy the SPI buffer (copy to tempBuffer from RecieveSPI a total of (10 * the size of a char) bytes
    // (ok so sizeof() is a little redundant when it's a char array but it's a good habit to get into)
    memcpy(tempBuffer,ReceiveSPI, 10*sizeof(char));

    // now maybe reset the counter so that the SPI buffer starts from the beginning again rather than doing that in the interrupt?

    _enable_irq() // re-enable interrupts
    
    sendSerial(tempBuffer);
    }
}

}

Finally a couple of notes on variable declarations:

I'm not sure what it's for but your variable tanda is used in both interrupts, that's not normally something you want to do.

The temp variables (temp for serial and temp1 for SPI) look like they are declared globally, those are very generic names, it would be safest the declare them local to the receive routines.

And if in doubt declare any variables modified in an interrupt but then used in the main code as being volatile, without that there is a risk that the compiler will optimize things and miss changes in the value.

Just wanted to reply when I saw yours. But I don't think he is running them interrupt based. Standard SPI(slave) has no interrupt based mode, and his Serial receive is doing a while loop with getc.

So easiest solution is most likely running Serial in interrupt mode, since that one already has support for interrupts. Then SPI can just stay blocking.

posted by Erik - 07 Aug 2014

I really should read the code more carefully. I saw a while loop in the serial input and just took it as the normal while(serial.readable()) {} loop and carried on to the next line.

At least that avoids the buffer overflow problem.

posted by Andy A 07 Aug 2014