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

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;
+}