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
surfboard.cpp
- Committer:
- avbotz
- Date:
- 2013-08-02
- Revision:
- 1:f69ec4c889ff
- Parent:
- 0:2381a319fc35
File content as of revision 1:f69ec4c889ff:
// 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; }