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?
#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
}
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.
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!
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)
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.
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);
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.
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);