Go Down

Topic: Ethernet2 (UDP) SPI transfers have a lot of dead time (Read 1 time) previous topic - next topic

weird_dave

I decided to write a separate piece of sample code to play around with SPI, without any of the the Ethernet stuff. Problem is, it doesn't work!
It gets to the SPI transfer part then falls over, I see "Transferring" on the serial monitor and never the "Done" (lines 26 and 28, wrapped around the SPI.transfer on line 27).
The Ethernet2 shield is attached to the SPI but nothing else (well, scope probes are). The transfers don't happen, the SPI clock doesn't change state.
If anyone can spot the idiot mistake I've made that would be great!
The Ethernet/SPI test code I posted previously still works, so it's not a short or other daft hardware issue.

Code: [Select]
#include <SPI.h>

const int SPIbuf_Size = 100;
byte SPIbuf [SPIbuf_Size];
const int FPGA_SPI_CSpin = 4;
unsigned long current_micros;
const unsigned long looptime = 2000000;
const int Serial_Baud = 115200;

void setup() {
  pinMode(FPGA_SPI_CSpin, OUTPUT);
  Serial.begin(Serial_Baud);
  Serial.println(F("Setup Complete"));
}

void loop() {
  current_micros = micros();
  for (int j = 0; j<256; j++)
  {
    Serial.print(F("Doing : "));
    Serial.println(j);
    SPIbuf[0] = j;
    SPIbuf[SPIbuf_Size-1] = j;
    SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
    digitalWrite(FPGA_SPI_CSpin, LOW);
    Serial.println(F("Transferring"));
    SPI.transfer (&SPIbuf, SPIbuf_Size);
    Serial.println(F("Done"));
    digitalWrite(FPGA_SPI_CSpin, HIGH);
    SPI.endTransaction();
    Serial.print(j);
    Serial.print(F(" : "));
    Serial.print(SPIbuf[0]);
    Serial.print(F(" : "));
    Serial.println(SPIbuf[SPIbuf_Size-1]);
    while ((micros()- current_micros)<looptime)
    {
     
    }
  }
}

weird_dave

Seems:
SPI.begin();
is required, shoved it in setup and it now works. I guess the Ethernet libraries are doing this and not
SPI.end();
when they are finished, making my other code work.

weird_dave

I just did a comparison between 28MHz and 42MHz, although the clocking was indeed faster, the deadtime increases to keep the 100 byte transfer at about 53us in both cases. I couldn't get 84MHz to work, it seemed to still clock at 42 :(

Paul Stoffregen

Are you communicating with other hosts on your local ethernet?  Or will you be talking to hosts on the internet, accessed through routers and high-latency links?

dlloyd

Quote
I just did a comparison between 28MHz and 42MHz, although the clocking was indeed faster, the deadtime increases to keep the 100 byte transfer at about 53us in both cases. I couldn't get 84MHz to work, it seemed to still clock at 42 :(
Yes, that matches my findings in reply 26. The SAM3X SPI hardware works without deadtime at up to 16.8MHz clock. Beyond this rate, the deadtime increases to cancel out the byte transfer time improvement because a wall has been hit.

According to the datasheet, DMA will optimize transfer rate ... I guess the DMA improvement would be noticed only if the SPI clock is set higher than 16.8MHz.

This looks interesting...

32.7.3.9 Peripheral Deselection with DMAC
When the Direct Memory Access Controller is used, the chip select line will remain low during the whole transfer since the TDRE flag is managed by the DMAC itself. The reloading of the SPI_TDR by the DMAC is done as soon as TDRE flag is set to one.

ard_newbie



Did you try turbospi.h library for Sam3x  ( https://github.com/anydream/TurboSPI ) ?


dlloyd

Yeah, now that's more like it!

SPI SCK @ 42MHz, no deadtime, 100 bytes transferred in 19.04µs!

5.25 MBps (42Mbps)


Code: [Select]
#include <TurboSPI.h>

TurboSPI    g_SPI;
DigitalPin  g_PinCS, g_PinRS;
uint8_t     g_Buffer[100];  // some data buffer to transfer
uint8_t     g_Divisor = 2;  // transfer speed set to MCU's clock divide by 2

void setup()
{
  // setup pins
  g_PinCS.Begin(45);
  g_PinRS.Begin(47);

  g_PinCS.PinMode(OUTPUT);
  g_PinRS.PinMode(OUTPUT);

  // setup SPI
  g_SPI.Begin();

  // fill the buffer with data
  for (uint8_t i = 0; i < sizeof(g_Buffer); i++) {
    g_Buffer[i] = i + 1;
  }
}

void loop()
{
  // setup speed and select slave
  g_SPI.Init(g_Divisor);
  g_PinCS.Low();

  // set some pins
  g_PinRS.High();

  // transfer data to slave
  g_SPI.Send(g_Buffer, sizeof(g_Buffer));

  // unselect slave
  g_PinCS.High();
}

weird_dave

Are you communicating with other hosts on your local ethernet?  Or will you be talking to hosts on the internet, accessed through routers and high-latency links?
Neither that time, this was SPI only test of 100 bytes.

Yes, that matches my findings in reply 26. The SAM3X SPI hardware works without deadtime at up to 16.8MHz clock. Beyond this rate, the deadtime increases to cancel out the byte transfer time improvement because a wall has been hit.
Oops, I forgot to include my 21MHz result, it was slower than 28MHz, about 65us if memory serves...
Have you done this?
Code: [Select]
// Edit occurances of SPI_CSR_DLYBCT(1) to SPI_CSR_DLYBCT(0) in
//  C:\Users\[USERNAME]\AppData\Local\Arduino15\packages\arduino\hardware\sam\1.6.9\libraries\SPI\src\SPI.cpp
// and C:\Users\[USERNAME]\AppData\Local\Arduino15\packages\arduino\hardware\sam\1.6.9\libraries\SPI\src\SPI.h


Yeah, now that's more like it!

SPI SCK @ 42MHz, no deadtime, 100 bytes transferred in 19.04µs!
That's rather good. It isn't obvious to me if it receives at the same time as transmitting, if it does then this improves the SPI part of my project (I'm effectively building an Ethernet to FPGA bridge, I don't want to control the wiznet directly hence the Due. I have the FPGA and Due talking via SPI full duplex).
The real task now is to try and modify the Ethernet library to use TurboSPI, not a task I'm looking forward to, there goes the weekend :D

dlloyd

Yes, it should receive at the same time. The MISO line is on pin 47.

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy