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(×tamp, 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();