Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: main.cpp
- Revision:
- 0:675506e540be
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp Mon Mar 23 19:22:04 2015 +0000
@@ -0,0 +1,351 @@
+
+#include "mbed.h"
+#include "ADS1299.h"
+
+Serial pc(USBTX, USBRX); // set up the COM
+SPI spi (PTD2,PTD3,PTD1); // mosi, miso, sck
+
+
+//define how I'd like my channels setup
+#define MAX_N_CHANNELS (8) //must be less than or equal to length of channelData in ADS1299 object!!
+int nActiveChannels = 8; //how many active channels would I like?
+byte gainCode = ADS_GAIN24; //how much gain do I want
+byte inputType = ADSINPUT_NORMAL; //here's the normal way to setup the channels
+//byte inputType = ADSINPUT_SHORTED; //here's another way to setup the channels
+//byte inputType = ADSINPUT_TESTSIG; //here's a third way to setup the channels
+
+//other variables
+long sampleCounter = 0; // used to time the tesing loop
+boolean is_running = false; // this flag is set in serialEvent on reciept of prompt
+#define PIN_STARTBINARY (7) //pull this pin to ground to start binary transfer
+//define PIN_STARTBINARY_OPENEEG (6)
+boolean startBecauseOfPin = false;
+boolean startBecauseOfSerial = false;
+
+#define OUTPUT_NOTHING (0)
+#define OUTPUT_TEXT (1)
+#define OUTPUT_BINARY (2)
+#define OUTPUT_BINARY_4CHAN (4)
+#define OUTPUT_BINARY_OPENEEG (6)
+#define OUTPUT_BINARY_OPENEEG_SYNTHETIC (7)
+int outputType;
+
+//Design filters (This BIQUAD class requires ~6K of program space! Ouch.)
+//For frequency response of these filters: http://www.earlevel.com/main/2010/12/20/biquad-calculator/
+#include <Biquad_multiChan.h> //modified from this source code: http://www.earlevel.com/main/2012/11/26/biquad-c-source-code/
+#define SAMPLE_RATE_HZ (250.0) //default setting for OpenBCI
+#define FILTER_Q (0.5) //critically damped is 0.707 (Butterworth)
+#define FILTER_PEAK_GAIN_DB (0.0) //we don't want any gain in the passband
+#define HP_CUTOFF_HZ (0.5) //set the desired cutoff for the highpass filter
+Biquad_multiChan stopDC_filter(MAX_N_CHANNELS,bq_type_highpass,HP_CUTOFF_HZ / SAMPLE_RATE_HZ, FILTER_Q, FILTER_PEAK_GAIN_DB); //one for each channel because the object maintains the filter states
+//Biquad_multiChan stopDC_filter(MAX_N_CHANNELS,bq_type_bandpass,10.0 / SAMPLE_RATE_HZ, 6.0, FILTER_PEAK_GAIN_DB); //one for each channel because the object maintains the filter states
+#define NOTCH_FREQ_HZ (60.0)
+#define NOTCH_Q (4.0) //pretty shap notch
+#define NOTCH_PEAK_GAIN_DB (0.0) //doesn't matter for this filter type
+Biquad_multiChan notch_filter1(MAX_N_CHANNELS,bq_type_notch,NOTCH_FREQ_HZ / SAMPLE_RATE_HZ, NOTCH_Q, NOTCH_PEAK_GAIN_DB); //one for each channel because the object maintains the filter states
+Biquad_multiChan notch_filter2(MAX_N_CHANNELS,bq_type_notch,NOTCH_FREQ_HZ / SAMPLE_RATE_HZ, NOTCH_Q, NOTCH_PEAK_GAIN_DB); //one for each channel because the object maintains the filter states
+boolean useFilters = false;
+
+
+
+DigitalOut CS (PTD0); // arduino pin 10 - chip select
+DigitalOut RST(PTD5); // arduino pin 9 - reset pin
+DigitalIn DRDY(PTA13); // arduino pin 8 - data ready pin
+DigitalOut myled(LED3); // debugging LED CONFLICT WITH SPI & LED1
+
+
+
+int main() {
+
+ ADS1299Manager ADSManager;
+ int OpenBCI_version = OPENBCI_V2; //assume V2
+ ADSManager.initialize(OpenBCI_version); //must do this VERY early in the setup...preferably first
+
+ spi.format(8,1); // spi: 8 bit, mode 1
+ spi.frequency(1000000); // spi sck frequency
+
+ pc.baud(115200);
+ pc.printf("\nADS1299 Stream Raw Data\n");
+ wait(2.0);
+
+ pc.printf("ADS1299-Arduino UNO - Stream Raw Data"); //read the string from Flash to save RAM
+ pc.printf("Configured as OpenBCI_Version code = ");pc.printf(OpenBCI_version);
+ Serial.flush();
+
+ // setup the channels as desired on the ADS1299..set gain, input type, referece (SRB1), and patient bias signal
+ for (int chan=1; chan <= nActiveChannels; chan++) {
+ ADSManager.activateChannel(chan, gainCode, inputType);
+ }
+
+ //print state of all registers
+ ADSManager.printAllRegisters();Serial.flush();
+
+ // setup hardware to allow a jumper or button to start the digitaltransfer
+ pinMode(PIN_STARTBINARY,INPUT); digitalWrite(PIN_STARTBINARY,HIGH); //activate pullup
+ //pinMode(PIN_STARTBINARY_OPENEEG,INPUT); digitalWrite(PIN_STARTBINARY_OPENEEG,HIGH); //activate pullup
+
+ // tell the controlling program that we're ready to start!
+ pc.printf("Press '?' to query and print ADS1299 register settings again"); //read it straight from flash
+ pc.printf("Press 1-8 to disable EEG Channels, q-i to enable (all enabled by default)");
+ pc.printf("Press 'F' to enable filters. 'f' to disable filters (disabled by default)");
+ pc.printf("Press 'x' (text) or 'b' (binary) to begin streaming data...");
+
+boolean firstReport = true;
+unsigned long totalMicrosBusy = 0; //use this to count time
+
+ while(1) {
+
+ if (is_running) {
+
+ //is data ready?
+ while(!(ADSManager.isDataAvailable())){ // watch the DRDY pin
+ delayMicroseconds(100);
+ }
+ unsigned long start_micros = micros();
+
+ //get the data
+ ADSManager.updateChannelData(); // update the channelData array
+ sampleCounter++; // increment my sample counter
+
+ //Apply filers to the data
+ if (useFilters) applyFilters();
+
+ //print the data
+ //if ((sampleCounter % 1) == 0) {
+ switch (outputType) {
+ case OUTPUT_NOTHING:
+ //don't output anything...the Arduino is still collecting data from the OpenBCI board...just nothing is being done with it
+ break;
+ case OUTPUT_BINARY:
+ ADSManager.writeChannelDataAsBinary(8,sampleCounter); //print all channels, whether active or not
+ break;
+ case OUTPUT_BINARY_4CHAN:
+ ADSManager.writeChannelDataAsBinary(4,sampleCounter); //print all channels, whether active or not
+ break;
+ case OUTPUT_BINARY_OPENEEG:
+ ADSManager.writeChannelDataAsOpenEEG_P2(sampleCounter); //print all channels, whether active or not
+ break;
+ case OUTPUT_BINARY_OPENEEG_SYNTHETIC:
+ ADSManager.writeChannelDataAsOpenEEG_P2(sampleCounter,true); //print all channels, whether active or not
+ break;
+ default:
+ ADSManager.printChannelDataAsText(8,sampleCounter); //print all channels, whether active or not
+ }// end of if(is_running)
+ }// end of while(1)
+
+ if(pc.readable()) {
+ serialEvent();
+ }
+
+}// end of main()
+
+
+#define ACTIVATE_SHORTED (2)
+#define ACTIVATE (1)
+#define DEACTIVATE (0)
+void serialEvent(){ //
+ char inChar = pc.getc();
+ switch (inChar)
+ {
+ case '1':
+ changeChannelState_maintainRunningState(1,DEACTIVATE); break;
+ case '2':
+ changeChannelState_maintainRunningState(2,DEACTIVATE); break;
+ case '3':
+ changeChannelState_maintainRunningState(3,DEACTIVATE); break;
+ case '4':
+ changeChannelState_maintainRunningState(4,DEACTIVATE); break;
+ case '5':
+ changeChannelState_maintainRunningState(5,DEACTIVATE); break;
+ case '6':
+ changeChannelState_maintainRunningState(6,DEACTIVATE); break;
+ case '7':
+ changeChannelState_maintainRunningState(7,DEACTIVATE); break;
+ case '8':
+ changeChannelState_maintainRunningState(8,DEACTIVATE); break;
+ case 'q':
+ changeChannelState_maintainRunningState(1,ACTIVATE); break;
+ case 'w':
+ changeChannelState_maintainRunningState(2,ACTIVATE); break;
+ case 'e':
+ changeChannelState_maintainRunningState(3,ACTIVATE); break;
+ case 'r':
+ changeChannelState_maintainRunningState(4,ACTIVATE); break;
+ case 't':
+ changeChannelState_maintainRunningState(5,ACTIVATE); break;
+ case 'y':
+ changeChannelState_maintainRunningState(6,ACTIVATE); break;
+ case 'u':
+ changeChannelState_maintainRunningState(7,ACTIVATE); break;
+ case 'i':
+ changeChannelState_maintainRunningState(8,ACTIVATE); break;
+ case '0':
+ activateAllChannelsToTestCondition(ADSINPUT_SHORTED,ADSTESTSIG_NOCHANGE,ADSTESTSIG_NOCHANGE); break;
+ case '-':
+ activateAllChannelsToTestCondition(ADSINPUT_TESTSIG,ADSTESTSIG_AMP_1X,ADSTESTSIG_PULSE_SLOW); break;
+ case '+':
+ activateAllChannelsToTestCondition(ADSINPUT_TESTSIG,ADSTESTSIG_AMP_1X,ADSTESTSIG_PULSE_FAST); break;
+ case '=':
+ //repeat the line above...just for human convenience
+ activateAllChannelsToTestCondition(ADSINPUT_TESTSIG,ADSTESTSIG_AMP_1X,ADSTESTSIG_PULSE_FAST); break;
+ case 'p':
+ activateAllChannelsToTestCondition(ADSINPUT_TESTSIG,ADSTESTSIG_AMP_2X,ADSTESTSIG_DCSIG); break;
+ case '[':
+ activateAllChannelsToTestCondition(ADSINPUT_TESTSIG,ADSTESTSIG_AMP_2X,ADSTESTSIG_PULSE_SLOW); break;
+ case ']':
+ activateAllChannelsToTestCondition(ADSINPUT_TESTSIG,ADSTESTSIG_AMP_2X,ADSTESTSIG_PULSE_FAST); break;
+ case 'n':
+ toggleRunState(OUTPUT_NOTHING);
+ startBecauseOfSerial = is_running;
+ if (is_running) Serial.println(F("FRDM: Starting, but not outputing to PC..."));
+ break;
+ case 'b':
+ toggleRunState(OUTPUT_BINARY);
+ startBecauseOfSerial = is_running;
+ if (is_running) Serial.println(F("FRDM: Starting binary..."));
+ break;
+ case 'v':
+ toggleRunState(OUTPUT_BINARY_4CHAN);
+ startBecauseOfSerial = is_running;
+ if (is_running) Serial.println(F("FRDM: Starting binary 4-chan..."));
+ break;
+ case 's':
+ stopRunning();
+ startBecauseOfSerial = is_running;
+ break;
+ case 'x':
+ toggleRunState(OUTPUT_TEXT);
+ startBecauseOfSerial = is_running;
+ if (is_running) Serial.println(F("FRDM: Starting text..."));
+ break;
+ case 'f':
+ useFilters = false;
+ Serial.println(F("FRDM: disabling filters"));
+ break;
+ case 'F':
+ useFilters = true;
+ Serial.println(F("FRDM: enabaling filters"));
+ break;
+ case '?':
+ //print state of all registers
+ ADSManager.printAllRegisters();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+boolean toggleRunState(int OUT_TYPE)
+{
+ if (is_running) {
+ return stopRunning();
+ } else {
+ return startRunning(OUT_TYPE);
+ }
+}
+
+boolean stopRunning(void) {
+ ADSManager.stop(); // stop the data acquisition
+ is_running = false;
+ return is_running;
+}
+
+boolean startRunning(int OUT_TYPE) {
+ outputType = OUT_TYPE;
+ ADSManager.start(); //start the data acquisition
+ is_running = true;
+ return is_running;
+}
+
+int changeChannelState_maintainRunningState(int chan, int start)
+{
+ boolean is_running_when_called = is_running;
+ int cur_outputType = outputType;
+
+ //must stop running to change channel settings
+ stopRunning();
+ if (start == true) {
+ Serial.print("Activating channel ");
+ Serial.println(chan);
+ ADSManager.activateChannel(chan,gainCode,inputType);
+ } else {
+ Serial.print("Deactivating channel ");
+ Serial.println(chan);
+ ADSManager.deactivateChannel(chan);
+ }
+
+ //restart, if it was running before
+ if (is_running_when_called == true) {
+ startRunning(cur_outputType);
+ }
+}
+
+int activateAllChannelsToTestCondition(int testInputCode, byte amplitudeCode, byte freqCode)
+{
+ boolean is_running_when_called = is_running;
+ int cur_outputType = outputType;
+
+ //set the test signal to the desired state
+ ADSManager.configureInternalTestSignal(amplitudeCode,freqCode);
+
+ //must stop running to change channel settings
+ stopRunning();
+
+ //loop over all channels to change their state
+ for (int Ichan=1; Ichan <= 8; Ichan++) {
+ ADSManager.activateChannel(Ichan,gainCode,testInputCode); //Ichan must be [1 8]...it does not start counting from zero
+ }
+
+ //restart, if it was running before
+ if (is_running_when_called == true) {
+ startRunning(cur_outputType);
+ }
+}
+
+long int runningAve[MAX_N_CHANNELS];
+int applyFilters(void) {
+ //scale factor for these coefficients was 32768 = 2^15
+ const static long int a0 = 32360L; //16 bit shift?
+ const static long int a1 = -2L*a0;
+ const static long int a2 = a0;
+ const static long int b1 = -64718L; //this is a shift of 17 bits!
+ const static long int b2 = 31955L;
+ static long int z1[MAX_N_CHANNELS], z2[MAX_N_CHANNELS];
+ long int val_int, val_in_down9, val_out, val_out_down9;
+ float val;
+ for (int Ichan=0; Ichan < MAX_N_CHANNELS; Ichan++) {
+ switch (1) {
+ case 1:
+ //use BiQuad
+ val = (float) ADSManager.channelData[Ichan]; //get the stored value for this sample
+ val = stopDC_filter.process(val,Ichan); //apply DC-blocking filter
+ break;
+ case 2:
+ //do fixed point, 1st order running ave
+ val_int = ADSManager.channelData[Ichan]; //get the stored value for this sample
+ //runningAve[Ichan]=( ((512-1)*(runningAve[Ichan]>>2)) + (val_int>>2) )>>7; // fs/0.5Hz = ~512 points..9 bits
+ //runningAve[Ichan]=( ((256-1)*(runningAve[Ichan]>>2)) + (val_int>>2) )>>6; // fs/1.0Hz = ~256 points...8 bits
+ runningAve[Ichan]=( ((128-1)*(runningAve[Ichan]>>1)) + (val_int>>1) )>>6; // fs/2.0Hz = ~128 points...7 bits
+ val = (float)(val_int - runningAve[Ichan]); //remove the DC
+ break;
+// case 3:
+// val_in_down9 = ADSManager.channelData[Ichan] >> 9; //get the stored value for this sample...bring 24-bit value down to 16-bit
+// val_out = (val_in_down9 * a0 + (z1[Ichan]>>9)) >> (16-9); //8bits were already removed...results in 24-bit value
+// val_out_down9 = val_out >> 9; //remove eight bits to go from 24-bit down to 16 bit
+// z1[Ichan] = (val_in_down9 * a1 + (z2[Ichan] >> 9) - b1 * val_out_down9 ) >> (16-9); //8-bits were pre-removed..end in 24 bit number
+// z2[Ichan] = (val_in_down9 * a2 - b2 * val_out_down9) >> (16-9); //8-bits were pre-removed...end in 24-bit number
+// val = (float)val_out;
+// break;
+ }
+ val = notch_filter1.process(val,Ichan); //apply 60Hz notch filter
+ val = notch_filter2.process(val,Ichan); //apply it again
+ ADSManager.channelData[Ichan] = (long) val; //save the value back into the main data-holding object
+ }
+ return 0;
+}
+
+
+
+
+