I'm aware that it only generates the clock when it has data to send. I actually don't care about the clock (other than as a side effect to see that the SPI interface is running) -- I care about the high/low signal generated based on the data I stuff into the SPI data output register.
Here's my setup code snipped from the bigger file linked above:
void setup() {
wdt_reset();
wdt_enable(WDTO_2S);
pinMode(PIN_MODULATOR, OUTPUT); // PB3, OC2A, MOSI -- modulator
digitalWrite(PIN_MODULATOR, LOW);
pinMode(PIN_SPI_CK, OUTPUT); // PB5, SCK, Arduino status LED (unfortunate)
digitalWrite(PIN_SPI_CK, HIGH);
pinMode(PIN_STATUS, OUTPUT); // PB5, SCK, application status LED
// flash indicator while booting
digitalWrite(PIN_STATUS, HIGH);
pinMode(PIN_SPI_SS, OUTPUT); // Configure as output to make sure SPI runs
digitalWrite(PIN_SPI_SS, HIGH);
pinMode(PIN_CARRIER, OUTPUT); // PD3, OC2B -- carrier
digitalWrite(PIN_CARRIER, LOW);
digitalWrite(PIN_SPI_CK, LOW); // and then it turns into a clock
digitalWrite(PIN_STATUS, LOW);
// set up SPI clock
setup_spi();
}
void setup_spi() {
// enable SPI
PRR = PRR | (1 << PRSPI);
// turn off fast mode if it's on
SPSR = 0;
// divide down to 125 kHz
SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPHA) | (1 << SPR1) | (1 << SPR0);
}
Here's the write-data code:
void blast_samples() {
// make MOSI modulate based on samples
unsigned char mval = 0;
unsigned short ticks = 0;
// write SPI just to get started
SPDR = 0x00;
unsigned char i = 0;
while ((i != nSamples) || (ticks != 0)) {
// Spend time while the data is shifted out generating the next data byte.
// This must run faster than 64 microseconds!
// (does it? my guess is this takes about 30 us... but I should measure!)
// The theory is that I can take an interrupt while doing this, but then
// defer interrupts while waiting for the next byte to go out, to get
// tight timing.
unsigned char nuByte = 0;
for (unsigned char j = 0; j != 8; ++j) {
if (ticks == 0) {
if (i != nSamples) {
ticks = samples[i];
i += 1;
if (ticks & 0x8000U) {
mval = 0xff;
ticks = ticks & 0x7fffU;
}
else {
mval = 0;
}
}
else {
ticks = 8 - j;
mval = 0;
}
}
nuByte = nuByte | (bitvals[j] & mval);
ticks -= 1;
}
// disable interrupts -- I know I won't call this with interrupts disabled
wdt_reset();
cli();
// wait for MOSI to complete
while (!(SPSR & (1 << SPIF))) {
// do nothing, with interrupts off!
}
// write SPI
SPDR = nuByte;
// enable interrupts -- I know I won't call this with interrupts disabled
sei();
}
ok(0xfbu); // debug output
// wait for pulses to clear
while (!(SPSR & (1 << SPIF))) {
// do nothing, until complete!
}
ok(0xfeu); // debug output
digitalWrite(11, LOW); // turn off modulator for sure
}
If I call this with nSamples == 0, it should wiggle the clock for 8 cycles and put low signal (0s) on MOSI. Then SPSR should get the SPIF bit set.
However, the clock never starts wiggling, and the program gets hung on the loop waiting for SPSR/SPIF to go high, and then the watchdog resets it.
Thus, I'm doing something wrong.
Btw: The reason I didn't find the SPI library was that I did a "grep -r" for SPDR in all .c/.cpp files, and it didn't come up. The reason for that is that the module defines its own constants, and only uses the AVR constants in a couple of inline functions in the .h file...
Which begs the question: Why does the SDCard library not use the SPI library, but instead bit-bangs itself?
Also, here's the Atmel sample code for SPI, which looks similar to mine. Maybe someone else can help me spot-the-difference?
void SPI_MasterInit(void)
{
/* Set MOSI and SCK output, all others input */
DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK);
/* Enable SPI, Master, set clock rate fck/16 */
SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
}
void SPI_MasterTransmit(char cData)
{
/* Start transmission */
SPDR = cData;
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)))
;
}
}