summaryrefslogtreecommitdiff
path: root/src-avr/ao_spi_slave.c
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2011-08-12 04:41:19 -0700
committerKeith Packard <keithp@keithp.com>2011-08-12 04:41:19 -0700
commitb3ba69f3eda0d07d7f2fc0922556a011c95d7951 (patch)
treeb648004575edcf3a0a4cf6c600f47bd06d45d8b5 /src-avr/ao_spi_slave.c
parentb6083ce00867051d4d513b91519cad6e4a91f07b (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.c118
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 */