reorganized the gyro code + implemented actual error checking
diff --git a/gyro_board/src/usb/CAN.c b/gyro_board/src/usb/CAN.c
index 6770328..591c6fc 100644
--- a/gyro_board/src/usb/CAN.c
+++ b/gyro_board/src/usb/CAN.c
@@ -10,7 +10,6 @@
 #include "flash.h"
 #include "partest.h"
 #include "analog.h"
-#include "spi.h"
 #include "LPCUSB/usbapi.h"
 #include "CAN.h"
 
diff --git a/gyro_board/src/usb/Makefile b/gyro_board/src/usb/Makefile
index 424df84..2dc2286 100644
--- a/gyro_board/src/usb/Makefile
+++ b/gyro_board/src/usb/Makefile
@@ -46,7 +46,7 @@
 	LPCUSB/usbcontrol.c \
 	LPCUSB/USB_SENSOR_STREAM.c \
 	LPCUSB/usbhw_lpc.c \
-	spi.c \
+	gyro.c \
 	LPCUSB/usbstdreq.c
 
 all: $(NAME).hex
diff --git a/gyro_board/src/usb/analog.h b/gyro_board/src/usb/analog.h
index 435d194..1de38e7 100644
--- a/gyro_board/src/usb/analog.h
+++ b/gyro_board/src/usb/analog.h
@@ -3,8 +3,6 @@
 
 #include <stdint.h>
 
-extern int64_t gyro_angle;
-
 void analog_init(void);
 int analog(int channel);
 
diff --git a/gyro_board/src/usb/data_struct.h b/gyro_board/src/usb/data_struct.h
index edccea3..aa0e782 100644
--- a/gyro_board/src/usb/data_struct.h
+++ b/gyro_board/src/usb/data_struct.h
@@ -5,6 +5,8 @@
 // In the fitpc code, frc971/input/gyro_board_data.h #includes this file.
 
 #pragma pack(push, 1)
+// Be careful with declaration order in here. ARM doesn't like unaligned
+// accesses!
 struct DATA_STRUCT_NAME {
   int64_t gyro_angle;
 
@@ -26,8 +28,13 @@
           uint8_t dip_switch1 : 1;
           uint8_t dip_switch2 : 1;
           uint8_t dip_switch3 : 1;
+          // If the current gyro_angle has been not updated because of a bad
+          // reading from the sensor.
+          uint8_t old_gyro_reading : 1;
+          // If we're not going to get any more good gyro_angles.
+          uint8_t bad_gyro : 1;
         };
-        uint8_t dip_switches;
+        uint8_t base_status;
       };
     };
     uint16_t header;
diff --git a/gyro_board/src/usb/encoder.c b/gyro_board/src/usb/encoder.c
index 581ddb4..6c4999c 100644
--- a/gyro_board/src/usb/encoder.c
+++ b/gyro_board/src/usb/encoder.c
@@ -6,6 +6,7 @@
 
 #include "digital.h"
 #include "analog.h"
+#include "gyro.h"
 
 // How long (in ms) to wait after a falling edge on the bottom indexer sensor
 // before reading the indexer encoder.
@@ -474,7 +475,9 @@
 }
 
 void fillSensorPacket(struct DataStruct *packet) {
-  packet->gyro_angle = gyro_angle;
+  packet->gyro_angle = gyro_output.angle;
+  packet->old_gyro_reading = gyro_output.last_reading_bad;
+  packet->bad_gyro = gyro_output.gyro_bad;
 
   packet->dip_switch0 = dip_switch(0);
   packet->dip_switch1 = dip_switch(1);
diff --git a/gyro_board/src/usb/gyro.c b/gyro_board/src/usb/gyro.c
new file mode 100644
index 0000000..d52a698
--- /dev/null
+++ b/gyro_board/src/usb/gyro.c
@@ -0,0 +1,342 @@
+#include "gyro.h"
+
+#include <stdio.h>
+#include <inttypes.h>
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "partest.h"
+
+struct GyroOutput gyro_output;
+
+static void gyro_disable_csel(void) {
+  // Set the CSEL pin high to deselect it.
+  GPIO0->FIOSET = 1 << 16;
+}
+
+static void gyro_enable_csel(void) {
+  // Clear the CSEL pin to select it.
+  GPIO0->FIOCLR = 1 << 16;
+}
+
+// Blocks until there is data available.
+static uint16_t spi_read(void) {
+  while (!(SSP0->SR & (1 << 2))) {}
+  return SSP0->DR;
+}
+
+// Blocks until there is space to enqueue data.
+static void spi_write(uint16_t data) {
+  while (!(SSP0->SR & (1 << 1))) {}
+  SSP0->DR = data;
+}
+
+static uint32_t do_gyro_read(uint32_t data, int *parity_error) {
+  *parity_error = 0;
+
+  gyro_enable_csel();
+  spi_write(data >> 16);
+  if (__builtin_parity(data & ~1) == 0) data |= 1;
+  spi_write(data);
+
+  uint16_t high_value = spi_read();
+  if (__builtin_parity(high_value) != 1) {
+    printf("high value 0x%"PRIx16" parity error\n", high_value);
+    *parity_error = 1;
+  }
+  uint16_t low_value = spi_read();
+  gyro_disable_csel();
+  if (__builtin_parity(low_value) != 1) {
+    printf("low value 0x%"PRIx16" parity error\n", high_value);
+    *parity_error = 1;
+  }
+
+  return high_value << 16 | low_value;
+}
+
+// Returns all of the non-data bits in the "header" except the parity from
+// value.
+static uint8_t gyro_status(uint32_t value) {
+  return (value >> 26) & ~4;
+}
+
+// Returns all of the error bits in the "footer" from value.
+static uint8_t gyro_errors(uint32_t value) {
+  return (value >> 1) & 0x7F;
+}
+
+// Performs a read from the gyro.
+// Sets *bad_reading to 1 if the result is potentially bad and *bad_gyro to 1 if
+// the gyro is bad and we're not going to get any more readings.
+static int16_t gyro_read(int *bad_reading, int *bad_gyro) {
+  *bad_reading = *bad_gyro = 0;
+
+  int parity_error;
+  uint32_t value = do_gyro_read(0x20000000, &parity_error);
+
+  if (parity_error) {
+    *bad_reading = 1;
+    return 0;
+  }
+
+  // This check assumes that the sequence bits are all 0, but they should be
+  // because that's all we send.
+  if (gyro_status(value) != 1) {
+    uint8_t status = gyro_status(value);
+    if (status == 0) {
+      printf("gyro says sensor data is bad\n");
+    } else {
+      printf("gyro gave weird status 0x%"PRIx8"\n", status);
+    }
+    *bad_reading = 1;
+  }
+
+  if (gyro_errors(value) != 0) {
+    uint8_t errors = gyro_errors(value);
+    if (errors & ~(1 << 1)) {
+      *bad_reading = 1;
+      // Error 1 (continuous self-test error) will set status to 0 if it's bad
+      // enough by itself.
+    }
+    if (errors & (1 << 6)) {
+      printf("gyro PLL error\n");
+    }
+    if (errors & (1 << 5)) {
+      printf("gyro quadrature error\n");
+    }
+    if (errors & (1 << 4)) {
+      printf("gyro non-volatile memory error\n");
+      *bad_gyro = 1;
+    }
+    if (errors & (1 << 3)) {
+      printf("gyro volatile memory error\n");
+      *bad_gyro = 1;
+    }
+    if (errors & (1 << 2)) {
+      printf("gyro power error\n");
+    }
+    if (errors & (1 << 1)) {
+      printf("gyro continuous self-test error\n");
+    }
+    if (errors & 1) {
+      printf("gyro unexpected self check mode\n");
+    }
+  }
+  if (*bad_gyro) {
+    *bad_reading = 1;
+    return 0;
+  } else {
+    return -(int16_t)(value >> 10 & 0xFFFF);
+  }
+}
+
+// Returns 1 if the setup failed or 0 if it succeeded.
+static int gyro_setup(void) {
+  for (int i = 0; i < 100; ++i) {
+	  portTickType wait_time = xTaskGetTickCount();
+    int parity_error;
+
+    // Wait for it to start up.
+	  vTaskDelayUntil(&wait_time, 100 / portTICK_RATE_MS);
+    // Get it started doing a check.
+    uint32_t value = do_gyro_read(0x20000003, &parity_error);
+    if (parity_error) continue;
+    // Its initial response is hardcoded to 1.
+    if (value != 1) {
+      printf("gyro unexpected initial response 0x%"PRIx32"\n", value);
+      // There's a chance that we're retrying because of a parity error
+      // previously, so keep going.
+    }
+
+    // Wait for it to assert the fault conditions.
+	  vTaskDelayUntil(&wait_time, 50 / portTICK_RATE_MS);
+    // Dummy read to clear the old latched state.
+    do_gyro_read(0x20000000, &parity_error);
+    if (parity_error) continue;
+
+    // Wait for it to clear the fault conditions.
+	  vTaskDelayUntil(&wait_time, 50 / portTICK_RATE_MS);
+    value = do_gyro_read(0x20000000, &parity_error);
+    if (parity_error) continue;
+    // If it's not reporting self test data.
+    if (gyro_status(value) != 2) {
+      printf("gyro first value 0x%"PRIx32" not self test data\n", value);
+      continue;
+    }
+    // If we don't see all of the errors.
+    if (gyro_errors(value) != 0x7F) {
+      printf("gyro self test value 0x%"PRIx32" is bad\n", value);
+      return 1;
+    }
+
+    // Wait for the sequential transfer delay.
+	  vTaskDelayUntil(&wait_time, 1 / portTICK_RATE_MS);
+    value = do_gyro_read(0x20000000, &parity_error);
+    if (parity_error) continue;
+    // It should still be reporting self test data.
+    if (gyro_status(value) != 2) {
+      printf("gyro second value 0x%"PRIx32" not self test data\n", value);
+      continue;
+    }
+    return 0;
+  }
+  return 1;
+}
+
+static portTASK_FUNCTION(gyro_read_task, pvParameters) {
+  // How many times per second to read the gyro value.
+  static const int kGyroReadFrequency = 200;
+  // How many times per second to flash the LED.
+  // Must evenly divide kGyroReadFrequency.
+  static const int kFlashFrequency = 10;
+
+  static const int kStartupCycles = kGyroReadFrequency * 2;
+  static const int kZeroingCycles = kGyroReadFrequency * 6;
+
+  // An accumulator for all of the values read while zeroing.
+  int32_t zero_bias = 0;
+
+  int startup_cycles_left = kStartupCycles;
+  int zeroing_cycles_left = kZeroingCycles;
+
+  // These are a pair that hold the offset calculated while zeroing.
+  // full_units_ is the base (in ticks) and remainder_ ranges between 0 and
+  // kZeroingCycles (like struct timespec). remainder_ is used to calculate which
+  // cycles to add an additional unit to the result.
+  int32_t full_units_offset = 0;
+  int32_t remainder_offset = 0;
+  // This keeps track of when to add 1 to the read value (using _offset).
+  int32_t remainder_sum = 0;
+
+  int32_t led_flash = 0;
+  vParTestSetLED(0, 0);
+
+  portTickType xLastGyroReadTime = xTaskGetTickCount();
+
+  for (;;) {
+    ++led_flash;
+    if (led_flash < kGyroReadFrequency / kFlashFrequency / 2) {
+      vParTestSetLED(1, 0);
+    } else {
+      vParTestSetLED(1, 1);
+    }
+    if (led_flash >= kGyroReadFrequency / kFlashFrequency) {
+      led_flash = 0;
+    }
+
+    vTaskDelayUntil(&xLastGyroReadTime,
+                    1000 / kGyroReadFrequency / portTICK_RATE_MS);
+
+    int bad_reading, bad_gyro;
+    int16_t gyro_value = gyro_read(&bad_reading, &bad_gyro);
+    if (bad_gyro) {
+      // We're just going to give up if this happens (write out that we're
+      // giving up and then never run anything else in this task).
+      vParTestSetLED(0, 1);
+      printf("gyro read task giving up because of bad gyro\n");
+      portENTER_CRITICAL();
+      gyro_output.gyro_bad = 1;
+      gyro_output.last_reading_bad = 1;
+      gyro_output.angle = 0;
+      portEXIT_CRITICAL();
+      vTaskDelete(NULL);
+      while (1) {}
+    }
+
+    if (startup_cycles_left) {
+      vParTestSetLED(2, 0);
+      --startup_cycles_left;
+      if (bad_reading) {
+        printf("gyro retrying startup wait because of bad reading\n");
+        startup_cycles_left = kStartupCycles;
+      }
+    } else if (zeroing_cycles_left) {
+      vParTestSetLED(2, 1);
+      --zeroing_cycles_left;
+      if (bad_reading) {
+        printf("gyro restarting zeroing because of bad reading\n");
+        zeroing_cycles_left = kZeroingCycles;
+        zero_bias = 0;
+      } else {
+        zero_bias -= gyro_value;
+        if (zeroing_cycles_left == 0) {
+          // Do all the nice math
+          full_units_offset = zero_bias / kZeroingCycles;
+          remainder_offset = zero_bias % kZeroingCycles;
+          if (remainder_offset < 0) {
+            remainder_offset += kZeroingCycles;
+            --full_units_offset;
+          }
+        }
+      }
+    } else {
+      vParTestSetLED(2, 0);
+
+      int64_t new_angle = gyro_output.angle;
+      if (!bad_reading) new_angle += gyro_value + full_units_offset;
+      if (remainder_sum >= kZeroingCycles) {
+        remainder_sum -= kZeroingCycles;
+        new_angle += 1;
+      }
+      portENTER_CRITICAL();
+      gyro_output.angle = new_angle;
+      gyro_output.last_reading_bad = bad_reading;
+      portEXIT_CRITICAL();
+      remainder_sum += remainder_offset;
+    }
+  }
+}
+
+void gyro_init(void) {
+  // Connect power and clock.
+  SC->PCONP |= PCONP_PCSSP0;
+  SC->PCLKSEL1 &= ~(3 << 10);
+  SC->PCLKSEL1 |= 1 << 10;
+
+  // Set up SSEL.
+  // It's is just a GPIO pin because we're the master (it would be special if we
+  // were a slave).
+  gyro_disable_csel();
+  GPIO0->FIODIR |= 1 << 16;
+  PINCON->PINSEL1 &= ~(3 << 0);
+  PINCON->PINSEL1 |= 0 << 0;
+
+  // Set up MISO0 and MOSI0.
+  PINCON->PINSEL1 &= ~(3 << 2 | 3 << 4);
+  PINCON->PINSEL1 |= 2 << 2 | 2 << 2;
+
+  // Set up SCK0.
+  PINCON->PINSEL0 &= ~(3 << 30);
+  PINCON->PINSEL0 |= (2 << 30);
+
+  // Make sure it's disabled.
+  SSP0->CR1 = 0;
+  SSP0->CR0 =
+      0xF /* 16 bit transfer */ |
+      0 << 4 /* SPI mode */ |
+      0 << 6 /* CPOL = 0 */ |
+      0 << 7 /* CPHA = 0 */;
+  // 14 clocks per cycle.  This works out to a ~7.2MHz bus.
+  // The gyro is rated for a maximum of 8.08MHz.
+  SSP0->CPSR = 14;
+  // Set it to master mode.
+  SSP0->CR1 |= 1 << 2;
+  // Finally, enable it.
+  // This has to be done after we're done messing with everything else.
+  SSP0->CR1 |= 1 << 1;
+
+  if (gyro_setup()) {
+    printf("gyro setup failed. not starting task\n");
+    gyro_output.angle = 0;
+    gyro_output.last_reading_bad = gyro_output.gyro_bad = 1;
+    return;
+  }
+
+  gyro_output.angle = 0;
+  gyro_output.last_reading_bad = 1;  // until we're started up
+  gyro_output.gyro_bad = 0;
+
+  xTaskCreate(gyro_read_task, (signed char *) "gyro",
+              configMINIMAL_STACK_SIZE + 100, NULL,
+              tskIDLE_PRIORITY + 2, NULL);
+}
diff --git a/gyro_board/src/usb/gyro.h b/gyro_board/src/usb/gyro.h
new file mode 100644
index 0000000..7b9521e
--- /dev/null
+++ b/gyro_board/src/usb/gyro.h
@@ -0,0 +1,19 @@
+#ifndef GYRO_BOARD_SRC_USB_GYRO_H_
+#define GYRO_BOARD_SRC_USB_GYRO_H_
+
+#include <stdint.h>
+
+// Does everything to set up the gyro code, including starting a task which
+// reads and integrates the gyro values and blinks the LEDs etc.
+void gyro_init(void);
+
+struct GyroOutput {
+  int64_t angle;
+  int last_reading_bad;
+  int gyro_bad;
+};
+// This gets updated in a portENTER_CRITICAL/portEXIT_CRITICAL() block so all of
+// the values will be in sync.
+extern struct GyroOutput gyro_output;
+
+#endif  // GYRO_BOARD_SRC_USB_GYRO_H_
diff --git a/gyro_board/src/usb/main.c b/gyro_board/src/usb/main.c
index 0df1c4c..4a5eca4 100644
--- a/gyro_board/src/usb/main.c
+++ b/gyro_board/src/usb/main.c
@@ -31,179 +31,19 @@
 /* Demo app includes. */
 #include "flash.h"
 #include "partest.h"
-#include "spi.h"
 #include "LPCUSB/usbapi.h"
 
 #include "analog.h"
 #include "digital.h"
 #include "encoder.h"
 #include "CAN.h"
-
-int64_t gyro_angle = 0;
-
-/*
- * Configure the hardware.
- */
-static void prvSetupHardware(void);
+#include "gyro.h"
 
 /*
  * The task that handles the USB stack.
  */
 extern void vUSBTask(void *pvParameters);
 
-extern int VCOM_getchar(void);
-
-int VCOM_putchar(int c);
-
-inline int32_t encoder()
-{
-  return (int32_t)QEI->QEIPOS;
-}
-
-static portTASK_FUNCTION(vPrintPeriodic, pvParameters)
-{
-  portTickType xLastFlashTime;
-
-  /* We need to initialise xLastFlashTime prior to the first call to
-     vTaskDelayUntil(). */
-  xLastFlashTime = xTaskGetTickCount();
-
-  digital_init();
-
-  analog_init();
-
-  encoder_init();
-
-  // Wait 100 ms for it to boot.
-  vTaskDelayUntil(&xLastFlashTime, 100 / portTICK_RATE_MS);
-  spi_init();
-
-  // Enable USB.  The PC has probably disconnected it now.
-  USBHwAllowConnect();
-
-  // TODO(aschuh): Write this into a gyro calibration function, and check all the outputs.
-  vTaskDelayUntil(&xLastFlashTime, 50 / portTICK_RATE_MS);
-  enable_gyro_csel();
-  printf("SPI Gyro Second Response 0x%x %x\n", transfer_spi_bytes(0x2000), transfer_spi_bytes(0x0000));
-  disable_gyro_csel();
-
-  vTaskDelayUntil(&xLastFlashTime, 50 / portTICK_RATE_MS);
-  enable_gyro_csel();
-  printf("SPI Gyro Third Response 0x%x %x\n", transfer_spi_bytes(0x2000), transfer_spi_bytes(0x0000));
-  disable_gyro_csel();
-
-  vTaskDelayUntil(&xLastFlashTime, 10 / portTICK_RATE_MS);
-  enable_gyro_csel();
-  printf("SPI Gyro Fourth Response 0x%x %x\n", transfer_spi_bytes(0x2000), transfer_spi_bytes(0x0000));
-  disable_gyro_csel();
-  const int hz = 200;
-  const int flash_hz = 10;
-  const int startup_cycles = hz * 2;
-  const int zeroing_cycles = hz * 6;
-  int32_t zero_bias = 0;
-  int32_t startup_cycles_left = startup_cycles;
-  int32_t zeroing_cycles_left = zeroing_cycles;
-  int32_t full_units_offset = 0;
-  int32_t remainder_offset = 0;
-  int32_t remainder_sum = 0;
-  int32_t led_flash = 0;
-  vParTestSetLED(0, 0);
-
-  for (;;) {
-    led_flash ++;
-    if (led_flash < hz / flash_hz / 2) {
-      vParTestSetLED(1, 0);
-    } else {
-      vParTestSetLED(1, 1);
-    }
-    if (led_flash >= hz / flash_hz) {
-      led_flash = 0;
-    }
-    /* Delay for half the flash period then turn the LED on. */
-    vTaskDelayUntil(&xLastFlashTime, 1000 / hz / portTICK_RATE_MS);
-    enable_gyro_csel();
-    uint16_t high_value = transfer_spi_bytes(0x2000);
-    uint16_t low_value = transfer_spi_bytes(0x0000);
-    disable_gyro_csel();
-    int16_t gyro_value = -((int16_t)((((uint32_t)high_value << 16) | (uint32_t)low_value) >> 10));
-
-    if (startup_cycles_left) {
-      vParTestSetLED(2, 0);
-      --startup_cycles_left;
-    } else if (zeroing_cycles_left) {
-      vParTestSetLED(2, 1);
-      //printf("Zeroing ");
-      --zeroing_cycles_left;
-      zero_bias -= gyro_value;
-      if (zeroing_cycles_left == 0) {
-        // Do all the nice math
-        full_units_offset = zero_bias / zeroing_cycles;
-        remainder_offset = zero_bias % zeroing_cycles;
-        if (remainder_offset < 0) {
-          remainder_offset += zeroing_cycles;
-          --full_units_offset;
-        }
-      }
-    } else {
-      vParTestSetLED(2, 0);
-      int64_t new_angle = gyro_angle + gyro_value + full_units_offset;
-      if (remainder_sum >= zeroing_cycles) {
-        remainder_sum -= zeroing_cycles;
-        new_angle += 1;
-      }
-      gyro_angle = new_angle;
-      remainder_sum += remainder_offset;
-    }
-    //printf("Angle %d Rate %d\n", (int)(gyro_angle / 16),
-    //       (int)(gyro_value + full_units_offset));
-
-    //printf("time: %d analog %d encoder %d goal %d\n", (int)i, (int)analog(5),
-    //       (int)encoder(), (int)goal);
-
-    /*
-    for(i = 0; i < 4; i++){
-      printf("analog(%d) => %d\n",i,analog(i));
-    }
-    for(i = 1; i < 13; i++){
-      printf("digital(%d) => %d\n",i,digital(i));
-    }
-    for(i = 0; i < 4; i++){
-      printf("dip(%d) => %d\n",i,dip(i));
-    }
-    for(i = 0; i < 4; i++){
-      printf("encoder(%d) => %d\n",i,encoder_bits(i));
-    }
-    for(i = 0; i < 4; i++){
-      printf("encoder_val(%d) => %d\n",i,(int)encoder_val(i));
-    }*/
-  }
-}
-
-int main(void) {
-  // Configure the hardware
-  prvSetupHardware();
-
-  /* Create the USB task. */
-  xTaskCreate(vUSBTask, (signed char *) "USB",
-              configMINIMAL_STACK_SIZE + 1020, (void *) NULL,
-              tskIDLE_PRIORITY + 3, NULL);
-
-  xTaskCreate(vPrintPeriodic, (signed char *) "PRINTx",
-              configMINIMAL_STACK_SIZE + 100, NULL,
-              tskIDLE_PRIORITY + 2, NULL);
-
-
-  initCAN();
-
-  // Start the scheduler.
-  vTaskStartScheduler();
-
-  /* Will only get here if there was insufficient memory to create the idle
-     task.  The idle task is created within vTaskStartScheduler(). */
-  for (;;) {}
-}
-/*-----------------------------------------------------------*/
-
 // Sets up (and connects) PLL0.
 // The CPU will be running at 100 MHz with a 12 MHz clock input when this is
 // done.
@@ -300,10 +140,8 @@
   while (((SC->PLL1STAT & (1 << 9)) == 0));
 }
 
-void prvSetupHardware(void)
-{
-  // Setup the peripherals.
-
+// Setup the peripherals.
+static void setup_hardware(void) {
   // Setup GPIO power.
   SC->PCONP = PCONP_PCGPIO;
 
@@ -314,14 +152,41 @@
 
   setup_PLL1();
 
-  // Setup the peripheral bus to be the same as the CCLK, 100 MHz.
   // Set CAN to run at CCLK/6, which should have it running about 1 Mbit (1.042)
   SC->PCLKSEL0 = 0xff555555;
 
   /* Configure the LEDs. */
   vParTestInitialise();
 }
-/*-----------------------------------------------------------*/
+
+int main(void) {
+  setup_hardware();
+
+  /* Create the USB task. */
+  xTaskCreate(vUSBTask, (signed char *) "USB",
+              configMINIMAL_STACK_SIZE + 1020, (void *) NULL,
+              tskIDLE_PRIORITY + 3, NULL);
+
+  digital_init();
+
+  analog_init();
+
+  encoder_init();
+
+  gyro_init();
+
+  // Enable USB.  The PC has probably disconnected it now.
+  USBHwAllowConnect();
+
+  initCAN();
+
+  // Start the scheduler.
+  vTaskStartScheduler();
+
+  /* Will only get here if there was insufficient memory to create the idle
+     task.  The idle task is created within vTaskStartScheduler(). */
+  for (;;) {}
+}
 
 void vApplicationStackOverflowHook(xTaskHandle *pxTask, signed char *pcTaskName)
 {
@@ -332,12 +197,11 @@
 
   for (;;);
 }
-/*-----------------------------------------------------------*/
 
 // This is what portCONFIGURE_TIMER_FOR_RUN_TIME_STATS in FreeRTOSConfig.h
 // actually calls.
-void vConfigureTimerForRunTimeStats(void)
-{
+// It sets up timer 0 to use for timing.
+void vConfigureTimerForRunTimeStats(void) {
   const unsigned long TCR_COUNT_RESET = 2, CTCR_CTM_TIMER = 0x00, TCR_COUNT_ENABLE = 0x01;
 
   /* This function configures a timer that is used as the time base when
diff --git a/gyro_board/src/usb/spi.c b/gyro_board/src/usb/spi.c
deleted file mode 100644
index de41866..0000000
--- a/gyro_board/src/usb/spi.c
+++ /dev/null
@@ -1,60 +0,0 @@
-#include "stdio.h"
-#include "FreeRTOS.h"
-#include "spi.h"
-
-void spi_init (void) {
-  SC->PCONP |= PCONP_PCSPI;
-  SC->PCLKSEL0 |= 0x00010000;
-
-  // Hook up the interrupt
-  //NVIC_EnableIRQ(SPI_IRQn);
-
-  // SCK
-  PINCON->PINSEL0 &= 0x3fffffff;
-  PINCON->PINSEL0 |= 0xc0000000;
-
-  // SSEL, MISO, MOSI
-  // SSEL is GPIO, and needs to be done manually.
-  disable_gyro_csel();
-  GPIO0->FIODIR |= 0x00010000;
-  PINCON->PINSEL1 &= 0xffffffc0;
-  PINCON->PINSEL1 |= 0x0000003c;
-
-  // Master mode, 16 bits/frame, enable interrupts
-  SPI->SPCR = 0x000000a4;
-  // 13 clocks per cycle.  This works out to a 7.7 mhz buss.
-  SPI->SPCCR = 0x0000000d;
-
-  // TODO(aschuh): Implement the gyro bring-up blocking first.
-  // Then use interrupts.
-  enable_gyro_csel();
-  printf("SPI Gyro Initial Response 0x%x %x\n", transfer_spi_bytes(0x2000), transfer_spi_bytes(0x0003));
-  disable_gyro_csel();
-}
-
-// TODO: DMA? SSP0?  SSP0 should have a buffer, which would be very nice.
-uint16_t transfer_spi_bytes(uint16_t data) {
-  SPI->SPDR = (uint32_t)data;
-  while (!(SPI->SPSR & 0x80));
-  return SPI->SPDR;
-}
-
-void disable_gyro_csel (void) {
-  // Set the CSEL pin high to deselect it.
-  GPIO0->FIOSET = 0x00010000;
-}
-
-void enable_gyro_csel (void) {
-  // Clear the CSEL pin high to select it.
-  GPIO0->FIOCLR = 0x00010000;
-}
-
-void SPI_IRQHandler(void) {
-  int status = SPI->SPSR;
-  if (status & 0x80) {
-    // Transfer completed.
-  }
-
-  // Clear the interrupt?
-  SPI->SPINT = 0x00000001;
-}
diff --git a/gyro_board/src/usb/spi.h b/gyro_board/src/usb/spi.h
deleted file mode 100644
index 6dbc511..0000000
--- a/gyro_board/src/usb/spi.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef __SPI_H__
-#define __SPI_H__
-
-void spi_init (void);
-uint16_t transfer_spi_bytes(uint16_t data);
-void disable_gyro_csel (void);
-void enable_gyro_csel (void);
-
-#endif // __SPI_H__