I rolled my own SPI routines because sometimes I needed to monkey with the clock phase and I have multiple devices that are communicating from different tasks.
/*** BeginHeader spin, SPIWriteChar, SPIWrite, SPIWriteDelay, SPIRead */
// Low level (bit bang) SPI routines
void spin (int revs);
void SPIWriteChar (unsigned char b, int clock);
void SPIWrite (unsigned char buffer[], int chars, int clock);
void SPIWriteDelay (unsigned char buffer[], int chars, int clock, int delay);
void SPIRead (unsigned char buffer[], int chars, int clock, int delay);
/*** EndHeader */
/* START FUNCTION DESCRIPTION **************************************************
spin
SYNTAX: void spin (int revs);
DESCRIPTION: Variable delay nop loop
PARAMETER1: revs, number of times through the loop
RETURN VALUE: None
SEE ALSO:
KEYWORDS:
END DESCRIPTION ***************************************************************/
nodebug root void spin (int revs) {
int i;
for (i=0; i
SYNTAX: void SPIWriteChar (unsigned char b, char clock);
DESCRIPTION: Bit-bang SPI Write routine
PARAMETER1: uchar b - Byte to be sent
PARAMETER2: char clock - 0 for latching on falling edge
RETURN VALUE: None
SEE ALSO: SPIWrite, SPIWriteDelay, SPIRead
KEYWORDS:
END DESCRIPTION ***************************************************************/
// SpinVal controls the bitrate of the SPI clock. Using 2 for 100kHz.
#define SpinVal 2
_IO_debug root void SPIWriteChar (unsigned char b, int clock) {
int j;
int x;
for (j=0; j<8; j++) {
x = (b & 0x80) == 0x80; //get the data bit
b <<= 1; //shift the data for the next bit
BitWrPortI(PCDR, &PCDRShadow, x, PC_SPI_MOSI); //set up data line
BitWrPortI(PDDR, &PDDRShadow, !clock, PD_SPI_CLK); //Clock high
spin (SpinVal);
BitWrPortI(PDDR, &PDDRShadow, clock, PD_SPI_CLK); //Clock low to latch data
spin (SpinVal);
}
}
/* START FUNCTION DESCRIPTION **************************************************
SPIWrite
SYNTAX: void SPIWrite (unsigned char buffer[], int chars, char clock);
DESCRIPTION: Write multiple characters via SPI
PARAMETER1: uchar buffer[] - Bytes to be sent
PARAMETER2: int chars - Number of bytes to send
PARAMETER3: char clock - 0 for latching on falling edge
RETURN VALUE: None
SEE ALSO: SPIWriteChar, SPIWriteDelay, SPIRead
KEYWORDS:
END DESCRIPTION ***************************************************************/
_IO_debug root void SPIWrite (unsigned char buffer[], int chars, int clock) {
int i;
for (i=0; i
SYNTAX: void SPIWriteDelay (unsigned char buffer[], int chars, char clock, char delay);
DESCRIPTION: Write multiple characters via SPI
PARAMETER1: uchar buffer[] - Bytes to be sent
PARAMETER2: int chars - Number of bytes to send
PARAMETER3: char clock - 0 for latching on falling edge
PARAMETER4: char delay - us to delay between characters
RETURN VALUE: None
SEE ALSO: SPIWriteChar, SPIWrite, SPIRead
KEYWORDS:
END DESCRIPTION ***************************************************************/
_IO_debug root void SPIWriteDelay (unsigned char buffer[], int chars, int clock, int delay) {
int i;
spin (delay + delay >> 1);
for (i=0; i> 1);
}
}
/* START FUNCTION DESCRIPTION **************************************************
SPIRead
SYNTAX: void SPIRead (unsigned char buffer[], int chars, char clock, char delay);
DESCRIPTION: Bit-bang SPI Read routine
PARAMETER1: uchar buffer[] - Destination of bytes that are read
PARAMETER2: int chars - Number of bytes to read
PARAMETER3: char clock - 0 for latching on falling edge
PARAMETER4: char delay - us delay before clocking in next character
RETURN VALUE: None
SEE ALSO: SPIWriteChar, SPIWrite, SPIWriteDelay
KEYWORDS:
END DESCRIPTION ***************************************************************/
_IO_debug root void SPIRead (unsigned char buffer[], int chars, int clock, int delay) {
int i;
int j;
char b;
int x;
BitWrPortI(PCDR, &PCDRShadow, 1, PC_SPI_MOSI); //set up data line
for (i=0; i 0) {
spin (delay + delay >> 1);
}
b = 0;
for (j=0; j<8; j++) {
BitWrPortI(PDDR, &PDDRShadow, !clock, PD_SPI_CLK); //Clock high
spin (SpinVal);
BitWrPortI(PDDR, &PDDRShadow, clock, PD_SPI_CLK); //Clock low to latch data
spin (SpinVal);
b <<= 1; //Shift the existing data
x = BitRdPortI(PDDR, PD_SPI_MISO); //receive the bit
b |= (char) x; //save the data bit
}
buffer[i] = b;
}
}
//#endif
Then each device had a couple driver routines like the one below. The SPIBusy flag keeps the routines from stepping on each other. Don’t forget the chip select line to each SPI device.
_IO_debug void MotorRdConfig (int axis) {
char retries;
if (axis < 1 || axis > 2) return;
while (SPIBusy);
SPIBusy = 1;
BitWrPortI(PDDR, &PDDRShadow, Mtr_clk_ph, PD_SPI_CLK); //fix the clock
SMConfig[axis].start = 0;
retries = 3;
while ((retries > 0) && (SMConfig[axis].start != 0x4D)) {
BitWrPortI(PDDR, &PDDRShadow, 0, axis - 1); // chip select low
SPIWriteChar (0x40, Mtr_clk_ph); // read all command
SPIRead((char *)&SMConfig[axis], 17, Mtr_clk_ph, Mtr_char_delay);
BitWrPortI(PDDR, &PDDRShadow, 1, axis - 1); // chip select high
retries -= 1;
if (SMConfig[axis].start != 0x4D)
spin (100); // kill some time before attempting retry
}
SPIBusy = 0;
}