Joel Murphy / Mbed 2 deprecated ADS_StreamRawData

Dependencies:   mbed

Committer:
biomurph
Date:
Mon Mar 23 19:22:04 2015 +0000
Revision:
0:675506e540be
Publishing this old ADS1299 code for the first time!

Who changed what in which revision?

UserRevisionLine numberNew contents of line
biomurph 0:675506e540be 1
biomurph 0:675506e540be 2
biomurph 0:675506e540be 3
biomurph 0:675506e540be 4 #include <ADS1299Manager.h>
biomurph 0:675506e540be 5
biomurph 0:675506e540be 6 typedef long int32;
biomurph 0:675506e540be 7 //typedef byte uint8_t;
biomurph 0:675506e540be 8
biomurph 0:675506e540be 9
biomurph 0:675506e540be 10 void ADS1299Manager::initialize(void) {
biomurph 0:675506e540be 11 initialize(OPENBCI_V2);
biomurph 0:675506e540be 12 }
biomurph 0:675506e540be 13
biomurph 0:675506e540be 14 //Initilize the ADS1299 controller...call this once
biomurph 0:675506e540be 15 void ADS1299Manager::initialize(const int version)
biomurph 0:675506e540be 16 {
biomurph 0:675506e540be 17 setVersionOpenBCI(version);
biomurph 0:675506e540be 18 ADS1299::initialize(PIN_DRDY,PIN_RST,PIN_CS,SCK_MHZ); // (DRDY pin, RST pin, CS pin, SCK frequency in MHz);
biomurph 0:675506e540be 19 delay(100);
biomurph 0:675506e540be 20
biomurph 0:675506e540be 21 verbose = false; // when verbose is true, there will be Serial feedback
biomurph 0:675506e540be 22 reset();
biomurph 0:675506e540be 23
biomurph 0:675506e540be 24 //set default state for internal test signal
biomurph 0:675506e540be 25 //ADS1299::WREG(CONFIG2,0b11010000);delay(1); //set internal test signal, default amplitude, default speed, datasheet PDF Page 41
biomurph 0:675506e540be 26 //ADS1299::WREG(CONFIG2,0b11010001);delay(1); //set internal test signal, default amplitude, 2x speed, datasheet PDF Page 41
biomurph 0:675506e540be 27 configureInternalTestSignal(ADSTESTSIG_AMP_1X,ADSTESTSIG_PULSE_FAST); //set internal test signal, default amplitude, 2x speed, datasheet PDF Page 41
biomurph 0:675506e540be 28
biomurph 0:675506e540be 29 };
biomurph 0:675506e540be 30
biomurph 0:675506e540be 31 void ADS1299Manager::setVersionOpenBCI(const int version)
biomurph 0:675506e540be 32 {
biomurph 0:675506e540be 33 if (version == OPENBCI_V1) {
biomurph 0:675506e540be 34 use_neg_inputs = false;
biomurph 0:675506e540be 35 for (int i=0; i < OPENBCI_NCHAN; i++) {
biomurph 0:675506e540be 36 use_SRB2[i] = false;
biomurph 0:675506e540be 37 }
biomurph 0:675506e540be 38 } else {
biomurph 0:675506e540be 39 use_neg_inputs = true;
biomurph 0:675506e540be 40 for (int i=0; i < OPENBCI_NCHAN; i++) {
biomurph 0:675506e540be 41 use_SRB2[i] = true;
biomurph 0:675506e540be 42 }
biomurph 0:675506e540be 43 }
biomurph 0:675506e540be 44 //setSRB1(use_SRB1()); //set whether SRB1 is active or not
biomurph 0:675506e540be 45 }
biomurph 0:675506e540be 46
biomurph 0:675506e540be 47 //reset all the ADS1299's settings. Call however you'd like. Stops all data acquisition
biomurph 0:675506e540be 48 void ADS1299Manager::reset(void)
biomurph 0:675506e540be 49 {
biomurph 0:675506e540be 50 ADS1299::RESET(); // send RESET command to default all registers
biomurph 0:675506e540be 51 ADS1299::SDATAC(); // exit Read Data Continuous mode to communicate with ADS
biomurph 0:675506e540be 52
biomurph 0:675506e540be 53 delay(100);
biomurph 0:675506e540be 54
biomurph 0:675506e540be 55 // turn off all channels
biomurph 0:675506e540be 56 for (int chan=1; chan <= 8; chan++) {
biomurph 0:675506e540be 57 deactivateChannel(chan);
biomurph 0:675506e540be 58 }
biomurph 0:675506e540be 59
biomurph 0:675506e540be 60 setSRB1(use_SRB1()); //set whether SRB1 is active or not
biomurph 0:675506e540be 61
biomurph 0:675506e540be 62 };
biomurph 0:675506e540be 63
biomurph 0:675506e540be 64
biomurph 0:675506e540be 65 //deactivate the given channel...note: stops data colleciton to issue its commands
biomurph 0:675506e540be 66 // N is the channel number: 1-8
biomurph 0:675506e540be 67 //
biomurph 0:675506e540be 68 void ADS1299Manager::deactivateChannel(int N)
biomurph 0:675506e540be 69 {
biomurph 0:675506e540be 70 byte reg, config;
biomurph 0:675506e540be 71
biomurph 0:675506e540be 72 //check the inputs
biomurph 0:675506e540be 73 if ((N < 1) || (N > 8)) return;
biomurph 0:675506e540be 74
biomurph 0:675506e540be 75 //proceed...first, disable any data collection
biomurph 0:675506e540be 76 ADS1299::SDATAC(); delay(1); // exit Read Data Continuous mode to communicate with ADS
biomurph 0:675506e540be 77
biomurph 0:675506e540be 78 //shut down the channel
biomurph 0:675506e540be 79 N = constrain(N-1,0,7); //subtracts 1 so that we're counting from 0, not 1
biomurph 0:675506e540be 80 reg = CH1SET+(byte)N;
biomurph 0:675506e540be 81 config = ADS1299::RREG(reg); delay(1);
biomurph 0:675506e540be 82 bitSet(config,7); //left-most bit (bit 7) = 1, so this shuts down the channel
biomurph 0:675506e540be 83 if (use_neg_inputs) bitClear(config,3); //bit 3 = 0 disconnects SRB2
biomurph 0:675506e540be 84 ADS1299::WREG(reg,config); delay(1);
biomurph 0:675506e540be 85
biomurph 0:675506e540be 86 //remove the channel from the bias generation...
biomurph 0:675506e540be 87 reg = BIAS_SENSP; if (use_neg_inputs) reg = BIAS_SENSN; //are we using the P inptus or the N inputs?
biomurph 0:675506e540be 88 config = ADS1299::RREG(reg); delay(1);//get the current bias settings
biomurph 0:675506e540be 89 bitClear(config,N); //clear this channel's bit to remove from bias generation
biomurph 0:675506e540be 90 ADS1299::WREG(reg,config); delay(1); //send the modified byte back to the ADS
biomurph 0:675506e540be 91
biomurph 0:675506e540be 92 };
biomurph 0:675506e540be 93
biomurph 0:675506e540be 94
biomurph 0:675506e540be 95 //Active a channel in single-ended mode
biomurph 0:675506e540be 96 // N is 1 through 8
biomurph 0:675506e540be 97 // gainCode is defined in the macros in the header file
biomurph 0:675506e540be 98 // inputCode is defined in the macros in the header file
biomurph 0:675506e540be 99 void ADS1299Manager::activateChannel(int N,byte gainCode,byte inputCode)
biomurph 0:675506e540be 100 {
biomurph 0:675506e540be 101 //check the inputs
biomurph 0:675506e540be 102 if ((N < 1) || (N > 8)) return;
biomurph 0:675506e540be 103
biomurph 0:675506e540be 104 //proceed...first, disable any data collection
biomurph 0:675506e540be 105 ADS1299::SDATAC(); delay(1); // exit Read Data Continuous mode to communicate with ADS
biomurph 0:675506e540be 106
biomurph 0:675506e540be 107 //active the channel using the given gain. Set MUX for normal operation
biomurph 0:675506e540be 108 //see ADS1299 datasheet, PDF p44
biomurph 0:675506e540be 109 N = constrain(N-1,0,7); //shift down by one
biomurph 0:675506e540be 110 byte configByte = 0b00000000; //left-most zero (bit 7) is to activate the channel
biomurph 0:675506e540be 111 gainCode = gainCode & 0b01110000; //bitwise AND to get just the bits we want and set the rest to zero
biomurph 0:675506e540be 112 configByte = configByte | gainCode; //bitwise OR to set just the gain bits high or low and leave the rest alone
biomurph 0:675506e540be 113 inputCode = inputCode & 0b00000111; //bitwise AND to get just the bits we want and set the rest to zero
biomurph 0:675506e540be 114 configByte = configByte | inputCode; //bitwise OR to set just the gain bits high or low and leave the rest alone
biomurph 0:675506e540be 115 if (use_SRB2[N]) configByte |= 0b00001000; //set the SRB2 flag...p44 in the data sheet
biomurph 0:675506e540be 116 ADS1299::WREG(CH1SET+(byte)N,configByte); delay(1);
biomurph 0:675506e540be 117
biomurph 0:675506e540be 118 //add this channel to the bias generation
biomurph 0:675506e540be 119 //see ADS1299 datasheet, PDF p44
biomurph 0:675506e540be 120 byte reg = BIAS_SENSP; if (use_neg_inputs) reg = BIAS_SENSN; //are we using the P inptus or the N inputs?
biomurph 0:675506e540be 121 byte biasSettings = ADS1299::RREG(reg); //get the current bias settings
biomurph 0:675506e540be 122 bitSet(biasSettings,N); //set this channel's bit
biomurph 0:675506e540be 123 ADS1299::WREG(reg,biasSettings); delay(1); //send the modified byte back to the ADS
biomurph 0:675506e540be 124
biomurph 0:675506e540be 125 // // Now, these actions are necessary whenever there is at least one active channel
biomurph 0:675506e540be 126 // // though they don't strictly need to be done EVERY time we activate a channel.
biomurph 0:675506e540be 127 // // just once after the reset.
biomurph 0:675506e540be 128
biomurph 0:675506e540be 129 //activate SRB1 as the Negative input for all channels, if needed
biomurph 0:675506e540be 130 setSRB1(use_SRB1());
biomurph 0:675506e540be 131
biomurph 0:675506e540be 132 //Finalize the bias setup...activate buffer and use internal reference for center of bias creation, datasheet PDF p42
biomurph 0:675506e540be 133 ADS1299::WREG(CONFIG3,0b11101100); delay(1);
biomurph 0:675506e540be 134 };
biomurph 0:675506e540be 135
biomurph 0:675506e540be 136 void ADS1299Manager::setSRB1(boolean desired_state) {
biomurph 0:675506e540be 137 if (desired_state) {
biomurph 0:675506e540be 138 ADS1299::WREG(MISC1,0b00100000); delay(1); //ADS1299 datasheet, PDF p46
biomurph 0:675506e540be 139 } else {
biomurph 0:675506e540be 140 ADS1299::WREG(MISC1,0b00000000); delay(1); //ADS1299 datasheet, PDF p46
biomurph 0:675506e540be 141 }
biomurph 0:675506e540be 142 }
biomurph 0:675506e540be 143
biomurph 0:675506e540be 144
biomurph 0:675506e540be 145 //Configure the test signals that can be inernally generated by the ADS1299
biomurph 0:675506e540be 146 void ADS1299Manager::configureInternalTestSignal(byte amplitudeCode, byte freqCode)
biomurph 0:675506e540be 147 {
biomurph 0:675506e540be 148 if (amplitudeCode == ADSTESTSIG_NOCHANGE) amplitudeCode = (ADS1299::RREG(CONFIG2) & (0b00000100));
biomurph 0:675506e540be 149 if (freqCode == ADSTESTSIG_NOCHANGE) freqCode = (ADS1299::RREG(CONFIG2) & (0b00000011));
biomurph 0:675506e540be 150 freqCode &= 0b00000011; //only the last two bits should be used
biomurph 0:675506e540be 151 amplitudeCode &= 0b00000100; //only this bit should be used
biomurph 0:675506e540be 152 byte message = 0b11010000 | freqCode | amplitudeCode; //compose the code
biomurph 0:675506e540be 153
biomurph 0:675506e540be 154 ADS1299::WREG(CONFIG2,message); delay(1);
biomurph 0:675506e540be 155
biomurph 0:675506e540be 156 //ADS1299::WREG(CONFIG2,0b11010000);delay(1); //set internal test signal, default amplitude, default speed, datasheet PDF Page 41
biomurph 0:675506e540be 157 //ADS1299::WREG(CONFIG2,0b11010001);delay(1); //set internal test signal, default amplitude, 2x speed, datasheet PDF Page 41
biomurph 0:675506e540be 158 //ADS1299::WREG(CONFIG2,0b11010101);delay(1); //set internal test signal, 2x amplitude, 2x speed, datasheet PDF Page 41
biomurph 0:675506e540be 159 //ADS1299::WREG(CONFIG2,0b11010011); delay(1); //set internal test signal, default amplitude, at DC, datasheet PDF Page 41
biomurph 0:675506e540be 160 //ADS1299::WREG(CONFIG3,0b01101100); delay(1); //use internal reference for center of bias creation, datasheet PDF p42
biomurph 0:675506e540be 161 }
biomurph 0:675506e540be 162
biomurph 0:675506e540be 163 //Start continuous data acquisition
biomurph 0:675506e540be 164 void ADS1299Manager::start(void)
biomurph 0:675506e540be 165 {
biomurph 0:675506e540be 166 ADS1299::RDATAC(); delay(1); // enter Read Data Continuous mode
biomurph 0:675506e540be 167 ADS1299::START(); //start the data acquisition
biomurph 0:675506e540be 168 }
biomurph 0:675506e540be 169
biomurph 0:675506e540be 170 //Query to see if data is available from the ADS1299...return TRUE is data is available
biomurph 0:675506e540be 171 int ADS1299Manager::isDataAvailable(void)
biomurph 0:675506e540be 172 {
biomurph 0:675506e540be 173 return (!(digitalRead(PIN_DRDY)));
biomurph 0:675506e540be 174 }
biomurph 0:675506e540be 175
biomurph 0:675506e540be 176 //Stop the continuous data acquisition
biomurph 0:675506e540be 177 void ADS1299Manager::stop(void)
biomurph 0:675506e540be 178 {
biomurph 0:675506e540be 179 ADS1299::STOP(); delay(1); //start the data acquisition
biomurph 0:675506e540be 180 ADS1299::SDATAC(); delay(1); // exit Read Data Continuous mode to communicate with ADS
biomurph 0:675506e540be 181 }
biomurph 0:675506e540be 182
biomurph 0:675506e540be 183 //print as text each channel's data
biomurph 0:675506e540be 184 // print channels 1-N (where N is 1-8...anything else will return with no action)
biomurph 0:675506e540be 185 // sampleNumber is a number that, if greater than zero, will be printed at the start of the line
biomurph 0:675506e540be 186 void ADS1299Manager::printChannelDataAsText(int N, long int sampleNumber)
biomurph 0:675506e540be 187 {
biomurph 0:675506e540be 188 //check the inputs
biomurph 0:675506e540be 189 if ((N < 1) || (N > 8)) return;
biomurph 0:675506e540be 190
biomurph 0:675506e540be 191 //print the sample number, if not disabled
biomurph 0:675506e540be 192 if (sampleNumber > 0) {
biomurph 0:675506e540be 193 pc.printf(sampleNumber);
biomurph 0:675506e540be 194 pc.printf(", ");
biomurph 0:675506e540be 195 }
biomurph 0:675506e540be 196
biomurph 0:675506e540be 197 //print each channel
biomurph 0:675506e540be 198 for (int chan = 0; chan < N; chan++ )
biomurph 0:675506e540be 199 {
biomurph 0:675506e540be 200 pc.printf(channelData[chan]);
biomurph 0:675506e540be 201 pc.printf(", ");
biomurph 0:675506e540be 202 }
biomurph 0:675506e540be 203
biomurph 0:675506e540be 204 //print end of line
biomurph 0:675506e540be 205 pc.printf("\n");
biomurph 0:675506e540be 206
biomurph 0:675506e540be 207 };
biomurph 0:675506e540be 208
biomurph 0:675506e540be 209
biomurph 0:675506e540be 210 //write as binary each channel's data
biomurph 0:675506e540be 211 // print channels 1-N (where N is 1-8...anything else will return with no action)
biomurph 0:675506e540be 212 // sampleNumber is a number that, if greater than zero, will be printed at the start of the line
biomurph 0:675506e540be 213 int32 val;
biomurph 0:675506e540be 214 byte *val_ptr = (byte *)(&val);
biomurph 0:675506e540be 215 void ADS1299Manager::writeChannelDataAsBinary(int N, long sampleNumber)
biomurph 0:675506e540be 216 {
biomurph 0:675506e540be 217 //check the inputs
biomurph 0:675506e540be 218 if ((N < 1) || (N > 8)) return;
biomurph 0:675506e540be 219
biomurph 0:675506e540be 220 // Write header
biomurph 0:675506e540be 221 pc.printf( (byte) PCKT_START);
biomurph 0:675506e540be 222 //byte byte_val = (1+8)*4;
biomurph 0:675506e540be 223 pc.printf((1+N)*4); //length of data payload, bytes
biomurph 0:675506e540be 224
biomurph 0:675506e540be 225
biomurph 0:675506e540be 226
biomurph 0:675506e540be 227 //print the sample number, if not disabled
biomurph 0:675506e540be 228 //val = sampleNumber;
biomurph 0:675506e540be 229 val = 1L;
biomurph 0:675506e540be 230 //ptr = (uint8_t *)(&val); //pretend that it is a string buffer so that Serial.write works easier
biomurph 0:675506e540be 231 //if (sampleNumber >= 0) {
biomurph 0:675506e540be 232 pc.printf(val_ptr,4); //4 bytes long
biomurph 0:675506e540be 233 //}
biomurph 0:675506e540be 234
biomurph 0:675506e540be 235 //print each channel
biomurph 0:675506e540be 236 for (int chan = 0; chan < N; chan++ )
biomurph 0:675506e540be 237 {
biomurph 0:675506e540be 238 val = (long)(channelData[chan]);
biomurph 0:675506e540be 239 pc.printf(val_ptr,4); //4 bytes long
biomurph 0:675506e540be 240 }
biomurph 0:675506e540be 241
biomurph 0:675506e540be 242 // Write footer
biomurph 0:675506e540be 243 pc.printf((byte)PCKT_END);
biomurph 0:675506e540be 244
biomurph 0:675506e540be 245 // force everything out
biomurph 0:675506e540be 246 //Serial.flush();
biomurph 0:675506e540be 247 };
biomurph 0:675506e540be 248
biomurph 0:675506e540be 249 //write channel data using binary format of ModularEEG so that it can be used by BrainBay (P2 protocol)
biomurph 0:675506e540be 250 //this only sends 6 channels of data, per the P2 protocol
biomurph 0:675506e540be 251 //http://www.shifz.org/brainbay/manuals/brainbay_developer_manual.pdf
biomurph 0:675506e540be 252 #define max_int16 (32767)
biomurph 0:675506e540be 253 #define min_int16 (-32767)
biomurph 0:675506e540be 254 void ADS1299Manager::writeChannelDataAsOpenEEG_P2(long sampleNumber) {
biomurph 0:675506e540be 255 ADS1299Manager::writeChannelDataAsOpenEEG_P2(sampleNumber,false);
biomurph 0:675506e540be 256 }
biomurph 0:675506e540be 257 #define synthetic_amplitude_counts (8950) //counts peak-to-peak...should be 100 uV pk-pk (100e-6 / (4.5 / 24 / 2^24))
biomurph 0:675506e540be 258 void ADS1299Manager::writeChannelDataAsOpenEEG_P2(long sampleNumber,boolean useSyntheticData) {
biomurph 0:675506e540be 259 byte sync0 = 0xA5;
biomurph 0:675506e540be 260 byte sync1 = 0x5A;
biomurph 0:675506e540be 261 byte version = 2;
biomurph 0:675506e540be 262
biomurph 0:675506e540be 263 pc.printf(sync0);
biomurph 0:675506e540be 264 pc.printf(sync1);
biomurph 0:675506e540be 265 pc.printf(version);
biomurph 0:675506e540be 266 pc.printf((byte) sampleNumber);
biomurph 0:675506e540be 267
biomurph 0:675506e540be 268 long val32; //32-bit
biomurph 0:675506e540be 269 int val_i16; //16-bit
biomurph 0:675506e540be 270 unsigned int val_u16; //16-bit
biomurph 0:675506e540be 271 byte *val16_ptr = (byte *)(&val_u16); //points to the memory for the variable above
biomurph 0:675506e540be 272 for (int chan = 0; chan < 6; chan++ )
biomurph 0:675506e540be 273 {
biomurph 0:675506e540be 274 //get this channel's data
biomurph 0:675506e540be 275 if (useSyntheticData) {
biomurph 0:675506e540be 276 //generate 10 uV pk-pk signal
biomurph 0:675506e540be 277 long time_samp_255 = (long)((sampleNumber) & (0x000000FF)); //make an 8-bit ramp waveform
biomurph 0:675506e540be 278 time_samp_255 = (long)((time_samp_255*(long)(chan+1)) & (0x000000FF)); //each channel is faster than the previous
biomurph 0:675506e540be 279 time_samp_255 += 256L*2L; //make zero mean...empirically tuned via BrainBay visualization
biomurph 0:675506e540be 280 val32 = (synthetic_amplitude_counts * time_samp_255) / 255L; //scaled zero-mean ramp
biomurph 0:675506e540be 281 } else {
biomurph 0:675506e540be 282 //get the real EEG data for this channel
biomurph 0:675506e540be 283 val32 = channelData[chan];
biomurph 0:675506e540be 284 }
biomurph 0:675506e540be 285
biomurph 0:675506e540be 286 //prepare the value for transmission
biomurph 0:675506e540be 287 val32 = val32 / (32); //shrink to fit within a 16-bit number
biomurph 0:675506e540be 288 val32 = constrain(val32,min_int16,max_int16); //constrain to fit in 16 bits
biomurph 0:675506e540be 289 val_u16 = (unsigned int) (val32 & (0x0000FFFF)); //truncate and cast
biomurph 0:675506e540be 290
biomurph 0:675506e540be 291 //pc.printf(val16_ptr,2); //low byte than high byte on Arduino
biomurph 0:675506e540be 292 pc.printf((byte)((val_u16 >> 8) & 0x00FF)); //high byte
biomurph 0:675506e540be 293 pc.printf((byte)(val_u16 & 0x00FF)); //low byte
biomurph 0:675506e540be 294
biomurph 0:675506e540be 295 }
biomurph 0:675506e540be 296 byte switches = 0b00000000; //the last thing required by the P2 data protocol
biomurph 0:675506e540be 297 pc.printf(switches);
biomurph 0:675506e540be 298 }
biomurph 0:675506e540be 299
biomurph 0:675506e540be 300
biomurph 0:675506e540be 301
biomurph 0:675506e540be 302 //print out the state of all the control registers
biomurph 0:675506e540be 303 void ADS1299Manager::printAllRegisters(void)
biomurph 0:675506e540be 304 {
biomurph 0:675506e540be 305 boolean prevVerboseState = verbose;
biomurph 0:675506e540be 306
biomurph 0:675506e540be 307 verbose = true;
biomurph 0:675506e540be 308 ADS1299::RREGS(0x00,0x10); // write the first registers
biomurph 0:675506e540be 309 delay(100); //stall to let all that data get read by the PC
biomurph 0:675506e540be 310 ADS1299::RREGS(0x11,0x17-0x11); // write the rest
biomurph 0:675506e540be 311 verbose = prevVerboseState;
biomurph 0:675506e540be 312 }
biomurph 0:675506e540be 313
biomurph 0:675506e540be 314 //only use SRB1 if all use_SRB2 are set to false
biomurph 0:675506e540be 315 boolean ADS1299Manager::use_SRB1(void) {
biomurph 0:675506e540be 316 for (int Ichan=0; Ichan < OPENBCI_NCHAN; Ichan++) {
biomurph 0:675506e540be 317 if (use_SRB2[Ichan]) {
biomurph 0:675506e540be 318 return false;
biomurph 0:675506e540be 319 }
biomurph 0:675506e540be 320 }
biomurph 0:675506e540be 321 return true;
biomurph 0:675506e540be 322 }
biomurph 0:675506e540be 323