altos-avr: Completely replace the spi slave code
authorKeith Packard <keithp@keithp.com>
Fri, 12 Aug 2011 11:41:19 +0000 (04:41 -0700)
committerKeith Packard <keithp@keithp.com>
Fri, 12 Aug 2011 11:41:19 +0000 (04:41 -0700)
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>
src-avr/ao.h
src-avr/ao_log_telescience.c
src-avr/ao_pins.h
src-avr/ao_spi_slave.c
src-avr/ao_telescience.c
src-avr/telescience/Makefile

index c548c618f87edc6281cb65adc9298bdf442d7e0b..fb3612d41a4a6a226b9ae85033236716ab8fed06 100644 (file)
@@ -201,7 +201,7 @@ struct ao_adc {
  * ao_adc.c
  */
 
-#define AO_ADC_RING    16
+#define AO_ADC_RING    8
 
 #define ao_adc_ring_next(n)    (((n) + 1) & (AO_ADC_RING - 1))
 #define ao_adc_ring_prev(n)    (((n) - 1) & (AO_ADC_RING - 1))
@@ -1343,6 +1343,7 @@ struct ao_fifo {
        (f).remove = ((f).remove + 1) & (AO_FIFO_SIZE-1); \
 } while(0)
 
+#define ao_fifo_reset(f)       ((f).insert = (f).remove = 0)
 #define ao_fifo_full(f)                ((((f).insert + 1) & (AO_FIFO_SIZE-1)) == (f).remove)
 #define ao_fifo_empty(f)       ((f).insert == (f).remove)
 
@@ -1423,12 +1424,15 @@ ao_debug_init(void);
 
 /* ao_spi_slave.c */
 
-void
+int
 ao_spi_slave_read(uint8_t *data, int len);
 
-void
+int
 ao_spi_slave_write(uint8_t *data, int len);
 
+void
+ao_spi_slave_debug(void);
+
 void
 ao_spi_slave_init(void);
 
index 6022ad21ab66077f453483885c746bb92c98b195..62e0493c8c693b013e79b97863ce42993d9248fe 100644 (file)
@@ -19,7 +19,7 @@
 #include "ao_product.h"
 
 static struct ao_task ao_log_task;
-static struct ao_task ao_spi_task;
+//static struct ao_task ao_spi_task;
 
 uint8_t        ao_log_running;
 uint8_t                ao_log_mutex;
@@ -233,47 +233,11 @@ ao_log_delete(void)
                printf ("Erased\n");
 }
 
-void
-ao_spi_telescience(void)
-{
-       static union {
-               struct ao_companion_command     command;
-               struct ao_companion_setup       setup;
-               struct ao_adc                   data;
-       } u;
-
-       for (;;) {
-               ao_spi_slave_read((uint8_t *) &u.command, sizeof (struct ao_companion_command));
-               switch (u.command.command) {
-               case AO_COMPANION_SETUP:
-                       u.setup.board_id = AO_idProduct_NUMBER;
-                       u.setup.board_id_inverse = ~AO_idProduct_NUMBER;
-                       u.setup.update_period = 10;
-                       u.setup.channels = NUM_ADC;
-                       ao_spi_slave_write((uint8_t *) &u.setup,
-                                          sizeof (struct ao_companion_setup));
-                       break;
-               case AO_COMPANION_FETCH:
-                       ao_adc_get(&u.data);
-                       ao_spi_slave_write((uint8_t *) &u.data.adc,
-                                          NUM_ADC * sizeof (uint16_t));
-                       if (u.command.flight_state >= ao_flight_boost &&
-                           u.command.flight_state < ao_flight_landed) {
-                               if (!ao_log_running)
-                                       ao_log_start();
-                       } else {
-                               if (ao_log_running)
-                                       ao_log_stop();
-                       }
-                       break;
-               }
-       }
-}
-
 const struct ao_cmds ao_log_cmds[] = {
        { ao_log_set,   "L <0 off, 1 on>\0Set logging mode" },
        { ao_log_list,  "l\0List stored flight logs" },
        { ao_log_delete, "d 1\0Delete all stored flights" },
+       { ao_spi_slave_debug, "s\0Dump SPI slave data" },
        { 0,    NULL },
 };
 
@@ -285,5 +249,5 @@ ao_log_init(void)
        ao_cmd_register(&ao_log_cmds[0]);
 
        ao_add_task(&ao_log_task, ao_log_telescience, "log");
-       ao_add_task(&ao_spi_task, ao_spi_telescience, "spi");
+//     ao_add_task(&ao_spi_task, ao_spi_telescience, "spi");
 }
index b927bc4b54c2a40a755a6e051bf0cb87c56ce030..afe1e941167ef29693fa64aef0d5596c61f743c4 100644 (file)
@@ -28,7 +28,7 @@
        #define USE_SERIAL_STDIN        0
        #define HAS_EEPROM              1
        #define USE_INTERNAL_FLASH      0
-       #define HAS_DBG                 1
+       #define HAS_DBG                 0
        #define DBG_ON_P1               1
        #define DBG_ON_P0               0
        #define IGNITE_ON_P2            1
@@ -54,7 +54,7 @@
        #define HAS_ADC                 1
        #define HAS_EEPROM              1
        #define USE_INTERNAL_FLASH      0
-       #define HAS_DBG                 1
+       #define HAS_DBG                 0
        #define DBG_ON_P1               1
        #define DBG_ON_P0               0
        #define IGNITE_ON_P2            1
index 5f1990d5cd767bfdcac6cf218a616f385fc7e1ef..8e01f586ed5d959d16485cc8d0e47371291903dd 100644 (file)
  */
 
 #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 */
index f0f88c51e3083d4e6d2cf0c512558031002603f6..e8d4e0c20e4b7fce456f50622400250676187482 100644 (file)
@@ -29,6 +29,7 @@ main(void)
        ao_timer_init();
        ao_cmd_init();
        ao_spi_init();
+       ao_spi_slave_init();
        ao_storage_init();
        ao_usb_init();
        ao_adc_init();
index b50559a91af8adce5272697cbd9b874748f34267..9b04fa6ed86e4ea36e6caef4bb13d32bb9071911 100644 (file)
@@ -18,7 +18,7 @@ DUDECPUTYPE=m32u4
 PROGRAMMER=usbtiny
 LOADCMD=avrdude
 LOADARG=-p $(DUDECPUTYPE) -c $(PROGRAMMER) -e -U flash:w:
-CC=avr-gcc -v
+CC=avr-gcc
 OBJCOPY=avr-objcopy
 
 ifndef VERSION
@@ -59,7 +59,7 @@ PRODUCT=TeleScience-v0.1
 MCU=atmega32u4
 PRODUCT_DEF=-DTELESCIENCE
 IDPRODUCT=0x000a
-CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -Os -mcall-prologues $(PRODUCT_DEF) -I. -DAVR
+CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -O3 -mcall-prologues $(PRODUCT_DEF) -I. -DAVR
 
 NICKLE=nickle