MBed-MBed SPI Investigation

01 Aug 2011

Hi Folks,

After a weeks trial and error, I have now got 2 MBEDS talking to each other via SPI, and I want to share this with others trying to do the same. In addition, I have a question on the SPI Slave behaviour - please see later in mail.

What I've done...

1. Connect two mbeds :- p5->p11, p6->p12, p7->p13 and p8->p14 (note that first is master, 2nd slave). Note that I connect straight, I do not cross MOSI and MISO. If I do cross these, I get zero values from the Slave.

2. Ensure that both mbeds have common earth. Not sure if this is necessary, but it did seem to help :-/

3. I am using breadboard, and I have found that (v. occasionally) it was necessary to re-seat the wires, or occasionally jiggle them around when it didn't work. Think this needs better contact work - which I intend to do when I do my real project. Also working at lower frequencies helps. Anyhow, it does work.

The code...

Master

#include "mbed.h"

SPI spi(p5, p6, p7); // mosi, miso, sclk
DigitalOut chipSelect(p8);

Serial pc(USBTX, USBRX); // tx, rx

int main() {

    int valueToSendToSlave = 20; // Starting value only, this increments
    spi.format(8,3);        // Setup:  bit data, high steady state clock, 2nd edge capture
    spi.frequency(1000000); //1MHz

    pc.printf("======================================================\r\n");
    pc.printf("Press any key to start...\r\n");
    pc.getc(); // wait for keyboard

    int counter = 1;
    while (1) {

        pc.printf("%d Value to send = %d ", counter++, valueToSendToSlave);
        
        chipSelect = 0; // Select device
        int dataFromSlave =  spi.write(valueToSendToSlave);
        chipSelect = 1; // Deselect device

        pc.printf("  returns %d\r\n", dataFromSlave);
        
        valueToSendToSlave++;
        
        wait(5); // Wait for 5 seconds for readability only
        
    }
}

Slave

#include "mbed.h"

SPISlave device(p11, p12, p13, p14); // mosi, miso, sclk, ssel

Serial pc(USBTX, USBRX); // tx, rx

int main() {

    int counter = 1;

    device.format(8,3);        // Setup:  bit data, high steady state clock, 2nd edge capture
    device.frequency(1000000); // 1MHz

    int reply = 99;
    device.reply(reply);              // Prime SPI with first reply
    device.reply(reply);              // Prime SPI with first reply, again

    pc.printf("======================================================\r\n");
    pc.printf("Startup Next reply will be %d\r\n", reply);

    while (1) {
        if (device.receive()) {
            int valueFromMaster = device.read();
            pc.printf("%d Something rxvd, and should have replied with %d\n\r", counter++, reply);
            device.reply(++reply);              // Prime SPI with next reply
            pc.printf("    Received value from Master (%d) Next reply will be %d \r\n", valueFromMaster, reply);
        }
    }
}

Output

Master

Press any key to start...
1 Value to send = 20   returns 0
2 Value to send = 21   returns 99
3 Value to send = 22   returns 100
4 Value to send = 23   returns 101
5 Value to send = 24   returns 102
6 Value to send = 25   returns 103

Slave

Startup Next reply will be 99
1 Something rxvd, and should have replied with 99
    Received value from Master (20) Next reply will be 100 
2 Something rxvd, and should have replied with 100
    Received value from Master (21) Next reply will be 101 
3 Something rxvd, and should have replied with 101
    Received value from Master (22) Next reply will be 102 
4 Something rxvd, and should have replied with 102
    Received value from Master (23) Next reply will be 103 
5 Something rxvd, and should have replied with 103
    Received value from Master (24) Next reply will be 104 

QUESTION: I think the first value returned from Slave should be 99, not 0. I dont understand why the first Master 'write()' doesn't provoke a Slave 'device.received()'?

Note the 2 'reply()' in the initial setups of the Slave. If you remove one of these, which I think is correct, the output is...

Master

Press any key to start...
1 Value to send = 20   returns 0
2 Value to send = 21   returns 100
3 Value to send = 22   returns 100
4 Value to send = 23   returns 102
5 Value to send = 24   returns 103
6 Value to send = 25   returns 104
7 Value to send = 26   returns 105

Slave

Startup Next reply will be 99

1 Something rxvd, and should have replied with 99
    Received value from Master (20) Next reply will be 100 
2 Something rxvd, and should have replied with 100
    Received value from Master (21) Next reply will be 101 
3 Something rxvd, and should have replied with 101
    Received value from Master (22) Next reply will be 102 
4 Something rxvd, and should have replied with 102
    Received value from Master (23) Next reply will be 103 
5 Something rxvd, and should have replied with 103
    Received value from Master (24) Next reply will be 104 
6 Something rxvd, and should have replied with 104
    Received value from Master (25) Next reply will be 105 
7 Something rxvd, and should have replied with 105
    Received value from Master (26) Next reply will be 106 

Notice how the Master never receives the initial value of 99.

I hope my logic is correct here. Can anybody help please?

Many Thanks Ian Hunter

03 Aug 2011

I'd be suspicious of the chipSelect signal.

It will be idling low from the time it is declared (in the DigitalOut statement) until it is raised after the first Master transmission.

Perhaps the Slave doesn't like being selected when its own format (or the Master's format) is changed.

Try setting chipSelect high right at the top of main() in the Master, and see if things change.

23 Aug 2011

I'm not having your problem with the initial reply being wrong but I am having problems in general with the mbed as a SPI slave.

Making multiple calls to reply() without corresponding read() calls causes lots of grief. For each call to reply() without a corresponding read() you seem to have to send that many bytes across the SPI bus before receive() actually says there is anything to receive. This really messes everything up.

My little test program uses a Cinterion TC65i module to send serial data to the mbed, sadly I don't have any free serial ports on the TC65i so I'm trying to send simple serial messages via the SPI. I have a problem where I seemed to be losing this one byte in/one byte out synchronisation. This didn't seem to happen if there was a large delay between each byte sent, say 10th second.

I wrote a simple Java program to write 0-9 at 100k baud. The mbed simply echos back the number received. This would often go wrong, the TC65i would see a reply to a byte and from then on there would be a misalignment. The received byte was not what the mbed should have been sending. The mbed's debug would shouldn't show any extra bytes and it's output was as expected. It's like the byte was received by the mbed but queued and the mbed program not told until another byte comes in.

So like with calling reply() multiple times makes it appear the mbed is buffering incoming data. Resetting the TC65i doesn't resynchronise the bytes thus making me think the mbed is the problem.

Sadly I don't have a scope that can log enough data to capture the problem and to look at the SPI bus, nor do I have a SPI bus analyser.

Would be nice to understand what's going on here.

19 Oct 2012

Hello Ian, Am new and, would like to know how the code was executed after compiling and saving to each embed.

10 Sep 2014

Ian Hunter wrote:

where should we look for the output.will it be displayed on the scree?do we require any new software installed to see the output? please help me out

24 Nov 2014

Hi folks,

I wanted to have two KL25Zs communicate with each other using SPI. When I used Ian Hunter's code, the KL25Z that should act as the slave gives me the following error: "pinmap not found for peripheral" I've verified the hardware connections. Anyone knows what is going wrong?

Thanks in advance, Adarsh

06 Jul 2017

Adarsh Mani wrote:

Hi folks,

I wanted to have two KL25Zs communicate with each other using SPI. When I used Ian Hunter's code, the KL25Z that should act as the slave gives me the following error: "pinmap not found for peripheral" I've verified the hardware connections. Anyone knows what is going wrong?

Thanks in advance, Adarsh

Too old question.. But maybe someone needs the answer. You are not using the correct pin for the CS signal or for the other SPI pins. Look at the source code and find the slave pins you should use. In my case with Nucleo-F030R8, for CS I needed to use PA_4 for cs ..not SPI_CS which is PB_6 for master SPI.