DSP program for the Surfboard hardware (PCB to be open sourced) http://www.avbotz.com/ourauv/electrical/signal-processing/
Dependencies: MODDMA SimpleIOMacros mbed-dsp mbed
Diff: surfboard.cpp
- Revision:
- 0:2381a319fc35
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/surfboard.cpp Fri Aug 02 02:23:36 2013 +0000 @@ -0,0 +1,278 @@ +// I think we should move this to the offline compiler so we can get loop unrolling. -- Kevin +// TODO: code size is small (4% of available space) so we should totally do loop unrolling + +#include "surfboard.h" + +// Might have to use IO Macros library for fast digital I/O http://mbed.org/users/AjK/code/SimpleIOMacros/ +// less abstracted InterruptIn http://mbed.org/forum/mbed/topic/2326/ +//InterruptIn drdy(p8); // active low +// interruptin too slow http://mbed.org/forum/mbed/topic/2326/ +DigitalOut sync(p14); // active low + +//Serial submarine(/*tx*/ p28, /*rx*/ p27); +Serial submarine(USBTX, USBRX); +// From sub to hydrophone board: +// r = start running +// s = stop running +// From hydrophone board to sub: +// h = hello world +// b = turned off because battery low + +DigitalOut avdd_ctl(p15); + +AnalogIn abat_sense(p16); +// We don't want the battery to go below 6 V. +// TODO: read the battery after each IIR batch? +// Calculate what the minimum battery voltage should be after it goes through +// the voltage divider and mbed AnalogIn ADC. +#define ABAT_RATIO ((2.21f / 6.95f) / 3.3f) +#define ABAT_THRESH_LO (ABAT_RATIO * 6.0f) +#define ABAT_THRESH_HI (ABAT_RATIO * 6.5f) +Ticker abat_tick; + +// On Surfboard v1.0, setting these does not actually control the power because +// of the modifications on the board. +DigitalOut clkvdd(p9), iovdd(p10); + +volatile bool fresh_data = false; + +// lights for debugging +// Replacing with SimpleIOMacros.h because each toggle takes ~300 ns (!!) +DigitalOut led1(LED1), // blinking: wait for run command. solid: ready + led2(LED2), // in function get_data() + led3(LED3), // toggles when IIR filter is run + led4(LED4); // toggles on fresh data +// Counts how many times we toggled the LED +uint32_t led1num, led2num, led3num, led4num; +Ticker* led1ticks[2]; + +int i_timestamps[NUM_CHANNELS]; + +// For saving received data to disk +LocalFileSystem local("local"); +bool log_data_enabled = true; + +// Call this function to reset the mbed +extern "C" void mbed_reset(); + +int main() +{ + pre_setup(); // For safety, this must be the first thing that runs + + /*for (int i = 0; i < sizeof(parsed)/sizeof(uint16_t); i++) + { + *(((int16_t*)parsed) + i) = 12345; + }*/ + + wait(5); + + led1ticks[0] = new Ticker(); + led1ticks[1] = new Ticker(); + + led1 = 1; + led1ticks[0]->attach(&led1_cb, 1.0); + wait_ms(60); + led1ticks[1]->attach(&led1_cb, 1.0); + led1 = 0; + + submarine.baud(115200); + submarine.putc('h'); + submarine.printf("%d ", sizeof(q15_t)); + + // Wait until we are told to turn on + //while (submarine.getc() != 'r'); + + submarine.attach(&submarine_cb); + led1ticks[0]->detach(); + led1ticks[1]->detach(); + + setup(); + + while (true) + { + if (fresh_data) + { + fresh_data = false; + + LED4_TOGGLE; + + if (log_data_enabled /*&& read_blocks > 3*/) + { + // Disable DRDY interrupt to prevent the buffer from changing + // while we save it. Writing to disk takes a long time. +// drdy.rise(NULL); + // Only log data once + log_data_enabled = false; + + FILE *fp = fopen("/local/out.csv", "w"); + + fprintf(fp, "Index,Ch1,Ch2,Ch3,Ch4\n"); + for (int i = 0; i < BLOCK_SIZE; i++) + { + fprintf(fp, "%d", i); + for (int j = 0; j < NUM_CHANNELS; j++) + { + fprintf(fp, ",%02X%02X%02X", parsed[write_block^1][j][i][0], parsed[write_block^1][j][i][1], parsed[write_block^1][j][i][2]); + //int16_t n = parsed[write_block^1][j][i]; + //fprintf(fp, ",%X", n); + } + fprintf(fp, "\n"); + } + + fclose(fp); + + // drdy.rise(&get_data); + } + + /*for (char i = 0; i < NUM_CHANNELS; i++) + { + arm_iir_lattice_q15(iir_filter+i, parsed[write_block^1][i], filtered, BLOCK_SIZE); + i_timestamps[i] = find_timestamp_tdoa(filtered); + }*/ + // hyperbolic positioning + // send it to the sub + } + } +} + +void pre_setup() +{ + +} + +int setup() +{ + int retValue = 0; + retValue += setup_ads1274(); + retValue += setup_dma(); + + led1 = 1; // Debug + + // Should be at the end of setup function, in case ADS1274 tries to send data + //drdy.rise(&get_data); + event_irq_init(); + + return retValue; +} + +// Return values +// 0: setup finished normally +// 1: setup aborted because battery voltage was too low +int setup_ads1274() +{ + // Don't start up if the battery is too low + abat_cb(); + abat_tick.attach(&abat_cb, 1); + + // Sequence the power-on of the ADC + iovdd = 1; + __nop(); + avdd_ctl = 1; + // Give it some time, just in case. + wait_ms(5); + // Now we can start driving pins without destroying the ADS1274 + // Turn on sampling clock (CLK) + clkvdd = 1; + + // ADS1274 needs 2^18 clk cycles + 129 conversions before data are valid + // minimum wait time = 2^18 / f_clk + 129 / f_data = 2^18/27MHz + 129/0.1MHz = 11 ms + wait_ms(11 + 1); + + // Datasheet suggested resetting the ads1274 after start up to synchronize outputs + // Need to put it low for at least 1 CLK period + // On mbed, this is 96 MHz/27MHz = 3.556 instruction cycles + sync = 1; + // Drive *sync to logic low for about 4 instruction cycles + sync = 0; + __nop(); __nop(); __nop(); __nop(); // wait 4 cycles + sync = 1; + // Wait 1/f_data = 1/0.1MHz = 10 us for new data to be valid + wait_us(10 + 1); + + return 0; // success +} + +void teardown() +{ + // Disable interrupts. Not sure if this is necessary, but I don't want samples to be read while we shut down + __disable_irq(); + + teardown_ads1274(); + teardown_dma(); +} + +void teardown_ads1274() +{ + // Turn off peripherals, then turn off ADS1274 + // Turn off CLK + clkvdd = 0; + __nop(); __nop(); + // Turn off op amps and analog power to ADS1274 + avdd_ctl = 0; + // Turn off IO power + iovdd = 0; +} + +// Called when the submarine sends a message to us +void submarine_cb() +{ + // Loop as long as there are more characters to be read + while (submarine.readable()) + { + // If we are told to stop + if (submarine.getc() == 's') + { + // Shut everything down + teardown(); + // Reset the mbed + mbed_reset(); + } + } +} + +// Called every few seconds to check the battery status +void abat_cb() +{ + if (abat_sense < ABAT_THRESH_LO) + { + // Uh oh, stop the hydrophone board + teardown(); + + submarine.putc('b'); + led1 = led2 = led3 = led4 = 0; + + // Wait until someone changes the battery + int num_hi = 0, loop_count = 0;; + while (num_hi < 100) + { + if (abat_sense > ABAT_THRESH_HI) + { + num_hi++; + } + else if (num_hi > 0) + { + num_hi--; + } + + if (loop_count == 32000) + { + led1 = led2 = led3 = led4 = !led1; + loop_count = 0; + } + else + { + loop_count++; + } + } + + // On battery replacement, wait for the user to plug the battery in all the way + wait_ms(3000); + + mbed_reset(); + } +} + +void led1_cb() +{ + led1 = !led1; +}