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
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 }
Generated on Tue Jul 12 2022 21:48:58 by 1.7.2