Add PIO SPI slave example

Open
#115 11 comments 0 reactions 1 assignee View on GitHub

@Wren6991 is already working on this.

Since May 19, 2021.

Assessment

This issue has not been assessed yet.

Description

I currently have an Arduino Mega in SPI master mode, and a RPi Pico in slave mode, communicating over SPI. I was using the mega to troubleshoot some issues I was having.

My pinout is:

Arduino MOSI -> Pico GP16 (SPI0 RX)
Arduino SS   -> Pico GP17 (SPI0 CSn)
Arduino GND  -> Pico GND 
Arduino SCLK -> Pico GP18 (SPI0 SCK)

Here is the Pico's code:

#include <stdio.h>
#include <string.h>
#include "pico/stdlib.h"
#include "pico/binary_info.h"
#include "hardware/spi.h"

int main() {
    stdio_init_all();

    printf("Initializing SPI...\n");

    // SPI initialisation. This example will use SPI at 1MHz.
    spi_init(spi_default, 1000*1000);

    spi_set_slave(spi_default, true);
    gpio_set_function(PICO_DEFAULT_SPI_RX_PIN, GPIO_FUNC_SPI);
    gpio_set_function(PICO_DEFAULT_SPI_SCK_PIN, GPIO_FUNC_SPI);
    gpio_set_function(PICO_DEFAULT_SPI_TX_PIN, GPIO_FUNC_SPI);
    gpio_set_function(PICO_DEFAULT_SPI_CSN_PIN, GPIO_FUNC_SPI);

    int bytesread = 0;
    uint8_t buffer[14];

    while(true)
    {
        bytesread = spi_read_blocking(spi_default, 0, buffer, 14);
        for(int i = 0; i < bytesread; i++)
        {
            printf("%02x ", buffer[i]);
        }
        printf("\n");
    }
}

and here is the Arduino's code:

#include <SPI.h>                            

void setup (void)
{
  SPI.begin();                            //Begins the SPI commnuication
  SPI.setClockDivider(SPI_CLOCK_DIV8);    //Sets clock for SPI communication at 1 MHz
  pinMode(SS, OUTPUT);
  digitalWrite(SS, HIGH);                 
}

//Hello, World! in hex
byte buf[14] = {0x48,0x65,0x6c,0x6c,0x6f,0x2c,0x20,0x57,0x6f,0x72,0x6c,0x64,0x21,0x00};

void loop(void)
{
  digitalWrite(SS, LOW);
  for(int i = 0; i < 14; i++){
    SPI.transfer(buf[i]);
  }
  digitalWrite(SS, HIGH);
  delay(100);
}

This code sends the byte array buffer over SPI, setting CS to LOW, completing the transfer, then setting CS back to HIGH, as this is how the SPI protocol is supposed to function. However, in doing so, the Pico only receives the first byte of each transfer, waiting until it recieves 14 bytes and then displaying all the first byte.

Pico serial output:
image

After doing some fiddling around with the code, I realized that if I change the loop to toggle CS on each byte sent, the Pico successfully receives all of the data.

void loop(void)
{
  for(int i = 0; i < 14; i++){
    digitalWrite(SS, LOW);
    SPI.transfer(buf[i]);
    digitalWrite(SS, HIGH);
  }
  delay(100);
}

New Pico serial output:
image

However, this is not how the SPI protocol should operate and makes the Pico incompatible with pretty much every SPI master device, and seems to be an issue in the pico's hardware_spi library, unless this is user error and if that is the case then I will gladly be corrected.

Dominant language
C
Stars
3.9k
Forks
1k
Avg merge
1d 16h
Merged PRs (30d)
1

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from raspberrypi/pico-examples

All issues in raspberrypi/pico-examples

Similar issues

More C issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.