implemented recovering from ADC errors
diff --git a/bbb_cape/src/cape/analog.c b/bbb_cape/src/cape/analog.c
index 855098c..297afd6 100644
--- a/bbb_cape/src/cape/analog.c
+++ b/bbb_cape/src/cape/analog.c
@@ -2,8 +2,6 @@
 
 #include <string.h>
 
-#include <STM32F2XX.h>
-
 #include "cape/util.h"
 #include "cape/led.h"
 
@@ -20,27 +18,13 @@
 
 #define NUM_CHANNELS 8
 
+// This file handles reading values from the MCP3008-I/SL ADC.
+
 uint16_t analog_readings[NUM_CHANNELS] __attribute__((aligned(8)));
 static volatile int current_channel;
 static volatile int partial_reading;
 static volatile int frame;
-
-static void start_read(int channel) {
-  // This needs to wait 13 cycles between enabling the CSEL pin and starting to
-  // send data.
-  // (100ns+8ns)*120MHz = 12.96
-
-  // Clear the CSEL pin to select it.
-  for (int i = 0; i < 9; ++i) gpio_off(CSEL_GPIO, CSEL_NUM);
-  current_channel = channel;
-  partial_reading = 0;
-  frame = 0;
-  SPI->DR = 1;  // start bit
-  uint16_t data = (1 << 15) /* not differential */ |
-      (channel << 12);
-  while (!(SPI->SR & SPI_SR_TXE));
-  SPI->DR = data;
-}
+static volatile int analog_errors;
 
 void SPI_IRQHandler(void) {
   uint32_t status = SPI->SR;
@@ -50,15 +34,15 @@
       frame = 1;
       partial_reading = value;
     } else {
+      frame = 2;
       // Masking off the high bits is important because there's nothing driving
       // the MISO line during the time the MCU receives them.
-      analog_readings[current_channel] = (partial_reading << 16 | value) & 0x3FF;
+      analog_readings[current_channel] =
+          (partial_reading << 16 | value) & 0x3FF;
       for (int i = 0; i < 100; ++i) gpio_off(CSEL_GPIO, CSEL_NUM);
       gpio_on(CSEL_GPIO, CSEL_NUM);
 
-      TIM->CR1 = TIM_CR1_OPM;
-      TIM->EGR = TIM_EGR_UG;
-      TIM->CR1 |= TIM_CR1_CEN;
+      current_channel = (current_channel + 1) % NUM_CHANNELS;
     }
   }
 }
@@ -66,7 +50,27 @@
 void TIM_IRQHandler(void) {
   TIM->SR = ~TIM_SR_CC1IF;
 
-  start_read((current_channel + 1) % NUM_CHANNELS);
+  if (frame != 2) {
+    // We're not done with the previous reading yet, so we're going to reset and
+    // try again.
+    // 270ns*120MHz = 32.4
+    for (int i = 0; i < 33; ++i) gpio_on(CSEL_GPIO, CSEL_NUM);
+    ++analog_errors;
+  }
+
+  // This needs to wait 13 cycles between enabling the CSEL pin and starting to
+  // send data.
+  // (100ns+8ns)*120MHz = 12.96
+
+  // Clear the CSEL pin to select it.
+  for (int i = 0; i < 9; ++i) gpio_off(CSEL_GPIO, CSEL_NUM);
+  partial_reading = 0;
+  frame = 0;
+  SPI->DR = 1;  // start bit
+  uint16_t data = (1 << 15) /* not differential */ |
+      (current_channel << 12);
+  while (!(SPI->SR & SPI_SR_TXE));
+  SPI->DR = data;
 }
 
 void analog_init(void) {
@@ -87,7 +91,7 @@
   NVIC_SetPriority(TIM_IRQn, 6);
   NVIC_EnableIRQ(TIM_IRQn);
 
-  TIM->CR1 = TIM_CR1_OPM;
+  TIM->CR1 = 0;
   TIM->DIER = TIM_DIER_CC1IE;
   TIM->CCMR1 = 0;
   // Make each tick take 1500ns.
@@ -104,5 +108,17 @@
   SPI->CR2 = SPI_CR2_RXNEIE;
   SPI->CR1 |= SPI_CR1_SPE;  // enable it
 
-  start_read(0);
+  current_channel = 0;
+  analog_errors = 0;
+
+  TIM->EGR = TIM_EGR_UG;
+  TIM->CR1 |= TIM_CR1_CEN;
+}
+
+int analog_get_errors(void) {
+  NVIC_DisableIRQ(TIM_IRQn);
+  int r = analog_errors;
+  analog_errors = 0;
+  NVIC_EnableIRQ(TIM_IRQn);
+  return r;
 }
diff --git a/bbb_cape/src/cape/analog.h b/bbb_cape/src/cape/analog.h
index 50038d5..cd9ce82 100644
--- a/bbb_cape/src/cape/analog.h
+++ b/bbb_cape/src/cape/analog.h
@@ -3,6 +3,8 @@
 
 #include <stdint.h>
 
+#include <STM32F2XX.h>
+
 // Starts up constantly reading analog values and storing them in an array to
 // be retrieved by analog_get.
 void analog_init(void);
@@ -14,4 +16,9 @@
   return analog_readings[num];
 }
 
+// Returns the number of errors since last called.
+// Must be called from something with priority equal to or lower than our
+// timer's IRQ.
+int analog_get_errors(void);
+
 #endif  // CAPE_ANALOG_H_
diff --git a/bbb_cape/src/cape/data_struct.h b/bbb_cape/src/cape/data_struct.h
index 4aa2a10..943e8c2 100644
--- a/bbb_cape/src/cape/data_struct.h
+++ b/bbb_cape/src/cape/data_struct.h
@@ -38,6 +38,8 @@
       // contents of flash for the main code (aka what's in the .hex file).
       uint32_t flash_checksum;
 
+      uint8_t analog_errors;
+
       struct {
         // If the current gyro_angle has been not updated because of a bad
         // reading from the sensor.
diff --git a/bbb_cape/src/cape/fill_packet.c b/bbb_cape/src/cape/fill_packet.c
index 97f9d8a..8d1f72a 100644
--- a/bbb_cape/src/cape/fill_packet.c
+++ b/bbb_cape/src/cape/fill_packet.c
@@ -40,6 +40,7 @@
   packet->uninitialized_gyro = !gyro_output.initialized;
   packet->zeroing_gyro = !gyro_output.zeroed;
   packet->bad_gyro = gyro_output.gyro_bad;
+  packet->analog_errors = analog_get_errors();
 
   robot_fill_packet(packet);
   //counter_update_u64_u16(&timestamp, TIMESTAMP_TIM->CNT);
diff --git a/frc971/input/sensor_receiver.cc b/frc971/input/sensor_receiver.cc
index 346a99d..057966a 100644
--- a/frc971/input/sensor_receiver.cc
+++ b/frc971/input/sensor_receiver.cc
@@ -160,6 +160,10 @@
         .Send();
   }
 
+  if (data->analog_errors != 0) {
+    LOG(WARNING, "%" PRIu8 " analog errors\n", data->analog_errors);
+  }
+
   other_sensors.MakeWithBuilder()
       .sonar_distance(sonar_translate(data->main.ultrasonic_pulse_length))
       .Send();