hello: trivial spi bits
authorTero Marttila <terom@paivola.fi>
Fri, 04 Apr 2014 00:26:16 +0300
changeset 55 04c625712e35
parent 54 ec42f36d8614
child 56 3b837eaf1b6d
hello: trivial spi bits
src/hello.c
src/spi.c
--- a/src/hello.c	Thu Apr 03 22:24:46 2014 +0300
+++ b/src/hello.c	Fri Apr 04 00:26:16 2014 +0300
@@ -3,6 +3,7 @@
 #include "stdlib.h"
 #include "timer.c" // XXX
 #include "serial.c" // XXX
+#include "spi.c" // XXX
 
 static enum state {
     START       = '\n',
@@ -116,13 +117,77 @@
     }
 }
 
+#define LED7_DDR    DDRB
+#define LED7_PORT   PORTB
+#define LED7_OE     PORTB1
+
+// common anode?
+#define LED7_ANODE  1
+
+static const uint8_t LED7SEG_FONT[] = {
+    0b00111111,	// 0
+    0b00000110,	// 1
+    0b01011011,	// 2
+    0b01001111,	// 3
+    0b01100110,	// 4
+    0b01101101,	// 5
+    0b01111101,	// 6
+    0b00000111,	// 7
+    0b01111111,	// 8
+    0b01100111,	// 9
+    0b01110111,	// A
+    0b01111100,	// B
+    0b00111001,	// C
+    0b01011110,	// D
+    0b01111001,	// E
+    0b01110001,	// F
+};
+
+enum {
+    LED7SEG_DOT     = 0b10000000,
+};
+
+void led7_init (void)
+{
+    sbi(&LED7_PORT, LED7_OE); // disabled (low)
+    sbi(&LED7_DDR, LED7_OE); // out
+}
+
+/*
+ * Update external IO.
+ */
+void led7_update (void)
+{
+    static char i = 0;
+    
+    if (i) {
+        // enable display
+        cbi(&LED7_PORT, LED7_OE);
+    }
+
+    char led7 = LED7SEG_FONT[i % sizeof(LED7SEG_FONT)];
+    
+    if (LED7_ANODE)
+        led7 = ~led7;
+
+    spi_tx[0] = led7;
+ 
+    i++;
+}
+
+#define DEBUG_DDR   DDRB
+#define DEBUG_PORT  PORTB
+#define DEBUG_LED   0
+
 int main (void)
 {
+    led7_init();
     timer_init();
     serial_init();
+    spi_init();
 
     // led_init();
-    sbi(&DDRB, DDB5);
+    sbi(&DEBUG_DDR, DEBUG_LED);
 
     sei();
 
@@ -133,19 +198,23 @@
     serial_write(state);
 
     while (true) {
+        // TODO: SPI timer
+        led7_update();
+        spi_update();
+
         // toggle
         if (led_state == 0) {
             timeout = 0;
-            cbi(&PORTB, PORTB5);
+            cbi(&DEBUG_PORT, DEBUG_LED);
 
         } else if (led_state == 255) {
             timeout = 0;
-            sbi(&PORTB, PORTB5);
+            sbi(&DEBUG_PORT, DEBUG_LED);
 
         } else {
             // as Hz
             timeout = (16000 / led_state);
-            xbi(&PORTB, PORTB5);
+            xbi(&DEBUG_PORT, DEBUG_LED);
         }
         
         // sleep
--- /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
+}