#define SPI_DDR DDRB
#define SPI_PORT PORTB
#define SPI_SCK PORTB5
#define SPI_MISO PORTB4
#define SPI_MOSI PORTB3
#define SPI_SS PORTB2
/* State */
#define SPI_COUNT 2
static char spi_rx[SPI_COUNT], spi_tx[SPI_COUNT];
enum {
SPI_DORD_MSB = 0b0,
SPI_DORD = SPI_DORD_MSB
};
enum {
SPI_CPOL_RISING = 0b0,
SPI_CPOL = SPI_CPOL_RISING
};
enum {
SPI_CPHA_SAMPLE = 0b0,
SPI_CPHA = SPI_CPHA_SAMPLE
};
enum {
SPI_CLOCK_4 = 0b000,
SPI_CLOCK_16 = 0b001,
SPI_CLOCK_64 = 0b010,
SPI_CLOCK_128 = 0b011,
SPI_CLOCK = SPI_CLOCK_16
};
/*
* Initialize in SPI master mode.
*/
void spi_init ()
{
// set output modes
sbi(&SPI_DDR, SPI_SCK); // out
sbi(&SPI_DDR, SPI_MOSI); // out
sbi(&SPI_DDR, SPI_SS); // out
// initialize bus
sbi(&SPI_PORT, SPI_SS); // high (off)
// set mode
SPCR = (
// SPI Interrupt Enable
(0b0 << SPIE) // disable
// SPI Enable
| (0b1 << SPE) // enable
// Data Order
| (SPI_DORD << DORD)
// Master/Slave Select
| (0b1 << MSTR) // master
// Clock Polarity
| (SPI_CPOL << CPOL)
// Clock Phase
| (SPI_CPHA << CPHA)
// SPI Clock Rate Select
| ((SPI_CLOCK & 0b11) << SPR0)
);
SPSR = (
(((SPI_CLOCK & 0b100) >> 2) << SPI2X)
);
}
/*
* Perform an SPI bus update.
*/
void spi_update ()
{
char i;
char *rx = spi_rx + SPI_COUNT, *tx = spi_tx + SPI_COUNT;
// start of packet
cbi(&SPI_PORT, SPI_SS); // low
for (i = SPI_COUNT; i > 0; i--) {
// out
SPDR = *--tx;
// sync
while (!tbi(&SPSR, SPIF))
;
*--rx = SPDR;
}
// end of packet
sbi(&SPI_PORT, SPI_SS); // high
}