--- 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
+}