SPI interface with PIC18 - Mbed as slave

09 Feb 2011

Hello,

I am new to mbed and I am working on a project which uses a PIC as wireless link (MIWI) control unit and then i want to transfer the data the PIC recieves to an mbed which controls the rest of the system.

I am planning to use the SPI interface for this but I am not having much success. The PIC is the SPI master and the mbed is the slave.

I send a number of bytes from the PIC and have based my code for the mbed on the example in the handbook:

Reply to a SPI master as slave

  1. include "mbed.h"

Serial pc(USBTX, USBRX); tx, rx SPISlave device(p5, p6, p7, p8); mosi, miso, sclk, ssel DigitalOut myled(LED1); DigitalOut myled2(LED2); int main() { pc.printf("Hello World!\n"); device.format (8,3); device.frequency(4000000); device.reply(0x05); Prime SPI with first reply while(1) { if(device.receive()) { myled = 1; int v = device.read(); pc.printf("\r Value is: %d \n", v);

device.reply(0x00); Make this the next reply } } }

This work although not always reliably and recieves the first byte. However it does not recieve any of the other bytes I have sent. Is device.recieve return 1 after each byte has been recived or just at the start of a data stream. I have tried adding additional device.read lines in the if statement but that does not work.

If device.recieve does return 1 after each byte is recieved then something is wrong because the code inside the if statement is only run once when i send multiple bytes. Does there need to be a time delay between sending the bytes from the PIC?

Can anyone help me with this problem.

Thanks,

Tom

09 Feb 2011

Don't know the answer, but here's the code properly formatted (hint: use <<code>> and <</code>> tags).

// Reply to a SPI master as slave

#include "mbed.h"


Serial pc(USBTX, USBRX); // tx, rx
SPISlave device(p5, p6, p7, p8); // mosi, miso, sclk, ssel
DigitalOut myled(LED1);
DigitalOut myled2(LED2);
int main()
{
    pc.printf("Hello World!\n");
    device.format (8,3);
    device.frequency(4000000);
    device.reply(0x05);              // Prime SPI with first reply
    while(1) {
        if(device.receive()) {
              myled = 1;
            int v = device.read();
            pc.printf("\r Value is: %d \n", v);  
            
         device.reply(0x00);         // Make this the next reply
        }
    }
} 
09 Feb 2011

You may want to check the serial clock frequency of the pic and mbed.

09 Feb 2011

    pc.printf("\r Value is: %d \n", v);  

You are probably over running the SPI input fifos. SPI is a lot faster than the default 9600buad of the serial and you are trying to output a lot of text.

Try increasing the Serial baud.

    pc.baud(115200);

But I guess that won't even be fast enough. Output buffering will get you further, for example replacing Serial with the MODSERIAL library will get you further, but for how long? Only until your output buffer fills!

So you'll probably need input buffering on the incoming SPI. However, your program looks like a "Hello World" program just to see how things work. I guess in your final design you won't actually be printf'ing anything. Basically, in your sample there's no IO speed matching. You have a lot more incoming faster than you can shuffle it out again.

09 Feb 2011

The SPI Slave that is offered in the standard library works, but in practice it is useless. There is no way of checking the transmit FIFO before putting any data in it. I have written an interrupt driven SPI Slave class with buffering for the mbed. It is not yet ready for publishing, but will be soon as it is part of my mbed challenge ...

09 Feb 2011

There is one thing I noticed from your sample. You preload the return value before you know what the master has sent. It's kind of normal for a master to send a byte followed by a null (don't care) byte to get a result assuming the slave doesn't know what the master wants in advance.

However, it's possible if you are controlling both ends then you could know what's going on, assuming you sync them. But one thing you can do is use the GPDMA to read a number of bytes into a buffer (assuming you know how many bytes to expect). You can also use another DMA channel to send bytes back out. The MODDMA library makes this really simple to do as it provides "terminal count" callbacks to let you know when the required number of bytes have been read. And if you use MODSERIAL you can combine that really easily with MODDMA. Lots of possibilities there.

10 Feb 2011

mbed as a slave to a pic?

no way!

10 Feb 2011

Hi Tom,

what SPI-mode are you using on the mbed and how are you transferring multiple data words to it from your PIC? If you are using mode 0 (CPOL=0 and CPHA=0; this is the default mode) or mode 2 (CPOL=1 and CPHA=0), you have to pulse SSEL high between every data word (4 to 16 bits depending on data frame format) of your stream. When using mode 1 or 3 instead, you can keep SSEL low for the whole data stream length.

For more details about this you have to read the SSP section of the LPC17xx user manual.

Best regards

Neni

20 Jun 2015

hello Tom ,

Were you able to solve the problem i am facing a same problem with PIC16 and mbed LPC1768 and I have tried keeping SSEL low during mode 1 but it doesnt work but strangely when the SSEL signal is left disconnected in air the mbed recieves the data and as soon as it is connected back to the input pin again no reception of MOSI data.

Regards, Kishwar