Pages: [1]   Go Down
Author Topic: How can I be sure I am getting true hardware SPI speed in this?  (Read 796 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Full Member
***
Karma: 0
Posts: 217
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
#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
}
Logged

"The old Europe"
Offline Offline
Edison Member
*
Karma: 1
Posts: 2005
Bootloaders suck!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

• 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!

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 129
Posts: 8530
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Rob Gray aka the GRAYnomad www.robgray.com

Offline Offline
Full Member
***
Karma: 0
Posts: 217
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


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!

Logged

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 129
Posts: 8530
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Rob Gray aka the GRAYnomad www.robgray.com

Offline Offline
Full Member
***
Karma: 0
Posts: 217
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


(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);
Logged

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 129
Posts: 8530
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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

« Last Edit: February 27, 2012, 03:27:38 am by Graynomad » Logged

Rob Gray aka the GRAYnomad www.robgray.com

Offline Offline
Full Member
***
Karma: 0
Posts: 217
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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!
« Last Edit: February 27, 2012, 01:14:36 am by db2db » Logged

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 129
Posts: 8530
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Should it be this? :
Yep, well done, you spotted the deliberate error smiley

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
Logged

Rob Gray aka the GRAYnomad www.robgray.com

Offline Offline
Full Member
***
Karma: 0
Posts: 217
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


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

Pages: [1]   Go Up
Jump to: