Go Down

Topic: How can I be sure I am getting true hardware SPI speed in this? (Read 1 time) previous topic - next topic

db2db

Is there a way to be sure if I am using the *hardware* SPI and getting that fast SPI speed? I have it all on the pins assigned as needed, but I am still having a speed issue in my program. When I have the display on, there is some slowdown, even if I only send a tiny bit of data to the display. (Using an Uno)

Can I be sure I'm enabling the fast hardware SPI here in this sample code?

Code: [Select]
#define LOAD 10      
#define DIN 11      
#define DOUT 12      
#define SPICLOCK 13  

int counterNumber1 = 0;
int counterNumber10 = 0;

void setup()
{
 int clr;
 pinMode(DIN, OUTPUT);    
 pinMode(SPICLOCK,OUTPUT);
 pinMode(LOAD,OUTPUT);
 digitalWrite(LOAD,HIGH); //disable device

 // SPCR = 01010000
 //interrupt disabled,spi enabled,msb 1st,master,clk low when idle,
 //sample on leading edge of clk,system clock/4 (fastest)
 SPCR = (1<<SPE)|(1<<MSTR);
 clr=SPSR;
 clr=SPDR;
 delay(10);

 //clear MAX7219 and format to receive data
 write_7seg(0x0C,1);
 write_7seg(0x09,0xFF);
 write_7seg(0x0A,0x0F);
 write_7seg(0x0B,0x04);
}

void loop()
{
 write_7seg(1, counterNumber1);
 write_7seg(2, counterNumber10);  
 delay (10)
}

//spi transfer function (from ATmega168 datasheet)
char spi_transfer(volatile char data)
{
 SPDR = data; // Start the transmission
 while (!(SPSR & (1<<SPIF))) // Wait the end of the transmission
 {
 };
 return SPDR; // return the received int
}

//MAX7219 data transfer function
int write_7seg(int digAddress, int displayValue)
{
 digitalWrite(LOAD,LOW); //MAX7219 chip select is active low
 //2 int data transfer to MAX7219
 spi_transfer(digAddress);
 spi_transfer(displayValue);
 digitalWrite(LOAD,HIGH); //release chip, signal end transfer
}

madworm

The fastest speed of the hardware SPI interface is actually F_OSC/2 - which is 8 MHz for a normal arduino.

If you need top-speed, use direct port manipulation for twiddling the chip-select line. You also seem to feed 'int'-s to a function that would run as well with an uint8_t. SPI sends bytes, no need for ints.
• Upload doesn't work? Do a loop-back test.
• There's absolutely NO excuse for not having an ISP!
• Your AVR needs a brain surgery? Use the online FUSE calculator.
My projects: RGB LED matrix, RGB LED ring, various ATtiny gadgets...
• Microsoft is not the answer. It is the question, and the answer is NO!

Graynomad

From what I can see you are currently running at fosc/4, you can get to fosc/2 by setting the SPI2X bit in the SPSR.

To see what rate you are running at (I assume you don't have any proper equipment) just write a loop to send 100000 bytes and time it.

______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

db2db


Thank you both for you replies. I took quite a lot of that code from elsewhere, so I don't fully understand your comments.
I don't need absolute max speed, but I'd like to avoid bottlenecks anywhere I can.

If you can be more specific about what to change, I'd really appreciate that!


Graynomad

I haven't done it but looking at the data sheet I would say that

SPSR = 1;

or

SPSR  = (1 << SPI2X); // same thing because SPI2X is bit 0 and the other bits are RO (read only)

Should give you fosc/2, however...

Quote
When I have the display on, there is some slowdown, even if I only send a tiny bit of data to the display.

What is slowing down? There's nothing else happening in the code you posted. Is there more to this than meets the eye?


______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

db2db


(This is just a test routine - the slowdowns are in the real program.)

I haven't used bitshift before so am trying to make sense of these lines:

SPSR  = (1 << SPI2X); // same thing because SPI2X is bit 0 and the other bits are RO (read only)
and
SPCR = (1<<SPE)|(1<<MSTR);

Graynomad

#6
Feb 27, 2012, 06:11 am Last Edit: Feb 27, 2012, 09:27 am by Graynomad Reason: 1
For example (1 << 2) means the value 1 shifted left 2 times,

00000001 << 2 == 00000100 == 4

The "values" SPI2X, SPE, MSTR etc are just #defines for numbers in a file somewhere so

(1<<SPE)

is just 1 shifted left by SPE bits.

That's fine to get a single bit set in a register but it clears all the other bits so to set multiple bits you have to OR several of these expressions.

Let's assume SPE = 2 and MSTR = 4 (they probably aren't but I couldn't be bothered looking them up)

(1<<SPE)|(1<<MSTR) == (1<<2)|(1<<4) == 00000010 | 00010000 == 000100010 == 0x12  ERROR fixed

so the value 0x12 is written into the register.

In my previous example

SPSR  = (1 << SPI2X); // same thing because SPI2X is bit 0 and the other bits are RO (read only)

SPI2X is actually defined as 0 so  (1 << SPI2X) ==  (1 << 0) == 1.

There's no real need to use these expressions but it saves using magic numbers, after a while you will look at  (1 << SPI2X) and know exactly what it means, if you write SPSR = 1 you will forever have to look it up in the data sheet.

______
Rob

Rob Gray aka the GRAYnomad www.robgray.com

db2db

#7
Feb 27, 2012, 06:52 am Last Edit: Feb 27, 2012, 07:14 am by db2db Reason: 1
VERY useful answer - thanks.

Is this right though?
"Let's assume SPE = 2 and MSTR = 4 (they probably aren't but I couldn't be bothered looking them up)
(1<<SPE)|(1<<MSTR) == (1<<1)|(1<<4) == 00000010 | 00010000 == 000100010 == 0x12"

Should it be this? :
(1<<SPE)|(1<<MSTR) == (1<<2)|(1<<4) == 00000100 | 00001000 == 00001100 == 0x12"

In the end, do I want to set SPCR as I have, then set the SPSR right after?
 // SPCR = 01010000
 //interrupt disabled,spi enabled,msb 1st,master,clk low when idle,
 //sample on leading edge of clk,system clock/4 (fastest)
 SPCR = (1<<SPE)|(1<<MSTR);
 SPSR  = (1 << SPI2X); //toggle this 0 to a 1 in order to switch on "SPI2X" register value
 clr=SPSR;
 clr=SPDR;

ALSO, as an example, if I wanted to slow things down I would set that rightmost SPRO bit on, by basically making that 0 a 1 like so:
 SPCR = (1<<SPE)|(1<<MSTR) |(1<< SPRO);

Thanks!

Graynomad

Quote
Should it be this? :

Yep, well done, you spotted the deliberate error :)

Quote
In the end, do I want to set SPCR as I have, then set the SPSR right after?

Yes although the order doesn't matter AFAIK.

Quote
ALSO, as an example, if I wanted to slow things down I would set that rightmost SPRO bit on, by basically making that 0 a 1 like so:
  SPCR = (1<<SPE)|(1<<MSTR) |(1<< SPRO);

That seems right, should give you fosc/8.

_____
Rob
Rob Gray aka the GRAYnomad www.robgray.com

db2db


Awesome, your assistance was really great, and very much appreciated!

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