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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers surfboard.cpp Source File

surfboard.cpp

00001 // I think we should move this to the offline compiler so we can get loop unrolling. -- Kevin
00002 // TODO: code size is small (4% of available space) so we should totally do loop unrolling
00003 
00004 #include "surfboard.h"
00005 
00006 // Might have to use IO Macros library for fast digital I/O http://mbed.org/users/AjK/code/SimpleIOMacros/
00007 // less abstracted InterruptIn http://mbed.org/forum/mbed/topic/2326/
00008 //InterruptIn drdy(p8); // active low
00009 // interruptin too slow http://mbed.org/forum/mbed/topic/2326/
00010 DigitalOut sync(p14); // active low
00011 
00012 //Serial submarine(/*tx*/ p28, /*rx*/ p27);
00013 Serial submarine(USBTX, USBRX);
00014 // From sub to hydrophone board:
00015 // r = start running
00016 // s = stop running
00017 // From hydrophone board to sub:
00018 // h = hello world
00019 // b = turned off because battery low
00020 
00021 DigitalOut avdd_ctl(p15);
00022 
00023 AnalogIn abat_sense(p16);
00024 // We don't want the battery to go below 6 V. 
00025 // TODO: read the battery after each IIR batch?
00026 // Calculate what the minimum battery voltage should be after it goes through
00027 // the voltage divider and mbed AnalogIn ADC.
00028 #define ABAT_RATIO ((2.21f / 6.95f) / 3.3f)
00029 #define ABAT_THRESH_LO (ABAT_RATIO * 6.0f)
00030 #define ABAT_THRESH_HI (ABAT_RATIO * 6.5f)
00031 Ticker abat_tick;
00032 
00033 // On Surfboard v1.0, setting these does not actually control the power because
00034 // of the modifications on the board.
00035 DigitalOut clkvdd(p9), iovdd(p10);
00036 
00037 volatile bool fresh_data = false;
00038 
00039 // lights for debugging
00040 // Replacing with SimpleIOMacros.h because each toggle takes ~300 ns (!!)
00041 DigitalOut led1(LED1), // blinking: wait for run command. solid: ready
00042            led2(LED2), // in function get_data()
00043            led3(LED3), // toggles when IIR filter is run
00044            led4(LED4); // toggles on fresh data
00045 // Counts how many times we toggled the LED
00046 uint32_t led1num, led2num, led3num, led4num;
00047 Ticker* led1ticks[2];
00048 
00049 int i_timestamps[NUM_CHANNELS];
00050 
00051 // For saving received data to disk
00052 LocalFileSystem local("local");
00053 bool log_data_enabled = true;
00054 
00055 // Call this function to reset the mbed
00056 extern "C" void mbed_reset();
00057 
00058 int main()
00059 {
00060     pre_setup(); // For safety, this must be the first thing that runs
00061     
00062     /*for (int i = 0; i < sizeof(parsed)/sizeof(uint16_t); i++)
00063     {
00064         *(((int16_t*)parsed) + i) = 12345;
00065     }*/
00066     
00067     wait(5);
00068     
00069     led1ticks[0] = new Ticker();
00070     led1ticks[1] = new Ticker();
00071     
00072     led1 = 1;
00073     led1ticks[0]->attach(&led1_cb, 1.0);
00074     wait_ms(60);
00075     led1ticks[1]->attach(&led1_cb, 1.0);
00076     led1 = 0;
00077     
00078     submarine.baud(115200);
00079     submarine.putc('h');
00080     submarine.printf("%d ", sizeof(q15_t));
00081     
00082     // Wait until we are told to turn on
00083     //while (submarine.getc() != 'r');
00084     
00085     submarine.attach(&submarine_cb);
00086     led1ticks[0]->detach();
00087     led1ticks[1]->detach();
00088     
00089     setup();
00090     
00091     while (true)
00092     {
00093         if (fresh_data)
00094         {
00095             fresh_data = false;
00096             
00097             LED4_TOGGLE;
00098             
00099             if (log_data_enabled /*&& read_blocks > 3*/)
00100             {
00101                 // Disable DRDY interrupt to prevent the buffer from changing
00102                 // while we save it. Writing to disk takes a long time.
00103 //                drdy.rise(NULL);
00104                 // Only log data once
00105                 log_data_enabled = false;
00106                 
00107                 FILE *fp = fopen("/local/out.csv", "w");
00108                 
00109                 fprintf(fp, "Index,Ch1,Ch2,Ch3,Ch4\n");
00110                 for (int i = 0; i < BLOCK_SIZE; i++)
00111                 {
00112                     fprintf(fp, "%d", i);
00113                     for (int j = 0; j < NUM_CHANNELS; j++)
00114                     {
00115                         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]);
00116                         //int16_t n = parsed[write_block^1][j][i];
00117                         //fprintf(fp, ",%X", n);
00118                     }
00119                     fprintf(fp, "\n");
00120                 }
00121                 
00122                 fclose(fp);
00123                 
00124               //  drdy.rise(&get_data);
00125             }
00126             
00127             /*for (char i = 0; i < NUM_CHANNELS; i++)
00128             {
00129                 arm_iir_lattice_q15(iir_filter+i, parsed[write_block^1][i], filtered, BLOCK_SIZE);
00130                 i_timestamps[i] = find_timestamp_tdoa(filtered);
00131             }*/
00132             // hyperbolic positioning
00133             // send it to the sub
00134         }
00135     }
00136 }
00137 
00138 void pre_setup()
00139 {
00140     
00141 }
00142 
00143 int setup()
00144 {
00145     int retValue = 0;
00146     retValue += setup_ads1274();
00147     retValue += setup_dma();
00148     
00149     led1 = 1;   // Debug
00150     
00151     // Should be at the end of setup function, in case ADS1274 tries to send data
00152     //drdy.rise(&get_data);
00153     event_irq_init();
00154     
00155     return retValue;
00156 }
00157 
00158 // Return values
00159 // 0: setup finished normally
00160 // 1: setup aborted because battery voltage was too low
00161 int setup_ads1274()
00162 {
00163     // Don't start up if the battery is too low
00164     abat_cb();
00165     abat_tick.attach(&abat_cb, 1);
00166     
00167     // Sequence the power-on of the ADC
00168     iovdd = 1;
00169     __nop();
00170     avdd_ctl = 1;
00171     // Give it some time, just in case.
00172     wait_ms(5);
00173     // Now we can start driving pins without destroying the ADS1274
00174     // Turn on sampling clock (CLK)
00175     clkvdd = 1;
00176     
00177     // ADS1274 needs 2^18 clk cycles + 129 conversions before data are valid
00178     // minimum wait time = 2^18 / f_clk + 129 / f_data = 2^18/27MHz + 129/0.1MHz = 11 ms
00179     wait_ms(11 + 1);
00180     
00181     // Datasheet suggested resetting the ads1274 after start up to synchronize outputs
00182     // Need to put it low for at least 1 CLK period
00183     // On mbed, this is 96 MHz/27MHz = 3.556 instruction cycles
00184     sync = 1;
00185     // Drive *sync to logic low for about 4 instruction cycles
00186     sync = 0;
00187     __nop(); __nop(); __nop(); __nop(); // wait 4 cycles
00188     sync = 1;
00189     // Wait 1/f_data = 1/0.1MHz = 10 us for new data to be valid
00190     wait_us(10 + 1);
00191     
00192     return 0; // success
00193 }
00194 
00195 void teardown()
00196 {
00197     // Disable interrupts. Not sure if this is necessary, but I don't want samples to be read while we shut down
00198     __disable_irq();
00199     
00200     teardown_ads1274();
00201     teardown_dma();
00202 }
00203 
00204 void teardown_ads1274()
00205 {
00206     // Turn off peripherals, then turn off ADS1274
00207     // Turn off CLK
00208     clkvdd = 0;
00209     __nop(); __nop();
00210     // Turn off op amps and analog power to ADS1274
00211     avdd_ctl = 0;
00212     // Turn off IO power
00213     iovdd = 0;
00214 }
00215 
00216 // Called when the submarine sends a message to us
00217 void submarine_cb()
00218 {
00219     // Loop as long as there are more characters to be read
00220     while (submarine.readable())
00221     {
00222         // If we are told to stop
00223         if (submarine.getc() == 's')
00224         {
00225             // Shut everything down
00226             teardown();
00227             // Reset the mbed
00228             mbed_reset();
00229         }
00230     }
00231 }
00232 
00233 // Called every few seconds to check the battery status
00234 void abat_cb()
00235 {
00236     if (abat_sense < ABAT_THRESH_LO)
00237     {
00238         // Uh oh, stop the hydrophone board
00239         teardown();
00240         
00241         submarine.putc('b');
00242         led1 = led2 = led3 = led4 = 0;
00243         
00244         // Wait until someone changes the battery
00245         int num_hi = 0, loop_count = 0;;
00246         while (num_hi < 100)
00247         {
00248             if (abat_sense > ABAT_THRESH_HI)
00249             {
00250                 num_hi++;
00251             }
00252             else if (num_hi > 0)
00253             {
00254                 num_hi--;
00255             }
00256             
00257             if (loop_count == 32000)
00258             {
00259                 led1 = led2 = led3 = led4 = !led1;
00260                 loop_count = 0;
00261             }
00262             else
00263             {
00264                 loop_count++;
00265             }
00266         }
00267         
00268         // On battery replacement, wait for the user to plug the battery in all the way
00269         wait_ms(3000);
00270         
00271         mbed_reset();
00272     }
00273 }
00274 
00275 void led1_cb()
00276 {
00277     led1 = !led1;
00278 }