@defragster Any speed that I set in the SPI above 4MHz locks it up. You can try it with the sketch that I listed. I hope and pray that the SPI gets fixed, getting to the full max speed is super important.
Meanwhile, here is what I came up with, toggling the lines directly in a loop. Please see complete code below. It runs close to 20 MHz. Not quite enough, and a little disappointing.
Code:
counter = 0;
delayStart();
CLEARPINA; // this will be the SPI clock pin
TOGGLEPINB; // for the oscilloscope
while( counter < 16 ) {
delayNext();
SETPINA;
uval |= (READPINC) << counter; // this will be the data input from the spi
counter++;
delayNext();
CLEARPINA;
}
TOGGLEPINB;
By manually toggling one line and reading the other, I can get to 19.4 MHz. The cpu cycle step is determined by iterating over values to see where it stops getting faster,
Code:
#include "Arduino.h"
#include <limits.h>
#include <SPI.h>
const int PinA = 2;
const int PinB = 1;
const int PinC = 0;
const int led = 13;
#define READPINC (CORE_PIN0_PINREG & CORE_PIN0_BITMASK)
#define SETPINA (CORE_PIN2_PORTSET = CORE_PIN2_BITMASK)
#define CLEARPINA (CORE_PIN2_PORTCLEAR = CORE_PIN2_BITMASK)
#define TOGGLEPINA (CORE_PIN2_PORTTOGGLE = CORE_PIN2_BITMASK)
#define SETPINB (CORE_PIN1_PORTSET = CORE_PIN1_BITMASK)
#define CLEARPINB (CORE_PIN1_PORTCLEAR = CORE_PIN1_BITMASK)
#define TOGGLEPINB (CORE_PIN1_PORTTOGGLE = CORE_PIN1_BITMASK)
#define RCVLEN 256
char rcvbuffer[RCVLEN];
uint16_t nrcvbuf = 0;
char *startsWith( char *s, const char *key ) {
int n = strlen(key);
if ( !strncmp( s, key, n ) ) {
return s + n;
}
return 0;
}
char *parseUint( char *s, unsigned int *u ) {
unsigned long int l;
char *p = s;
l = strtoul( s, &p, 0 );
if ( (p > s) && (l <= UINT_MAX) ) {
*u = (unsigned int) l;
return p;
}
return 0;
}
void setup() {
pinMode(led, OUTPUT);
pinMode(PinA, OUTPUT);
digitalWriteFast(PinA, LOW);
pinMode(PinB, OUTPUT);
digitalWriteFast(PinB, LOW);
pinMode(PinC, INPUT);
Serial.begin(9600);
delay(100);
}
uint32_t cyccnt = ARM_DWT_CYCCNT;
uint32_t cyccnt1 = ARM_DWT_CYCCNT;
static uint32_t cycdelay = 13; // this is the fastest the read loop can go, by experiment
inline void delayStart( ) {
cyccnt = ARM_DWT_CYCCNT;
}
inline void delayNext( ) {
do {
cyccnt1 = ARM_DWT_CYCCNT;
} while ( cyccnt1 - cyccnt < cycdelay );
cyccnt = cyccnt1;
}
void loop() {
uint16_t nlen = 0;
char *pc;
char c;
unsigned int counter = 0;
unsigned int utmp = 0;
unsigned int uval = 0;
while ( Serial.available() ) {
c = Serial.read();
if ( c ) {
if ( iscntrl( c ) ) {
nlen = nrcvbuf;
rcvbuffer[nrcvbuf] = 0;
nrcvbuf = 0;
break;
}
else if ( nrcvbuf || !isspace(c) ) {
rcvbuffer[nrcvbuf++] = c;
}
if ( nrcvbuf >= RCVLEN ) {
Serial.println( (char *)"Error: buffer overflow" );
nrcvbuf = 0;
}
}
}
if ( nlen > 0 ) {
if ( (pc = startsWith( rcvbuffer, "test divider")) && parseUint( pc, &utmp ) ) {
SPI.begin();
SPI.setClockDivider(utmp);
digitalToggleFast(PinA );
utmp = SPI.transfer16(0xFFFF);
digitalToggleFast(PinA );
SPI.end();
Serial.println( utmp );
}
else if ( (pc = startsWith( rcvbuffer, "test settings")) && parseUint( pc, &utmp )) {
SPISettings settings( utmp, MSBFIRST, SPI_MODE0);
SPI.beginTransaction(settings);
digitalToggleFast(PinA );
//SPI.transfer16(0xFFFF);
utmp = SPI.transfer(0xFF);
digitalToggleFast(PinA );
SPI.endTransaction();
Serial.println( utmp );
}
else if ( (pc = startsWith( rcvbuffer, "test timing")) ) {
Serial.println( cycdelay );
counter = 0;
CLEARPINA;
delayStart();
TOGGLEPINB;
while( counter < 16 ) {
delayNext();
SETPINA;
uval |= (READPINC) << counter;
counter++;
delayNext();
CLEARPINA;
}
TOGGLEPINB;
}
else {
Serial.print( "unknown command //" );
Serial.print( (char *) rcvbuffer );
Serial.println( "//" );
}
nlen = 0;
Serial.println( "DONE" );
}
delay(100);
}