I’ve got SPI communication working perfectly well in the following configuration:
Master: Seed Wio Terminal (platformIO using Seeed Arduino SPI library)
Slave: AU + Br using the SPI peripheral component with the following acf:
pin sck A5
pin sdi A6
pin sdo A9
pin cs A2
Now master->slave
communication works perfectly well at 24 MHz, but slave->master
communication is garbled if the SPI clock is above 12 MHz.
This gives me about 700 KB/sec in both directions simultaneously.
Question: does anyone know if the speed limitation is in the AU, or is it more likely that the WIO can’t keep up?
Lucid code (github):
module alchitry_top (
input clk, // 100MHz clock
input rst_n, // reset button (active low)
output led[8], // 8 user controllable LEDs
input usb_rx, // USB->Serial input
output usb_tx, // USB->Serial output
input sck, // spi clock
input sdi, // spi mosi
output sdo, // spi miso
input cs // spi slave select
) {
/*
SPI Mode 0 = CPOL 0 CPHA 0
SPI Mode 1 = CPOL 0 CPHA 1
SPI Mode 2 = CPOL 1 CPHA 0
SPI Mode 3 = CPOL 1 CPHA 1
*/
sig rst // reset signal
.clk(clk) {
// The reset conditioner is used to synchronize the reset signal to the FPGA
// clock. This ensures the entire FPGA comes out of reset at the same time.
reset_conditioner reset_cond
.rst(rst) {
fifo echo (#WIDTH(8), #ENTRIES(256))
fifo forward (#WIDTH(8), #ENTRIES(256))
uart_rx rx (#BAUD(1000000), #CLK_FREQ(100000000))
uart_tx tx (#BAUD(1000000), #CLK_FREQ(100000000))
spi_peripheral spi (#CPOL(0), #CPHA(0), .cs(cs), .sck(sck), .sdi(sdi))
}
dff have_char[1]
dff next_char[8]
}
always {
reset_cond.in = ~rst_n // input raw inverted reset signal
rst = reset_cond.out // conditioned reset
// connect usb
tx.block = 0
rx.rx = usb_rx
usb_tx = tx.tx
// connect spi
spi.data_in = 8h00
sdo = spi.sdo
// init echo fifo
echo.din = 0
echo.wput = 0
echo.rget = 0
// init forward fifo
forward.din =0
forward.wput = 0
forward.rget = 0
// leds
led[0] = echo.empty
led[1] = echo.full
led[2] = forward.empty
led[3] = forward.full
led[7] = cs
led[6] = sck
led[5] = 0
led[4] = 0
// echo eceived characters (spi or console) to console
if (! echo.empty && !tx.busy ) {
echo.rget = 1
tx.data = echo.dout
tx.new_data = 1
} else {
tx.data = 0
tx.new_data = 0
}
// store input from console in spi forward buffer
if (rx.new_data && !echo.full) {
echo.din = rx.data
echo.wput = 1
if (! forward.full) {
forward.din = rx.data
forward.wput = 1
}
}
// SPI data has to be ready to send before SPI transfer starts
if (!have_char.q) {
if (!forward.empty) {
forward.rget = 1
next_char.d = forward.dout
} else {
next_char.d = 8hff
}
have_char.d = 1
}
spi.data_in = next_char.q
// store received spi inout in console echo buffer
if (spi.done) {
have_char.d = 0 // need next char to send
if (!echo.full) {
echo.din = spi.data_out
echo.wput = 1
}
}
}
}
Wio code (github):
#include <Arduino.h>
#include <SPI.h>
#include "debug.h"
#include <tft_functions.h>
#include <battery.h>
#include "buttons.h"
// for documentation
const auto spi_ss = PIN_SPI_SS; // (50ul) = BCM24 = pin 18 on wio breakout
const auto spi_mosi = PIN_SPI_MOSI; // (48ul) = BCM10 = pin 19 on wio breakout
const auto spi_miso = PIN_SPI_MISO; // (47ul) = BCM9 = pin 21 on wio breakout
const auto spi_sck = PIN_SPI_SCK; // (49ul) = BCM11 = pin 23 on wio breakout
const char *tqbf = "the quick brown fox jumps over the lazy dog\r\n";
// local function declarations here:
static void setup_debug();
static void setup_spi();
static void print_hex(uint8_t x);
static void wait_btn();
void setup()
{
setup_debug();
// buttons
init_buttons();
// initialize tft
init_tft();
tft_clear();
// initialize battery
init_battery();
printBatteryStats();
// initialize spi
setup_spi();
}
static unsigned char txbuf[64];
static unsigned char rxbuf[64];
void loop()
{
memset(txbuf, 0xff, sizeof(txbuf));
memset(rxbuf, 0xff, sizeof(rxbuf));
size_t count = strlen(tqbf);
memcpy(txbuf, tqbf, count);
tft_println("Start SPI");
// 24MHz transmit is OK, but receive is max 12 Mhz
SPI.beginTransaction(SPISettings((int)12000000, MSBFIRST, (uint8_t)SPI_MODE0));
// TXBUF != NULL => write and read simultaneously
// TXBUF == NULL => read only
// SPI.transfer(txbuf, rxbuf, count, false);
// SPI.waitForTransfer();
digitalWrite(PIN_SPI_SS, LOW);
for (size_t i = 0; i < count; i++)
{
rxbuf[i] = SPI.transfer(txbuf[i]);
}
digitalWrite(PIN_SPI_SS, HIGH);
SPI.endTransaction();
tft_println("SPI complete");
#ifdef DEBUG
for (size_t i = 0; i < count; i++)
{
print_hex(rxbuf[i]);
if (rxbuf[i] != 0xff && rxbuf[i] != 0x00)
{
tft_print(String((char)rxbuf[i]));
}
}
Serial.println();
for (size_t i = 0; i < count; i++)
{
print_hex(txbuf[i]);
}
Serial.println();
#endif
wait_btn();
tft_clear();
}
static void print_hex(uint8_t x)
{
if (x < 16)
{
Serial.print('0');
}
Serial.print(x, HEX);
}
static void setup_debug()
{
#ifdef DEBUG
Serial.begin(115200);
int n = 250;
while (!Serial && n-- > 0)
{
delay(1);
}
delay(100);
#endif
}
static void setup_spi()
{
tft_println("SPI setup");
pinMode(PIN_SPI_SS, OUTPUT);
digitalWrite(PIN_SPI_SS, HIGH);
SPI.begin();
/*
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
SPI.setClockDivider(1);
*/
tft_println("SPI initialised");
wait_btn();
tft_clear();
}
static void wait_btn()
{
while (digitalRead(WIO_KEY_B) == HIGH)
{
delay(1);
}
while (digitalRead(WIO_KEY_B) == LOW)
{
delay(1);
}
}