Bitbang SPI on Arduino DUE:timing delay issue

Hi,
As you know Arduino DUE works at 84MHz and It's too fast for many SPI devices,using Bitbang SPI.
After days of testing,changing delay values, I decided to ask: Is there someone how has SPI bitbang working on DUE at speed of (about) 5MHz?
The code I posted in the attachment is part of a library that uses mode 0,LSB first SPI (and this is the reason why I don't use HW SPI).
Unfortunately I don't own on oscilloscope.
Thanks for reply.

ArduinoDUE_bitbangSPI.c (896 Bytes)

Hi

I have no experience with the DUE. But Arduino offers a SPI bus reduction: e.g. SPI.setClockDivider(SPI_CLOCK_DIV128);

However, isn't this wrong?

static inline void delayCycles(int cycles)
{
    for (int i=0; i++; i<cycles)
    __asm__("nop\n\t");
       // __nop();
}

Shouldn't it be?

static inline void delayCycles(int cycles)
{
    for (int i=0; i<cycles; i++)
    __asm__("nop\n\t");
       // __nop();
}

This little bit bang SPI MSB first baby works for me:

void SPIBBWriteMSB(byte value)
{
  for (byte i = 0; i < 8; i++)
  {
    if (value > 127) 
      digitalWrite(pinNo_MOSI, HIGH);
    else 
      digitalWrite(pinNo_MOSI, LOW);

    digitalWrite(pinNo_SCK, HIGH);

    value = value << 1;

    digitalWrite(pinNo_SCK, LOW);
  }
}

I didn't see the last part of the post,sorry!!

If I right understood you are using bitbang SPI on predefined SPI pins for your boards? right?

True the SPI... is from the Wire library. Just wondered if it was possible.

Anyway, the clock and data sequence in SPI is critical.

I have never seen the for-loop syntax before you are using. Indeed the compiler doesn't complain but that does not mean that everything is as it is supposed to be.

Wow,You are right,this is an error! I copy and paste the code and don't noticed this!

My doubt about pins to use is that:

if you use SPI.begin,then SPI.setClockDivider then you are using MISO,MOSI,CLK pins on ICSP header.
Those pins are managed by SPI registers.
if you use digitalWrite(_MOSI,HIGH) or digitalWrite(_CLK,HIGH) on the same pins, then you assume that MISO,MOSI,CLK are managed by PIO registers...

I'm a bit confusing...are you using something like this?

#include <SPI.h>
#include <yourlibrary.h>
//pins on the Arduino UNO ICSP header
#define pinNo_SCK  (2)
#define pinNo_MOSI (3)
#define pinNo_MISO (5)

void setup()
{
  
  SPI.begin();
  SPI.setClockDivider(SPI_CLOCK_DIV128);
}

and in yourlibrary.h you use the function void SPIBBWriteMSB(byte value)
that uses bitbang (e.g digitalWrite(pinNo_MOSI, HIGH) )

Is that what you use?

The code I posted in the attachment is part of a library that uses mode 0,LSB first SPI (and this is the reason why I don't use HW SPI).

Have you tried something like this?

// http://arduino.cc/en/Reference/DueExtendedSPI

#include <SPI.h>

void setup() {
  SPI.begin(10);                    // can use pins 4, 10, or 52 for CS.
  SPI.setClockDivider(10, 17);      // 4.94 MHz SCK
  SPI.setDataMode(10, SPI_MODE0);
  SPI.setBitOrder(10, LSBFIRST);
}

void loop() {
 byte response = SPI.transfer(10, 0xFF);
}

If you need to use completely different pins for SPI (and still use hardware SPI), then USART0 could be configured for SPI Master, Mode 0, LSB first as follows (untested):

/*-----------------------------
Signal  SPI Master  Arduino Pin
-------------------------------
RXD0    MISO        RX1     19
TXD0    MOSI        TX1     18
RTS0    CS          D2       2
SCK0    SCK         SDA1    70
------------------------------*/

void setup() {
  Serial1.begin(9600);  // pre-initialize USART0
  USART0config();       // setup SPI mode, clock and pins
}

void loop() {
  USART0->US_THR = 0xAA;  // transfer byte 0xAA
  delay(1000);
}

void USART0config() {
  USART0->US_WPMR = 0x55534100;   // Unlock the USART Mode register
  USART0->US_MR |= 0x401CE;       // SPI MODE0 (LSBFIRST), 8_BIT, SPI_MASTER
  USART0->US_BRGR = 17;           // Clock Divider (SCK = 4.94MHz)

  PIOA->PIO_WPMR = 0x50494F00;    // Unlock PIOA Write Protect Mode Register
  PIOB->PIO_WPMR = 0x50494F00;    // Unlock PIOB Write Protect Mode Register
  PIOB->PIO_ABSR |= (0u << 25);   // CS: Assign A14 I/O to the Peripheral A function
  PIOB->PIO_PDR |= (1u << 25);    // CS: Disable PIO control, enable peripheral control
  PIOA->PIO_ABSR |= (1u << 17);   // SCK: Assign A16 I/O to the Peripheral B function
  PIOA->PIO_PDR |= (1u << 17);    // SCK: Disable PIO control, enable peripheral control
  PIOA->PIO_ABSR |= (0u << 10);   // MOSI: Assign PA13 I/O to the Peripheral A function
  PIOA->PIO_PDR |= (1u << 10);    // MOSI: Disable PIO control, enable peripheral control
  PIOA->PIO_ABSR |= (0u << 11);   // MISO: Assign A12 I/O to the Peripheral A function
  PIOA->PIO_PDR |= (1u << 11);    // MISO: Disable PIO control, enable peripheral control
}

This should work for USART1 (untested):

/*-----------------------------
Signal  SPI Master  Arduino Pin
-------------------------------
RXD0    MISO        RX2     17
TXD0    MOSI        TX2     16
RTS0    CS          D23     23
SCK0    SCK         A0      54
------------------------------*/

void setup() {
  Serial2.begin(9600);  // pre-initialize USART1
  USART1config();       // setup mode, clock and pins
}

void loop() {
  USART1->US_THR = 0xAA;  // transfer byte 0xAA
  delay(1000);
  }

void USART1config() {
  USART1->US_WPMR = 0x55534100;   // Unlock the USART Mode register
  USART1->US_MR |= 0x401CE;       // SPI MODE0 (LSBFIRST), 8_BIT, SPI_MASTER
  USART1->US_BRGR = 17;           // Clock Divider (SCK = 4.94MHz)

  PIOA->PIO_WPMR = 0x50494F00;    // Unlock PIOA Write Protect Mode Register
  PIOB->PIO_WPMR = 0x50494F00;    // Unlock PIOB Write Protect Mode Register
  PIOA->PIO_ABSR |= (0u << 14);   // CS: Assign A14 I/O to the Peripheral A function
  PIOA->PIO_PDR |= (1u << 14);    // CS: Disable PIO control, enable peripheral control
  PIOA->PIO_ABSR |= (0u << 16);   // SCK: Assign A16 I/O to the Peripheral A function
  PIOA->PIO_PDR |= (1u << 16);    // SCK: Disable PIO control, enable peripheral control
  PIOA->PIO_ABSR |= (0u << 13);   // MOSI: Assign PA13 I/O to the Peripheral A function
  PIOA->PIO_PDR |= (1u << 13);    // MOSI: Disable PIO control, enable peripheral control
  PIOA->PIO_ABSR |= (0u << 12);   // MISO: Assign A12 I/O to the Peripheral A function
  PIOA->PIO_PDR |= (1u << 12);    // MISO: Disable PIO control, enable peripheral control
}