diff options
author | Keith Packard <keithp@keithp.com> | 2011-08-12 04:41:19 -0700 |
---|---|---|
committer | Keith Packard <keithp@keithp.com> | 2011-08-12 04:41:19 -0700 |
commit | b3ba69f3eda0d07d7f2fc0922556a011c95d7951 (patch) | |
tree | b648004575edcf3a0a4cf6c600f47bd06d45d8b5 /src-avr/ao_spi_slave.c | |
parent | b6083ce00867051d4d513b91519cad6e4a91f07b (diff) |
altos-avr: Completely replace the spi slave code
Turns out the AVR we're using sucks at doing SPI slave. To get it
running at a reasonable data rate, I had to completely gut the
'sensible' code and run everything from the ISR with interrupts
disabled.
Even with this, the maximum SPI clock rate is somewhere around
200kHz. That's due to the singled buffered nature of the transmit
queue, the amount of time available between finishing one byte and
starting the next is very very small.
Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'src-avr/ao_spi_slave.c')
-rw-r--r-- | src-avr/ao_spi_slave.c | 118 |
1 files changed, 60 insertions, 58 deletions
diff --git a/src-avr/ao_spi_slave.c b/src-avr/ao_spi_slave.c index 5f1990d5..8e01f586 100644 --- a/src-avr/ao_spi_slave.c +++ b/src-avr/ao_spi_slave.c @@ -16,83 +16,85 @@ */ #include "ao.h" +#include "ao_product.h" -__xdata struct ao_fifo ao_spi_slave_rx_fifo; -__xdata struct ao_fifo ao_spi_slave_tx_fifo; +static struct ao_companion_command ao_companion_command; +static const struct ao_companion_setup ao_companion_setup = { + .board_id = AO_idProduct_NUMBER, + .board_id_inverse = ~AO_idProduct_NUMBER, + .update_period = 50, + .channels = NUM_ADC +}; -static volatile uint8_t ao_spi_slave_tx_started; - -static void -ao_spi_slave_tx_start(void) +static void ao_spi_slave_recv(void) { - if (!ao_spi_slave_tx_started && !ao_fifo_empty(ao_spi_slave_tx_fifo)) { - ao_spi_slave_tx_started = 1; - ao_fifo_remove(ao_spi_slave_tx_fifo, SPDR); - } -} + uint8_t *buf; + uint8_t len; -ISR(SPI_STC_vect) -{ - uint8_t spsr; + len = sizeof (ao_companion_command); + buf = (uint8_t *) &ao_companion_command; + while (len--) { + while (!(SPSR & (1 << SPIF))) + ; + *buf++ = SPDR; + } - spsr = SPSR; - if (SPIF & (1 << SPIF)) { - uint8_t byte = SPDR; - if (!ao_fifo_full(ao_spi_slave_rx_fifo)) - ao_fifo_insert(ao_spi_slave_rx_fifo, byte); - ao_spi_slave_tx_started = 0; - ao_spi_slave_tx_start(); - ao_wakeup(&ao_spi_slave_rx_fifo); - ao_wakeup(&ao_spi_slave_tx_fifo); + /* Figure out the outbound data */ + switch (ao_companion_command.command) { + case AO_COMPANION_SETUP: + buf = (uint8_t *) &ao_companion_setup; + len = sizeof (ao_companion_setup); + break; + case AO_COMPANION_FETCH: + buf = (uint8_t *) &ao_adc_ring[ao_adc_ring_prev(ao_adc_head)].adc; + len = NUM_ADC * sizeof (uint16_t); + break; + default: + return; } -} -static void -ao_spi_slave_put(uint8_t b) __critical -{ - cli(); - while (ao_fifo_full(ao_spi_slave_tx_fifo)) - ao_sleep(&ao_spi_slave_tx_fifo); - ao_fifo_insert(ao_spi_slave_tx_fifo, b); - ao_spi_slave_tx_start(); - sei(); + /* Send the outbound data */ + while (len--) { + SPDR = *buf++; + while (!(SPSR & (1 << SPIF))) + ; + } + (void) SPDR; } -static uint8_t -ao_spi_slave_get(void) __critical -{ - uint8_t b; - - cli(); - while (ao_fifo_empty(ao_spi_slave_rx_fifo)) - ao_sleep(&ao_spi_slave_rx_fifo); - ao_fifo_remove(ao_spi_slave_rx_fifo, b); - sei(); - return b; -} +static uint8_t ao_spi_slave_running; -void -ao_spi_slave_read(uint8_t *data, int len) +ISR(PCINT0_vect) { - while (len--) { - ao_spi_slave_put(0); - *data++ = ao_spi_slave_get(); + if ((PINB & (1 << PINB0)) == 0) { + if (!(PCMSK0 & (1 << PCINT1))) + PCMSK0 |= (1 << PCINT1); + else { + PCMSK0 &= ~(1 << PCINT1); + cli(); + if (!ao_spi_slave_running) { + ao_spi_slave_running = 1; + ao_spi_slave_recv(); + } + sei(); + } + } else { + ao_spi_slave_running = 0; } } -void -ao_spi_slave_write(uint8_t *data, int len) -{ - while (len--) { - ao_spi_slave_put(*data++); - (void) ao_spi_slave_get(); - } +void ao_spi_slave_debug(void) { + printf ("slave running %d\n", ao_spi_slave_running); } void ao_spi_slave_init(void) { - SPCR = (1 << SPIE) | /* Enable SPI interrupts */ + PCMSK0 |= (1 << PCINT0); /* Enable PCINT0 pin change */ + PCICR |= (1 << PCIE0); /* Enable pin change interrupt */ + + DDRB = (DDRB & 0xf0) | (1 << 3); + SPCR = (0 << SPIE) | /* Disable SPI interrupts */ (1 << SPE) | /* Enable SPI */ (0 << DORD) | /* MSB first */ (0 << MSTR) | /* Slave mode */ |