--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/spi.c Fri Apr 04 00:26:16 2014 +0300
@@ -0,0 +1,106 @@
+#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 1
+
+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
+}