# HG changeset patch # User Tero Marttila # Date 1396560376 -10800 # Node ID 04c625712e3570ff392941cd6cd941fb071f260f # Parent ec42f36d861491051468946dcc004787e8691952 hello: trivial spi bits diff -r ec42f36d8614 -r 04c625712e35 src/hello.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 diff -r ec42f36d8614 -r 04c625712e35 src/spi.c --- /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 +}