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.
main.cpp
- Committer:
- biomurph
- Date:
- 2015-03-23
- Revision:
- 0:675506e540be
File content as of revision 0:675506e540be:
#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;
}