OpenBCI 32bit board variation with STM32L476 mircocontroller and mbed support
Revision 1:4683702d7ad8, committed 2017-01-22
- Comitter:
- akpc806a
- Date:
- Sun Jan 22 04:10:11 2017 +0000
- Parent:
- 0:2cb59ea20ace
- Commit message:
- OpenBCI 32bit board variation with STM32L476 mircocontroller and mbed support. Version V2 of firmware, forked from the same official version for the PIC32 board.
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Definitions.h Sun Jan 22 04:10:11 2017 +0000 @@ -0,0 +1,383 @@ +// +// Definitions_32.h +// +// +// Created by Conor Russomanno, Luke Travis, and Joel Murphy. Summer 2013. +// Modified by Joel Murphy, Summer 2014 +// Joel Added Daisy Functionality Fall 2014 +// + +#ifndef _____OpenBCI_32bit_Library_Definitions_h +#define _____OpenBCI_32bit_Library_Definitions_h + +// The default baud rate +#define OPENBCI_BAUD_RATE 115200 + +// File transmissions +#define OPENBCI_BOP 'A' // Begining of stream packet +#define OPENBCI_EOP_STND_ACCEL 0xC0 // End of standard stream packet +#define OPENBCI_EOP_STND_RAW_AUX 0xC1 // End of stream packet with raw packet +#define OPENBCI_EOP_USER_DEFINED 0xC2 // End of stream packet, user defined +#define OPENBCI_EOP_ACCEL_TIME_SET 0xC3 // End of time sync up with accel stream packet +#define OPENBCI_EOP_ACCEL_TIME_SYNCED 0xC4 // End of time synced stream packet +#define OPENBCI_EOP_RAW_AUX_TIME_SET 0xC5 // End of time sync up stream packet +#define OPENBCI_EOP_RAW_AUX_TIME_SYNCED 0xC6 // End of time synced stream packet + +//PIN CONNECTIONS +/* +// MBED: pin definitions are in PlatformDefs.h +#define ADS_DRDY 9 // ADS data ready pin +#define ADS_RST 4 // ADS reset pin +#define BOARD_ADS 8 // ADS chip select +#define DAISY_ADS 3 // ADS Daisy chip select +#define BOTH_ADS 5 // Slave Select Both ADS chips +#define SD_SS 2 // SD card chip select +#define LIS3DH_SS 1 // LIS3DH chip select +#define LIS3DH_DRDY 0 // LIS3DH data ready pin +#define OPENBCI_PIN_LED 11 +#define OPENBCI_PIN_PGC 12 +*/ +#define BOTH_ADS 5 // Slave Select Both ADS chips + +//ADS1299 SPI Command Definition Byte Assignments +#define _WAKEUP 0x02 // Wake-up from standby mode +#define _STANDBY 0x04 // Enter Standby mode +#define _RESET 0x06 // Reset the device registers to default +#define _START 0x08 // Start and restart (synchronize) conversions +#define _STOP 0x0A // Stop conversion +#define _RDATAC 0x10 // Enable Read Data Continuous mode (default mode at power-up) +#define _SDATAC 0x11 // Stop Read Data Continuous mode +#define _RDATA 0x12 // Read data by command supports multiple read back + +//ASD1299 Register Addresses +#define ADS_ID 0x3E // product ID for ADS1299 +#define ID_REG 0x00 // this register contains ADS_ID +#define CONFIG1 0x01 +#define CONFIG2 0x02 +#define CONFIG3 0x03 +#define LOFF 0x04 +#define CH1SET 0x05 +#define CH2SET 0x06 +#define CH3SET 0x07 +#define CH4SET 0x08 +#define CH5SET 0x09 +#define CH6SET 0x0A +#define CH7SET 0x0B +#define CH8SET 0x0C +#define BIAS_SENSP 0x0D +#define BIAS_SENSN 0x0E +#define LOFF_SENSP 0x0F +#define LOFF_SENSN 0x10 +#define LOFF_FLIP 0x11 +#define LOFF_STATP 0x12 +#define LOFF_STATN 0x13 +//#define GPIO 0x14 // MBED: interfere with STM32 library +static const int GPIO = 0x14; +#define MISC1 0x15 +#define MISC2 0x16 +#define CONFIG4 0x17 + +#define OUTPUT_NOTHING (0) // quiet +#define OUTPUT_8_CHAN (1) // not using Daisy module +#define OUTPUT_16_CHAN (2) // using Daisy module +#define ON_BOARD (BOARD_ADS) // slave address for on board ADS +#define ON_DAISY (DAISY_ADS) // slave address for daisy ADS +// CHANNEL SETTINGS +#define POWER_DOWN (0) +#define GAIN_SET (1) +#define INPUT_TYPE_SET (2) +#define BIAS_SET (3) +#define SRB2_SET (4) +#define SRB1_SET (5) +#define YES (0x01) +#define NO (0x00) + +//gainCode choices +#define ADS_GAIN01 (0b00000000) // 0x00 +#define ADS_GAIN02 (0b00010000) // 0x10 +#define ADS_GAIN04 (0b00100000) // 0x20 +#define ADS_GAIN06 (0b00110000) // 0x30 +#define ADS_GAIN08 (0b01000000) // 0x40 +#define ADS_GAIN12 (0b01010000) // 0x50 +#define ADS_GAIN24 (0b01100000) // 0x60 + +//inputType choices +#define ADSINPUT_NORMAL (0b00000000) +#define ADSINPUT_SHORTED (0b00000001) +#define ADSINPUT_BIAS_MEAS (0b00000010) +#define ADSINPUT_MVDD (0b00000011) +#define ADSINPUT_TEMP (0b00000100) +#define ADSINPUT_TESTSIG (0b00000101) +#define ADSINPUT_BIAS_DRP (0b00000110) +#define ADSINPUT_BIAL_DRN (0b00000111) + +//test signal choices...ADS1299 datasheet page 41 +#define ADSTESTSIG_AMP_1X (0b00000000) +#define ADSTESTSIG_AMP_2X (0b00000100) +#define ADSTESTSIG_PULSE_SLOW (0b00000000) +#define ADSTESTSIG_PULSE_FAST (0b00000001) +#define ADSTESTSIG_DCSIG (0b00000011) +#define ADSTESTSIG_NOCHANGE (0b11111111) + +//Lead-off signal choices +#define LOFF_MAG_6NA (0b00000000) +#define LOFF_MAG_24NA (0b00000100) +#define LOFF_MAG_6UA (0b00001000) +#define LOFF_MAG_24UA (0b00001100) +#define LOFF_FREQ_DC (0b00000000) +#define LOFF_FREQ_7p8HZ (0b00000001) +#define LOFF_FREQ_31p2HZ (0b00000010) +#define LOFF_FREQ_FS_4 (0b00000011) +#define PCHAN (0) +#define NCHAN (1) +#define OFF (0) +#define ON (1) + +// used for channel settings +#define ACTIVATE_SHORTED (2) +#define ACTIVATE (1) +#define DEACTIVATE (0) + +#define PCKT_START 0xA0 // prefix for data packet error checking +#define PCKT_END 0xC0 // postfix for data packet error checking + +// daisy module +#define CLK_EN 5 + +//LIS3DH +//#define READ_REG 0x80 // MBED: interfere with STM32 library +static const int READ_REG = 0x80; + +#define READ_MULTI 0x40 + +#define STATUS_REG_AUX 0x07 // axis over-run and data available flags (see 0x27) +#define OUT_ADC1_L 0x08 // +#define OUT_ADC1_H 0x09 // +#define OUT_ADC2_L 0x0A // ADC input values (check DS) +#define OUT_ADC2_H 0x0B // +#define OUT_ADC3_L 0x0C // +#define OUT_ADC3_H 0x0D // +#define INT_COUNTER_REG 0x0E // ?? +#define WHO_AM_I 0x0F // DEVICE ID 0x33 +#define TMP_CFG_REG 0x1F // ADC enable (0x80) Temperature sensor enable (0x40) +#define CTRL_REG1 0x20 // Data Rate Power Mode X enable Y enable Z enable (on >0x10) +#define CTRL_REG2 0x21 // High Pass Filter Stuph +#define CTRL_REG3 0x22 // INT1 select register +#define CTRL_REG4 0x23 // Block update timing endian G-force resolution self test SPI pins +#define CTRL_REG5 0x24 // reboot FIFO enable latch 4D detection +#define CTRL_REG6 0x25 // ?? +#define REFERENCE 0x26 // interrupt reference +#define STATUS_REG2 0x27 // axis overrun and availale flags (see 0x07) +#define OUT_X_L 0x28 // +#define OUT_X_H 0x29 // +#define OUT_Y_L 0x2A // tripple axis values (see 0x0A) +#define OUT_Y_H 0x2B // +#define OUT_Z_L 0x2C // +#define OUT_Z_H 0x2D // +#define FIFO_CTRL_REG 0x2E // FIFO mode trigger output pin select (?) +#define FIFO_SRC_REG 0x2F // ?? +#define INT1_CFG 0x30 // 6 degree control register +#define INT1_SOURCE 0x31 // axis threshold interrupt control +#define INT1_THS 0x32 // INT1 threshold +#define INT1_DURATION 0x33 // INT1 duration +#define CLICK_CFG 0x38 // click on axis +#define CLICK_SRC 0x39 // other click +#define CLICK_THS 0x3A // more click +#define TIME_LIMIT 0x3B // click related +#define TIME_LATENCY 0x3C // and so on +#define TIME_WINDOW 0x3D // contined click + +#define SCALE_2G 0x00 //(b00000000) // +/- 2G sensitivity +#define SCALE_4G 0x10 //(b00010000) // +/- 4G sensitivity +#define SCALE_8G 0x20 //(b00100000) // +/- 8G sensitivity +#define SCALE_16G 0x30 //(b00110000) // +/- 16G sensitivity +#define RATE_1HZ 0x10 //(b00010000) // 1Hz sample rate in normal or low-power mode +#define RATE_10HZ 0x20 //(b00100000) // 10Hz sample rate in normal or low-power mode +#define RATE_25HZ 0x30 //(b00110000) // 25Hz sample rate in normal or low-power mode +#define RATE_50HZ 0x40 //(b01000000) // 50Hz sample rate in normal or low-power mode +#define RATE_100HZ 0x50 //(b01010000) // 100Hz sample rate in normal or low-power mode +#define RATE_200HZ 0x60 //(b01100000) // 200Hz sample rate in normal or low-power mode +#define RATE_400HZ 0x70 //(b01110000) // 400Hz sample rate in normal or low-power mode +#define RATE_1600HZ_LP 0x80 //(b10000000) // 1600Hz sample rate in low-power mode +#define RATE_1250HZ_N 0x90 //(b10010000) // 1250Hz sample rate in normal mode +#define RATE_5000HZ_LP 0x90 //(b10010000) // 5000Hz sample rate in low-power mode +#define ACCEL_AXIS_X 0x07 // x axis +#define ACCEL_AXIS_Y 0x08 // y axis +#define ACCEL_AXIS_Z 0x09 // z axis + +// OPENBCI_COMMANDS +/** Turning channels off */ +#define OPENBCI_CHANNEL_OFF_1 '1' +#define OPENBCI_CHANNEL_OFF_2 '2' +#define OPENBCI_CHANNEL_OFF_3 '3' +#define OPENBCI_CHANNEL_OFF_4 '4' +#define OPENBCI_CHANNEL_OFF_5 '5' +#define OPENBCI_CHANNEL_OFF_6 '6' +#define OPENBCI_CHANNEL_OFF_7 '7' +#define OPENBCI_CHANNEL_OFF_8 '8' +#define OPENBCI_CHANNEL_OFF_9 'q' +#define OPENBCI_CHANNEL_OFF_10 'w' +#define OPENBCI_CHANNEL_OFF_11 'e' +#define OPENBCI_CHANNEL_OFF_12 'r' +#define OPENBCI_CHANNEL_OFF_13 't' +#define OPENBCI_CHANNEL_OFF_14 'y' +#define OPENBCI_CHANNEL_OFF_15 'u' +#define OPENBCI_CHANNEL_OFF_16 'i' + +/** Turn channels on */ +#define OPENBCI_CHANNEL_ON_1 '!' +#define OPENBCI_CHANNEL_ON_2 '@' +#define OPENBCI_CHANNEL_ON_3 '#' +#define OPENBCI_CHANNEL_ON_4 '$' +#define OPENBCI_CHANNEL_ON_5 '%' +#define OPENBCI_CHANNEL_ON_6 '^' +#define OPENBCI_CHANNEL_ON_7 '&' +#define OPENBCI_CHANNEL_ON_8 '*' +#define OPENBCI_CHANNEL_ON_9 'Q' +#define OPENBCI_CHANNEL_ON_10 'W' +#define OPENBCI_CHANNEL_ON_11 'E' +#define OPENBCI_CHANNEL_ON_12 'R' +#define OPENBCI_CHANNEL_ON_13 'T' +#define OPENBCI_CHANNEL_ON_14 'Y' +#define OPENBCI_CHANNEL_ON_15 'U' +#define OPENBCI_CHANNEL_ON_16 'I' + +/** Test Signal Control Commands + * 1x - Voltage will be 1 * (VREFP - VREFN) / 2.4 mV + * 2x - Voltage will be 2 * (VREFP - VREFN) / 2.4 mV + */ +#define OPENBCI_TEST_SIGNAL_CONNECT_TO_DC 'p' +#define OPENBCI_TEST_SIGNAL_CONNECT_TO_GROUND '0' +#define OPENBCI_TEST_SIGNAL_CONNECT_TO_PULSE_1X_FAST '=' +#define OPENBCI_TEST_SIGNAL_CONNECT_TO_PULSE_1X_SLOW '-' +#define OPENBCI_TEST_SIGNAL_CONNECT_TO_PULSE_2X_FAST ']' +#define OPENBCI_TEST_SIGNAL_CONNECT_TO_PULSE_2X_SLOW '[' + +/** Channel Setting Commands */ +#define OPENBCI_CHANNEL_CMD_ADC_Normal '0' +#define OPENBCI_CHANNEL_CMD_ADC_Shorted '1' +#define OPENBCI_CHANNEL_CMD_ADC_BiasDRP '6' +#define OPENBCI_CHANNEL_CMD_ADC_BiasDRN '7' +#define OPENBCI_CHANNEL_CMD_ADC_BiasMethod '2' +#define OPENBCI_CHANNEL_CMD_ADC_MVDD '3' +#define OPENBCI_CHANNEL_CMD_ADC_Temp '4' +#define OPENBCI_CHANNEL_CMD_ADC_TestSig '5' +#define OPENBCI_CHANNEL_CMD_BIAS_INCLUDE '1' +#define OPENBCI_CHANNEL_CMD_BIAS_REMOVE '0' +#define OPENBCI_CHANNEL_CMD_CHANNEL_1 '1' +#define OPENBCI_CHANNEL_CMD_CHANNEL_2 '2' +#define OPENBCI_CHANNEL_CMD_CHANNEL_3 '3' +#define OPENBCI_CHANNEL_CMD_CHANNEL_4 '4' +#define OPENBCI_CHANNEL_CMD_CHANNEL_5 '5' +#define OPENBCI_CHANNEL_CMD_CHANNEL_6 '6' +#define OPENBCI_CHANNEL_CMD_CHANNEL_7 '7' +#define OPENBCI_CHANNEL_CMD_CHANNEL_8 '8' +#define OPENBCI_CHANNEL_CMD_CHANNEL_9 'Q' +#define OPENBCI_CHANNEL_CMD_CHANNEL_10 'W' +#define OPENBCI_CHANNEL_CMD_CHANNEL_11 'E' +#define OPENBCI_CHANNEL_CMD_CHANNEL_12 'R' +#define OPENBCI_CHANNEL_CMD_CHANNEL_13 'T' +#define OPENBCI_CHANNEL_CMD_CHANNEL_14 'Y' +#define OPENBCI_CHANNEL_CMD_CHANNEL_15 'U' +#define OPENBCI_CHANNEL_CMD_CHANNEL_16 'I' +#define OPENBCI_CHANNEL_CMD_GAIN_1 '0' +#define OPENBCI_CHANNEL_CMD_GAIN_2 '1' +#define OPENBCI_CHANNEL_CMD_GAIN_4 '2' +#define OPENBCI_CHANNEL_CMD_GAIN_6 '3' +#define OPENBCI_CHANNEL_CMD_GAIN_8 '4' +#define OPENBCI_CHANNEL_CMD_GAIN_12 '5' +#define OPENBCI_CHANNEL_CMD_GAIN_24 '6' +#define OPENBCI_CHANNEL_CMD_LATCH 'X' +#define OPENBCI_CHANNEL_CMD_POWER_OFF '1' +#define OPENBCI_CHANNEL_CMD_POWER_ON '0' +#define OPENBCI_CHANNEL_CMD_SET 'x' +#define OPENBCI_CHANNEL_CMD_SRB1_CONNECT '1' +#define OPENBCI_CHANNEL_CMD_SRB1_DISCONNECT '0' +#define OPENBCI_CHANNEL_CMD_SRB2_CONNECT '1' +#define OPENBCI_CHANNEL_CMD_SRB2_DISCONNECT '0' + +/** Default Channel Settings */ +#define OPENBCI_CHANNEL_DEFAULT_ALL_SET 'd' +#define OPENBCI_CHANNEL_DEFAULT_ALL_REPORT 'D' + +/** LeadOff Impedance Commands */ +#define OPENBCI_CHANNEL_IMPEDANCE_LATCH 'Z' +#define OPENBCI_CHANNEL_IMPEDANCE_SET 'z' +#define OPENBCI_CHANNEL_IMPEDANCE_TEST_SIGNAL_APPLIED '1' +#define OPENBCI_CHANNEL_IMPEDANCE_TEST_SIGNAL_APPLIED_NOT '0' + +/** SD card Commands */ +#define OPENBCI_SD_LOG_FOR_HOUR_1 'G' +#define OPENBCI_SD_LOG_FOR_HOUR_2 'H' +#define OPENBCI_SD_LOG_FOR_HOUR_4 'J' +#define OPENBCI_SD_LOG_FOR_HOUR_12 'K' +#define OPENBCI_SD_LOG_FOR_HOUR_24 'L' +#define OPENBCI_SD_LOG_FOR_MIN_5 'A' +#define OPENBCI_SD_LOG_FOR_MIN_15 'S' +#define OPENBCI_SD_LOG_FOR_MIN_30 'F' +#define OPENBCI_SD_LOG_FOR_SEC_14 'a' +#define OPENBCI_SD_LOG_STOP 'j' + +/** Stream Data Commands */ +#define OPENBCI_STREAM_START 'b' +#define OPENBCI_STREAM_STOP 's' + +/** Miscellaneous */ +#define OPENBCI_MISC_QUERY_REGISTER_SETTINGS '?' +#define OPENBCI_MISC_SOFT_RESET 'v' + +/** 16 Channel Commands */ +#define OPENBCI_CHANNEL_MAX_NUMBER_8 'c' +#define OPENBCI_CHANNEL_MAX_NUMBER_16 'C' + +/** Set Packet Type */ +#define OPENBCI_BOARD_MODE_SET '/' +#define OPENBCI_BOARD_MODE_DEFAULT '0' +#define OPENBCI_BOARD_MODE_DEBUG '1' +#define OPENBCI_BOARD_MODE_WIFI '2' +#define OPENBCI_BOARD_MODE_INPUT_ANALOG '3' +#define OPENBCI_BOARD_MODE_INPUT_DIGITAL '4' + +/** Sync Clocks */ +#define OPENBCI_TIME_SET '<' +#define OPENBCI_TIME_STOP '>' + +/** Possible number of channels */ +#define OPENBCI_NUMBER_OF_CHANNELS_DAISY 16 +#define OPENBCI_NUMBER_OF_CHANNELS_DEFAULT 8 + +/** Helpful numbers */ +#define OPENBCI_NUMBER_OF_BOARD_SETTINGS 1 +#define OPENBCI_NUMBER_OF_CHANNEL_SETTINGS 6 +#define OPENBCI_NUMBER_OF_LEAD_OFF_SETTINGS 2 + +/** Possible Sample Rates*/ +#define OPENBCI_SAMPLE_RATE_125 125 +#define OPENBCI_SAMPLE_RATE_250 250 + +/** Packet Size */ +#define OPENBCI_PACKET_SIZE 33 + +/** Impedance Calculation Variables */ +#define OPENBCI_LEAD_OFF_DRIVE_AMPS 0.000000006 +#define OPENBCI_LEAD_OFF_FREQUENCY_HZ 31 + +/** Raw data packet types/codes */ +#define OPENBCI_PACKET_TYPE_V3 0 // 0000 +#define OPENBCI_PACKET_TYPE_TIME_SYNCED 1 // 0001 +#define OPENBCI_PACKET_TYPE_TIME_SET 2 // 0010 +#define OPENBCI_PACKET_TYPE_USER_DEFINED 3 // 0011 +#define OPENBCI_PACKET_TYPE_RAW_AUX 4 // 0100 + +#define OPENBCI_TIME_OUT_MS_1 1 +#define OPENBCI_TIME_OUT_MS_3 3 + +#define OPENBCI_NUMBER_OF_BYTES_SETTINGS_CHANNEL 9 +#define OPENBCI_NUMBER_OF_BYTES_SETTINGS_LEAD_OFF 5 + +#define OPENBCI_NUMBER_OF_BYTES_AUX 6 + +#define OPENBCI_FIRMWARE_VERSION_V1 1 +#define OPENBCI_FIRMWARE_VERSION_V2 1 + +#endif
--- a/Definitions_32_Daisy.h Sun Dec 04 03:38:44 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,192 +0,0 @@ -// -// Definitions_32.h -// -// -// Created by Conor Russomanno, Luke Travis, and Joel Murphy. Summer 2013. -// Modified by Joel Murphy, Summer 2014 -// Joel Added Daisy Functionality Fall 2014 -// - -#ifndef _Definitions_32_Daisy_h -#define _Definitions_32_Daisy_h - -//PIN CONNECTIONS -/* -// MBED: pin definitions are in PlatformDefs.h - #define ADS_DRDY 9 // ADS data ready pin - #define ADS_RST 4 // ADS reset pin - #define BOARD_ADS 8 // ADS chip select - #define DAISY_ADS 3 // ADS Daisy chip select - - #define SD_SS 2 // SD card chip select - #define LIS3DH_SS 1 // LIS3DH chip select - #define LIS3DH_DRDY 0 // LIS3DH data ready pin -*/ -#define BOTH_ADS 5 // Slave Select Both ADS chips - -//ADS1299 SPI Command Definition Byte Assignments -#define _WAKEUP 0x02 // Wake-up from standby mode -#define _STANDBY 0x04 // Enter Standby mode -#define _RESET 0x06 // Reset the device registers to default -#define _START 0x08 // Start and restart (synchronize) conversions -#define _STOP 0x0A // Stop conversion -#define _RDATAC 0x10 // Enable Read Data Continuous mode (default mode at power-up) -#define _SDATAC 0x11 // Stop Read Data Continuous mode -#define _RDATA 0x12 // Read data by command; supports multiple read back - -//ASD1299 Register Addresses -#define ADS_ID 0x3E // product ID for ADS1299 -#define ID_REG 0x00 // this register contains ADS_ID -#define CONFIG1 0x01 -#define CONFIG2 0x02 -#define CONFIG3 0x03 -#define LOFF 0x04 -#define CH1SET 0x05 -#define CH2SET 0x06 -#define CH3SET 0x07 -#define CH4SET 0x08 -#define CH5SET 0x09 -#define CH6SET 0x0A -#define CH7SET 0x0B -#define CH8SET 0x0C -#define BIAS_SENSP 0x0D -#define BIAS_SENSN 0x0E -#define LOFF_SENSP 0x0F -#define LOFF_SENSN 0x10 -#define LOFF_FLIP 0x11 -#define LOFF_STATP 0x12 -#define LOFF_STATN 0x13 -//#define GPIO 0x14 // MBED: interfere with STM32 library -static const int GPIO = 0x14; -#define MISC1 0x15 -#define MISC2 0x16 -#define CONFIG4 0x17 - -#define OUTPUT_NOTHING (0) // quiet -#define OUTPUT_8_CHAN (1) // not using Daisy module -#define OUTPUT_16_CHAN (2) // using Daisy module -#define ON_BOARD (BOARD_ADS) // slave address for on board ADS -#define ON_DAISY (DAISY_ADS) // slave address for daisy ADS -// CHANNEL SETTINGS -#define POWER_DOWN (0) -#define GAIN_SET (1) -#define INPUT_TYPE_SET (2) -#define BIAS_SET (3) -#define SRB2_SET (4) -#define SRB1_SET (5) -#define YES (0x01) -#define NO (0x00) - -//gainCode choices -#define ADS_GAIN01 (0b00000000) // 0x00 -#define ADS_GAIN02 (0b00010000) // 0x10 -#define ADS_GAIN04 (0b00100000) // 0x20 -#define ADS_GAIN06 (0b00110000) // 0x30 -#define ADS_GAIN08 (0b01000000) // 0x40 -#define ADS_GAIN12 (0b01010000) // 0x50 -#define ADS_GAIN24 (0b01100000) // 0x60 - -//inputType choices -#define ADSINPUT_NORMAL (0b00000000) -#define ADSINPUT_SHORTED (0b00000001) -#define ADSINPUT_BIAS_MEAS (0b00000010) -#define ADSINPUT_MVDD (0b00000011) -#define ADSINPUT_TEMP (0b00000100) -#define ADSINPUT_TESTSIG (0b00000101) -#define ADSINPUT_BIAS_DRP (0b00000110) -#define ADSINPUT_BIAL_DRN (0b00000111) - -//test signal choices...ADS1299 datasheet page 41 -#define ADSTESTSIG_AMP_1X (0b00000000) -#define ADSTESTSIG_AMP_2X (0b00000100) -#define ADSTESTSIG_PULSE_SLOW (0b00000000) -#define ADSTESTSIG_PULSE_FAST (0b00000001) -#define ADSTESTSIG_DCSIG (0b00000011) -#define ADSTESTSIG_NOCHANGE (0b11111111) - -//Lead-off signal choices -#define LOFF_MAG_6NA (0b00000000) -#define LOFF_MAG_24NA (0b00000100) -#define LOFF_MAG_6UA (0b00001000) -#define LOFF_MAG_24UA (0b00001100) -#define LOFF_FREQ_DC (0b00000000) -#define LOFF_FREQ_7p8HZ (0b00000001) -#define LOFF_FREQ_31p2HZ (0b00000010) -#define LOFF_FREQ_FS_4 (0b00000011) -#define PCHAN (0) -#define NCHAN (1) -#define OFF (0) -#define ON (1) - -// used for channel settings -#define ACTIVATE_SHORTED (2) -#define ACTIVATE (1) -#define DEACTIVATE (0) - -#define PCKT_START 0xA0 // prefix for data packet error checking -#define PCKT_END 0xC0 // postfix for data packet error checking - -// daisy module -#define CLK_EN 5 - -//LIS3DH -//#define READ_REG 0x80 // MBED: interfere with STM32 library -static const int READ_REG = 0x80; - -#define READ_MULTI 0x40 - -#define STATUS_REG_AUX 0x07 // axis over-run and data available flags (see 0x27) -#define OUT_ADC1_L 0x08 // -#define OUT_ADC1_H 0x09 // -#define OUT_ADC2_L 0x0A // ADC input values (check DS) -#define OUT_ADC2_H 0x0B // -#define OUT_ADC3_L 0x0C // -#define OUT_ADC3_H 0x0D // -#define INT_COUNTER_REG 0x0E // ?? -#define WHO_AM_I 0x0F // DEVICE ID = 0x33 -#define TMP_CFG_REG 0x1F // ADC enable (0x80); Temperature sensor enable (0x40) -#define CTRL_REG1 0x20 // Data Rate; Power Mode; X enable; Y enable; Z enable (on >= 0x10) -#define CTRL_REG2 0x21 // High Pass Filter Stuph -#define CTRL_REG3 0x22 // INT1 select register -#define CTRL_REG4 0x23 // Block update timing; endian; G-force; resolution; self test; SPI pins -#define CTRL_REG5 0x24 // reboot; FIFO enable; latch; 4D detection; -#define CTRL_REG6 0x25 // ?? -#define REFERENCE 0x26 // interrupt reference -#define STATUS_REG2 0x27 // axis overrun and availale flags (see 0x07) -#define OUT_X_L 0x28 // -#define OUT_X_H 0x29 // -#define OUT_Y_L 0x2A // tripple axis values (see 0x0A) -#define OUT_Y_H 0x2B // -#define OUT_Z_L 0x2C // -#define OUT_Z_H 0x2D // -#define FIFO_CTRL_REG 0x2E // FIFO mode; trigger output pin select (?); -#define FIFO_SRC_REG 0x2F // ?? -#define INT1_CFG 0x30 // 6 degree control register -#define INT1_SOURCE 0x31 // axis threshold interrupt control -#define INT1_THS 0x32 // INT1 threshold -#define INT1_DURATION 0x33 // INT1 duration -#define CLICK_CFG 0x38 // click on axis -#define CLICK_SRC 0x39 // other click -#define CLICK_THS 0x3A // more click -#define TIME_LIMIT 0x3B // click related -#define TIME_LATENCY 0x3C // and so on -#define TIME_WINDOW 0x3D // contined click - -#define SCALE_2G 0x00 //(b00000000) // +/- 2G sensitivity -#define SCALE_4G 0x10 //(b00010000) // +/- 4G sensitivity -#define SCALE_8G 0x20 //(b00100000) // +/- 8G sensitivity -#define SCALE_16G 0x30 //(b00110000) // +/- 16G sensitivity -#define RATE_1HZ 0x10 //(b00010000) // 1Hz sample rate in normal or low-power mode -#define RATE_10HZ 0x20 //(b00100000) // 10Hz sample rate in normal or low-power mode -#define RATE_25HZ 0x30 //(b00110000) // 25Hz sample rate in normal or low-power mode -#define RATE_50HZ 0x40 //(b01000000) // 50Hz sample rate in normal or low-power mode -#define RATE_100HZ 0x50 //(b01010000) // 100Hz sample rate in normal or low-power mode -#define RATE_200HZ 0x60 //(b01100000) // 200Hz sample rate in normal or low-power mode -#define RATE_400HZ 0x70 //(b01110000) // 400Hz sample rate in normal or low-power mode -#define RATE_1600HZ_LP 0x80 //(b10000000) // 1600Hz sample rate in low-power mode -#define RATE_1250HZ_N 0x90 //(b10010000) // 1250Hz sample rate in normal mode -#define RATE_5000HZ_LP 0x90 //(b10010000) // 5000Hz sample rate in low-power mode - - - -#endif
--- a/OpenBCI_32_Daisy.cpp Sun Dec 04 03:38:44 2016 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1140 +0,0 @@
-
-/*
- OpenBCI 32bit Library
- Place the containing folder into your libraries folder insdie the arduino folder in your Documents folder
-
- This library will work with a single OpenBCI 32bit board, or
- an OpenBCI 32bit board with an OpenBCI Daisy Module attached.
-
-*/
-
-#include "OpenBCI_32_Daisy.h"
-
-
-// <<<<<<<<<<<<<<<<<<<<<<<<< BOARD WIDE FUNCTIONS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-
-void OpenBCI_32_Daisy::initialize(){
- pinMode(SD_SS,OUTPUT); digitalWrite(SD_SS,HIGH); // de-select SDcard if present
- pinMode(BOARD_ADS, OUTPUT); digitalWrite(BOARD_ADS,HIGH);
- pinMode(DAISY_ADS, OUTPUT); digitalWrite(DAISY_ADS,HIGH);
- pinMode(LIS3DH_SS,OUTPUT); digitalWrite(LIS3DH_SS,HIGH);
- spi.begin();
- spi.setSpeed(4000000); // use 4MHz for ADS and LIS3DH
- spi.setMode(DSPI_MODE0); // default to SD card mode!
- initialize_ads(); // hard reset ADS, set pin directions
- initialize_accel(SCALE_4G); // set pin directions, G scale, DRDY interrupt, power down
-}
-
-void OpenBCI_32_Daisy::printAllRegisters(){
- if(!isRunning){
- Serial0.println("\nBoard ADS Registers");
- printADSregisters(BOARD_ADS);
- if(daisyPresent){
- Serial0.println("\nDaisy ADS Registers");
- printADSregisters(DAISY_ADS);
- }
- Serial0.println("\nLIS3DH Registers");
- LIS3DH_readAllRegs();
- }
-}
-
-void OpenBCI_32_Daisy::startStreaming(){ // needs daisy functionality
- startADS();
-}
-
-void OpenBCI_32_Daisy::sendChannelData(){
-Serial0.write(0xA0); // start byte
- Serial0.write(sampleCounter); // 1 byte
- ADS_writeChannelData(); // 24 bytes
- if(useAux){
- writeAuxData(); // 6 bytes of aux data
- }else if(useAccel){ // or
- LIS3DH_writeAxisData(); // 6 bytes of accelerometer data
- }else{
- byte zero = 0x00;
- for(int i=0; i<6; i++){
- Serial0.write(zero);
- }
- }
-Serial0.write(0xC0); // end byte
- sampleCounter++;
-}
-
-void OpenBCI_32_Daisy::writeAuxData(){
- for(int i=0; i<3; i++){
- Serial0.write(highByte(auxData[i])); // write 16 bit axis data MSB first
- Serial0.write(lowByte(auxData[i])); // axisData is array of type short (16bit)
- auxData[i] = 0; // reset auxData bytes to 0
- }
-}
-
-void OpenBCI_32_Daisy::stopStreaming(){
- stopADS();
-}
-
-//SPI communication method
-byte OpenBCI_32_Daisy::xfer(byte _data)
-{
- byte inByte;
- inByte = spi.transfer(_data);
- return inByte;
-}
-
-//SPI chip select method
-void OpenBCI_32_Daisy::csLow(int SS)
-{ // select an SPI slave to talk to
- switch(SS){
- case BOARD_ADS:
- spi.setMode(DSPI_MODE1); spi.setSpeed(4000000); digitalWrite(BOARD_ADS, LOW); break;
- case LIS3DH_SS:
- spi.setMode(DSPI_MODE3); spi.setSpeed(4000000); digitalWrite(LIS3DH_SS, LOW); break;
- case SD_SS:
- spi.setMode(DSPI_MODE0); spi.setSpeed(20000000); digitalWrite(SD_SS, LOW); break;
- case DAISY_ADS:
- spi.setMode(DSPI_MODE1); spi.setSpeed(4000000); digitalWrite(DAISY_ADS, LOW); break;
- case BOTH_ADS:
- spi.setMode(DSPI_MODE1); spi.setSpeed(4000000);
- digitalWrite(BOARD_ADS,LOW); digitalWrite(DAISY_ADS,LOW); break;
- default: break;
- }
-}
-
-void OpenBCI_32_Daisy::csHigh(int SS)
-{ // deselect SPI slave
- switch(SS){
- case BOARD_ADS:
- digitalWrite(BOARD_ADS, HIGH); spi.setSpeed(20000000); break;
- case LIS3DH_SS:
- digitalWrite(LIS3DH_SS, HIGH); spi.setSpeed(20000000); break;
- case SD_SS:
- digitalWrite(SD_SS, HIGH); spi.setSpeed(4000000); break;
- case DAISY_ADS:
- digitalWrite(DAISY_ADS, HIGH); spi.setSpeed(20000000); break;
- case BOTH_ADS:
- digitalWrite(BOARD_ADS, HIGH); digitalWrite(DAISY_ADS, HIGH);
- spi.setSpeed(20000000); break;
- default:
- break;
- }
- spi.setMode(DSPI_MODE0); // DEFAULT TO SD MODE!
-}
-
-// <<<<<<<<<<<<<<<<<<<<<<<<< END OF BOARD WIDE FUNCTIONS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-// *************************************************************************************
-// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ADS1299 FUNCTIONS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-
-
-void OpenBCI_32_Daisy::initialize_ads(){
-// recommended power up sequence requiers >Tpor (~32mS)
- delay(50);
- pinMode(ADS_RST,OUTPUT);
- digitalWrite(ADS_RST,LOW); // reset pin connected to both ADS ICs
- delayMicroseconds(4); // toggle reset pin
- digitalWrite(ADS_RST,HIGH); // this will reset the Daisy if it is present
- delayMicroseconds(20); // recommended to wait 18 Tclk before using device (~8uS);
-// initalize the data ready chip select and reset pins:
- pinMode(ADS_DRDY, INPUT); // we get DRDY asertion from the on-board ADS
- delay(40);
- resetADS(BOARD_ADS); // reset the on-board ADS registers, and stop DataContinuousMode
- delay(10);
- WREG(CONFIG1,0xB6,BOARD_ADS); // tell on-board ADS to output its clk, set the data rate to 250SPS
- delay(40);
- resetADS(DAISY_ADS); // software reset daisy module if present
- delay(10);
- daisyPresent = smellDaisy(); // check to see if daisy module is present
- if(!daisyPresent){
- WREG(CONFIG1,0x96,BOARD_ADS); // turn off clk output if no daisy present
- numChannels = 8; // expect up to 8 ADS channels
- }else{
- numChannels = 16; // expect up to 16 ADS channels
- }
-
- // DEFAULT CHANNEL SETTINGS FOR ADS
- defaultChannelSettings[POWER_DOWN] = NO; // on = NO, off = YES
- defaultChannelSettings[GAIN_SET] = ADS_GAIN24; // Gain setting
- defaultChannelSettings[INPUT_TYPE_SET] = ADSINPUT_NORMAL;// input muxer setting
- defaultChannelSettings[BIAS_SET] = YES; // add this channel to bias generation
- defaultChannelSettings[SRB2_SET] = YES; // connect this P side to SRB2
- defaultChannelSettings[SRB1_SET] = NO; // don't use SRB1
-
- for(int i=0; i<numChannels; i++){
- for(int j=0; j<6; j++){
- channelSettings[i][j] = defaultChannelSettings[j]; // assign default settings
- }
- useInBias[i] = true; // keeping track of Bias Generation
- useSRB2[i] = true; // keeping track of SRB2 inclusion
- }
- boardUseSRB1 = daisyUseSRB1 = false;
-
- writeChannelSettings(); // write settings to the on-board and on-daisy ADS if present
-
- WREG(CONFIG3,0b11101100,BOTH_ADS); delay(1); // enable internal reference drive and etc.
- for(int i=0; i<numChannels; i++){ // turn off the impedance measure signal
- leadOffSettings[i][PCHAN] = OFF;
- leadOffSettings[i][NCHAN] = OFF;
- }
- verbosity = false; // when verbosity is true, there will be Serial feedback
- firstDataPacket = true;
-}
-
-boolean OpenBCI_32_Daisy::smellDaisy(void){ // check if daisy present
- boolean isDaisy = false;
- byte setting = RREG(ID_REG,DAISY_ADS); // try to read the daisy product ID
- if(verbosity){Serial0.print("Daisy ID 0x"); Serial0.println(setting,HEX);}
- if(setting == ADS_ID) {isDaisy = true;} // should read as 0x3E
- return isDaisy;
-}
-
-void OpenBCI_32_Daisy::removeDaisy(void){
- if(daisyPresent){
- SDATAC(DAISY_ADS);
- RESET(DAISY_ADS);
- STANDBY(DAISY_ADS);
- daisyPresent = false;
- if(!isRunning) Serial0.println("daisy removed");
- }else{
- if(!isRunning) Serial0.println("no daisy to remove!");
- }
-}
-
-void OpenBCI_32_Daisy::attachDaisy(void){
- WREG(CONFIG1,0xB6,BOARD_ADS); // tell on-board ADS to output the clk, set the data rate to 250SPS
- delay(40);
- resetADS(DAISY_ADS); // software reset daisy module if present
- delay(10);
- daisyPresent = smellDaisy();
- if(!daisyPresent){
- WREG(CONFIG1,0x96,BOARD_ADS); // turn off clk output if no daisy present
- numChannels = 8; // expect up to 8 ADS channels
- if(!isRunning) Serial0.println("no daisy to attach!");
- }else{
- numChannels = 16; // expect up to 16 ADS channels
- if(!isRunning) Serial0.println("daisy attached");
- }
-}
-
-//reset all the ADS1299's settings. Stops all data acquisition
-void OpenBCI_32_Daisy::resetADS(int targetSS)
-{
- int startChan, stopChan;
- if(targetSS == BOARD_ADS) {startChan = 1; stopChan = 8;}
- if(targetSS == DAISY_ADS) {startChan = 9; stopChan = 16;}
- RESET(targetSS); // send RESET command to default all registers
- SDATAC(targetSS); // exit Read Data Continuous mode to communicate with ADS
- delay(100);
- // turn off all channels
- for (int chan=startChan; chan <= stopChan; chan++) {
- deactivateChannel(chan);
- }
-}
-
-void OpenBCI_32_Daisy::setChannelsToDefault(void){
- for(int i=0; i<numChannels; i++){
- for(int j=0; j<6; j++){
- channelSettings[i][j] = defaultChannelSettings[j];
- }
- useInBias[i] = true; // keeping track of Bias Generation
- useSRB2[i] = true; // keeping track of SRB2 inclusion
- }
- boardUseSRB1 = daisyUseSRB1 = false;
-
- writeChannelSettings(); // write settings to on-board ADS
-
- for(int i=0; i<numChannels; i++){ // turn off the impedance measure signal
- leadOffSettings[i][PCHAN] = OFF;
- leadOffSettings[i][NCHAN] = OFF;
- }
- changeChannelLeadOffDetect(); // write settings to all ADS
-
-
- WREG(MISC1,0x00,BOARD_ADS); // open SRB1 switch on-board
- if(daisyPresent){ WREG(MISC1,0x00,DAISY_ADS); } // open SRB1 switch on-daisy
-}
-
-
-void OpenBCI_32_Daisy::reportDefaultChannelSettings(void){
-
- Serial0.write(defaultChannelSettings[POWER_DOWN] + '0'); // on = NO, off = YES
- Serial0.write((defaultChannelSettings[GAIN_SET] >> 4) + '0'); // Gain setting
- Serial0.write(defaultChannelSettings[INPUT_TYPE_SET] +'0');// input muxer setting
- Serial0.write(defaultChannelSettings[BIAS_SET] + '0'); // add this channel to bias generation
- Serial0.write(defaultChannelSettings[SRB2_SET] + '0'); // connect this P side to SRB2
- Serial0.write(defaultChannelSettings[SRB1_SET] + '0'); // don't use SRB1
-}
-
-// write settings for ALL 8 channels for a given ADS board
-// channel settings: powerDown, gain, inputType, SRB2, SRB1
-void OpenBCI_32_Daisy::writeChannelSettings(){
- boolean use_SRB1 = false;
- byte setting, startChan, endChan, targetSS;
-
- for(int b=0; b<2; b++){
- if(b == 0){ targetSS = BOARD_ADS; startChan = 0; endChan = 8; }
- if(b == 1){
- if(!daisyPresent){ return; }
- targetSS = DAISY_ADS; startChan = 8; endChan = 16;
- }
-
- SDATAC(targetSS); delay(1); // exit Read Data Continuous mode to communicate with ADS
-
- for(byte i=startChan; i<endChan; i++){ // write 8 channel settings
- setting = 0x00;
- if(channelSettings[i][POWER_DOWN] == YES){setting |= 0x80;}
- setting |= channelSettings[i][GAIN_SET]; // gain
- setting |= channelSettings[i][INPUT_TYPE_SET]; // input code
- if(channelSettings[i][SRB2_SET] == YES){
- setting |= 0x08; // close this SRB2 switch
- useSRB2[i] = true; // remember SRB2 state for this channel
- }else{
- useSRB2[i] = false; // rememver SRB2 state for this channel
- }
- WREG(CH1SET+(i-startChan),setting,targetSS); // write this channel's register settings
-
- // add or remove this channel from inclusion in BIAS generation
- setting = RREG(BIAS_SENSP,targetSS); //get the current P bias settings
- if(channelSettings[i][BIAS_SET] == YES){
- bitSet(setting,i-startChan); useInBias[i] = true; //add this channel to the bias generation
- }else{
- bitClear(setting,i-startChan); useInBias[i] = false; //remove this channel from bias generation
- }
- WREG(BIAS_SENSP,setting,targetSS); delay(1); //send the modified byte back to the ADS
-
- setting = RREG(BIAS_SENSN,targetSS); //get the current N bias settings
- if(channelSettings[i][BIAS_SET] == YES){
- bitSet(setting,i-startChan); //set this channel's bit to add it to the bias generation
- }else{
- bitClear(setting,i-startChan); // clear this channel's bit to remove from bias generation
- }
- WREG(BIAS_SENSN,setting,targetSS); delay(1); //send the modified byte back to the ADS
-
- if(channelSettings[i][SRB1_SET] == YES){
- use_SRB1 = true; // if any of the channel setting closes SRB1, it is closed for all
- }
- } // end of CHnSET and BIAS settings
- } // end of board select loop
- if(use_SRB1){
- for(int i=startChan; i<endChan; i++){
- channelSettings[i][SRB1_SET] = YES;
- }
- WREG(MISC1,0x20,targetSS); // close SRB1 swtich
- if(targetSS == BOARD_ADS){ boardUseSRB1 = true; }
- if(targetSS == DAISY_ADS){ daisyUseSRB1 = true; }
- }else{
- for(int i=startChan; i<endChan; i++){
- channelSettings[i][SRB1_SET] = NO;
- }
- WREG(MISC1,0x00,targetSS); // open SRB1 switch
- if(targetSS == BOARD_ADS){ boardUseSRB1 = false; }
- if(targetSS == DAISY_ADS){ daisyUseSRB1 = false; }
- }
-}
-
-// write settings for a SPECIFIC channel on a given ADS board
-void OpenBCI_32_Daisy::writeChannelSettings(byte N){
-
- byte setting, startChan, endChan, targetSS;
- if(N < 9){ // channels 1-8 on board
- targetSS = BOARD_ADS; startChan = 0; endChan = 8;
- }else{ // channels 9-16 on daisy module
- if(!daisyPresent) { return; }
- targetSS = DAISY_ADS; startChan = 8; endChan = 16;
- }
-// function accepts channel 1-16, must be 0 indexed to work with array
- N = constrain(N-1,startChan,endChan-1); //subtracts 1 so that we're counting from 0, not 1
-// first, disable any data collection
- SDATAC(targetSS); delay(1); // exit Read Data Continuous mode to communicate with ADS
-
- setting = 0x00;
- if(channelSettings[N][POWER_DOWN] == YES) setting |= 0x80;
- setting |= channelSettings[N][GAIN_SET]; // gain
- setting |= channelSettings[N][INPUT_TYPE_SET]; // input code
- if(channelSettings[N][SRB2_SET] == YES){
- setting |= 0x08; // close this SRB2 switch
- useSRB2[N] = true; // keep track of SRB2 usage
- }else{
- useSRB2[N] = false;
- }
- WREG(CH1SET+(N-startChan), setting, targetSS); // write this channel's register settings
-
- // add or remove from inclusion in BIAS generation
- setting = RREG(BIAS_SENSP,targetSS); //get the current P bias settings
- if(channelSettings[N][BIAS_SET] == YES){
- useInBias[N] = true;
- bitSet(setting,N-startChan); //set this channel's bit to add it to the bias generation
- }else{
- useInBias[N] = false;
- bitClear(setting,N-startChan); // clear this channel's bit to remove from bias generation
- }
- WREG(BIAS_SENSP,setting,targetSS); delay(1); //send the modified byte back to the ADS
- setting = RREG(BIAS_SENSN,targetSS); //get the current N bias settings
- if(channelSettings[N][BIAS_SET] == YES){
- bitSet(setting,N-startChan); //set this channel's bit to add it to the bias generation
- }else{
- bitClear(setting,N-startChan); // clear this channel's bit to remove from bias generation
- }
- WREG(BIAS_SENSN,setting,targetSS); delay(1); //send the modified byte back to the ADS
-
-// if SRB1 is closed or open for one channel, it will be the same for all channels
- if(channelSettings[N][SRB1_SET] == YES){
- for(int i=startChan; i<endChan; i++){
- channelSettings[i][SRB1_SET] = YES;
- }
- if(targetSS == BOARD_ADS) boardUseSRB1 = true;
- if(targetSS == DAISY_ADS) daisyUseSRB1 = true;
- setting = 0x20; // close SRB1 swtich
- }
- if(channelSettings[N][SRB1_SET] == NO){
- for(int i=startChan; i<endChan; i++){
- channelSettings[i][SRB1_SET] = NO;
- }
- if(targetSS == BOARD_ADS) boardUseSRB1 = false;
- if(targetSS == DAISY_ADS) daisyUseSRB1 = false;
- setting = 0x00; // open SRB1 switch
- }
- WREG(MISC1,setting,targetSS);
-}
-
-// deactivate the given channel.
-void OpenBCI_32_Daisy::deactivateChannel(byte N)
-{
- byte setting, startChan, endChan, targetSS;
- if(N < 9){
- targetSS = BOARD_ADS; startChan = 0; endChan = 8;
- }else{
- if(!daisyPresent) { return; }
- targetSS = DAISY_ADS; startChan = 8; endChan = 16;
- }
- SDATAC(targetSS); delay(1); // exit Read Data Continuous mode to communicate with ADS
- N = constrain(N-1,startChan,endChan-1); //subtracts 1 so that we're counting from 0, not 1
-
- setting = RREG(CH1SET+(N-startChan),targetSS); delay(1); // get the current channel settings
- bitSet(setting,7); // set bit7 to shut down channel
- bitClear(setting,3); // clear bit3 to disclude from SRB2 if used
- WREG(CH1SET+(N-startChan),setting,targetSS); delay(1); // write the new value to disable the channel
-
- //remove the channel from the bias generation...
- setting = RREG(BIAS_SENSP,targetSS); delay(1); //get the current bias settings
- bitClear(setting,N-startChan); //clear this channel's bit to remove from bias generation
- WREG(BIAS_SENSP,setting,targetSS); delay(1); //send the modified byte back to the ADS
-
- setting = RREG(BIAS_SENSN,targetSS); delay(1); //get the current bias settings
- bitClear(setting,N-startChan); //clear this channel's bit to remove from bias generation
- WREG(BIAS_SENSN,setting,targetSS); delay(1); //send the modified byte back to the ADS
-
- leadOffSettings[N][0] = leadOffSettings[N][1] = NO;
- changeChannelLeadOffDetect(N+1);
-}
-
-void OpenBCI_32_Daisy::activateChannel(byte N)
-{
- byte setting, startChan, endChan, targetSS;
- if(N < 9){
- targetSS = BOARD_ADS; startChan = 0; endChan = 8;
- }else{
- if(!daisyPresent) { return; }
- targetSS = DAISY_ADS; startChan = 8; endChan = 16;
- }
-
- N = constrain(N-1,startChan,endChan-1); // 0-7 or 8-15
-
- SDATAC(targetSS); // exit Read Data Continuous mode to communicate with ADS
- setting = 0x00;
-// channelSettings[N][POWER_DOWN] = NO; // keep track of channel on/off in this array REMOVE?
- setting |= channelSettings[N][GAIN_SET]; // gain
- setting |= channelSettings[N][INPUT_TYPE_SET]; // input code
- if(useSRB2[N] == true){channelSettings[N][SRB2_SET] = YES;}else{channelSettings[N][SRB2_SET] = NO;}
- if(channelSettings[N][SRB2_SET] == YES) {bitSet(setting,3);} // close this SRB2 switch
- WREG(CH1SET+(N-startChan),setting,targetSS);
- // add or remove from inclusion in BIAS generation
- if(useInBias[N]){channelSettings[N][BIAS_SET] = YES;}else{channelSettings[N][BIAS_SET] = NO;}
- setting = RREG(BIAS_SENSP,targetSS); //get the current P bias settings
- if(channelSettings[N][BIAS_SET] == YES){
- bitSet(setting,N-startChan); //set this channel's bit to add it to the bias generation
- useInBias[N] = true;
- }else{
- bitClear(setting,N-startChan); // clear this channel's bit to remove from bias generation
- useInBias[N] = false;
- }
- WREG(BIAS_SENSP,setting,targetSS); delay(1); //send the modified byte back to the ADS
- setting = RREG(BIAS_SENSN,targetSS); //get the current N bias settings
- if(channelSettings[N][BIAS_SET] == YES){
- bitSet(setting,N-startChan); //set this channel's bit to add it to the bias generation
- }else{
- bitClear(setting,N-startChan); // clear this channel's bit to remove from bias generation
- }
- WREG(BIAS_SENSN,setting,targetSS); delay(1); //send the modified byte back to the ADS
-
- setting = 0x00;
- if(targetSS == BOARD_ADS && boardUseSRB1 == true) setting = 0x20;
- if(targetSS == DAISY_ADS && daisyUseSRB1 == true) setting = 0x20;
- WREG(MISC1,setting,targetSS); // close all SRB1 swtiches
-}
-
-// change the lead off detect settings for all channels
-void OpenBCI_32_Daisy::changeChannelLeadOffDetect()
-{
- byte setting, startChan, endChan, targetSS;
-
- for(int b=0; b<2; b++){
- if(b == 0){ targetSS = BOARD_ADS; startChan = 0; endChan = 8; }
- if(b == 1){
- if(!daisyPresent){ return; }
- targetSS = DAISY_ADS; startChan = 8; endChan = 16;
- }
-
- SDATAC(targetSS); delay(1); // exit Read Data Continuous mode to communicate with ADS
- byte P_setting = RREG(LOFF_SENSP,targetSS);
- byte N_setting = RREG(LOFF_SENSN,targetSS);
-
- for(int i=startChan; i<endChan; i++){
- if(leadOffSettings[i][PCHAN] == ON){
- bitSet(P_setting,i-startChan);
- }else{
- bitClear(P_setting,i-startChan);
- }
- if(leadOffSettings[i][NCHAN] == ON){
- bitSet(N_setting,i-startChan);
- }else{
- bitClear(N_setting,i-startChan);
- }
- WREG(LOFF_SENSP,P_setting,targetSS);
- WREG(LOFF_SENSN,N_setting,targetSS);
- }
- }
-}
-
-// change the lead off detect settings for specified channel
-void OpenBCI_32_Daisy::changeChannelLeadOffDetect(byte N) // N arrives as zero indexed
-{
- byte setting, targetSS, startChan; //, endChan;
-
- if(N < 0x08){
- targetSS = BOARD_ADS; startChan = 0x00; //endChan = 0x08;
- }else{
- if(!daisyPresent) { Serial0.println("no daisy attached!"); return; }
- targetSS = DAISY_ADS; startChan = 0x08; //endChan = 0x10;
- }
-
-
- // N = constrain(N-1,startChan,endChan-1);
- // SDATAC(targetSS); delay(1); // exit Read Data Continuous mode to communicate with ADS
- byte P_setting = RREG(LOFF_SENSP,targetSS);
- byte N_setting = RREG(LOFF_SENSN,targetSS);
-
- if(leadOffSettings[N][PCHAN] == ON){
- bitSet(P_setting,N-startChan);
- }else{
- bitClear(P_setting,N-startChan);
- }
- if(leadOffSettings[N][NCHAN] == ON){
- bitSet(N_setting,N-startChan);
- }else{
- bitClear(N_setting,N-startChan);
- }
- WREG(LOFF_SENSP,P_setting,targetSS);
- WREG(LOFF_SENSN,N_setting,targetSS);
-}
-
-void OpenBCI_32_Daisy::configureLeadOffDetection(byte amplitudeCode, byte freqCode)
-{
- amplitudeCode &= 0b00001100; //only these two bits should be used
- freqCode &= 0b00000011; //only these two bits should be used
-
- byte setting, targetSS;
- for(int i=0; i<2; i++){
- if(i == 0){ targetSS = BOARD_ADS; }
- if(i == 1){
- if(!daisyPresent){ return; }
- targetSS = DAISY_ADS;
- }
- setting = RREG(LOFF,targetSS); //get the current bias settings
- //reconfigure the byte to get what we want
- setting &= 0b11110000; //clear out the last four bits
- setting |= amplitudeCode; //set the amplitude
- setting |= freqCode; //set the frequency
- //send the config byte back to the hardware
- WREG(LOFF,setting,targetSS); delay(1); //send the modified byte back to the ADS
- }
-}
-
-//Configure the test signals that can be inernally generated by the ADS1299
-void OpenBCI_32_Daisy::configureInternalTestSignal(byte amplitudeCode, byte freqCode)
-{
- byte setting, targetSS;
- for(int i=0; i<2; i++){
- if(i == 0){ targetSS = BOARD_ADS;}
- if(i == 1){
- if(daisyPresent == false){ return; }
- targetSS = DAISY_ADS;
- }
- if (amplitudeCode == ADSTESTSIG_NOCHANGE) amplitudeCode = (RREG(CONFIG2,targetSS) & (0b00000100));
- if (freqCode == ADSTESTSIG_NOCHANGE) freqCode = (RREG(CONFIG2,targetSS) & (0b00000011));
- freqCode &= 0b00000011; //only the last two bits are used
- amplitudeCode &= 0b00000100; //only this bit is used
- byte setting = 0b11010000 | freqCode | amplitudeCode; //compose the code
- WREG(CONFIG2,setting,targetSS); delay(1);
- }
-}
-
-void OpenBCI_32_Daisy::changeInputType(byte inputCode){
-
- for(int i=0; i<numChannels; i++){
- channelSettings[i][INPUT_TYPE_SET] = inputCode;
- }
-
- writeChannelSettings();
-
-}
-
-// Start continuous data acquisition
-void OpenBCI_32_Daisy::startADS(void) // NEEDS ADS ADDRESS, OR BOTH?
-{
- sampleCounter = 0;
- firstDataPacket = true;
- RDATAC(BOTH_ADS); // enter Read Data Continuous mode
- delay(1);
- START(BOTH_ADS); // start the data acquisition
- delay(1);
- isRunning = true;
-}
-
-// Query to see if data is available from the ADS1299...return TRUE is data is available
-boolean OpenBCI_32_Daisy::isDataAvailable(void)
-{
- return (!(digitalRead(ADS_DRDY)));
-}
-
-// CALLED WHEN DRDY PIN IS ASSERTED. NEW ADS DATA AVAILABLE!
-void OpenBCI_32_Daisy::updateChannelData(){
- updateBoardData();
- if(daisyPresent) {updateDaisyData();}
-}
-
-void OpenBCI_32_Daisy::updateBoardData(){
- byte inByte;
- int byteCounter = 0;
-
- if(daisyPresent && !firstDataPacket){
- for(int i=0; i<8; i++){ // shift and average the byte arrays
- lastBoardChannelDataInt[i] = boardChannelDataInt[i]; // remember the last samples
- }
- }
- csLow(BOARD_ADS); // open SPI
- for(int i=0; i<3; i++){
- inByte = xfer(0x00); // read status register (1100 + LOFF_STATP + LOFF_STATN + GPIO[7:4])
- boardStat = (boardStat << 8) | inByte;
- }
- for(int i = 0; i<8; i++){
- for(int j=0; j<3; j++){ // read 24 bits of channel data in 8 3 byte chunks
- inByte = xfer(0x00);
- boardChannelDataRaw[byteCounter] = inByte; // raw data goes here
- byteCounter++;
- boardChannelDataInt[i] = (boardChannelDataInt[i]<<8) | inByte; // int data goes here
- }
- }
- csHigh(BOARD_ADS); // close SPI
- // need to convert 24bit to 32bit if using the filter
- for(int i=0; i<8; i++){ // convert 3 byte 2's compliment to 4 byte 2's compliment
- if(bitRead(boardChannelDataInt[i],23) == 1){
- boardChannelDataInt[i] |= 0xFF000000;
- }else{
- boardChannelDataInt[i] &= 0x00FFFFFF;
- }
- }
- if(daisyPresent && !firstDataPacket){
- byteCounter = 0;
- for(int i=0; i<8; i++){ // take the average of this and the last sample
- meanBoardChannelDataInt[i] = (lastBoardChannelDataInt[i] + boardChannelDataInt[i])/2;
- }
- for(int i=0; i<8; i++){ // place the average values in the meanRaw array
- for(int b=2; b>=0; b--){
- meanBoardDataRaw[byteCounter] = (meanBoardChannelDataInt[i] >> (b*8)) & 0xFF;
- byteCounter++;
- }
- }
- }
-
- if(firstDataPacket == true){firstDataPacket = false;}
-}
-
-void OpenBCI_32_Daisy::updateDaisyData(){
- byte inByte;
- int byteCounter = 0;
-
- if(daisyPresent && !firstDataPacket){
- for(int i=0; i<8; i++){ // shift and average the byte arrays
- lastDaisyChannelDataInt[i] = daisyChannelDataInt[i]; // remember the last samples
- }
- }
-
- csLow(DAISY_ADS); // open SPI
- for(int i=0; i<3; i++){
- inByte = xfer(0x00); // read status register (1100 + LOFF_STATP + LOFF_STATN + GPIO[7:4])
- daisyStat = (daisyStat << 8) | inByte;
- }
- for(int i = 0; i<8; i++){
- for(int j=0; j<3; j++){ // read 24 bits of channel data in 8 3 byte chunks
- inByte = xfer(0x00);
- daisyChannelDataRaw[byteCounter] = inByte; // raw data goes here
- byteCounter++;
- daisyChannelDataInt[i] = (daisyChannelDataInt[i]<<8) | inByte; // int data goes here
- }
- }
- csHigh(DAISY_ADS); // close SPI
- // need to convert 24bit to 32bit
- for(int i=0; i<8; i++){ // convert 3 byte 2's compliment to 4 byte 2's compliment
- if(bitRead(daisyChannelDataInt[i],23) == 1){
- daisyChannelDataInt[i] |= 0xFF000000;
- }else{
- daisyChannelDataInt[i] &= 0x00FFFFFF;
- }
- }
- if(daisyPresent && !firstDataPacket){
- byteCounter = 0;
- for(int i=0; i<8; i++){ // average this sample with the last sample
- meanDaisyChannelDataInt[i] = (lastDaisyChannelDataInt[i] + daisyChannelDataInt[i])/2;
- }
- for(int i=0; i<8; i++){ // place the average values in the meanRaw array
- for(int b=2; b>=0; b--){
- meanDaisyDataRaw[byteCounter] = (meanDaisyChannelDataInt[i] >> (b*8)) & 0xFF;
- byteCounter++;
- }
- }
- }
-
- if(firstDataPacket == true){firstDataPacket = false;}
-}
-
-// Stop the continuous data acquisition
-void OpenBCI_32_Daisy::stopADS()
-{
- STOP(BOTH_ADS); // stop the data acquisition
- delay(1);
- SDATAC(BOTH_ADS); // stop Read Data Continuous mode to communicate with ADS
- delay(1);
- isRunning = false;
-}
-
-
-//write as binary each channel's data
-void OpenBCI_32_Daisy::ADS_writeChannelData()
-{
-
- if(daisyPresent){
- if(sampleCounter % 2 != 0){ //CHECK SAMPLE ODD-EVEN AND SEND THE APPROPRIATE ADS DATA
- for (int i=0; i<24; i++){
- Serial0.write(meanBoardDataRaw[i]); // send board data on odd samples
- }
- }else{
- for (int i=0; i<24; i++){
- Serial0.write(meanDaisyDataRaw[i]); // send daisy data on even samples
- }
- }
- }else{
- for(int i=0; i<24; i++){
- Serial0.write(boardChannelDataRaw[i]);
- }
- }
-}
-
-
-//print out the state of all the control registers
-void OpenBCI_32_Daisy::printADSregisters(int targetSS)
-{
- boolean prevverbosityState = verbosity;
- verbosity = true; // set up for verbosity output
- RREGS(0x00,0x0C,targetSS); // read out the first registers
- delay(10); // stall to let all that data get read by the PC
- RREGS(0x0D,0x17-0x0D,targetSS); // read out the rest
- verbosity = prevverbosityState;
-}
-
-byte OpenBCI_32_Daisy::ADS_getDeviceID(int targetSS) { // simple hello world com check
- byte data = RREG(ID_REG,targetSS);
- if(verbosity){ // verbosity otuput
- Serial0.print("On Board ADS ID ");
- printHex(data); Serial0.println();
- }
- return data;
-}
-
-//System Commands
-void OpenBCI_32_Daisy::WAKEUP(int targetSS) {
- csLow(targetSS);
- xfer(_WAKEUP);
- csHigh(targetSS);
- delayMicroseconds(3); //must wait 4 tCLK cycles before sending another command (Datasheet, pg. 35)
-}
-
-void OpenBCI_32_Daisy::STANDBY(int targetSS) { // only allowed to send WAKEUP after sending STANDBY
- csLow(targetSS);
- xfer(_STANDBY);
- csHigh(targetSS);
-}
-
-void OpenBCI_32_Daisy::RESET(int targetSS) { // reset all the registers to default settings
- csLow(targetSS);
- xfer(_RESET);
- delayMicroseconds(12); //must wait 18 tCLK cycles to execute this command (Datasheet, pg. 35)
- csHigh(targetSS);
-}
-
-void OpenBCI_32_Daisy::START(int targetSS) { //start data conversion
- csLow(targetSS);
- xfer(_START); // KEEP ON-BOARD AND ON-DAISY IN SYNC
- csHigh(targetSS);
-}
-
-void OpenBCI_32_Daisy::STOP(int targetSS) { //stop data conversion
- csLow(targetSS);
- xfer(_STOP); // KEEP ON-BOARD AND ON-DAISY IN SYNC
- csHigh(targetSS);
-}
-
-void OpenBCI_32_Daisy::RDATAC(int targetSS) {
- csLow(targetSS);
- xfer(_RDATAC); // read data continuous
- csHigh(targetSS);
- delayMicroseconds(3);
-}
-void OpenBCI_32_Daisy::SDATAC(int targetSS) {
- csLow(targetSS);
- xfer(_SDATAC);
- csHigh(targetSS);
- delayMicroseconds(10); //must wait at least 4 tCLK cycles after executing this command (Datasheet, pg. 37)
-}
-
-
-// THIS NEEDS CLEANING AND UPDATING TO THE NEW FORMAT
-void OpenBCI_32_Daisy::RDATA(int targetSS) { // use in Stop Read Continuous mode when DRDY goes low
- byte inByte; // to read in one sample of the channels
- csLow(targetSS); // open SPI
- xfer(_RDATA); // send the RDATA command
- for(int i=0; i<3; i++){ // read in the status register and new channel data
- inByte = xfer(0x00);
- boardStat = (boardStat<<8) | inByte; // read status register (1100 + LOFF_STATP + LOFF_STATN + GPIO[7:4])
- }
- if(targetSS == BOARD_ADS){
- for(int i = 0; i<8; i++){
- for(int j=0; j<3; j++){ // read in the new channel data
- inByte = xfer(0x00);
- boardChannelDataInt[i] = (boardChannelDataInt[i]<<8) | inByte;
- }
- }
- for(int i=0; i<8; i++){
- if(bitRead(boardChannelDataInt[i],23) == 1){ // convert 3 byte 2's compliment to 4 byte 2's compliment
- boardChannelDataInt[i] |= 0xFF000000;
- }else{
- boardChannelDataInt[i] &= 0x00FFFFFF;
- }
- }
- }else{
- for(int i = 0; i<8; i++){
- for(int j=0; j<3; j++){ // read in the new channel data
- inByte = xfer(0x00);
- daisyChannelDataInt[i] = (daisyChannelDataInt[i]<<8) | inByte;
- }
- }
- for(int i=0; i<8; i++){
- if(bitRead(daisyChannelDataInt[i],23) == 1){ // convert 3 byte 2's compliment to 4 byte 2's compliment
- daisyChannelDataInt[i] |= 0xFF000000;
- }else{
- daisyChannelDataInt[i] &= 0x00FFFFFF;
- }
- }
- }
- csHigh(targetSS); // close SPI
-
-
-}
-
-byte OpenBCI_32_Daisy::RREG(byte _address,int targetSS) { // reads ONE register at _address
- byte opcode1 = _address + 0x20; // RREG expects 001rrrrr where rrrrr = _address
- csLow(targetSS); // open SPI
- xfer(opcode1); // opcode1
- xfer(0x00); // opcode2
- regData[_address] = xfer(0x00);// update mirror location with returned byte
- csHigh(targetSS); // close SPI
- if (verbosity){ // verbosity output
- printRegisterName(_address);
- printHex(_address);
- Serial0.print(", ");
- printHex(regData[_address]);
- Serial0.print(", ");
- for(byte j = 0; j<8; j++){
- Serial0.print(bitRead(regData[_address], 7-j));
- if(j!=7) Serial0.print(", ");
- }
-
- Serial0.println();
- }
- return regData[_address]; // return requested register value
-}
-
-
-// Read more than one register starting at _address
-void OpenBCI_32_Daisy::RREGS(byte _address, byte _numRegistersMinusOne, int targetSS) {
-
- byte opcode1 = _address + 0x20; // RREG expects 001rrrrr where rrrrr = _address
- csLow(targetSS); // open SPI
- xfer(opcode1); // opcode1
- xfer(_numRegistersMinusOne); // opcode2
- for(int i = 0; i <= _numRegistersMinusOne; i++){
- regData[_address + i] = xfer(0x00); // add register byte to mirror array
- }
- csHigh(targetSS); // close SPI
- if(verbosity){ // verbosity output
- for(int i = 0; i<= _numRegistersMinusOne; i++){
- printRegisterName(_address + i);
- printHex(_address + i);
- Serial0.print(", ");
- printHex(regData[_address + i]);
- Serial0.print(", ");
- for(int j = 0; j<8; j++){
- Serial0.print(bitRead(regData[_address + i], 7-j));
- if(j!=7) Serial0.print(", ");
- }
- Serial0.println();
- delay(30);
- }
- }
-}
-
-void OpenBCI_32_Daisy::WREG(byte _address, byte _value, int target_SS) { // Write ONE register at _address
- byte opcode1 = _address + 0x40; // WREG expects 010rrrrr where rrrrr = _address
- csLow(target_SS); // open SPI
- xfer(opcode1); // Send WREG command & address
- xfer(0x00); // Send number of registers to read -1
- xfer(_value); // Write the value to the register
- csHigh(target_SS); // close SPI
- regData[_address] = _value; // update the mirror array
- if(verbosity){ // verbosity output
- Serial0.print("Register ");
- printHex(_address);
- Serial0.println(" modified.");
- }
-}
-
-void OpenBCI_32_Daisy::WREGS(byte _address, byte _numRegistersMinusOne, int targetSS) {
- byte opcode1 = _address + 0x40; // WREG expects 010rrrrr where rrrrr = _address
- csLow(targetSS); // open SPI
- xfer(opcode1); // Send WREG command & address
- xfer(_numRegistersMinusOne); // Send number of registers to read -1
- for (int i=_address; i <=(_address + _numRegistersMinusOne); i++){
- xfer(regData[i]); // Write to the registers
- }
- csHigh(targetSS);
- if(verbosity){
- Serial0.print("Registers ");
- printHex(_address); Serial0.print(" to ");
- printHex(_address + _numRegistersMinusOne);
- Serial0.println(" modified");
- }
-}
-
-
-// <<<<<<<<<<<<<<<<<<<<<<<<< END OF ADS1299 FUNCTIONS >>>>>>>>>>>>>>>>>>>>>>>>>
-// ******************************************************************************
-// <<<<<<<<<<<<<<<<<<<<<<<<< LIS3DH FUNCTIONS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-
-
-void OpenBCI_32_Daisy::initialize_accel(byte g){
- byte setting = g | 0x08; // mask the g range for REG4
- pinMode(LIS3DH_DRDY,INPUT); // setup dataReady interupt from accelerometer
- LIS3DH_write(TMP_CFG_REG, 0x00); // DISable ADC inputs, enable temperature sensor
- LIS3DH_write(CTRL_REG1, 0x08); // disable accel, low power mode
- LIS3DH_write(CTRL_REG2, 0x00); // don't use the high pass filter
- LIS3DH_write(CTRL_REG3, 0x00); // no interrupts yet
- LIS3DH_write(CTRL_REG4, setting); // set scale to g, high resolution
- LIS3DH_write(CTRL_REG5, 0x00); // no boot, no fifo
- LIS3DH_write(CTRL_REG6, 0x00);
- LIS3DH_write(REFERENCE, 0x00);
- DRDYpinValue = lastDRDYpinValue = digitalRead(LIS3DH_DRDY); // take a reading to seed these variables
-}
-
-void OpenBCI_32_Daisy::enable_accel(byte Hz){
- for(int i=0; i<3; i++){
- axisData[i] = 0; // clear the axisData array so we don't get any stale news
- }
- byte setting = Hz | 0x07; // mask the desired frequency
- LIS3DH_write(CTRL_REG1, setting); // set freq and enable all axis in normal mode
- LIS3DH_write(CTRL_REG3, 0x10); // enable DRDY1 on INT1 (tied to PIC pin 0, LIS3DH_DRDY)
-}
-
-void OpenBCI_32_Daisy::disable_accel(){
- LIS3DH_write(CTRL_REG1, 0x08); // power down, low power mode
- LIS3DH_write(CTRL_REG3, 0x00); // disable DRDY1 on INT1
-}
-
-byte OpenBCI_32_Daisy::LIS3DH_getDeviceID(){
- return LIS3DH_read(WHO_AM_I);
-}
-
-boolean OpenBCI_32_Daisy::LIS3DH_DataAvailable(){
- boolean x = false;
- if((LIS3DH_read(STATUS_REG2) & 0x08) > 0) x = true; // read STATUS_REG
- return x;
-}
-
-boolean OpenBCI_32_Daisy::LIS3DH_DataReady(){
- boolean r = false;
- DRDYpinValue = digitalRead(LIS3DH_DRDY); // take a look at LIS3DH_DRDY pin
- if(DRDYpinValue != lastDRDYpinValue){ // if the value has changed since last looking
- if(DRDYpinValue == HIGH){ // see if this is the rising edge
- r = true; // if so, there is fresh data!
- }
- lastDRDYpinValue = DRDYpinValue; // keep track of the changing pin
- }
- return r;
-}
-
-void OpenBCI_32_Daisy::LIS3DH_writeAxisData(void){
- for(int i=0; i<3; i++){
- Serial0.write(highByte(axisData[i])); // write 16 bit axis data MSB first
- Serial0.write(lowByte(axisData[i])); // axisData is array of type short (16bit)
- axisData[i] = 0;
- }
-}
-
-byte OpenBCI_32_Daisy::LIS3DH_read(byte reg){
- reg |= READ_REG; // add the READ_REG bit
- csLow(LIS3DH_SS); // take spi
- spi.transfer(reg); // send reg to read
- byte inByte = spi.transfer(0x00); // retrieve data
- csHigh(LIS3DH_SS); // release spi
- return inByte;
-}
-
-void OpenBCI_32_Daisy::LIS3DH_write(byte reg, byte value){
- csLow(LIS3DH_SS); // take spi
- spi.transfer(reg); // send reg to write
- spi.transfer(value); // write value
- csHigh(LIS3DH_SS); // release spi
-}
-
-int OpenBCI_32_Daisy::LIS3DH_read16(byte reg){ // use for reading axis data.
- int inData;
- reg |= READ_REG | READ_MULTI; // add the READ_REG and READ_MULTI bits
- csLow(LIS3DH_SS); // take spi
- spi.transfer(reg); // send reg to start reading from
- inData = spi.transfer(0x00) | (spi.transfer(0x00) << 8); // get the data and arrange it
- csHigh(LIS3DH_SS); // release spi
- return inData;
-}
-
-int OpenBCI_32_Daisy::getX(){
- return LIS3DH_read16(OUT_X_L);
-}
-
-int OpenBCI_32_Daisy::getY(){
- return LIS3DH_read16(OUT_Y_L);
-}
-
-int OpenBCI_32_Daisy::getZ(){
- return LIS3DH_read16(OUT_Z_L);
-}
-
-void OpenBCI_32_Daisy::LIS3DH_updateAxisData(){
- axisData[0] = getX();
- axisData[1] = getY();
- axisData[2] = getZ();
-}
-
-void OpenBCI_32_Daisy::LIS3DH_readAllRegs(){
-
- byte inByte;
-
- for (int i = STATUS_REG_AUX; i <= WHO_AM_I; i++){
- inByte = LIS3DH_read(i);
- Serial0.print("0x0");Serial0.print(i,HEX);
- Serial0.print("\t");Serial0.println(inByte,HEX);
- delay(20);
- }
- Serial0.println();
-
- for (int i = TMP_CFG_REG; i <= INT1_DURATION; i++){
- inByte = LIS3DH_read(i);
- // printRegisterName(i);
- Serial0.print("0x");Serial0.print(i,HEX);
- Serial0.print("\t");Serial0.println(inByte,HEX);
- delay(20);
- }
- Serial0.println();
-
- for (int i = CLICK_CFG; i <= TIME_WINDOW; i++){
- inByte = LIS3DH_read(i);
- Serial0.print("0x");Serial0.print(i,HEX);
- Serial0.print("\t");Serial0.println(inByte,HEX);
- delay(20);
- }
-
-}
-
-
-
-// <<<<<<<<<<<<<<<<<<<<<<<<< END OF LIS3DH FUNCTIONS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-
-
-
-// String-Byte converters for ADS
-void OpenBCI_32_Daisy::printRegisterName(byte _address) {
- switch(_address){
- case ID_REG:
- Serial0.print("ADS_ID, "); break;
- case CONFIG1:
- Serial0.print("CONFIG1, "); break;
- case CONFIG2:
- Serial0.print("CONFIG2, "); break;
- case CONFIG3:
- Serial0.print("CONFIG3, "); break;
- case LOFF:
- Serial0.print("LOFF, "); break;
- case CH1SET:
- Serial0.print("CH1SET, "); break;
- case CH2SET:
- Serial0.print("CH2SET, "); break;
- case CH3SET:
- Serial0.print("CH3SET, "); break;
- case CH4SET:
- Serial0.print("CH4SET, "); break;
- case CH5SET:
- Serial0.print("CH5SET, "); break;
- case CH6SET:
- Serial0.print("CH6SET, "); break;
- case CH7SET:
- Serial0.print("CH7SET, "); break;
- case CH8SET:
- Serial0.print("CH8SET, "); break;
- case BIAS_SENSP:
- Serial0.print("BIAS_SENSP, "); break;
- case BIAS_SENSN:
- Serial0.print("BIAS_SENSN, "); break;
- case LOFF_SENSP:
- Serial0.print("LOFF_SENSP, "); break;
- case LOFF_SENSN:
- Serial0.print("LOFF_SENSN, "); break;
- case LOFF_FLIP:
- Serial0.print("LOFF_FLIP, "); break;
- case LOFF_STATP:
- Serial0.print("LOFF_STATP, "); break;
- case LOFF_STATN:
- Serial0.print("LOFF_STATN, "); break;
- case GPIO:
- Serial0.print("GPIO, "); break;
- case MISC1:
- Serial0.print("MISC1, "); break;
- case MISC2:
- Serial0.print("MISC2, "); break;
- case CONFIG4:
- Serial0.print("CONFIG4, "); break;
- default:
- break;
- }
-}
-
-// Used for printing HEX in verbosity feedback mode
-void OpenBCI_32_Daisy::printHex(byte _data){
- Serial0.print("0x");
- if(_data < 0x10) Serial0.print("0");
- Serial0.print(_data, HEX);
-}
--- a/OpenBCI_32_Daisy.h Sun Dec 04 03:38:44 2016 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,137 +0,0 @@
-/*
- insert header here
-
-*/
-#ifndef _____OpenBCI_32_Daisy__
-#define _____OpenBCI_32_Daisy__
-
-
-//#include <DSPI.h> // MBED: not needed
-//#include <WProgram.h> // MBED: not needed
-#include "PlatformDefs.h" // MBED: hardware emulation
-#include "Definitions_32_Daisy.h"
-
-
-
-
-class OpenBCI_32_Daisy {
-public:
- DSPI0 spi; // use DSPI library
-
-// BOARD
- boolean useAccel;
- boolean useAux;
- void initialize(void); // ADD DAISY USE outputType
- void printAllRegisters(void); // ADD DAISY USE outputType
- void sendChannelData(void); // send the current data with sample number
- void startStreaming(void); // ADD DAISY USE outputType
- void stopStreaming(void); // ADD DAISY USE outputType
-
-// ADS1299
- void initialize_ads(void);
- void updateChannelSettings(void);
- void writeChannelSettings(void);
- void writeChannelSettings(byte);
- void setChannelsToDefault(void);
- void setChannelsToEMG(void);
- void setChannelsToECG(void);
- void reportDefaultChannelSettings(void);
- void printADSregisters(int);
- void WAKEUP(int); // get out of low power mode
- void STANDBY(int); // go into low power mode
- void RESET(int); // set all register values to default
- void START(int); // start data acquisition
- void STOP(int); // stop data acquisition
- void RDATAC(int); // go into read data continuous mode
- void SDATAC(int); // get out of read data continuous mode
- void RDATA(int); // read data one-shot
- byte RREG(byte,int); // read one ADS register
- void RREGS(byte,byte,int); // read multiple ADS registers
- void WREG(byte,byte,int); // write one ADS register
- void WREGS(byte,byte,int); // write multiple ADS registers
- byte ADS_getDeviceID(int);
- void printRegisterName(byte); // used for verbosity
- void printHex(byte); // used for verbosity
- void updateChannelData(void); // retrieve data from ADS
- void updateBoardData(void);
- void updateDaisyData(void);
- byte xfer(byte); // SPI Transfer function
- void resetADS(int); // reset all the ADS1299's settings
- void startADS(void);
- void stopADS(void);
- void activateChannel(byte); // enable the selected channel
- void deactivateChannel(byte); // disable given channel 1-8(16)
- void configureLeadOffDetection(byte,byte);
- void changeChannelLeadOffDetect(void);
- void changeChannelLeadOffDetect(byte);
- void configureInternalTestSignal(byte,byte);
- void changeInputType(byte);
- boolean isDataAvailable(void);
- void ADS_writeChannelData(void);
- // void ADS_printDeviceID(int); //
- boolean smellDaisy(void);
- void removeDaisy(void);
- void attachDaisy(void);
- void writeAuxData(void);
-
- short auxData[3];
- byte regData[24]; // array is used to mirror register data
- byte lastBoardDataRaw[24];
- byte boardChannelDataRaw[24]; // array to hold raw channel data
- byte meanBoardDataRaw[24];
- byte lastDaisyDataRaw[24];
- byte daisyChannelDataRaw[24];
- byte meanDaisyDataRaw[24];
- int boardStat; // used to hold the status register
- int daisyStat;
- int boardChannelDataInt[8]; // array used when reading channel data as ints
- int lastBoardChannelDataInt[8];
- int meanBoardChannelDataInt[8];
- int daisyChannelDataInt[8]; // array used when reading channel data as ints
- int lastDaisyChannelDataInt[8];
- int meanDaisyChannelDataInt[8];
- int numChannels;
- byte channelSettings[16][6]; // array to hold current channel settings
- byte defaultChannelSettings[6]; // default channel settings
- byte leadOffSettings[16][2]; // used to control on/off of impedance measure for P and N side of each channel
- boolean useInBias[16]; // used to remember if we were included in Bias before channel power down
- boolean useSRB2[16];
- boolean boardUseSRB1; // used to keep track of if we are using SRB1
- boolean daisyUseSRB1;
- boolean verbosity; // turn on/off Serial verbosity
- boolean daisyPresent;
- boolean firstDataPacket;
- byte sampleCounter;
-
-// LIS3DH
- short axisData[3];
- void initialize_accel(byte); // initialize
- void enable_accel(byte); // start acceleromoeter with default settings
- void disable_accel(void); // stop data acquisition and go into low power mode
- byte LIS3DH_getDeviceID(void);
- byte LIS3DH_read(byte); // read a register on LIS3DH
- void LIS3DH_write(byte,byte); // write a register on LIS3DH
- int LIS3DH_read16(byte); // read two bytes, used to get axis data
- int getX(void);
- int getY(void);
- int getZ(void);
- boolean LIS3DH_DataReady(void); // check LIS3DH_DRDY pin
- boolean LIS3DH_DataAvailable(void); // check LIS3DH STATUS_REG2
- void LIS3DH_readAllRegs(void);
- void LIS3DH_writeAxisData(void);
- void LIS3DH_updateAxisData(void);
-
- void csLow(int);
- void csHigh(int);
-
-
-private:
-// ADS1299
- boolean isRunning;
-// LIS3DH
- int DRDYpinValue;
- int lastDRDYpinValue;
-
-};
-
-#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/OpenBCI_32bit_Library.cpp Sun Jan 22 04:10:11 2017 +0000
@@ -0,0 +1,2859 @@
+/*
+OpenBCI 32bit Library
+Place the containing folder into your libraries folder insdie the arduino folder in your Documents folder
+
+This library will work with a single OpenBCI 32bit board, or
+an OpenBCI 32bit board with an OpenBCI Daisy Module attached.
+
+*/
+
+#include "OpenBCI_32bit_Library.h"
+
+/***************************************************/
+/** PUBLIC METHODS *********************************/
+/***************************************************/
+// CONSTRUCTOR
+OpenBCI_32bit_Library::OpenBCI_32bit_Library() {
+ curBoardMode = OPENBCI_BOARD_MODE_DEFAULT;
+ daisyPresent = false;
+ sniffMode = false;
+ useAccel = false;
+ useAux = false;
+ channelDataAvailable = false;
+ initializeVariables();
+}
+
+/**
+* @description: The function the OpenBCI board will call in setup.
+* @author: AJ Keller (@pushtheworldllc)
+*/
+void OpenBCI_32bit_Library::begin(void) {
+ curBoardMode = OPENBCI_BOARD_MODE_DEFAULT;
+ // Bring the board up
+ boardBegin();
+}
+
+/**
+* @description: The function the OpenBCI board will call in setup. Turns sniff mode
+* on and allows you to tap into the serial port that is broken out on the OpenBCI
+* 32bit board. You must alter this file:
+* On Mac:
+* `/Users/username/Documents/Arduino/hardware/chipkit-core/pic32/variants/openbci/Board_Defs.h`
+* On Windows:
+* `C:\Users\username\Documents\Arduino\hardware\chipkit-core\pic32\variants\openbci\Board_Defs.h`
+* Specifically lines `311` and `313` from `7` and `10` to `11` and `12` for
+* `_SER1_TX_PIN` and `_SER1_RX_PIN` respectively. Check out this sweet gif if
+* you are a visual person http://g.recordit.co/3jH01sMD6Y.gif
+* You will need to reflash your board! But now you can connect to pins `11`
+* `12` via a FTDI serial port driver, really any serial to USB driver would
+* work. Remember to use 3V3, 115200 baud, and have a common ground!
+* @author: AJ Keller (@pushtheworldllc)
+*/
+void OpenBCI_32bit_Library::beginDebug(void) {
+ // Bring the board up
+ boolean started = boardBeginDebug();
+ curBoardMode = OPENBCI_BOARD_MODE_DEBUG;
+
+ sniffMode = true;
+
+ if (Serial1) {
+ if (started) {
+ Serial1.println("Board up");
+ } else {
+ Serial1.println("Board err");
+ }
+
+ }
+}
+
+/**
+* @description: The function the OpenBCI board will call in setup. This sets up the hardware serial port on D11 and D12
+* @author: AJ Keller (@pushtheworldllc)
+*/
+boolean OpenBCI_32bit_Library::beginSecondarySerial(void) {
+ // Initalize the serial 1 port
+ Serial1.begin(OPENBCI_BAUD_RATE);
+ return true;
+}
+
+
+/**
+* @description Called in every `loop()` and checks `Serial0`
+* @returns {boolean} - `true` if there is data ready to be read
+*/
+boolean OpenBCI_32bit_Library::hasDataSerial0(void) {
+ if (Serial0.available()) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/**
+* @description Called in every `loop()` and checks `Serial0`
+* @returns {boolean} - `true` if there is data ready to be read
+*/
+boolean OpenBCI_32bit_Library::hasDataSerial1(void) {
+ if (Serial1.available()) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/**
+* @description Called if `hasDataSerial0` is true, returns a char from `Serial0`
+* @returns {char} - A char from the serial port
+*/
+char OpenBCI_32bit_Library::getCharSerial0(void) {
+ return Serial0.read();
+}
+
+/**
+* @description Called if `hasDataSerial1` is true, returns a char from `Serial1`
+* @returns {char} - A char from the serial port
+*/
+char OpenBCI_32bit_Library::getCharSerial1(void) {
+ return Serial1.read();
+}
+
+/**
+* @description If `isSerialAvailableForRead()` is `true` then this function is
+* called. Reads from `Serial0` first and foremost, which comes from the RFduino.
+* If `sniffMode` is true and `Serial0` didn't have any data, we will try to
+* read from `Serial1`. If both are not available then we will return a `0x00`
+* which is NOT a command that the system will recognize, aka this function has
+* many safe guards.
+* @returns {char} - The character from the serial port.
+*/
+// char OpenBCI_32bit_Library::readOneSerialChar(void) {
+// if (Serial0.available()) {
+// return Serial0.read();
+// } else if (sniffMode && Serial1.available()) {
+// return Serial1.read();
+// } else {
+// return 0x00;
+// }
+// }
+
+/**
+* @description Public function for sending data to the PC
+* @param data {char *} - The data you want to send
+* @author AJ Keller (@pushtheworldllc)
+*/
+void OpenBCI_32bit_Library::writeSerial(char *data, int len) {
+ for (int i = 0; i < len; i++) {
+ Serial0.write(data[i]);
+ }
+}
+
+/**
+ * @description While processing incoming multi byte messages these will turn
+ * true.
+ * @return {boolean} - True if processing a message and false otherwise
+ */
+boolean OpenBCI_32bit_Library::isProcessingMultibyteMsg(void) {
+ return isProcessingIncomingSettingsChannel || isProcessingIncomingSettingsLeadOff || settingBoardMode;
+}
+
+/**
+ * @description Process one char at a time from serial port. This is the main
+ * command processor for the OpenBCI system. Considered mission critical for
+ * normal operation.
+ * @param `character` {char} - The character to process.
+ * @return {boolean} - `true` if the command was recognized, `false` if not
+ */
+boolean OpenBCI_32bit_Library::processChar(char character) {
+ if (sniffMode && Serial1) {
+ Serial1.print("pC: "); Serial1.println(character);
+ }
+
+ if (isProcessingMultibyteMsg()) {
+ if (isProcessingIncomingSettingsChannel) {
+ processIncomingChannelSettings(character);
+ } else if (isProcessingIncomingSettingsLeadOff) {
+ processIncomingLeadOffSettings(character);
+ } else if (settingBoardMode) {
+ processIncomingBoardMode(character);
+ }
+ } else { // Normal...
+ switch (character){
+ //TURN CHANNELS ON/OFF COMMANDS
+ case OPENBCI_CHANNEL_OFF_1:
+ streamSafeChannelDeactivate(1);
+ break;
+ case OPENBCI_CHANNEL_OFF_2:
+ streamSafeChannelDeactivate(2);
+ break;
+ case OPENBCI_CHANNEL_OFF_3:
+ streamSafeChannelDeactivate(3);
+ break;
+ case OPENBCI_CHANNEL_OFF_4:
+ streamSafeChannelDeactivate(4);
+ break;
+ case OPENBCI_CHANNEL_OFF_5:
+ streamSafeChannelDeactivate(5);
+ break;
+ case OPENBCI_CHANNEL_OFF_6:
+ streamSafeChannelDeactivate(6);
+ break;
+ case OPENBCI_CHANNEL_OFF_7:
+ streamSafeChannelDeactivate(7);
+ break;
+ case OPENBCI_CHANNEL_OFF_8:
+ streamSafeChannelDeactivate(8);
+ break;
+ case OPENBCI_CHANNEL_OFF_9:
+ streamSafeChannelDeactivate(9);
+ break;
+ case OPENBCI_CHANNEL_OFF_10:
+ streamSafeChannelDeactivate(10);
+ break;
+ case OPENBCI_CHANNEL_OFF_11:
+ streamSafeChannelDeactivate(11);
+ break;
+ case OPENBCI_CHANNEL_OFF_12:
+ streamSafeChannelDeactivate(12);
+ break;
+ case OPENBCI_CHANNEL_OFF_13:
+ streamSafeChannelDeactivate(13);
+ break;
+ case OPENBCI_CHANNEL_OFF_14:
+ streamSafeChannelDeactivate(14);
+ break;
+ case OPENBCI_CHANNEL_OFF_15:
+ streamSafeChannelDeactivate(15);
+ break;
+ case OPENBCI_CHANNEL_OFF_16:
+ streamSafeChannelDeactivate(16);
+ break;
+
+ case OPENBCI_CHANNEL_ON_1:
+ streamSafeChannelActivate(1);
+ break;
+ case OPENBCI_CHANNEL_ON_2:
+ streamSafeChannelActivate(2);
+ break;
+ case OPENBCI_CHANNEL_ON_3:
+ streamSafeChannelActivate(3);
+ break;
+ case OPENBCI_CHANNEL_ON_4:
+ streamSafeChannelActivate(4);
+ break;
+ case OPENBCI_CHANNEL_ON_5:
+ streamSafeChannelActivate(5);
+ break;
+ case OPENBCI_CHANNEL_ON_6:
+ streamSafeChannelActivate(6);
+ break;
+ case OPENBCI_CHANNEL_ON_7:
+ streamSafeChannelActivate(7);
+ break;
+ case OPENBCI_CHANNEL_ON_8:
+ streamSafeChannelActivate(8);
+ break;
+ case OPENBCI_CHANNEL_ON_9:
+ streamSafeChannelActivate(9);
+ break;
+ case OPENBCI_CHANNEL_ON_10:
+ streamSafeChannelActivate(10);
+ break;
+ case OPENBCI_CHANNEL_ON_11:
+ streamSafeChannelActivate(11);
+ break;
+ case OPENBCI_CHANNEL_ON_12:
+ streamSafeChannelActivate(12);
+ break;
+ case OPENBCI_CHANNEL_ON_13:
+ streamSafeChannelActivate(13);
+ break;
+ case OPENBCI_CHANNEL_ON_14:
+ streamSafeChannelActivate(14);
+ break;
+ case OPENBCI_CHANNEL_ON_15:
+ streamSafeChannelActivate(15);
+ break;
+ case OPENBCI_CHANNEL_ON_16:
+ streamSafeChannelActivate(16);
+ break;
+
+ // TEST SIGNAL CONTROL COMMANDS
+ case OPENBCI_TEST_SIGNAL_CONNECT_TO_GROUND:
+ activateAllChannelsToTestCondition(ADSINPUT_SHORTED,ADSTESTSIG_NOCHANGE,ADSTESTSIG_NOCHANGE);
+ break;
+ case OPENBCI_TEST_SIGNAL_CONNECT_TO_PULSE_1X_SLOW:
+ activateAllChannelsToTestCondition(ADSINPUT_TESTSIG,ADSTESTSIG_AMP_1X,ADSTESTSIG_PULSE_SLOW);
+ break;
+ case OPENBCI_TEST_SIGNAL_CONNECT_TO_PULSE_1X_FAST:
+ activateAllChannelsToTestCondition(ADSINPUT_TESTSIG,ADSTESTSIG_AMP_1X,ADSTESTSIG_PULSE_FAST);
+ break;
+ case OPENBCI_TEST_SIGNAL_CONNECT_TO_DC:
+ activateAllChannelsToTestCondition(ADSINPUT_TESTSIG,ADSTESTSIG_AMP_2X,ADSTESTSIG_DCSIG);
+ break;
+ case OPENBCI_TEST_SIGNAL_CONNECT_TO_PULSE_2X_SLOW:
+ activateAllChannelsToTestCondition(ADSINPUT_TESTSIG,ADSTESTSIG_AMP_2X,ADSTESTSIG_PULSE_SLOW);
+ break;
+ case OPENBCI_TEST_SIGNAL_CONNECT_TO_PULSE_2X_FAST:
+ activateAllChannelsToTestCondition(ADSINPUT_TESTSIG,ADSTESTSIG_AMP_2X,ADSTESTSIG_PULSE_FAST);
+ break;
+
+
+ // CHANNEL SETTING COMMANDS
+ case OPENBCI_CHANNEL_CMD_SET: // This is the first byte that tells us to expect more commands
+ isProcessingIncomingSettingsChannel = true;
+ numberOfIncomingSettingsProcessedChannel = 1;
+ break;
+
+ // LEAD OFF IMPEDANCE DETECTION COMMANDS
+ case OPENBCI_CHANNEL_IMPEDANCE_SET:
+ isProcessingIncomingSettingsLeadOff = true;
+ numberOfIncomingSettingsProcessedLeadOff = 1;
+ break;
+
+ case OPENBCI_CHANNEL_DEFAULT_ALL_SET: // reset all channel settings to default
+ if(!streaming) {
+ Serial0.println("updating channel settings to default");
+ sendEOT();
+ }
+ streamSafeSetAllChannelsToDefault();
+ break;
+ case OPENBCI_CHANNEL_DEFAULT_ALL_REPORT: // report the default settings
+ reportDefaultChannelSettings();
+ break;
+
+
+
+ // DAISY MODULE COMMANDS
+ case OPENBCI_CHANNEL_MAX_NUMBER_8: // use 8 channel mode
+ if(daisyPresent){
+ removeDaisy();
+ }
+ break;
+ case OPENBCI_CHANNEL_MAX_NUMBER_16: // use 16 channel mode
+ if(daisyPresent == false){
+ attachDaisy();
+ }
+ if(daisyPresent){
+ Serial0.print("16");
+ }else{
+ Serial0.print("8");
+ }
+ sendEOT();
+ break;
+
+ // STREAM DATA AND FILTER COMMANDS
+ case OPENBCI_STREAM_START: // stream data
+ if(useAccel){
+ enable_accel(RATE_25HZ);
+ } // fire up the accelerometer if you want it
+ streamStart(); // turn on the fire hose
+ break;
+ case OPENBCI_STREAM_STOP: // stop streaming data
+ if(useAccel){
+ disable_accel();
+ } // shut down the accelerometer if you're using it
+ streamStop();
+ break;
+
+ // INITIALIZE AND VERIFY
+ case OPENBCI_MISC_SOFT_RESET:
+ boardReset(); // initialize ADS and read device IDs
+ break;
+ // QUERY THE ADS AND ACCEL REGITSTERS
+ case OPENBCI_MISC_QUERY_REGISTER_SETTINGS:
+ if (!streaming) {
+ printAllRegisters(); // print the ADS and accelerometer register values
+ }
+ break;
+
+ // TIME SYNC
+ case OPENBCI_TIME_SET:
+ // Set flag to send time packet
+ if (streaming) {
+ sendTimeSyncUpPacket = true;
+ } else {
+ Serial0.print("Time stamp ON");
+ sendEOT();
+ }
+ timeSynced = true;
+ break;
+
+ case OPENBCI_TIME_STOP:
+ // Stop the Sync
+ timeSynced = false;
+ if (!streaming) {
+ Serial0.print("Time stamp OFF");
+ sendEOT();
+ }
+ break;
+
+ // PACKET SET TYPE
+ case OPENBCI_BOARD_MODE_SET:
+ // Tell this function which case that is
+ settingBoardMode = true;
+ break;
+
+ default:
+ return false;
+ }
+ }
+ return true;
+}
+
+/**
+ * @description Reads a status register to see if there is new accelerometer
+ * data.
+ * @returns {boolean} `true` if the accelerometer has new data.
+ */
+boolean OpenBCI_32bit_Library::accelHasNewData(void) {
+ return LIS3DH_DataAvailable();
+}
+
+/**
+ * @description Reads from the accelerometer to get new X, Y, and Z data. Updates
+ * the global array `axisData`.
+ */
+void OpenBCI_32bit_Library::accelUpdateAxisData(void) {
+ LIS3DH_updateAxisData();
+}
+
+/**
+ * @description Reads from the accelerometer to get new X, Y, and Z data.
+ */
+void OpenBCI_32bit_Library::accelWriteAxisData(void) {
+ LIS3DH_writeAxisData();
+}
+
+/**
+* @description: This is a function that is called once and confiures all pins on
+* the PIC32 uC
+* @author: AJ Keller (@pushtheworldllc)
+*/
+boolean OpenBCI_32bit_Library::boardBegin(void) {
+ // Initalize the serial port baud rate
+ Serial0.begin(OPENBCI_BAUD_RATE);
+
+ pinMode(OPENBCI_PIN_LED, OUTPUT);
+ pinMode(OPENBCI_PIN_PGC, OUTPUT);
+
+ // Startup for interrupt
+ setIntVector(_EXTERNAL_4_VECTOR, ADS_DRDY_Service); // connect interrupt to ISR
+ setIntPriority(_EXTERNAL_4_VECTOR, 4, 0); // set interrupt priority and sub priority
+ clearIntFlag(_EXTERNAL_4_IRQ); // these two need to be done together
+ setIntEnable(_EXTERNAL_4_IRQ); // clear any flags before enabing the irq
+
+ // Do a soft reset
+ boardReset();
+
+ return true;
+}
+
+/**
+* @description: This is a function that is called once and confiures all pins on
+* the PIC32 uC
+* @author: AJ Keller (@pushtheworldllc)
+*/
+boolean OpenBCI_32bit_Library::boardBeginDebug(void) {
+ // Initalize the serial port baud rate
+ Serial0.begin(OPENBCI_BAUD_RATE);
+
+ // Initalize the serial debug port
+ Serial1.begin(OPENBCI_BAUD_RATE);
+
+ // Startup for interrupt
+ setIntVector(_EXTERNAL_4_VECTOR, ADS_DRDY_Service); // connect interrupt to ISR
+ setIntPriority(_EXTERNAL_4_VECTOR, 4, 0); // set interrupt priority and sub priority
+ clearIntFlag(_EXTERNAL_4_IRQ); // these two need to be done together
+ setIntEnable(_EXTERNAL_4_IRQ); // clear any flags before enabing the irq
+
+ // Do a soft reset
+ boardReset();
+
+ return true;
+}
+
+/**
+* @description: This is a function that is called once and confiures the Pic to run in secondary serial mode
+* @param baudRate {int} - The baudRate you want the secondary serial port to run at.
+* @author: AJ Keller (@pushtheworldllc)
+*/
+boolean OpenBCI_32bit_Library::boardBeginDebug(int baudRate) {
+ // Initalize the serial port baud rate
+ Serial0.begin(OPENBCI_BAUD_RATE);
+
+ // Initalize the serial debug port
+ Serial1.begin(baudRate);
+
+ // Do a soft reset
+ boardReset();
+
+ return true;
+}
+
+/**
+* @description: This is a function that can be called multiple times, this is
+* what we refer to as a `soft reset`. You will hear/see this
+* many times.
+* @author: AJ Keller (@pushtheworldllc)
+*/
+void OpenBCI_32bit_Library::boardReset(void) {
+ initialize(); // initalizes accelerometer and on-board ADS and on-daisy ADS if present
+ delay(500);
+
+ Serial0.println("OpenBCI V3 8-16 channel");
+ configureLeadOffDetection(LOFF_MAG_6NA, LOFF_FREQ_31p2HZ);
+ Serial0.print("On Board ADS1299 Device ID: 0x"); Serial0.println(ADS_getDeviceID(ON_BOARD),HEX);
+ if(daisyPresent){ // library will set this in initialize() if daisy present and functional
+ Serial0.print("On Daisy ADS1299 Device ID: 0x"); Serial0.println(ADS_getDeviceID(ON_DAISY),HEX);
+ }
+ Serial0.print("LIS3DH Device ID: 0x"); Serial0.println(LIS3DH_getDeviceID(),HEX);
+ Serial0.println("Firmware: v2.0.0");
+ sendEOT();
+}
+
+/**
+* @description: Simple method to send the EOT over serial...
+* @author: AJ Keller (@pushtheworldllc)
+*/
+void OpenBCI_32bit_Library::sendEOT(void) {
+ Serial0.print("$$$");
+}
+
+
+
+void OpenBCI_32bit_Library::activateAllChannelsToTestCondition(byte testInputCode, byte amplitudeCode, byte freqCode)
+{
+ boolean wasStreaming = streaming;
+
+ // Stop streaming if you are currently streaming
+ if (streaming) {
+ streamStop();
+ }
+
+ //set the test signal to the desired state
+ configureInternalTestSignal(amplitudeCode,freqCode);
+ //change input type settings for all channels
+ changeInputType(testInputCode);
+
+ // Restart stream if need be
+ if (wasStreaming) {
+ streamStart();
+ }
+}
+
+/**
+ * @description When a 'z' is found on the serial port, we jump to this function
+ * where we continue to read from the serial port and read the
+ * remaining 4 bytes.
+ * @param `character` - {char} - The character you want to process...
+ */
+void OpenBCI_32bit_Library::processIncomingBoardMode(char c) {
+
+ if (isValidBoardType(c)) {
+ curBoardMode = c;
+ if (!streaming) {
+ Serial0.print("Success: Board type set");
+ sendEOT();
+ }
+ } else {
+ if (!streaming) {
+ Serial0.print("Failure: invalid board mode");
+ sendEOT();
+ }
+ }
+ settingBoardMode = false;
+}
+
+/**
+ * @description When a 'x' is found on the serial port, we jump to this function
+ * where we continue to read from the serial port and read the
+ * remaining 7 bytes.
+ */
+void OpenBCI_32bit_Library::processIncomingChannelSettings(char character) {
+
+ if (character == OPENBCI_CHANNEL_CMD_LATCH && numberOfIncomingSettingsProcessedChannel < OPENBCI_NUMBER_OF_BYTES_SETTINGS_CHANNEL - 1) {
+ // We failed somehow and should just abort
+ numberOfIncomingSettingsProcessedChannel = 0;
+
+ // put flag back down
+ isProcessingIncomingSettingsChannel = false;
+
+ if (!streaming) {
+ Serial0.print("Channel setting failure: too few chars"); sendEOT();
+ }
+
+ return;
+ }
+ switch (numberOfIncomingSettingsProcessedChannel) {
+ case 1: // channel number
+ currentChannelSetting = getChannelCommandForAsciiChar(character);
+ break;
+ case 2: // POWER_DOWN
+ channelSettings[currentChannelSetting][POWER_DOWN] = getNumberForAsciiChar(character);
+ break;
+ case 3: // GAIN_SET
+ channelSettings[currentChannelSetting][GAIN_SET] = getGainForAsciiChar(character);
+ break;
+ case 4: // INPUT_TYPE_SET
+ channelSettings[currentChannelSetting][INPUT_TYPE_SET] = getNumberForAsciiChar(character);
+ break;
+ case 5: // BIAS_SET
+ channelSettings[currentChannelSetting][BIAS_SET] = getNumberForAsciiChar(character);
+ break;
+ case 6: // SRB2_SET
+ channelSettings[currentChannelSetting][SRB2_SET] = getNumberForAsciiChar(character);
+ break;
+ case 7: // SRB1_SET
+ channelSettings[currentChannelSetting][SRB1_SET] = getNumberForAsciiChar(character);
+ break;
+ case 8: // 'X' latch
+ if (character != OPENBCI_CHANNEL_CMD_LATCH) {
+ if (!streaming) {
+ Serial0.print("Err: 9th char not ");
+ Serial0.println(OPENBCI_CHANNEL_CMD_LATCH);
+ sendEOT();
+ }
+ // We failed somehow and should just abort
+ numberOfIncomingSettingsProcessedChannel = 0;
+
+ // put flag back down
+ isProcessingIncomingSettingsChannel = false;
+
+ }
+ break;
+ default: // should have exited
+ if (!streaming) {
+ Serial0.print("Err: too many chars");
+ sendEOT();
+ }
+ // We failed somehow and should just abort
+ numberOfIncomingSettingsProcessedChannel = 0;
+
+ // put flag back down
+ isProcessingIncomingSettingsChannel = false;
+ return;
+ }
+
+ // increment the number of bytes processed
+ numberOfIncomingSettingsProcessedChannel++;
+
+ if (numberOfIncomingSettingsProcessedChannel == (OPENBCI_NUMBER_OF_BYTES_SETTINGS_CHANNEL)) {
+ // We are done processing channel settings...
+
+ if (!streaming) {
+ Serial0.print("Channel set for "); Serial0.println(currentChannelSetting + 1); sendEOT();
+ }
+
+ if (sniffMode && Serial1) {
+ Serial1.print("Channel set for "); Serial1.println(currentChannelSetting + 1);
+ }
+
+ // Set channel settings
+ streamSafeChannelSettingsForChannel(currentChannelSetting + 1, channelSettings[currentChannelSetting][POWER_DOWN], channelSettings[currentChannelSetting][GAIN_SET], channelSettings[currentChannelSetting][INPUT_TYPE_SET], channelSettings[currentChannelSetting][BIAS_SET], channelSettings[currentChannelSetting][SRB2_SET], channelSettings[currentChannelSetting][SRB1_SET]);
+
+ // Reset
+ numberOfIncomingSettingsProcessedChannel = 0;
+
+ // put flag back down
+ isProcessingIncomingSettingsChannel = false;
+ }
+}
+
+/**
+ * @description When a 'z' is found on the serial port, we jump to this function
+ * where we continue to read from the serial port and read the
+ * remaining 4 bytes.
+ * @param `character` - {char} - The character you want to process...
+ */
+void OpenBCI_32bit_Library::processIncomingLeadOffSettings(char character) {
+
+ if (character == OPENBCI_CHANNEL_IMPEDANCE_LATCH && numberOfIncomingSettingsProcessedLeadOff < OPENBCI_NUMBER_OF_BYTES_SETTINGS_LEAD_OFF - 1) {
+ // We failed somehow and should just abort
+ // reset numberOfIncomingSettingsProcessedLeadOff
+ numberOfIncomingSettingsProcessedLeadOff = 0;
+
+ // put flag back down
+ isProcessingIncomingSettingsLeadOff = false;
+
+ if (!streaming) {
+ Serial0.print("Lead off failure: too few chars"); sendEOT();
+ }
+
+ return;
+ }
+ switch (numberOfIncomingSettingsProcessedLeadOff) {
+ case 1: // channel number
+ currentChannelSetting = getChannelCommandForAsciiChar(character);
+ break;
+ case 2: // pchannel setting
+ leadOffSettings[currentChannelSetting][PCHAN] = getNumberForAsciiChar(character);
+ break;
+ case 3: // nchannel setting
+ leadOffSettings[currentChannelSetting][NCHAN] = getNumberForAsciiChar(character);
+ break;
+ case 4: // 'Z' latch
+ if (character != OPENBCI_CHANNEL_IMPEDANCE_LATCH) {
+ if (!streaming) {
+ Serial0.print("Err: 5th char not ");
+ Serial0.println(OPENBCI_CHANNEL_IMPEDANCE_LATCH);
+ sendEOT();
+ }
+ // We failed somehow and should just abort
+ // reset numberOfIncomingSettingsProcessedLeadOff
+ numberOfIncomingSettingsProcessedLeadOff = 0;
+
+ // put flag back down
+ isProcessingIncomingSettingsLeadOff = false;
+
+ }
+ break;
+ default: // should have exited
+ if (!streaming) {
+ Serial0.print("Err: too many chars ");
+ sendEOT();
+ }
+ // We failed somehow and should just abort
+ // reset numberOfIncomingSettingsProcessedLeadOff
+ numberOfIncomingSettingsProcessedLeadOff = 0;
+
+ // put flag back down
+ isProcessingIncomingSettingsLeadOff = false;
+ return;
+ }
+
+ // increment the number of bytes processed
+ numberOfIncomingSettingsProcessedLeadOff++;
+
+ if (numberOfIncomingSettingsProcessedLeadOff == (OPENBCI_NUMBER_OF_BYTES_SETTINGS_LEAD_OFF)) {
+ // We are done processing lead off settings...
+
+ if (!streaming) {
+ Serial0.print("Lead off set for "); Serial0.println(currentChannelSetting + 1); sendEOT();
+ }
+
+ if (sniffMode && Serial1) {
+ Serial1.print("Lead off set for "); Serial1.println(currentChannelSetting + 1);
+ }
+
+ // Set lead off settings
+ streamSafeLeadOffSetForChannel(currentChannelSetting + 1,leadOffSettings[currentChannelSetting][PCHAN],leadOffSettings[currentChannelSetting][NCHAN]);
+
+ // reset numberOfIncomingSettingsProcessedLeadOff
+ numberOfIncomingSettingsProcessedLeadOff = 0;
+
+ // put flag back down
+ isProcessingIncomingSettingsLeadOff = false;
+ }
+}
+
+
+boolean OpenBCI_32bit_Library::isValidBoardType(char c) {
+ switch (c) {
+ case OPENBCI_BOARD_MODE_DEFAULT:
+ case OPENBCI_BOARD_MODE_DEBUG:
+ case OPENBCI_BOARD_MODE_WIFI:
+ case OPENBCI_BOARD_MODE_INPUT_ANALOG:
+ case OPENBCI_BOARD_MODE_INPUT_DIGITAL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+
+// <<<<<<<<<<<<<<<<<<<<<<<<< BOARD WIDE FUNCTIONS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+
+void OpenBCI_32bit_Library::initialize(){
+ pinMode(SD_SS,OUTPUT); digitalWrite(SD_SS,HIGH); // de-select SDcard if present
+ pinMode(BOARD_ADS, OUTPUT); digitalWrite(BOARD_ADS,HIGH);
+ pinMode(DAISY_ADS, OUTPUT); digitalWrite(DAISY_ADS,HIGH);
+ pinMode(LIS3DH_SS,OUTPUT); digitalWrite(LIS3DH_SS,HIGH);
+ spi.begin();
+ spi.setSpeed(4000000); // use 4MHz for ADS and LIS3DH
+ spi.setMode(DSPI_MODE0); // default to SD card mode!
+ initialize_ads(); // hard reset ADS, set pin directions
+ initialize_accel(SCALE_4G); // set pin directions, G scale, DRDY interrupt, power down
+ initializeVariables();
+}
+
+// void __USER_ISR ADS_DRDY_Service() {
+void __USER_ISR ADS_DRDY_Service() {
+ clearIntFlag(_EXTERNAL_4_IRQ); // clear the irq, or else it will continually interrupt!
+ if(bitRead(PORTA,0) == 0){
+ board.channelDataAvailable = true;
+ }
+}
+
+void OpenBCI_32bit_Library::initializeVariables(void) {
+ streaming = false;
+ sendTimeSyncUpPacket = false;
+ timeSynced = false;
+ isProcessingIncomingSettingsChannel = false;
+ isProcessingIncomingSettingsLeadOff = false;
+ settingBoardMode = false;
+ numberOfIncomingSettingsProcessedChannel = 0;
+ numberOfIncomingSettingsProcessedLeadOff = 0;
+ currentChannelSetting = 0;
+ timeOffset = 0;
+ timeSetCharArrived = 0;
+ streamPacketType = (char)OPENBCI_PACKET_TYPE_V3;
+}
+
+void OpenBCI_32bit_Library::printAllRegisters(){
+ if(!isRunning){
+ Serial0.println("\nBoard ADS Registers");
+ printADSregisters(BOARD_ADS);
+ if(daisyPresent){
+ Serial0.println("\nDaisy ADS Registers");
+ printADSregisters(DAISY_ADS);
+ }
+ Serial0.println("\nLIS3DH Registers");
+ LIS3DH_readAllRegs();
+ sendEOT();
+ }
+}
+
+/**
+ * @description Writes channel data and `axisData` array to serial port in
+ * the correct stream packet format.
+ *
+ * Adds stop byte `OPENBCI_EOP_STND_ACCEL`. See `OpenBCI_32bit_Library_Definitions.h`
+ */
+void OpenBCI_32bit_Library::sendChannelDataWithAccel(void) {
+
+ Serial0.write(OPENBCI_SOP_SYMBOL);
+
+ Serial0.write(sampleCounter); // 1 byte
+
+ ADS_writeChannelData(); // 24 bytes
+
+ accelWriteAxisData(); // 6 bytes
+
+ Serial0.write(OPENBCI_EOP_STND_ACCEL); // 0xC0
+
+ sampleCounter++;
+
+}
+
+/**
+ * @description Writes channel data and `auxData` array to serial port in
+ * the correct stream packet format.
+ *
+ * Adds stop byte `OPENBCI_EOP_STND_RAW_AUX`. See `OpenBCI_32bit_Library_Definitions.h`
+ */
+void OpenBCI_32bit_Library::sendChannelDataWithRawAux(void) {
+
+ Serial0.write(OPENBCI_SOP_SYMBOL);
+
+ Serial0.write(sampleCounter); // 1 byte
+
+ ADS_writeChannelData(); // 24 bytes
+
+ writeAuxData(); // 6 bytes
+
+ Serial0.write(OPENBCI_EOP_STND_RAW_AUX); // 0xC1 - 1 byte
+
+ sampleCounter++;
+}
+
+/**
+ * @description Writes channel data, `axisData` array, and 4 byte unsigned time
+ * stamp in ms to serial port in the correct stream packet format.
+ *
+ * `axisData` will be split up and sent on the samples with `sampleCounter` of
+ * 7, 8, and 9 for X, Y, and Z respectively. Driver writers parse accordingly.
+ *
+ * If the global variable `sendTimeSyncUpPacket` is `true` (set by `processChar`
+ * getting a time sync set `<` command) then:
+ * Adds stop byte `OPENBCI_EOP_ACCEL_TIME_SET` and sets `sendTimeSyncUpPacket`
+ * to `false`.
+ * Else if `sendTimeSyncUpPacket` is `false` then:
+ * Adds stop byte `OPENBCI_EOP_ACCEL_TIME_SYNCED`
+ */
+void OpenBCI_32bit_Library::sendChannelDataWithTimeAndAccel(void) {
+
+ Serial0.write(OPENBCI_SOP_SYMBOL);
+
+ Serial0.write(sampleCounter); // 1 byte
+
+ ADS_writeChannelData(); // 24 bytes
+
+ // send two bytes of either accel data or blank
+ switch (sampleCounter % 10) {
+ case ACCEL_AXIS_X: // 7
+ LIS3DH_writeAxisDataForAxis(ACCEL_AXIS_X);
+ break;
+ case ACCEL_AXIS_Y: // 8
+ LIS3DH_writeAxisDataForAxis(ACCEL_AXIS_Y);
+ break;
+ case ACCEL_AXIS_Z: // 9
+ LIS3DH_writeAxisDataForAxis(ACCEL_AXIS_Z);
+ break;
+ default:
+ Serial0.write((byte)0x00); // high byte
+ Serial0.write((byte)0x00); // low byte
+ break;
+ }
+
+ writeTimeCurrent(); // 4 bytes
+
+ if (sendTimeSyncUpPacket) {
+ sendTimeSyncUpPacket = false;
+ Serial0.write(OPENBCI_EOP_ACCEL_TIME_SET); // 0xC3
+ } else {
+ Serial0.write(OPENBCI_EOP_ACCEL_TIME_SYNCED); // 0xC4
+ }
+
+ sampleCounter++;
+}
+
+/**
+ * @description Writes channel data, `auxData[0]` 2 bytes, and 4 byte unsigned
+ * time stamp in ms to serial port in the correct stream packet format.
+ *
+ * If the global variable `sendTimeSyncUpPacket` is `true` (set by `processChar`
+ * getting a time sync set `<` command) then:
+ * Adds stop byte `OPENBCI_EOP_RAW_AUX_TIME_SET` and sets `sendTimeSyncUpPacket`
+ * to `false`.
+ * Else if `sendTimeSyncUpPacket` is `false` then:
+ * Adds stop byte `OPENBCI_EOP_RAW_AUX_TIME_SYNCED`
+ */
+void OpenBCI_32bit_Library::sendChannelDataWithTimeAndRawAux(void) {
+
+ Serial0.print(OPENBCI_SOP_SYMBOL);
+
+ Serial0.write(sampleCounter); // 1 byte
+
+ ADS_writeChannelData(); // 24 bytes
+
+ Serial0.write(highByte(auxData[0])); // 2 bytes of aux data
+ Serial0.write(lowByte(auxData[0]));
+
+ writeTimeCurrent(); // 4 bytes
+
+ if (sendTimeSyncUpPacket) {
+ sendTimeSyncUpPacket = false;
+ Serial0.write(OPENBCI_EOP_RAW_AUX_TIME_SET); // 0xC5
+ } else {
+ Serial0.write(OPENBCI_EOP_RAW_AUX_TIME_SYNCED); // 0xC6
+ }
+
+ sampleCounter++;
+
+}
+
+/**
+ * @description Writes channel data, aux data, and footer to serial port. This
+ * is the old way to send channel data. Based on global variables `useAux`
+ * and `useAccel` Must keep for portability. Will look to deprecate in 3.0.0.
+ *
+ * If `useAccel` is `true` then sends data from `axisData` array and sets the
+ * contents of `axisData` to `0`.
+ * If `useAux` is `true` then sends data from `auxData` array and sets the
+ * contents of `auxData` to `0`.
+ *
+ * Adds stop byte `OPENBCI_EOP_STND_ACCEL`. See `OpenBCI_32bit_Library_Definitions.h`
+ */
+void OpenBCI_32bit_Library::sendChannelData(void) {
+
+ Serial0.print(OPENBCI_SOP_SYMBOL);
+
+ Serial0.write(sampleCounter); // 1 byte
+ ADS_writeChannelData(); // 24 bytes
+ if(useAux){
+ writeAuxData(); // 6 bytes of aux data
+ } else if(useAccel){ // or
+ LIS3DH_writeAxisData(); // 6 bytes of accelerometer data
+ } else{
+ for(int i=0; i<6; i++){
+ Serial0.write((byte)0x00);
+ }
+ }
+
+ Serial0.write(OPENBCI_EOP_STND_ACCEL); // 0xF0
+
+ sampleCounter++;
+}
+
+void OpenBCI_32bit_Library::writeAuxData(){
+ for(int i=0; i<3; i++){
+ Serial0.write(highByte(auxData[i])); // write 16 bit axis data MSB first
+ Serial0.write(lowByte(auxData[i])); // axisData is array of type short (16bit)
+ auxData[i] = 0; // reset auxData bytes to 0
+ }
+}
+
+void OpenBCI_32bit_Library::writeTimeCurrent(void) {
+ uint32_t newTime = millis(); // serialize the number, placing the MSB in lower packets
+ for (int j = 3; j >= 0; j--) {
+ Serial0.write(newTime >> (j*8));
+ }
+}
+
+//SPI communication method
+byte OpenBCI_32bit_Library::xfer(byte _data)
+{
+ byte inByte;
+ inByte = spi.transfer(_data);
+ return inByte;
+}
+
+//SPI chip select method
+void OpenBCI_32bit_Library::csLow(int SS)
+{ // select an SPI slave to talk to
+ switch(SS){
+ case BOARD_ADS:
+ spi.setMode(DSPI_MODE1);
+ spi.setSpeed(4000000);
+ digitalWrite(BOARD_ADS, LOW);
+ break;
+ case LIS3DH_SS:
+ spi.setMode(DSPI_MODE3);
+ spi.setSpeed(4000000);
+ digitalWrite(LIS3DH_SS, LOW);
+ break;
+ case SD_SS:
+ spi.setMode(DSPI_MODE0);
+ spi.setSpeed(20000000);
+ digitalWrite(SD_SS, LOW);
+ break;
+ case DAISY_ADS:
+ spi.setMode(DSPI_MODE1);
+ spi.setSpeed(4000000);
+ digitalWrite(DAISY_ADS, LOW);
+ break;
+ case BOTH_ADS:
+ spi.setMode(DSPI_MODE1);
+ spi.setSpeed(4000000);
+ digitalWrite(BOARD_ADS,LOW);
+ digitalWrite(DAISY_ADS,LOW);
+ break;
+ default:
+ break;
+ }
+}
+
+void OpenBCI_32bit_Library::csHigh(int SS)
+{ // deselect SPI slave
+ switch(SS){
+ case BOARD_ADS:
+ digitalWrite(BOARD_ADS, HIGH);
+ spi.setSpeed(20000000);
+ break;
+ case LIS3DH_SS:
+ digitalWrite(LIS3DH_SS, HIGH);
+ spi.setSpeed(20000000);
+ break;
+ case SD_SS:
+ digitalWrite(SD_SS, HIGH);
+ spi.setSpeed(4000000);
+ break;
+ case DAISY_ADS:
+ digitalWrite(DAISY_ADS, HIGH);
+ spi.setSpeed(20000000);
+ break;
+ case BOTH_ADS:
+ digitalWrite(BOARD_ADS, HIGH);
+ digitalWrite(DAISY_ADS, HIGH);
+ spi.setSpeed(20000000); break;
+ default:
+ break;
+ }
+ spi.setMode(DSPI_MODE0); // DEFAULT TO SD MODE!
+}
+
+// <<<<<<<<<<<<<<<<<<<<<<<<< END OF BOARD WIDE FUNCTIONS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+// *************************************************************************************
+// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ADS1299 FUNCTIONS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+
+
+void OpenBCI_32bit_Library::initialize_ads(){
+// recommended power up sequence requiers >Tpor (~32mS)
+ delay(50);
+ pinMode(ADS_RST,OUTPUT);
+ digitalWrite(ADS_RST,LOW); // reset pin connected to both ADS ICs
+ delayMicroseconds(4); // toggle reset pin
+ digitalWrite(ADS_RST,HIGH); // this will reset the Daisy if it is present
+ delayMicroseconds(20); // recommended to wait 18 Tclk before using device (~8uS);
+// initalize the data ready chip select and reset pins:
+ pinMode(ADS_DRDY, INPUT); // we get DRDY asertion from the on-board ADS
+ delay(40);
+ resetADS(BOARD_ADS); // reset the on-board ADS registers, and stop DataContinuousMode
+ delay(10);
+ WREG(CONFIG1,0xB6,BOARD_ADS); // tell on-board ADS to output its clk, set the data rate to 250SPS
+ delay(40);
+ resetADS(DAISY_ADS); // software reset daisy module if present
+ delay(10);
+ daisyPresent = smellDaisy(); // check to see if daisy module is present
+ if(!daisyPresent){
+ WREG(CONFIG1,0x96,BOARD_ADS); // turn off clk output if no daisy present
+ numChannels = 8; // expect up to 8 ADS channels
+ }else{
+ numChannels = 16; // expect up to 16 ADS channels
+ }
+
+ // DEFAULT CHANNEL SETTINGS FOR ADS
+ defaultChannelSettings[POWER_DOWN] = NO; // on = NO, off = YES
+ defaultChannelSettings[GAIN_SET] = ADS_GAIN24; // Gain setting
+ defaultChannelSettings[INPUT_TYPE_SET] = ADSINPUT_NORMAL;// input muxer setting
+ defaultChannelSettings[BIAS_SET] = YES; // add this channel to bias generation
+ defaultChannelSettings[SRB2_SET] = YES; // connect this P side to SRB2
+ defaultChannelSettings[SRB1_SET] = NO; // don't use SRB1
+
+ for(int i=0; i<numChannels; i++){
+ for(int j=0; j<6; j++){
+ channelSettings[i][j] = defaultChannelSettings[j]; // assign default settings
+ }
+ useInBias[i] = true; // keeping track of Bias Generation
+ useSRB2[i] = true; // keeping track of SRB2 inclusion
+ }
+ boardUseSRB1 = daisyUseSRB1 = false;
+
+ writeChannelSettings(); // write settings to the on-board and on-daisy ADS if present
+
+ WREG(CONFIG3,0b11101100,BOTH_ADS); delay(1); // enable internal reference drive and etc.
+ for(int i=0; i<numChannels; i++){ // turn off the impedance measure signal
+ leadOffSettings[i][PCHAN] = OFF;
+ leadOffSettings[i][NCHAN] = OFF;
+ }
+ verbosity = false; // when verbosity is true, there will be Serial feedback
+ firstDataPacket = true;
+
+ streaming = false;
+}
+
+//////////////////////////////////////////////
+///////////// STREAM METHODS /////////////////
+//////////////////////////////////////////////
+
+/**
+* @description Used to activate a channel, if running must stop and start after...
+* @param channelNumber int the channel you want to change
+* @author AJ Keller (@pushtheworldllc)
+*/
+void OpenBCI_32bit_Library::streamSafeChannelActivate(byte channelNumber) {
+ boolean wasStreaming = streaming;
+
+ // Stop streaming if you are currently streaming
+ if (streaming) {
+ streamStop();
+ }
+
+ // Activate the channel
+ activateChannel(channelNumber);
+
+ // Restart stream if need be
+ if (wasStreaming) {
+ streamStart();
+ }
+}
+
+/**
+* @description Used to deactivate a channel, if running must stop and start after...
+* @param channelNumber int the channel you want to change
+* @author AJ Keller (@pushtheworldllc)
+*/
+void OpenBCI_32bit_Library::streamSafeChannelDeactivate(byte channelNumber){
+ boolean wasStreaming = streaming;
+
+ // Stop streaming if you are currently streaming
+ if (streaming) {
+ streamStop();
+ }
+
+ // deactivate the channel
+ deactivateChannel(channelNumber);
+
+ // Restart stream if need be
+ if (wasStreaming) {
+ streamStart();
+ }
+}
+
+/**
+ * @description Used to set lead off for a channel, if running must stop and start after...
+ * @param `channelNumber` - [byte] - The channel you want to change
+ * @param `pInput` - [byte] - Apply signal to P input, either ON (1) or OFF (0)
+ * @param `nInput` - [byte] - Apply signal to N input, either ON (1) or OFF (0)
+ * @author AJ Keller (@pushtheworldllc)
+ */
+void OpenBCI_32bit_Library::streamSafeLeadOffSetForChannel(byte channelNumber, byte pInput, byte nInput) {
+ boolean wasStreaming = streaming;
+
+ // Stop streaming if you are currently streaming
+ if (streaming) {
+ streamStop();
+ }
+
+ changeChannelLeadOffDetect(channelNumber);
+
+ // leadOffSetForChannel(channelNumber, pInput, nInput);
+
+ // Restart stream if need be
+ if (wasStreaming) {
+ streamStart();
+ }
+}
+
+/**
+ * @description Used to set lead off for a channel, if running must stop and start after...
+ * @param see `.channelSettingsSetForChannel()` for parameters
+ * @author AJ Keller (@pushtheworldllc)
+ */
+void OpenBCI_32bit_Library::streamSafeChannelSettingsForChannel(byte channelNumber, byte powerDown, byte gain, byte inputType, byte bias, byte srb2, byte srb1) {
+ boolean wasStreaming = streaming;
+
+ // Stop streaming if you are currently streaming
+ if (streaming) {
+ streamStop();
+ }
+
+ writeChannelSettings(channelNumber);
+
+ // channelSettingsSetForChannel(channelNumber, powerDown, gain, inputType, bias, srb2, srb1);
+
+ // Restart stream if need be
+ if (wasStreaming) {
+ streamStart();
+ }
+}
+
+/**
+ * @description Used to report (Serial0.print) the default channel settings
+ * if running must stop and start after...
+ * @author AJ Keller (@pushtheworldllc)
+ */
+void OpenBCI_32bit_Library::streamSafeReportAllChannelDefaults(void) {
+ boolean wasStreaming = streaming;
+
+ // Stop streaming if you are currently streaming
+ if (streaming) {
+ streamStop();
+ }
+
+ reportDefaultChannelSettings();
+
+ // Restart stream if need be
+ if (wasStreaming) {
+ streamStart();
+ }
+}
+
+/**
+ * @description Used to set all channels on Board (and Daisy) to the default
+ * channel settings if running must stop and start after...
+ * @author AJ Keller (@pushtheworldllc)
+ */
+void OpenBCI_32bit_Library::streamSafeSetAllChannelsToDefault(void) {
+ boolean wasStreaming = streaming;
+
+ // Stop streaming if you are currently streaming
+ if (streaming) {
+ streamStop();
+ }
+
+ setChannelsToDefault();
+
+ // Restart stream if need be
+ if (wasStreaming) {
+ streamStart();
+ }
+}
+
+/**
+* @description Call this to start the streaming data from the ADS1299
+* @returns boolean if able to start streaming
+*/
+void OpenBCI_32bit_Library::streamStart(){ // needs daisy functionality
+ streaming = true;
+ startADS();
+ if (sniffMode && Serial1) {
+ Serial1.println("ADS Started");
+ }
+}
+
+/**
+* @description Call this to stop streaming from the ADS1299
+* @returns boolean if able to stop streaming
+*/
+void OpenBCI_32bit_Library::streamStop(){
+ streaming = false;
+ stopADS();
+ if (sniffMode && Serial1) {
+ Serial1.println("ADS Stopped");
+ }
+
+}
+
+//////////////////////////////////////////////
+////////////// DAISY METHODS /////////////////
+//////////////////////////////////////////////
+boolean OpenBCI_32bit_Library::smellDaisy(void){ // check if daisy present
+ boolean isDaisy = false;
+ byte setting = RREG(ID_REG,DAISY_ADS); // try to read the daisy product ID
+ if(verbosity){Serial0.print("Daisy ID 0x"); Serial0.println(setting,HEX); sendEOT();}
+ if(setting == ADS_ID) {isDaisy = true;} // should read as 0x3E
+ return isDaisy;
+}
+
+void OpenBCI_32bit_Library::removeDaisy(void){
+ if(daisyPresent){
+ // Daisy removed
+ SDATAC(DAISY_ADS);
+ RESET(DAISY_ADS);
+ STANDBY(DAISY_ADS);
+ daisyPresent = false;
+ if(!isRunning) {
+ Serial0.println("daisy removed");
+ sendEOT();
+ }
+ }else{
+ if(!isRunning) {
+ Serial0.println("no daisy to remove!");
+ sendEOT();
+ }
+ }
+}
+
+void OpenBCI_32bit_Library::attachDaisy(void){
+ WREG(CONFIG1,0xB6,BOARD_ADS); // tell on-board ADS to output the clk, set the data rate to 250SPS
+ delay(40);
+ resetADS(DAISY_ADS); // software reset daisy module if present
+ delay(10);
+ daisyPresent = smellDaisy();
+ if(!daisyPresent){
+ WREG(CONFIG1,0x96,BOARD_ADS); // turn off clk output if no daisy present
+ numChannels = 8; // expect up to 8 ADS channels
+ if(!isRunning) Serial0.println("no daisy to attach!");
+ }else{
+ numChannels = 16; // expect up to 16 ADS channels
+ if(!isRunning) Serial0.println("daisy attached");
+ }
+}
+
+//reset all the ADS1299's settings. Stops all data acquisition
+void OpenBCI_32bit_Library::resetADS(int targetSS)
+{
+ int startChan, stopChan;
+ if(targetSS == BOARD_ADS) {startChan = 1; stopChan = 8;}
+ if(targetSS == DAISY_ADS) {startChan = 9; stopChan = 16;}
+ RESET(targetSS); // send RESET command to default all registers
+ SDATAC(targetSS); // exit Read Data Continuous mode to communicate with ADS
+ delay(100);
+ // turn off all channels
+ for (int chan=startChan; chan <= stopChan; chan++) {
+ deactivateChannel(chan);
+ }
+}
+
+void OpenBCI_32bit_Library::setChannelsToDefault(void){
+ for(int i=0; i<numChannels; i++){
+ for(int j=0; j<6; j++){
+ channelSettings[i][j] = defaultChannelSettings[j];
+ }
+ useInBias[i] = true; // keeping track of Bias Generation
+ useSRB2[i] = true; // keeping track of SRB2 inclusion
+ }
+ boardUseSRB1 = daisyUseSRB1 = false;
+
+ writeChannelSettings(); // write settings to on-board ADS
+
+ for(int i=0; i<numChannels; i++){ // turn off the impedance measure signal
+ leadOffSettings[i][PCHAN] = OFF;
+ leadOffSettings[i][NCHAN] = OFF;
+ }
+ changeChannelLeadOffDetect(); // write settings to all ADS
+
+
+ WREG(MISC1,0x00,BOARD_ADS); // open SRB1 switch on-board
+ if(daisyPresent){ WREG(MISC1,0x00,DAISY_ADS); } // open SRB1 switch on-daisy
+}
+
+// void OpenBCI_32bit_Library::setChannelsToDefault(void){
+
+// // Reset the global channel settings array to default
+// resetChannelSettingsArrayToDefault(channelSettings);
+// // Write channel settings to board (and daisy) ADS
+// channelSettingsArraySetForAll();
+
+// // Reset the global lead off settings array to default
+// resetLeadOffArrayToDefault(leadOffSettings);
+// // Write lead off settings to board (and daisy) ADS
+// leadOffSetForAllChannels();
+
+// WREG(MISC1,0x00,BOARD_ADS); // open SRB1 switch on-board
+// if(daisyPresent){ // open SRB1 switch on-daisy
+// WREG(MISC1,0x00,DAISY_ADS);
+// }
+// }
+
+/**
+ * @description Writes the default channel settings over the serial port
+ */
+void OpenBCI_32bit_Library::reportDefaultChannelSettings(void){
+ Serial0.write(getDefaultChannelSettingForSettingAscii(POWER_DOWN)); // on = NO, off = YES
+ Serial0.write(getDefaultChannelSettingForSettingAscii(GAIN_SET)); // Gain setting
+ Serial0.write(getDefaultChannelSettingForSettingAscii(INPUT_TYPE_SET)); // input muxer setting
+ Serial0.write(getDefaultChannelSettingForSettingAscii(BIAS_SET)); // add this channel to bias generation
+ Serial0.write(getDefaultChannelSettingForSettingAscii(SRB2_SET)); // connect this P side to SRB2
+ Serial0.write(getDefaultChannelSettingForSettingAscii(SRB1_SET)); // don't use SRB1
+ sendEOT();
+}
+
+/**
+ * @description Set all channels using global channelSettings array
+ * @author AJ Keller (@pushtheworldllc)
+ */
+// void OpenBCI_32bit_Library::channelSettingsArraySetForAll(void) {
+// byte channelNumberUpperLimit;
+
+// // The upper limit of the channels, either 8 or 16
+// channelNumberUpperLimit = daisyPresent ? OPENBCI_NUMBER_OF_CHANNELS_DAISY : OPENBCI_NUMBER_OF_CHANNELS_DEFAULT;
+
+// // Loop through all channels
+// for (byte i = 1; i <= channelNumberUpperLimit; i++) {
+// // Set for this channel
+// channelSettingsSetForChannel(i, channelSettings[i][POWER_DOWN], channelSettings[i][GAIN_SET], channelSettings[i][INPUT_TYPE_SET], channelSettings[i][BIAS_SET], channelSettings[i][SRB2_SET], channelSettings[i][SRB1_SET]);
+// }
+// }
+
+/**
+ * @description Set channel using global channelSettings array for channelNumber
+ * @param `channelNumber` - [byte] - 1-16 channel number
+ * @author AJ Keller (@pushtheworldllc)
+ */
+// void OpenBCI_32bit_Library::channelSettingsArraySetForChannel(byte channelNumber) {
+// // contstrain the channel number to 0-15
+// char index = getConstrainedChannelNumber(channelNumber);
+
+// // Set for this channel
+// channelSettingsSetForChannel(channelNumber, channelSettings[index][POWER_DOWN], channelSettings[index][GAIN_SET], channelSettings[index][INPUT_TYPE_SET], channelSettings[index][BIAS_SET], channelSettings[index][SRB2_SET], channelSettings[index][SRB1_SET]);
+// }
+
+/**
+ * @description To add a usability abstraction layer above channel setting commands. Due to the
+ * extensive and highly specific nature of the channel setting command chain.
+ * @param `channelNumber` - [byte] (1-16) for index, so convert channel to array prior
+ * @param `powerDown` - [byte] - YES (1) or NO (0)
+ * Powers channel down
+ * @param `gain` - [byte] - Sets the gain for the channel
+ * ADS_GAIN01 (0b00000000) // 0x00
+ * ADS_GAIN02 (0b00010000) // 0x10
+ * ADS_GAIN04 (0b00100000) // 0x20
+ * ADS_GAIN06 (0b00110000) // 0x30
+ * ADS_GAIN08 (0b01000000) // 0x40
+ * ADS_GAIN12 (0b01010000) // 0x50
+ * ADS_GAIN24 (0b01100000) // 0x60
+ * @param `inputType` - [byte] - Selects the ADC channel input source, either:
+ * ADSINPUT_NORMAL (0b00000000)
+ * ADSINPUT_SHORTED (0b00000001)
+ * ADSINPUT_BIAS_MEAS (0b00000010)
+ * ADSINPUT_MVDD (0b00000011)
+ * ADSINPUT_TEMP (0b00000100)
+ * ADSINPUT_TESTSIG (0b00000101)
+ * ADSINPUT_BIAS_DRP (0b00000110)
+ * ADSINPUT_BIAL_DRN (0b00000111)
+ * @param `bias` - [byte] (YES (1) -> Include in bias (default), NO (0) -> remove from bias)
+ * selects to include the channel input in bias generation
+ * @param `srb2` - [byte] (YES (1) -> Connect this input to SRB2 (default),
+ * NO (0) -> Disconnect this input from SRB2)
+ * Select to connect (YES) this channel's P input to the SRB2 pin. This closes
+ * a switch between P input and SRB2 for the given channel, and allows the
+ * P input to also remain connected to the ADC.
+ * @param `srb1` - [byte] (YES (1) -> connect all N inputs to SRB1,
+ * NO (0) -> Disconnect all N inputs from SRB1 (default))
+ * Select to connect (YES) all channels' N inputs to SRB1. This effects all pins,
+ * and disconnects all N inputs from the ADC.
+ * @author AJ Keller (@pushtheworldllc)
+ */
+// void OpenBCI_32bit_Library::channelSettingsSetForChannel(byte channelNumber, byte powerDown, byte gain, byte inputType, byte bias, byte srb2, byte srb1) {
+// byte setting, targetSS;
+
+// // contstrain the channel number to 0-15
+// char index = getConstrainedChannelNumber(channelNumber);
+
+// // Get the slave select pin for this channel
+// targetSS = getTargetSSForConstrainedChannelNumber(index);
+
+// if (sniffMode && Serial1) {
+// if (targetSS == BOARD_ADS) {
+// Serial1.print("Set channel "); Serial1.print(channelNumber); Serial1.println(" settings");
+// }
+// }
+
+// // first, disable any data collection
+// SDATAC(targetSS); delay(1); // exit Read Data Continuous mode to communicate with ADS
+
+// setting = 0x00;
+
+// // Set the power down bit
+// if(powerDown == YES) {
+// setting |= 0x80;
+// }
+
+// // Set the gain bits
+// setting |= gain;
+
+// // Set input type bits
+// setting |= inputType;
+
+// if(srb2 == YES){
+// setting |= 0x08; // close this SRB2 switch
+// useSRB2[index] = true; // keep track of SRB2 usage
+// }else{
+// useSRB2[index] = false;
+// }
+
+// byte channelNumberRegister = 0x00;
+
+// // Since we are addressing 8 bit registers, we need to subtract 8 from the
+// // channelNumber if we are addressing the Daisy ADS
+// if (targetSS == DAISY_ADS) {
+// channelNumberRegister = index - OPENBCI_NUMBER_OF_CHANNELS_DEFAULT;
+// } else {
+// channelNumberRegister = index;
+// }
+// WREG(CH1SET+channelNumberRegister, setting, targetSS); // write this channel's register settings
+
+// // add or remove from inclusion in BIAS generation
+// setting = RREG(BIAS_SENSP,targetSS); //get the current P bias settings
+// if(bias == YES){
+// useInBias[index] = true;
+// bitSet(setting,channelNumberRegister); //set this channel's bit to add it to the bias generation
+// }else{
+// useInBias[index] = false;
+// bitClear(setting,channelNumberRegister); // clear this channel's bit to remove from bias generation
+// }
+// WREG(BIAS_SENSP,setting,targetSS); delay(1); //send the modified byte back to the ADS
+
+// setting = RREG(BIAS_SENSN,targetSS); //get the current N bias settings
+// if(bias == YES){
+// bitSet(setting,channelNumberRegister); //set this channel's bit to add it to the bias generation
+// }else{
+// bitClear(setting,channelNumberRegister); // clear this channel's bit to remove from bias generation
+// }
+// WREG(BIAS_SENSN,setting,targetSS); delay(1); //send the modified byte back to the ADS
+
+// byte startChan = targetSS == BOARD_ADS ? 0 : OPENBCI_CHANNEL_MAX_NUMBER_8 - 1;
+// byte endChan = targetSS == BOARD_ADS ? OPENBCI_CHANNEL_MAX_NUMBER_8 : OPENBCI_CHANNEL_MAX_NUMBER_16 - 1;
+// // if SRB1 is closed or open for one channel, it will be the same for all channels
+// if(srb1 == YES){
+// for(int i=startChan; i<endChan; i++){
+// channelSettings[i][SRB1_SET] = YES;
+// }
+// if(targetSS == BOARD_ADS) boardUseSRB1 = true;
+// if(targetSS == DAISY_ADS) daisyUseSRB1 = true;
+// setting = 0x20; // close SRB1 swtich
+// }
+// if(srb1 == NO){
+// for(int i=startChan; i<endChan; i++){
+// channelSettings[i][SRB1_SET] = NO;
+// }
+// if(targetSS == BOARD_ADS) boardUseSRB1 = false;
+// if(targetSS == DAISY_ADS) daisyUseSRB1 = false;
+// setting = 0x00; // open SRB1 switch
+// }
+// WREG(MISC1,setting,targetSS);
+// }
+
+// write settings for ALL 8 channels for a given ADS board
+// channel settings: powerDown, gain, inputType, SRB2, SRB1
+void OpenBCI_32bit_Library::writeChannelSettings(){
+ boolean use_SRB1 = false;
+ byte setting, startChan, endChan, targetSS;
+
+ for(int b=0; b<2; b++){
+ if(b == 0){ targetSS = BOARD_ADS; startChan = 0; endChan = 8; }
+ if(b == 1){
+ if(!daisyPresent){ return; }
+ targetSS = DAISY_ADS; startChan = 8; endChan = 16;
+ }
+
+ SDATAC(targetSS); delay(1); // exit Read Data Continuous mode to communicate with ADS
+
+ for(byte i=startChan; i<endChan; i++){ // write 8 channel settings
+ setting = 0x00;
+ if(channelSettings[i][POWER_DOWN] == YES){setting |= 0x80;}
+ setting |= channelSettings[i][GAIN_SET]; // gain
+ setting |= channelSettings[i][INPUT_TYPE_SET]; // input code
+ if(channelSettings[i][SRB2_SET] == YES){
+ setting |= 0x08; // close this SRB2 switch
+ useSRB2[i] = true; // remember SRB2 state for this channel
+ }else{
+ useSRB2[i] = false; // rememver SRB2 state for this channel
+ }
+ WREG(CH1SET+(i-startChan),setting,targetSS); // write this channel's register settings
+
+ // add or remove this channel from inclusion in BIAS generation
+ setting = RREG(BIAS_SENSP,targetSS); //get the current P bias settings
+ if(channelSettings[i][BIAS_SET] == YES){
+ bitSet(setting,i-startChan); useInBias[i] = true; //add this channel to the bias generation
+ }else{
+ bitClear(setting,i-startChan); useInBias[i] = false; //remove this channel from bias generation
+ }
+ WREG(BIAS_SENSP,setting,targetSS); delay(1); //send the modified byte back to the ADS
+
+ setting = RREG(BIAS_SENSN,targetSS); //get the current N bias settings
+ if(channelSettings[i][BIAS_SET] == YES){
+ bitSet(setting,i-startChan); //set this channel's bit to add it to the bias generation
+ }else{
+ bitClear(setting,i-startChan); // clear this channel's bit to remove from bias generation
+ }
+ WREG(BIAS_SENSN,setting,targetSS); delay(1); //send the modified byte back to the ADS
+
+ if(channelSettings[i][SRB1_SET] == YES){
+ use_SRB1 = true; // if any of the channel setting closes SRB1, it is closed for all
+ }
+ } // end of CHnSET and BIAS settings
+ } // end of board select loop
+ if(use_SRB1){
+ for(int i=startChan; i<endChan; i++){
+ channelSettings[i][SRB1_SET] = YES;
+ }
+ WREG(MISC1,0x20,targetSS); // close SRB1 swtich
+ if(targetSS == BOARD_ADS){ boardUseSRB1 = true; }
+ if(targetSS == DAISY_ADS){ daisyUseSRB1 = true; }
+ }else{
+ for(int i=startChan; i<endChan; i++){
+ channelSettings[i][SRB1_SET] = NO;
+ }
+ WREG(MISC1,0x00,targetSS); // open SRB1 switch
+ if(targetSS == BOARD_ADS){ boardUseSRB1 = false; }
+ if(targetSS == DAISY_ADS){ daisyUseSRB1 = false; }
+ }
+}
+
+// write settings for a SPECIFIC channel on a given ADS board
+void OpenBCI_32bit_Library::writeChannelSettings(byte N){
+
+ byte setting, startChan, endChan, targetSS;
+ if(N < 9){ // channels 1-8 on board
+ targetSS = BOARD_ADS; startChan = 0; endChan = 8;
+ }else{ // channels 9-16 on daisy module
+ if(!daisyPresent) { return; }
+ targetSS = DAISY_ADS; startChan = 8; endChan = 16;
+ }
+// function accepts channel 1-16, must be 0 indexed to work with array
+ N = constrain(N-1,startChan,endChan-1); //subtracts 1 so that we're counting from 0, not 1
+// first, disable any data collection
+ SDATAC(targetSS); delay(1); // exit Read Data Continuous mode to communicate with ADS
+
+ setting = 0x00;
+ if(channelSettings[N][POWER_DOWN] == YES) setting |= 0x80;
+ setting |= channelSettings[N][GAIN_SET]; // gain
+ setting |= channelSettings[N][INPUT_TYPE_SET]; // input code
+ if(channelSettings[N][SRB2_SET] == YES){
+ setting |= 0x08; // close this SRB2 switch
+ useSRB2[N] = true; // keep track of SRB2 usage
+ }else{
+ useSRB2[N] = false;
+ }
+ WREG(CH1SET+(N-startChan), setting, targetSS); // write this channel's register settings
+
+ // add or remove from inclusion in BIAS generation
+ setting = RREG(BIAS_SENSP,targetSS); //get the current P bias settings
+ if(channelSettings[N][BIAS_SET] == YES){
+ useInBias[N] = true;
+ bitSet(setting,N-startChan); //set this channel's bit to add it to the bias generation
+ }else{
+ useInBias[N] = false;
+ bitClear(setting,N-startChan); // clear this channel's bit to remove from bias generation
+ }
+ WREG(BIAS_SENSP,setting,targetSS); delay(1); //send the modified byte back to the ADS
+ setting = RREG(BIAS_SENSN,targetSS); //get the current N bias settings
+ if(channelSettings[N][BIAS_SET] == YES){
+ bitSet(setting,N-startChan); //set this channel's bit to add it to the bias generation
+ }else{
+ bitClear(setting,N-startChan); // clear this channel's bit to remove from bias generation
+ }
+ WREG(BIAS_SENSN,setting,targetSS); delay(1); //send the modified byte back to the ADS
+
+// if SRB1 is closed or open for one channel, it will be the same for all channels
+ if(channelSettings[N][SRB1_SET] == YES){
+ for(int i=startChan; i<endChan; i++){
+ channelSettings[i][SRB1_SET] = YES;
+ }
+ if(targetSS == BOARD_ADS) boardUseSRB1 = true;
+ if(targetSS == DAISY_ADS) daisyUseSRB1 = true;
+ setting = 0x20; // close SRB1 swtich
+ }
+ if(channelSettings[N][SRB1_SET] == NO){
+ for(int i=startChan; i<endChan; i++){
+ channelSettings[i][SRB1_SET] = NO;
+ }
+ if(targetSS == BOARD_ADS) boardUseSRB1 = false;
+ if(targetSS == DAISY_ADS) daisyUseSRB1 = false;
+ setting = 0x00; // open SRB1 switch
+ }
+ WREG(MISC1,setting,targetSS);
+}
+
+// deactivate the given channel.
+void OpenBCI_32bit_Library::deactivateChannel(byte N)
+{
+ byte setting, startChan, endChan, targetSS;
+ if(N < 9){
+ targetSS = BOARD_ADS; startChan = 0; endChan = 8;
+ }else{
+ if(!daisyPresent) { return; }
+ targetSS = DAISY_ADS; startChan = 8; endChan = 16;
+ }
+ SDATAC(targetSS); delay(1); // exit Read Data Continuous mode to communicate with ADS
+ N = constrain(N-1,startChan,endChan-1); //subtracts 1 so that we're counting from 0, not 1
+
+ setting = RREG(CH1SET+(N-startChan),targetSS); delay(1); // get the current channel settings
+ bitSet(setting,7); // set bit7 to shut down channel
+ bitClear(setting,3); // clear bit3 to disclude from SRB2 if used
+ WREG(CH1SET+(N-startChan),setting,targetSS); delay(1); // write the new value to disable the channel
+
+ //remove the channel from the bias generation...
+ setting = RREG(BIAS_SENSP,targetSS); delay(1); //get the current bias settings
+ bitClear(setting,N-startChan); //clear this channel's bit to remove from bias generation
+ WREG(BIAS_SENSP,setting,targetSS); delay(1); //send the modified byte back to the ADS
+
+ setting = RREG(BIAS_SENSN,targetSS); delay(1); //get the current bias settings
+ bitClear(setting,N-startChan); //clear this channel's bit to remove from bias generation
+ WREG(BIAS_SENSN,setting,targetSS); delay(1); //send the modified byte back to the ADS
+
+ leadOffSettings[N][0] = leadOffSettings[N][1] = NO;
+ changeChannelLeadOffDetect(N+1);
+}
+
+void OpenBCI_32bit_Library::activateChannel(byte N)
+{
+ byte setting, startChan, endChan, targetSS;
+ if(N < 9){
+ targetSS = BOARD_ADS; startChan = 0; endChan = 8;
+ }else{
+ if(!daisyPresent) { return; }
+ targetSS = DAISY_ADS; startChan = 8; endChan = 16;
+ }
+
+ N = constrain(N-1,startChan,endChan-1); // 0-7 or 8-15
+
+ SDATAC(targetSS); // exit Read Data Continuous mode to communicate with ADS
+ setting = 0x00;
+// channelSettings[N][POWER_DOWN] = NO; // keep track of channel on/off in this array REMOVE?
+ setting |= channelSettings[N][GAIN_SET]; // gain
+ setting |= channelSettings[N][INPUT_TYPE_SET]; // input code
+ if(useSRB2[N] == true){channelSettings[N][SRB2_SET] = YES;}else{channelSettings[N][SRB2_SET] = NO;}
+ if(channelSettings[N][SRB2_SET] == YES) {bitSet(setting,3);} // close this SRB2 switch
+ WREG(CH1SET+(N-startChan),setting,targetSS);
+ // add or remove from inclusion in BIAS generation
+ if(useInBias[N]){channelSettings[N][BIAS_SET] = YES;}else{channelSettings[N][BIAS_SET] = NO;}
+ setting = RREG(BIAS_SENSP,targetSS); //get the current P bias settings
+ if(channelSettings[N][BIAS_SET] == YES){
+ bitSet(setting,N-startChan); //set this channel's bit to add it to the bias generation
+ useInBias[N] = true;
+ }else{
+ bitClear(setting,N-startChan); // clear this channel's bit to remove from bias generation
+ useInBias[N] = false;
+ }
+ WREG(BIAS_SENSP,setting,targetSS); delay(1); //send the modified byte back to the ADS
+ setting = RREG(BIAS_SENSN,targetSS); //get the current N bias settings
+ if(channelSettings[N][BIAS_SET] == YES){
+ bitSet(setting,N-startChan); //set this channel's bit to add it to the bias generation
+ }else{
+ bitClear(setting,N-startChan); // clear this channel's bit to remove from bias generation
+ }
+ WREG(BIAS_SENSN,setting,targetSS); delay(1); //send the modified byte back to the ADS
+
+ setting = 0x00;
+ if(targetSS == BOARD_ADS && boardUseSRB1 == true) setting = 0x20;
+ if(targetSS == DAISY_ADS && daisyUseSRB1 == true) setting = 0x20;
+ WREG(MISC1,setting,targetSS); // close all SRB1 swtiches
+}
+
+// change the lead off detect settings for all channels
+void OpenBCI_32bit_Library::changeChannelLeadOffDetect()
+{
+ byte setting, startChan, endChan, targetSS;
+
+ for(int b=0; b<2; b++){
+ if(b == 0){ targetSS = BOARD_ADS; startChan = 0; endChan = 8; }
+ if(b == 1){
+ if(!daisyPresent){ return; }
+ targetSS = DAISY_ADS; startChan = 8; endChan = 16;
+ }
+
+ SDATAC(targetSS); delay(1); // exit Read Data Continuous mode to communicate with ADS
+ byte P_setting = RREG(LOFF_SENSP,targetSS);
+ byte N_setting = RREG(LOFF_SENSN,targetSS);
+
+ for(int i=startChan; i<endChan; i++){
+ if(leadOffSettings[i][PCHAN] == ON){
+ bitSet(P_setting,i-startChan);
+ }else{
+ bitClear(P_setting,i-startChan);
+ }
+ if(leadOffSettings[i][NCHAN] == ON){
+ bitSet(N_setting,i-startChan);
+ }else{
+ bitClear(N_setting,i-startChan);
+ }
+ WREG(LOFF_SENSP,P_setting,targetSS);
+ WREG(LOFF_SENSN,N_setting,targetSS);
+ }
+ }
+}
+
+// change the lead off detect settings for specified channel
+void OpenBCI_32bit_Library::changeChannelLeadOffDetect(byte N)
+{
+ byte setting, targetSS, startChan, endChan;
+
+ if(N < 9){
+ targetSS = BOARD_ADS; startChan = 0; endChan = 8;
+ }else{
+ if(!daisyPresent) { return; }
+ targetSS = DAISY_ADS; startChan = 8; endChan = 16;
+ }
+
+ N = constrain(N-1,startChan,endChan-1);
+ SDATAC(targetSS); delay(1); // exit Read Data Continuous mode to communicate with ADS
+ byte P_setting = RREG(LOFF_SENSP,targetSS);
+ byte N_setting = RREG(LOFF_SENSN,targetSS);
+
+ if(leadOffSettings[N][PCHAN] == ON){
+ bitSet(P_setting,N-startChan);
+ }else{
+ bitClear(P_setting,N-startChan);
+ }
+ if(leadOffSettings[N][NCHAN] == ON){
+ bitSet(N_setting,N-startChan);
+ }else{
+ bitClear(N_setting,N-startChan);
+ }
+ WREG(LOFF_SENSP,P_setting,targetSS);
+ WREG(LOFF_SENSN,N_setting,targetSS);
+}
+
+void OpenBCI_32bit_Library::configureLeadOffDetection(byte amplitudeCode, byte freqCode)
+{
+ amplitudeCode &= 0b00001100; //only these two bits should be used
+ freqCode &= 0b00000011; //only these two bits should be used
+
+ byte setting, targetSS;
+ for(int i=0; i<2; i++){
+ if(i == 0){ targetSS = BOARD_ADS; }
+ if(i == 1){
+ if(!daisyPresent){ return; }
+ targetSS = DAISY_ADS;
+ }
+ setting = RREG(LOFF,targetSS); //get the current bias settings
+ //reconfigure the byte to get what we want
+ setting &= 0b11110000; //clear out the last four bits
+ setting |= amplitudeCode; //set the amplitude
+ setting |= freqCode; //set the frequency
+ //send the config byte back to the hardware
+ WREG(LOFF,setting,targetSS); delay(1); //send the modified byte back to the ADS
+ }
+}
+
+// // deactivate the given channel.
+// void OpenBCI_32bit_Library::deactivateChannel(byte N)
+// {
+// byte setting, startChan, endChan, targetSS;
+// if(N < 9){
+// targetSS = BOARD_ADS; startChan = 0; endChan = 8;
+// }else{
+// if(!daisyPresent) { return; }
+// targetSS = DAISY_ADS; startChan = 8; endChan = 16;
+// }
+// SDATAC(targetSS); delay(1); // exit Read Data Continuous mode to communicate with ADS
+// N = constrain(N-1,startChan,endChan-1); //subtracts 1 so that we're counting from 0, not 1
+
+// setting = RREG(CH1SET+(N-startChan),targetSS); delay(1); // get the current channel settings
+// bitSet(setting,7); // set bit7 to shut down channel
+// bitClear(setting,3); // clear bit3 to disclude from SRB2 if used
+// WREG(CH1SET+(N-startChan),setting,targetSS); delay(1); // write the new value to disable the channel
+
+// //remove the channel from the bias generation...
+// setting = RREG(BIAS_SENSP,targetSS); delay(1); //get the current bias settings
+// bitClear(setting,N-startChan); //clear this channel's bit to remove from bias generation
+// WREG(BIAS_SENSP,setting,targetSS); delay(1); //send the modified byte back to the ADS
+
+// setting = RREG(BIAS_SENSN,targetSS); delay(1); //get the current bias settings
+// bitClear(setting,N-startChan); //clear this channel's bit to remove from bias generation
+// WREG(BIAS_SENSN,setting,targetSS); delay(1); //send the modified byte back to the ADS
+
+// leadOffSettings[N][PCHAN] = leadOffSettings[N][NCHAN] = NO;
+// leadOffSetForChannel(N+1, NO, NO);
+// }
+
+// void OpenBCI_32bit_Library::activateChannel(byte N)
+// {
+// byte setting, startChan, endChan, targetSS;
+// if(N < 9){
+// targetSS = BOARD_ADS; startChan = 0; endChan = 8;
+// }else{
+// if(!daisyPresent) { return; }
+// targetSS = DAISY_ADS; startChan = 8; endChan = 16;
+// }
+
+// N = constrain(N-1,startChan,endChan-1); // 0-7 or 8-15
+
+// SDATAC(targetSS); // exit Read Data Continuous mode to communicate with ADS
+// setting = 0x00;
+// // channelSettings[N][POWER_DOWN] = NO; // keep track of channel on/off in this array REMOVE?
+// setting |= channelSettings[N][GAIN_SET]; // gain
+// setting |= channelSettings[N][INPUT_TYPE_SET]; // input code
+// if(useSRB2[N] == true){channelSettings[N][SRB2_SET] = YES;}else{channelSettings[N][SRB2_SET] = NO;}
+// if(channelSettings[N][SRB2_SET] == YES) {bitSet(setting,3);} // close this SRB2 switch
+// WREG(CH1SET+(N-startChan),setting,targetSS);
+// // add or remove from inclusion in BIAS generation
+// if(useInBias[N]){channelSettings[N][BIAS_SET] = YES;}else{channelSettings[N][BIAS_SET] = NO;}
+// setting = RREG(BIAS_SENSP,targetSS); //get the current P bias settings
+// if(channelSettings[N][BIAS_SET] == YES){
+// bitSet(setting,N-startChan); //set this channel's bit to add it to the bias generation
+// useInBias[N] = true;
+// }else{
+// bitClear(setting,N-startChan); // clear this channel's bit to remove from bias generation
+// useInBias[N] = false;
+// }
+// WREG(BIAS_SENSP,setting,targetSS); delay(1); //send the modified byte back to the ADS
+// setting = RREG(BIAS_SENSN,targetSS); //get the current N bias settings
+// if(channelSettings[N][BIAS_SET] == YES){
+// bitSet(setting,N-startChan); //set this channel's bit to add it to the bias generation
+// }else{
+// bitClear(setting,N-startChan); // clear this channel's bit to remove from bias generation
+// }
+// WREG(BIAS_SENSN,setting,targetSS); delay(1); //send the modified byte back to the ADS
+
+// setting = 0x00;
+// if(targetSS == BOARD_ADS && boardUseSRB1 == true) setting = 0x20;
+// if(targetSS == DAISY_ADS && daisyUseSRB1 == true) setting = 0x20;
+// WREG(MISC1,setting,targetSS); // close all SRB1 swtiches
+// }
+
+//////////////////////////////////////////////
+///////////// LEAD OFF METHODS ///////////////
+//////////////////////////////////////////////
+
+/**
+ * @description Runs through the `leadOffSettings` global array to set/change
+ * the lead off signals for all inputs of all channels.
+ * @author AJ Keller (@pushtheworldllc)
+ */
+// void OpenBCI_32bit_Library::leadOffSetForAllChannels(void) {
+// byte channelNumberUpperLimit;
+
+// // The upper limit of the channels, either 8 or 16
+// channelNumberUpperLimit = daisyPresent ? OPENBCI_NUMBER_OF_CHANNELS_DAISY : OPENBCI_NUMBER_OF_CHANNELS_DEFAULT;
+
+// // Loop through all channels
+// for (int i = 1; i <= channelNumberUpperLimit; i++) {
+// leadOffSetForChannel((byte)i,leadOffSettings[i-1][PCHAN],leadOffSettings[i-1][NCHAN]);
+// }
+// }
+
+/**
+ * @description Used to set lead off for a channel
+ * @param `channelNumber` - [byte] - The channel you want to change
+ * @param `pInput` - [byte] - Apply signal to P input, either ON (1) or OFF (0)
+ * @param `nInput` - [byte] - Apply signal to N input, either ON (1) or OFF (0)
+ * @author AJ Keller (@pushtheworldllc)
+ */
+// void OpenBCI_32bit_Library::leadOffSetForChannel(byte channelNumber, byte pInput, byte nInput) {
+
+// // contstrain the channel number to 0-15
+// channelNumber = getConstrainedChannelNumber(channelNumber);
+
+// // Get the slave select pin for this channel
+// byte targetSS = getTargetSSForConstrainedChannelNumber(channelNumber);
+
+// // exit Read Data Continuous mode to communicate with ADS
+// SDATAC(targetSS);
+// delay(1);
+
+// // Read P register
+// byte P_setting = RREG(LOFF_SENSP,targetSS);
+
+// // Read N register
+// byte N_setting = RREG(LOFF_SENSN,targetSS);
+
+// // Since we are addressing 8 bit registers, we need to subtract 8 from the
+// // channelNumber if we are addressing the Daisy ADS
+// if (targetSS == DAISY_ADS) {
+// channelNumber -= OPENBCI_NUMBER_OF_CHANNELS_DEFAULT;
+// }
+
+// // If pInput is ON then we want to set, otherwise we want to clear
+// if (pInput == ON) {
+// bitSet(P_setting, channelNumber);
+// } else {
+// bitClear(P_setting, channelNumber);
+// }
+// // Write to the P register
+// WREG(LOFF_SENSP,P_setting,targetSS);
+
+// // If nInput is ON then we want to set, otherwise we want to clear
+// if (nInput == ON) {
+// bitSet(N_setting, channelNumber);
+// } else {
+// bitClear(N_setting, channelNumber);
+// }
+// // Write to the N register
+// WREG(LOFF_SENSN,N_setting,targetSS);
+// }
+
+/**
+ * @description This sets the LOFF register on the Board ADS and the Daisy ADS
+ * @param `amplitudeCode` - [byte] - The amplitude of the of impedance signal.
+ * See `.setleadOffForSS()` for complete description
+ * @param `freqCode` - [byte] - The frequency of the impedance signal can be either.
+ * See `.setleadOffForSS()` for complete description
+ * @author AJ Keller (@pushtheworldllc)
+ */
+// void OpenBCI_32bit_Library::leadOffConfigureSignalForAll(byte amplitudeCode, byte freqCode)
+// {
+// // Set the lead off detection for the on board ADS
+// leadOffConfigureSignalForTargetSS(BOARD_ADS, amplitudeCode, freqCode);
+
+// // if the daisy board is present, set that register as well
+// if (daisyPresent) {
+// leadOffConfigureSignalForTargetSS(DAISY_ADS, amplitudeCode, freqCode);
+// }
+// }
+
+/**
+ * @description This sets the LOFF (lead off) register for the given ADS with slave
+ * select
+ * @param `targetSS` - [byte] - The Slave Select pin.
+ * @param `amplitudeCode` - [byte] - The amplitude of the of impedance signal.
+ * LOFF_MAG_6NA (0b00000000)
+ * LOFF_MAG_24NA (0b00000100)
+ * LOFF_MAG_6UA (0b00001000)
+ * LOFF_MAG_24UA (0b00001100)
+ * @param `freqCode` - [byte] - The frequency of the impedance signal can be either.
+ * LOFF_FREQ_DC (0b00000000)
+ * LOFF_FREQ_7p8HZ (0b00000001)
+ * LOFF_FREQ_31p2HZ (0b00000010)
+ * LOFF_FREQ_FS_4 (0b00000011)
+ * @author Joel/Leif/Conor (@OpenBCI) Summer 2014
+ */
+// void OpenBCI_32bit_Library::leadOffConfigureSignalForTargetSS(byte targetSS, byte amplitudeCode, byte freqCode) {
+// byte setting;
+
+// amplitudeCode &= 0b00001100; //only these two bits should be used
+// freqCode &= 0b00000011; //only these two bits should be used
+
+// setting = RREG(LOFF,targetSS); //get the current bias settings
+// //reconfigure the byte to get what we want
+// setting &= 0b11110000; //clear out the last four bits
+// setting |= amplitudeCode; //set the amplitude
+// setting |= freqCode; //set the frequency
+// //send the config byte back to the hardware
+// WREG(LOFF,setting,targetSS); delay(1); //send the modified byte back to the ADS
+// }
+
+//Configure the test signals that can be inernally generated by the ADS1299
+void OpenBCI_32bit_Library::configureInternalTestSignal(byte amplitudeCode, byte freqCode)
+{
+ byte setting, targetSS;
+ for(int i=0; i<2; i++){
+ if(i == 0){ targetSS = BOARD_ADS;}
+ if(i == 1){
+ if(daisyPresent == false){ return; }
+ targetSS = DAISY_ADS;
+ }
+ if (amplitudeCode == ADSTESTSIG_NOCHANGE) amplitudeCode = (RREG(CONFIG2,targetSS) & (0b00000100));
+ if (freqCode == ADSTESTSIG_NOCHANGE) freqCode = (RREG(CONFIG2,targetSS) & (0b00000011));
+ freqCode &= 0b00000011; //only the last two bits are used
+ amplitudeCode &= 0b00000100; //only this bit is used
+ byte setting = 0b11010000 | freqCode | amplitudeCode; //compose the code
+ WREG(CONFIG2,setting,targetSS); delay(1);
+ if (sniffMode && Serial1) {
+ Serial1.print("Wrote to CONFIG2: ");
+ Serial1.print(setting,BIN);
+ }
+ }
+}
+
+void OpenBCI_32bit_Library::changeInputType(byte inputCode){
+
+ for(int i=0; i<numChannels; i++){
+ channelSettings[i][INPUT_TYPE_SET] = inputCode;
+ }
+
+ // OLD CODE REVERT
+ //channelSettingsArraySetForAll();
+
+ writeChannelSettings();
+}
+
+// Start continuous data acquisition
+void OpenBCI_32bit_Library::startADS(void) // NEEDS ADS ADDRESS, OR BOTH?
+{
+ sampleCounter = 0;
+ firstDataPacket = true;
+ RDATAC(BOTH_ADS); // enter Read Data Continuous mode
+ delay(1);
+ START(BOTH_ADS); // start the data acquisition
+ delay(1);
+ isRunning = true;
+}
+
+/**
+ * @description Check status register to see if data is available from the ADS1299.
+ * @returns {boolean} - `true` if data is available
+ */
+boolean OpenBCI_32bit_Library::waitForNewChannelData(void) {
+ return !isADSDataAvailable();
+}
+
+/**
+ * @description Check status register to see if data is available from the ADS1299.
+ * @returns {boolean} - `true` if data is available
+ */
+boolean OpenBCI_32bit_Library::isADSDataAvailable(void) {
+ return (!(digitalRead(ADS_DRDY)));
+}
+
+// CALLED WHEN DRDY PIN IS ASSERTED. NEW ADS DATA AVAILABLE!
+void OpenBCI_32bit_Library::updateChannelData(){
+ // this needs to be reset, or else it will constantly flag us
+ channelDataAvailable = false;
+ updateBoardData();
+ if(daisyPresent) {updateDaisyData();}
+}
+
+void OpenBCI_32bit_Library::updateBoardData(){
+ byte inByte;
+ int byteCounter = 0;
+
+ if(daisyPresent && !firstDataPacket){
+ for(int i=0; i < 8; i++){ // shift and average the byte arrays
+ lastBoardChannelDataInt[i] = boardChannelDataInt[i]; // remember the last samples
+ }
+ }
+
+ csLow(BOARD_ADS); // open SPI
+ for(int i=0; i<3; i++){
+ inByte = xfer(0x00); // read status register (1100 + LOFF_STATP + LOFF_STATN + GPIO[7:4])
+ boardStat = (boardStat << 8) | inByte;
+ }
+ for(int i = 0; i<8; i++){
+ for(int j=0; j<3; j++){ // read 24 bits of channel data in 8 3 byte chunks
+ inByte = xfer(0x00);
+ boardChannelDataRaw[byteCounter] = inByte; // raw data goes here
+ byteCounter++;
+ boardChannelDataInt[i] = (boardChannelDataInt[i]<<8) | inByte; // int data goes here
+ }
+ }
+ csHigh(BOARD_ADS); // close SPI
+
+ // need to convert 24bit to 32bit if using the filter
+ for(int i=0; i<8; i++){ // convert 3 byte 2's compliment to 4 byte 2's compliment
+ if(bitRead(boardChannelDataInt[i],23) == 1){
+ boardChannelDataInt[i] |= 0xFF000000;
+ } else{
+ boardChannelDataInt[i] &= 0x00FFFFFF;
+ }
+ }
+ if(daisyPresent && !firstDataPacket){
+ byteCounter = 0;
+ for(int i=0; i<8; i++){ // take the average of this and the last sample
+ meanBoardChannelDataInt[i] = (lastBoardChannelDataInt[i] + boardChannelDataInt[i])/2;
+ }
+ for(int i=0; i<8; i++){ // place the average values in the meanRaw array
+ for(int b=2; b>=0; b--){
+ meanBoardDataRaw[byteCounter] = (meanBoardChannelDataInt[i] >> (b*8)) & 0xFF;
+ byteCounter++;
+ }
+ }
+ }
+
+ if(firstDataPacket == true){
+ firstDataPacket = false;
+ }
+}
+
+void OpenBCI_32bit_Library::updateDaisyData(){
+ byte inByte;
+ int byteCounter = 0;
+
+ if(daisyPresent && !firstDataPacket){
+ for(int i=0; i<8; i++){ // shift and average the byte arrays
+ lastDaisyChannelDataInt[i] = daisyChannelDataInt[i]; // remember the last samples
+ }
+ }
+
+ csLow(DAISY_ADS); // open SPI
+ for(int i=0; i<3; i++){
+ inByte = xfer(0x00); // read status register (1100 + LOFF_STATP + LOFF_STATN + GPIO[7:4])
+ daisyStat = (daisyStat << 8) | inByte;
+ }
+ for(int i = 0; i<8; i++){
+ for(int j=0; j<3; j++){ // read 24 bits of channel data in 8 3 byte chunks
+ inByte = xfer(0x00);
+ daisyChannelDataRaw[byteCounter] = inByte; // raw data goes here
+ byteCounter++;
+ daisyChannelDataInt[i] = (daisyChannelDataInt[i]<<8) | inByte; // int data goes here
+ }
+ }
+ csHigh(DAISY_ADS); // close SPI
+ // need to convert 24bit to 32bit
+ for(int i=0; i<8; i++){ // convert 3 byte 2's compliment to 4 byte 2's compliment
+ if(bitRead(daisyChannelDataInt[i],23) == 1){
+ daisyChannelDataInt[i] |= 0xFF000000;
+ }else{
+ daisyChannelDataInt[i] &= 0x00FFFFFF;
+ }
+ }
+ if(daisyPresent && !firstDataPacket){
+ byteCounter = 0;
+ for(int i=0; i<8; i++){ // average this sample with the last sample
+ meanDaisyChannelDataInt[i] = (lastDaisyChannelDataInt[i] + daisyChannelDataInt[i])/2;
+ }
+ for(int i=0; i<8; i++){ // place the average values in the meanRaw array
+ for(int b=2; b>=0; b--){
+ meanDaisyDataRaw[byteCounter] = (meanDaisyChannelDataInt[i] >> (b*8)) & 0xFF;
+ byteCounter++;
+ }
+ }
+ }
+
+ if(firstDataPacket == true) {
+ firstDataPacket = false;
+ }
+}
+
+// Stop the continuous data acquisition
+void OpenBCI_32bit_Library::stopADS()
+{
+ STOP(BOTH_ADS); // stop the data acquisition
+ delay(1);
+ SDATAC(BOTH_ADS); // stop Read Data Continuous mode to communicate with ADS
+ delay(1);
+ isRunning = false;
+}
+
+
+//write as binary each channel's data
+void OpenBCI_32bit_Library::ADS_writeChannelData()
+{
+
+ if(daisyPresent){
+ if(sampleCounter % 2 != 0){ //CHECK SAMPLE ODD-EVEN AND SEND THE APPROPRIATE ADS DATA
+ for (int i=0; i<24; i++){
+ Serial0.write(meanBoardDataRaw[i]); // send board data on odd samples
+ }
+ }else{
+ for (int i=0; i<24; i++){
+ Serial0.write(meanDaisyDataRaw[i]); // send daisy data on even samples
+ }
+ }
+ }else{
+ for(int i=0; i<24; i++){
+ Serial0.write(boardChannelDataRaw[i]);
+ }
+ }
+}
+
+
+//print out the state of all the control registers
+void OpenBCI_32bit_Library::printADSregisters(int targetSS)
+{
+ boolean prevverbosityState = verbosity;
+ verbosity = true; // set up for verbosity output
+ RREGS(0x00,0x0C,targetSS); // read out the first registers
+ delay(10); // stall to let all that data get read by the PC
+ RREGS(0x0D,0x17-0x0D,targetSS); // read out the rest
+ verbosity = prevverbosityState;
+}
+
+byte OpenBCI_32bit_Library::ADS_getDeviceID(int targetSS) { // simple hello world com check
+ byte data = RREG(ID_REG,targetSS);
+ if(verbosity){ // verbosity otuput
+ Serial0.print("On Board ADS ID ");
+ printHex(data); Serial0.println();
+ sendEOT();
+ }
+ return data;
+}
+
+//System Commands
+void OpenBCI_32bit_Library::WAKEUP(int targetSS) {
+ csLow(targetSS);
+ xfer(_WAKEUP);
+ csHigh(targetSS);
+ delayMicroseconds(3); //must wait 4 tCLK cycles before sending another command (Datasheet, pg. 35)
+}
+
+void OpenBCI_32bit_Library::STANDBY(int targetSS) { // only allowed to send WAKEUP after sending STANDBY
+ csLow(targetSS);
+ xfer(_STANDBY);
+ csHigh(targetSS);
+}
+
+void OpenBCI_32bit_Library::RESET(int targetSS) { // reset all the registers to default settings
+ csLow(targetSS);
+ xfer(_RESET);
+ delayMicroseconds(12); //must wait 18 tCLK cycles to execute this command (Datasheet, pg. 35)
+ csHigh(targetSS);
+}
+
+void OpenBCI_32bit_Library::START(int targetSS) { //start data conversion
+ csLow(targetSS);
+ xfer(_START); // KEEP ON-BOARD AND ON-DAISY IN SYNC
+ csHigh(targetSS);
+}
+
+void OpenBCI_32bit_Library::STOP(int targetSS) { //stop data conversion
+ csLow(targetSS);
+ xfer(_STOP); // KEEP ON-BOARD AND ON-DAISY IN SYNC
+ csHigh(targetSS);
+}
+
+void OpenBCI_32bit_Library::RDATAC(int targetSS) {
+ csLow(targetSS);
+ xfer(_RDATAC); // read data continuous
+ csHigh(targetSS);
+ delayMicroseconds(3);
+}
+void OpenBCI_32bit_Library::SDATAC(int targetSS) {
+ csLow(targetSS);
+ xfer(_SDATAC);
+ csHigh(targetSS);
+ delayMicroseconds(10); //must wait at least 4 tCLK cycles after executing this command (Datasheet, pg. 37)
+}
+
+
+// THIS NEEDS CLEANING AND UPDATING TO THE NEW FORMAT
+void OpenBCI_32bit_Library::RDATA(int targetSS) { // use in Stop Read Continuous mode when DRDY goes low
+ byte inByte; // to read in one sample of the channels
+ csLow(targetSS); // open SPI
+ xfer(_RDATA); // send the RDATA command
+ for(int i=0; i<3; i++){ // read in the status register and new channel data
+ inByte = xfer(0x00);
+ boardStat = (boardStat<<8) | inByte; // read status register (1100 + LOFF_STATP + LOFF_STATN + GPIO[7:4])
+ }
+ if(targetSS == BOARD_ADS){
+ for(int i = 0; i<8; i++){
+ for(int j=0; j<3; j++){ // read in the new channel data
+ inByte = xfer(0x00);
+ boardChannelDataInt[i] = (boardChannelDataInt[i]<<8) | inByte;
+ }
+ }
+ for(int i=0; i<8; i++){
+ if(bitRead(boardChannelDataInt[i],23) == 1){ // convert 3 byte 2's compliment to 4 byte 2's compliment
+ boardChannelDataInt[i] |= 0xFF000000;
+ }else{
+ boardChannelDataInt[i] &= 0x00FFFFFF;
+ }
+ }
+}else{
+ for(int i = 0; i<8; i++){
+ for(int j=0; j<3; j++){ // read in the new channel data
+ inByte = xfer(0x00);
+ daisyChannelDataInt[i] = (daisyChannelDataInt[i]<<8) | inByte;
+ }
+ }
+ for(int i=0; i<8; i++){
+ if(bitRead(daisyChannelDataInt[i],23) == 1){ // convert 3 byte 2's compliment to 4 byte 2's compliment
+ daisyChannelDataInt[i] |= 0xFF000000;
+ }else{
+ daisyChannelDataInt[i] &= 0x00FFFFFF;
+ }
+}
+}
+csHigh(targetSS); // close SPI
+
+
+}
+
+byte OpenBCI_32bit_Library::RREG(byte _address,int targetSS) { // reads ONE register at _address
+ byte opcode1 = _address + 0x20; // RREG expects 001rrrrr where rrrrr = _address
+ csLow(targetSS); // open SPI
+ xfer(opcode1); // opcode1
+ xfer(0x00); // opcode2
+ regData[_address] = xfer(0x00);// update mirror location with returned byte
+ csHigh(targetSS); // close SPI
+ if (verbosity){ // verbosity output
+ printRegisterName(_address);
+ printHex(_address);
+ Serial0.print(", ");
+ printHex(regData[_address]);
+ Serial0.print(", ");
+ for(byte j = 0; j<8; j++){
+ Serial0.print(bitRead(regData[_address], 7-j));
+ if(j!=7) Serial0.print(", ");
+ }
+
+ Serial0.println();
+ }
+ return regData[_address]; // return requested register value
+}
+
+
+// Read more than one register starting at _address
+void OpenBCI_32bit_Library::RREGS(byte _address, byte _numRegistersMinusOne, int targetSS) {
+
+ byte opcode1 = _address + 0x20; // RREG expects 001rrrrr where rrrrr = _address
+ csLow(targetSS); // open SPI
+ xfer(opcode1); // opcode1
+ xfer(_numRegistersMinusOne); // opcode2
+ for(int i = 0; i <= _numRegistersMinusOne; i++){
+ regData[_address + i] = xfer(0x00); // add register byte to mirror array
+ }
+ csHigh(targetSS); // close SPI
+ if(verbosity){ // verbosity output
+ for(int i = 0; i<= _numRegistersMinusOne; i++){
+ printRegisterName(_address + i);
+ printHex(_address + i);
+ Serial0.print(", ");
+ printHex(regData[_address + i]);
+ Serial0.print(", ");
+ for(int j = 0; j<8; j++){
+ Serial0.print(bitRead(regData[_address + i], 7-j));
+ if(j!=7) Serial0.print(", ");
+ }
+ Serial0.println();
+ delay(30);
+ }
+ }
+}
+
+void OpenBCI_32bit_Library::WREG(byte _address, byte _value, int target_SS) { // Write ONE register at _address
+ byte opcode1 = _address + 0x40; // WREG expects 010rrrrr where rrrrr = _address
+ csLow(target_SS); // open SPI
+ xfer(opcode1); // Send WREG command & address
+ xfer(0x00); // Send number of registers to read -1
+ xfer(_value); // Write the value to the register
+ csHigh(target_SS); // close SPI
+ regData[_address] = _value; // update the mirror array
+ if(verbosity){ // verbosity output
+ Serial0.print("Register ");
+ printHex(_address);
+ Serial0.println(" modified.");
+ sendEOT();
+ }
+}
+
+void OpenBCI_32bit_Library::WREGS(byte _address, byte _numRegistersMinusOne, int targetSS) {
+ byte opcode1 = _address + 0x40; // WREG expects 010rrrrr where rrrrr = _address
+ csLow(targetSS); // open SPI
+ xfer(opcode1); // Send WREG command & address
+ xfer(_numRegistersMinusOne); // Send number of registers to read -1
+ for (int i=_address; i <=(_address + _numRegistersMinusOne); i++){
+ xfer(regData[i]); // Write to the registers
+ }
+ csHigh(targetSS);
+ if(verbosity){
+ Serial0.print("Registers ");
+ printHex(_address); Serial0.print(" to ");
+ printHex(_address + _numRegistersMinusOne);
+ Serial0.println(" modified");
+ sendEOT();
+ }
+}
+
+
+// <<<<<<<<<<<<<<<<<<<<<<<<< END OF ADS1299 FUNCTIONS >>>>>>>>>>>>>>>>>>>>>>>>>
+// ******************************************************************************
+// <<<<<<<<<<<<<<<<<<<<<<<<< LIS3DH FUNCTIONS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+
+
+void OpenBCI_32bit_Library::initialize_accel(byte g){
+ byte setting = g | 0x08; // mask the g range for REG4
+ pinMode(LIS3DH_DRDY,INPUT); // setup dataReady interupt from accelerometer
+ LIS3DH_write(TMP_CFG_REG, 0x00); // DISable ADC inputs, enable temperature sensor
+ LIS3DH_write(CTRL_REG1, 0x08); // disable accel, low power mode
+ LIS3DH_write(CTRL_REG2, 0x00); // don't use the high pass filter
+ LIS3DH_write(CTRL_REG3, 0x00); // no interrupts yet
+ LIS3DH_write(CTRL_REG4, setting); // set scale to g, high resolution
+ LIS3DH_write(CTRL_REG5, 0x00); // no boot, no fifo
+ LIS3DH_write(CTRL_REG6, 0x00);
+ LIS3DH_write(REFERENCE, 0x00);
+ DRDYpinValue = lastDRDYpinValue = digitalRead(LIS3DH_DRDY); // take a reading to seed these variables
+}
+
+void OpenBCI_32bit_Library::enable_accel(byte Hz){
+ for(int i=0; i<3; i++){
+ axisData[i] = 0; // clear the axisData array so we don't get any stale news
+ }
+ byte setting = Hz | 0x07; // mask the desired frequency
+ LIS3DH_write(CTRL_REG1, setting); // set freq and enable all axis in normal mode
+ LIS3DH_write(CTRL_REG3, 0x10); // enable DRDY1 on INT1 (tied to PIC pin 0, LIS3DH_DRDY)
+}
+
+void OpenBCI_32bit_Library::disable_accel(){
+ LIS3DH_write(CTRL_REG1, 0x08); // power down, low power mode
+ LIS3DH_write(CTRL_REG3, 0x00); // disable DRDY1 on INT1
+}
+
+byte OpenBCI_32bit_Library::LIS3DH_getDeviceID(){
+ return LIS3DH_read(WHO_AM_I);
+}
+
+boolean OpenBCI_32bit_Library::LIS3DH_DataAvailable(){
+ boolean x = false;
+ if((LIS3DH_read(STATUS_REG2) & 0x08) > 0) x = true; // read STATUS_REG
+ return x;
+}
+
+boolean OpenBCI_32bit_Library::LIS3DH_DataReady(){
+ boolean r = false;
+ DRDYpinValue = digitalRead(LIS3DH_DRDY); // take a look at LIS3DH_DRDY pin
+ if(DRDYpinValue != lastDRDYpinValue){ // if the value has changed since last looking
+ if(DRDYpinValue == HIGH){ // see if this is the rising edge
+ r = true; // if so, there is fresh data!
+ }
+ lastDRDYpinValue = DRDYpinValue; // keep track of the changing pin
+ }
+ return r;
+}
+
+void OpenBCI_32bit_Library::LIS3DH_writeAxisData(void){
+ for(int i=0; i<3; i++){
+ Serial0.write(highByte(axisData[i])); // write 16 bit axis data MSB first
+ Serial0.write(lowByte(axisData[i])); // axisData is array of type short (16bit)
+ axisData[i] = 0;
+ }
+}
+
+void OpenBCI_32bit_Library::LIS3DH_writeAxisDataForAxis(uint8_t axis) {
+ if (axis > 2) axis = 0;
+ Serial0.write(highByte(axisData[axis])); // write 16 bit axis data MSB first
+ Serial0.write(lowByte(axisData[axis])); // axisData is array of type short (16bit)
+ axisData[axis] = 0;
+}
+
+byte OpenBCI_32bit_Library::LIS3DH_read(byte reg){
+ reg |= READ_REG; // add the READ_REG bit
+ csLow(LIS3DH_SS); // take spi
+ spi.transfer(reg); // send reg to read
+ byte inByte = spi.transfer(0x00); // retrieve data
+ csHigh(LIS3DH_SS); // release spi
+ return inByte;
+}
+
+void OpenBCI_32bit_Library::LIS3DH_write(byte reg, byte value){
+ csLow(LIS3DH_SS); // take spi
+ spi.transfer(reg); // send reg to write
+ spi.transfer(value); // write value
+ csHigh(LIS3DH_SS); // release spi
+}
+
+int OpenBCI_32bit_Library::LIS3DH_read16(byte reg){ // use for reading axis data.
+ int inData;
+ reg |= READ_REG | READ_MULTI; // add the READ_REG and READ_MULTI bits
+ csLow(LIS3DH_SS); // take spi
+ spi.transfer(reg); // send reg to start reading from
+ inData = spi.transfer(0x00) | (spi.transfer(0x00) << 8); // get the data and arrange it
+ csHigh(LIS3DH_SS); // release spi
+ return inData;
+}
+
+int OpenBCI_32bit_Library::getX(){
+ return LIS3DH_read16(OUT_X_L);
+}
+
+int OpenBCI_32bit_Library::getY(){
+ return LIS3DH_read16(OUT_Y_L);
+}
+
+int OpenBCI_32bit_Library::getZ(){
+ return LIS3DH_read16(OUT_Z_L);
+}
+
+void OpenBCI_32bit_Library::LIS3DH_updateAxisData(){
+ axisData[0] = getX();
+ axisData[1] = getY();
+ axisData[2] = getZ();
+}
+
+void OpenBCI_32bit_Library::LIS3DH_readAllRegs(){
+
+ byte inByte;
+
+ for (int i = STATUS_REG_AUX; i <= WHO_AM_I; i++){
+ inByte = LIS3DH_read(i);
+ Serial0.print("0x0");Serial0.print(i,HEX);
+ Serial0.print("\t");Serial0.println(inByte,HEX);
+ delay(20);
+ }
+ Serial0.println();
+
+ for (int i = TMP_CFG_REG; i <= INT1_DURATION; i++){
+ inByte = LIS3DH_read(i);
+ // printRegisterName(i);
+ Serial0.print("0x");Serial0.print(i,HEX);
+ Serial0.print("\t");Serial0.println(inByte,HEX);
+ delay(20);
+ }
+ Serial0.println();
+
+ for (int i = CLICK_CFG; i <= TIME_WINDOW; i++){
+ inByte = LIS3DH_read(i);
+ Serial0.print("0x");Serial0.print(i,HEX);
+ Serial0.print("\t");Serial0.println(inByte,HEX);
+ delay(20);
+ }
+
+}
+
+
+
+// <<<<<<<<<<<<<<<<<<<<<<<<< END OF LIS3DH FUNCTIONS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+
+
+
+// String-Byte converters for ADS
+void OpenBCI_32bit_Library::printRegisterName(byte _address) {
+ switch(_address){
+ case ID_REG:
+ Serial0.print("ADS_ID, "); break;
+ case CONFIG1:
+ Serial0.print("CONFIG1, "); break;
+ case CONFIG2:
+ Serial0.print("CONFIG2, "); break;
+ case CONFIG3:
+ Serial0.print("CONFIG3, "); break;
+ case LOFF:
+ Serial0.print("LOFF, "); break;
+ case CH1SET:
+ Serial0.print("CH1SET, "); break;
+ case CH2SET:
+ Serial0.print("CH2SET, "); break;
+ case CH3SET:
+ Serial0.print("CH3SET, "); break;
+ case CH4SET:
+ Serial0.print("CH4SET, "); break;
+ case CH5SET:
+ Serial0.print("CH5SET, "); break;
+ case CH6SET:
+ Serial0.print("CH6SET, "); break;
+ case CH7SET:
+ Serial0.print("CH7SET, "); break;
+ case CH8SET:
+ Serial0.print("CH8SET, "); break;
+ case BIAS_SENSP:
+ Serial0.print("BIAS_SENSP, "); break;
+ case BIAS_SENSN:
+ Serial0.print("BIAS_SENSN, "); break;
+ case LOFF_SENSP:
+ Serial0.print("LOFF_SENSP, "); break;
+ case LOFF_SENSN:
+ Serial0.print("LOFF_SENSN, "); break;
+ case LOFF_FLIP:
+ Serial0.print("LOFF_FLIP, "); break;
+ case LOFF_STATP:
+ Serial0.print("LOFF_STATP, "); break;
+ case LOFF_STATN:
+ Serial0.print("LOFF_STATN, "); break;
+ case GPIO:
+ Serial0.print("GPIO, "); break;
+ case MISC1:
+ Serial0.print("MISC1, "); break;
+ case MISC2:
+ Serial0.print("MISC2, "); break;
+ case CONFIG4:
+ Serial0.print("CONFIG4, "); break;
+ default:
+ break;
+ }
+}
+
+// Used for printing HEX in verbosity feedback mode
+void OpenBCI_32bit_Library::printHex(byte _data){
+ Serial0.print("0x");
+ if(_data < 0x10) Serial0.print("0");
+ Serial0.print(_data, HEX);
+}
+
+/**
+ * @description Converts ascii character to byte value for channel setting bytes
+ * @param `asciiChar` - [char] - The ascii character to convert
+ * @return [char] - Byte number value of acsii character, defaults to 0
+ * @author AJ Keller (@pushtheworldllc)
+ */
+char OpenBCI_32bit_Library::getChannelCommandForAsciiChar(char asciiChar) {
+ switch(asciiChar){
+ case OPENBCI_CHANNEL_CMD_CHANNEL_1:
+ return 0x00;
+ case OPENBCI_CHANNEL_CMD_CHANNEL_2:
+ return 0x01;
+ case OPENBCI_CHANNEL_CMD_CHANNEL_3:
+ return 0x02;
+ case OPENBCI_CHANNEL_CMD_CHANNEL_4:
+ return 0x03;
+ case OPENBCI_CHANNEL_CMD_CHANNEL_5:
+ return 0x04;
+ case OPENBCI_CHANNEL_CMD_CHANNEL_6:
+ return 0x05;
+ case OPENBCI_CHANNEL_CMD_CHANNEL_7:
+ return 0x06;
+ case OPENBCI_CHANNEL_CMD_CHANNEL_8:
+ return 0x07;
+ case OPENBCI_CHANNEL_CMD_CHANNEL_9:
+ return 0x08;
+ case OPENBCI_CHANNEL_CMD_CHANNEL_10:
+ return 0x09;
+ case OPENBCI_CHANNEL_CMD_CHANNEL_11:
+ return 0x0A;
+ case OPENBCI_CHANNEL_CMD_CHANNEL_12:
+ return 0x0B;
+ case OPENBCI_CHANNEL_CMD_CHANNEL_13:
+ return 0x0C;
+ case OPENBCI_CHANNEL_CMD_CHANNEL_14:
+ return 0x0D;
+ case OPENBCI_CHANNEL_CMD_CHANNEL_15:
+ return 0x0E;
+ case OPENBCI_CHANNEL_CMD_CHANNEL_16:
+ return 0x0F;
+ default:
+ return 0x00;
+ }
+}
+
+/**
+ * @description Converts ascii '0' to number 0 and ascii '1' to number 1
+ * @param `asciiChar` - [char] - The ascii character to convert
+ * @return [char] - Byte number value of acsii character, defaults to 0
+ * @author AJ Keller (@pushtheworldllc)
+ */
+char OpenBCI_32bit_Library::getYesOrNoForAsciiChar(char asciiChar) {
+ switch (asciiChar) {
+ case '1':
+ return ACTIVATE;
+ case '0':
+ default:
+ return DEACTIVATE;
+ }
+}
+
+/**
+ * @description Converts ascii character to get gain from channel settings
+ * @param `asciiChar` - [char] - The ascii character to convert
+ * @return [char] - Byte number value of acsii character, defaults to 0
+ * @author AJ Keller (@pushtheworldllc)
+ */
+char OpenBCI_32bit_Library::getGainForAsciiChar(char asciiChar) {
+
+ char output = 0x00;
+
+ if (asciiChar < '0' || asciiChar > '6') {
+ asciiChar = '6'; // Default to 24
+ }
+
+ output = asciiChar - '0';
+
+ return output << 4;
+}
+
+/**
+ * @description Converts ascii character to get gain from channel settings
+ * @param `asciiChar` - [char] - The ascii character to convert
+ * @return [char] - Byte number value of acsii character, defaults to 0
+ * @author AJ Keller (@pushtheworldllc)
+ */
+char OpenBCI_32bit_Library::getNumberForAsciiChar(char asciiChar) {
+ if (asciiChar < '0' || asciiChar > '9') {
+ asciiChar = '0';
+ }
+
+ // Convert ascii char to number
+ asciiChar -= '0';
+
+ return asciiChar;
+}
+
+/**
+ * @description Used to set the channelSettings array to default settings
+ * @param `setting` - [byte] - The byte you need a setting for....
+ * @returns - [byte] - Retuns the proper byte for the input setting, defualts to 0
+ */
+byte OpenBCI_32bit_Library::getDefaultChannelSettingForSetting(byte setting) {
+ switch (setting) {
+ case POWER_DOWN:
+ return NO;
+ case GAIN_SET:
+ return ADS_GAIN24;
+ case INPUT_TYPE_SET:
+ return ADSINPUT_NORMAL;
+ case BIAS_SET:
+ return YES;
+ case SRB2_SET:
+ return YES;
+ case SRB1_SET:
+ default:
+ return NO;
+ }
+}
+
+/**
+ * @description Used to set the channelSettings array to default settings
+ * @param `setting` - [byte] - The byte you need a setting for....
+ * @returns - [char] - Retuns the proper ascii char for the input setting, defaults to '0'
+ */
+char OpenBCI_32bit_Library::getDefaultChannelSettingForSettingAscii(byte setting) {
+ switch (setting) {
+ case GAIN_SET: // Special case where GAIN_SET needs to be shifted first
+ return (ADS_GAIN24 >> 4) + '0';
+ default: // All other settings are just adding the ascii value for '0'
+ return getDefaultChannelSettingForSetting(setting) + '0';
+ }
+}
+
+/**
+ * @description Convert user channelNumber for use in array indexs by subtracting 1,
+ * also make sure N is not greater than 15 or less than 0
+ * @param `channelNumber` - [byte] - The channel number
+ * @return [byte] - Constrained channel number
+ */
+char OpenBCI_32bit_Library::getConstrainedChannelNumber(byte channelNumber) {
+ return constrain(channelNumber - 1, 0, OPENBCI_NUMBER_OF_CHANNELS_DAISY - 1);
+}
+
+/**
+ * @description Get slave select pin for channelNumber
+ * @param `channelNumber` - [byte] - The channel number
+ * @return [byte] - Constrained channel number
+ */
+char OpenBCI_32bit_Library::getTargetSSForConstrainedChannelNumber(byte channelNumber) {
+ // Is channelNumber in the range of default [0,7]
+ if (channelNumber < OPENBCI_NUMBER_OF_CHANNELS_DEFAULT) {
+ return BOARD_ADS;
+ } else {
+ return DAISY_ADS;
+ }
+}
+
+/**
+ * @description Used to set the channelSettings array to default settings
+ * @param `channelSettingsArray` - [byte **] - Takes a two dimensional array of
+ * length OPENBCI_NUMBER_OF_CHANNELS_DAISY by 6 elements
+ */
+void OpenBCI_32bit_Library::resetChannelSettingsArrayToDefault(byte channelSettingsArray[][OPENBCI_NUMBER_OF_CHANNEL_SETTINGS]) {
+ // Loop through all channels
+ for (int i = 0; i < OPENBCI_NUMBER_OF_CHANNELS_DAISY; i++) {
+ channelSettingsArray[i][POWER_DOWN] = getDefaultChannelSettingForSetting(POWER_DOWN); // on = NO, off = YES
+ channelSettingsArray[i][GAIN_SET] = getDefaultChannelSettingForSetting(GAIN_SET); // Gain setting
+ channelSettingsArray[i][INPUT_TYPE_SET] = getDefaultChannelSettingForSetting(INPUT_TYPE_SET); // input muxer setting
+ channelSettingsArray[i][BIAS_SET] = getDefaultChannelSettingForSetting(BIAS_SET); // add this channel to bias generation
+ channelSettingsArray[i][SRB2_SET] = getDefaultChannelSettingForSetting(SRB2_SET); // connect this P side to SRB2
+ channelSettingsArray[i][SRB1_SET] = getDefaultChannelSettingForSetting(SRB1_SET); // don't use SRB1
+
+ useInBias[i] = true; // keeping track of Bias Generation
+ useSRB2[i] = true; // keeping track of SRB2 inclusion
+ }
+
+ boardUseSRB1 = daisyUseSRB1 = false;
+}
+
+/**
+ * @description Used to set the channelSettings array to default settings
+ * @param `channelSettingsArray` - [byte **] - A two dimensional array of
+ * length OPENBCI_NUMBER_OF_CHANNELS_DAISY by 2 elements
+ */
+void OpenBCI_32bit_Library::resetLeadOffArrayToDefault(byte leadOffArray[][OPENBCI_NUMBER_OF_LEAD_OFF_SETTINGS]) {
+ // Loop through all channels
+ for (int i = 0; i < OPENBCI_NUMBER_OF_CHANNELS_DAISY; i++) {
+ leadOffArray[i][PCHAN] = OFF;
+ leadOffArray[i][NCHAN] = OFF;
+ }
+}
+
+OpenBCI_32bit_Library board;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/OpenBCI_32bit_Library.h Sun Jan 22 04:10:11 2017 +0000
@@ -0,0 +1,249 @@
+/*
+ insert header here
+
+*/
+#ifndef _____OpenBCI_32bit__
+#define _____OpenBCI_32bit__
+
+
+//#include <DSPI.h> // MBED: not needed
+//#include <Arduino.h> // MBED: not needed
+#include "PlatformDefs.h" // MBED: arduino hardware emulation
+#include "Definitions.h"
+
+void __USER_ISR ADS_DRDY_Service(void);
+class OpenBCI_32bit_Library {
+
+public:
+
+ // Start up functions
+ OpenBCI_32bit_Library();
+ boolean accelHasNewData(void);
+ void accelUpdateAxisData(void);
+ void accelWriteAxisData(void);
+ void begin(void);
+ void beginDebug(void);
+ boolean beginSecondarySerial(void);
+ char getCharSerial0(void);
+ char getCharSerial1(void);
+ boolean hasDataSerial0(void);
+ boolean hasDataSerial1(void);
+
+
+ void writeSerial(char *data, int len);
+
+ boolean isADSDataAvailable(void);
+
+
+
+ void writeTimeCurrent(void);
+ void writeZeroAux(void);
+ void activateAllChannelsToTestCondition(byte testInputCode, byte amplitudeCode, byte freqCode);
+
+ void channelSettingsArraySetForAll(void);
+ void channelSettingsArraySetForChannel(byte N);
+ void channelSettingsSetForChannel(byte channelNumber, byte powerDown, byte gain, byte inputType, byte bias, byte srb2, byte srb1);
+
+ void leadOffConfigureSignalForAll(byte amplitudeCode, byte freqCode);
+ void leadOffConfigureSignalForTargetSS(byte targetSS, byte amplitudeCode, byte freqCode);
+
+ void leadOffSetForAllChannels(void);
+ void leadOffSetForChannel(byte channelNumber, byte pInput, byte nInput);
+
+ boolean processChar(char character);
+ void processIncomingBoardMode(char character);
+ void processIncomingChannelSettings(char character);
+ void processIncomingLeadOffSettings(char character);
+
+ void resetChannelSettingsArrayToDefault(byte channelSettingsArray[][OPENBCI_NUMBER_OF_CHANNEL_SETTINGS]);
+ void resetLeadOffArrayToDefault(byte leadOffArray[][OPENBCI_NUMBER_OF_LEAD_OFF_SETTINGS]);
+
+ void sendChannelDataWithAccel(void);
+ void sendChannelDataWithRawAux(void);
+ void sendChannelDataWithTimeAndAccel(void);
+ void sendChannelDataWithTimeAndRawAux(void);
+
+ void streamSafeChannelDeactivate(byte channelNumber);
+ void streamSafeChannelActivate(byte channelNumber);
+ void streamSafeChannelSettingsForChannel(byte channelNumber, byte powerDown, byte gain, byte inputType, byte bias, byte srb2, byte srb1);
+ void streamSafeSetAllChannelsToDefault(void);
+ void streamSafeReportAllChannelDefaults(void);
+ void streamSafeLeadOffSetForChannel(byte channelNumber, byte pInput, byte nInput);
+ void streamSafeTimeSendSyncSetPacket(void);
+ void streamStart(void);
+ void streamStop(void);
+
+ // OLD CODE REVERT
+ void writeChannelSettings();
+ void writeChannelSettings(byte N);
+ void changeChannelLeadOffDetect();
+ void changeChannelLeadOffDetect(byte N);
+ void configureLeadOffDetection(byte amplitudeCode, byte freqCode);
+
+ boolean waitForNewChannelData(void);
+
+ // Variables
+ boolean daisy;
+ boolean sniffMode;
+ boolean streaming;
+ boolean timeSynced;
+ boolean sendTimeSyncUpPacket;
+ boolean isProcessingIncomingSettingsChannel;
+ boolean isProcessingIncomingSettingsLeadOff;
+ boolean settingBoardMode;
+ volatile boolean channelDataAvailable;
+
+ boolean isProcessingMultibyteMsg(void);
+ boolean isValidBoardType(char c);
+
+ uint8_t curBoardMode;
+
+ int numberOfIncomingSettingsProcessedChannel;
+ int numberOfIncomingSettingsProcessedLeadOff;
+ char streamPacketType;
+ char currentChannelSetting;
+
+ // Getters
+ char getChannelCommandForAsciiChar(char asciiChar);
+ char getConstrainedChannelNumber(byte channelNumber);
+ byte getDefaultChannelSettingForSetting(byte setting);
+ char getDefaultChannelSettingForSettingAscii(byte setting);
+ char getGainForAsciiChar(char asciiChar);
+ char getNumberForAsciiChar(char asciiChar);
+ char getTargetSSForConstrainedChannelNumber(byte channelNumber);
+ char getYesOrNoForAsciiChar(char asciiChar);
+
+ DSPI0 spi; // use DSPI library
+
+// BOARD
+ boolean useAccel;
+ boolean useAux;
+ void initialize(void);
+ void initializeVariables(void);
+ void printAllRegisters(void);
+ void sendChannelData(void); // send the current data with sample number
+
+
+// ADS1299
+ void initialize_ads(void);
+ void setChannelsToDefault(void);
+ void reportDefaultChannelSettings(void);
+ void printADSregisters(int);
+ void WAKEUP(int); // get out of low power mode
+ void STANDBY(int); // go into low power mode
+ void RESET(int); // set all register values to default
+ void START(int); // start data acquisition
+ void STOP(int); // stop data acquisition
+ void RDATAC(int); // go into read data continuous mode
+ void SDATAC(int); // get out of read data continuous mode
+ void RDATA(int); // read data one-shot
+ byte RREG(byte,int); // read one ADS register
+ void RREGS(byte,byte,int); // read multiple ADS registers
+ void WREG(byte,byte,int); // write one ADS register
+ void WREGS(byte,byte,int); // write multiple ADS registers
+ byte ADS_getDeviceID(int);
+ void printRegisterName(byte); // used for verbosity
+ void printHex(byte); // used for verbosity
+ void updateChannelData(void); // retrieve data from ADS
+ void updateBoardData(void);
+ void updateDaisyData(void);
+ byte xfer(byte); // SPI Transfer function
+ void resetADS(int); // reset all the ADS1299's settings
+ void startADS(void);
+ void stopADS(void);
+ void activateChannel(byte); // enable the selected channel
+ void deactivateChannel(byte); // disable given channel 1-8(16)
+ void configureInternalTestSignal(byte,byte);
+
+ void changeInputType(byte);
+
+ void ADS_writeChannelData(void);
+ // void ADS_printDeviceID(int); //
+ boolean smellDaisy(void);
+ void removeDaisy(void);
+ void attachDaisy(void);
+ void writeAuxData(void);
+
+ short auxData[3]; // This is user faceing
+ byte regData[24]; // array is used to mirror register data
+ byte lastBoardDataRaw[24];
+ byte boardChannelDataRaw[24]; // array to hold raw channel data
+ byte meanBoardDataRaw[24];
+ byte lastDaisyDataRaw[24];
+ byte daisyChannelDataRaw[24];
+ byte meanDaisyDataRaw[24];
+ int boardStat; // used to hold the status register
+ int daisyStat;
+ int boardChannelDataInt[8]; // array used when reading channel data as ints
+ int lastBoardChannelDataInt[8];
+ int meanBoardChannelDataInt[8];
+ int daisyChannelDataInt[8]; // array used when reading channel data as ints
+ int lastDaisyChannelDataInt[8];
+ int meanDaisyChannelDataInt[8];
+ int numChannels;
+ byte channelSettings[OPENBCI_NUMBER_OF_CHANNELS_DAISY][OPENBCI_NUMBER_OF_CHANNEL_SETTINGS]; // array to hold current channel settings
+ byte defaultChannelSettings[OPENBCI_NUMBER_OF_CHANNEL_SETTINGS]; // default channel settings
+ byte leadOffSettings[OPENBCI_NUMBER_OF_CHANNELS_DAISY][OPENBCI_NUMBER_OF_LEAD_OFF_SETTINGS]; // used to control on/off of impedance measure for P and N side of each channel
+ boolean useInBias[OPENBCI_NUMBER_OF_CHANNELS_DAISY]; // used to remember if we were included in Bias before channel power down
+ boolean useSRB2[OPENBCI_NUMBER_OF_CHANNELS_DAISY];
+ boolean boardUseSRB1; // used to keep track of if we are using SRB1
+ boolean daisyUseSRB1;
+ boolean verbosity; // turn on/off Serial verbosity
+ boolean daisyPresent;
+ boolean firstDataPacket;
+ byte sampleCounter;
+
+// LIS3DH
+ short axisData[3];
+ void initialize_accel(byte); // initialize
+ void enable_accel(byte); // start acceleromoeter with default settings
+ void disable_accel(void); // stop data acquisition and go into low power mode
+ byte LIS3DH_getDeviceID(void);
+ byte LIS3DH_read(byte); // read a register on LIS3DH
+ void LIS3DH_write(byte,byte); // write a register on LIS3DH
+ int LIS3DH_read16(byte); // read two bytes, used to get axis data
+ int getX(void);
+ int getY(void);
+ int getZ(void);
+ boolean LIS3DH_DataReady(void); // check LIS3DH_DRDY pin
+ boolean LIS3DH_DataAvailable(void); // check LIS3DH STATUS_REG2
+ void LIS3DH_readAllRegs(void);
+ void LIS3DH_writeAxisData(void);
+ void LIS3DH_writeAxisDataForAxis(uint8_t axis);
+ void LIS3DH_updateAxisData(void);
+
+ void csLow(int);
+ void csHigh(int);
+
+ //
+ boolean boardBegin(void);
+ boolean boardBeginDebug(void);
+ boolean boardBeginDebug(int);
+ void boardReset(void);
+ void ledFlash(int numberOfFlashes);
+ void sendEOT(void);
+
+ char buffer[1];
+
+// ADS1299
+ boolean isRunning;
+// LIS3DH
+ int DRDYpinValue;
+ int lastDRDYpinValue;
+
+ // Time sync Variables
+ unsigned long timeOffset;
+ unsigned long timeSetCharArrived;
+ unsigned long timeComputer;
+ unsigned long timeCurrent;
+ // Time sync Methods
+ // unsigned long timeGet(void);
+ // void timeSet(char character);
+ void timeSendSyncSetPacket(void);
+
+};
+
+// This let's us call into the class from within the library if necessary
+extern OpenBCI_32bit_Library board;
+
+#endif
--- a/PlatformDefs.h Sun Dec 04 03:38:44 2016 +0000 +++ b/PlatformDefs.h Sun Jan 22 04:10:11 2017 +0000 @@ -4,7 +4,7 @@ #define boolean unsigned char #define byte unsigned char - +#define __USER_ISR #define HIGH 1 #define LOW 0 @@ -25,6 +25,7 @@ #include "PlatformUart.h" extern platformUart Serial0; +extern platformUart_Dummy Serial1; #include "PlatformSPI.h" @@ -35,3 +36,15 @@ #define writeDataToSDcard(x) #define setupSDcard(x) 1 #define closeSDfile(x) 0 + +#define setIntVector(x,y) +#define setIntPriority(x,y,z) +#define clearIntFlag(x) +//#define setIntEnable(x) + +#define PORTA 0 +#define _EXTERNAL_4_IRQ 0 + +#define millis() time(NULL) + +#define OPENBCI_SOP_SYMBOL 0xA0//'A' \ No newline at end of file
--- a/PlatformGPIO.cpp Sun Dec 04 03:38:44 2016 +0000
+++ b/PlatformGPIO.cpp Sun Jan 22 04:10:11 2017 +0000
@@ -9,7 +9,7 @@
DigitalOut daisy_SS(DAISY_ADS);
DigitalOut accel_SS(LIS3DH_SS);
-DigitalIn adc_ready(ADS_DRDY);
+InterruptIn adc_ready(ADS_DRDY);
DigitalIn accel_ready(LIS3DH_DRDY);
void digitalWrite(int pin, unsigned char value)
@@ -38,3 +38,11 @@
if (pin == LIS3DH_DRDY)
return accel_ready;
}
+
+// external interrupt as ready signal
+extern void ADS_DRDY_Service();
+
+void setIntEnable(int x)
+{
+ adc_ready.fall(&ADS_DRDY_Service);
+}
\ No newline at end of file
--- a/PlatformGPIO.h Sun Dec 04 03:38:44 2016 +0000 +++ b/PlatformGPIO.h Sun Jan 22 04:10:11 2017 +0000 @@ -19,5 +19,6 @@ void digitalWrite(int pin, unsigned char value); unsigned char digitalRead(int pin); +void setIntEnable(int x); #endif \ No newline at end of file
--- a/PlatformSPI.cpp Sun Dec 04 03:38:44 2016 +0000
+++ b/PlatformSPI.cpp Sun Jan 22 04:10:11 2017 +0000
@@ -7,7 +7,7 @@
void DSPI0::begin()
{
-
+
}
void DSPI0::setSpeed(int speed_hz)
--- a/PlatformUart.cpp Sun Dec 04 03:38:44 2016 +0000
+++ b/PlatformUart.cpp Sun Jan 22 04:10:11 2017 +0000
@@ -2,8 +2,11 @@
#include "PlatformUart.h"
#include "mbed.h"
+#include "SerialBuffered.h"
-Serial uart(PA_9, PA_10, 115200); // Serial(PinName tx, PinName rx, const char *name=NULL, int baud = MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE);
+
+//Serial uart(PA_9, PA_10, 115200); // Serial(PinName tx, PinName rx, const char *name=NULL, int baud = MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE);
+SerialBuffered uart( 256, PA_9, PA_10, 115200 );
int platformUart::write(int data)
@@ -199,19 +202,17 @@
}
-extern void eventSerial();
+
+
unsigned char rx_data;
-unsigned char rx_avalible;
// Interupt Routine to read in data from serial port
void Rx_interrupt()
{
- while (uart.readable())
+ //while (uart.readable())
{
rx_data = uart.getc();
- rx_avalible = 1;
-
- eventSerial();
+ //byteQueue_Put(&rxQueue, rx_data);
}
}
@@ -219,24 +220,23 @@
platformUart::platformUart()
{
- rx_data = 0;
- rx_avalible = 0;
+ //byteQueue_Init(&rxQueue);
- uart.attach(&Rx_interrupt, Serial::RxIrq);
+ //uart.attach(&Rx_interrupt, Serial::RxIrq);
}
unsigned char platformUart::available()
{
- return rx_avalible;
+ return uart.readable(); //!(byteQueue_IsEmpty(&rxQueue));
}
unsigned char platformUart::read()
{
- rx_avalible = 0;
- return rx_data;
+ return uart.getc(); //byteQueue_Get(&rxQueue);
}
-platformUart Serial0;
\ No newline at end of file
+platformUart Serial0;
+platformUart_Dummy Serial1;
\ No newline at end of file
--- a/PlatformUart.h Sun Dec 04 03:38:44 2016 +0000
+++ b/PlatformUart.h Sun Jan 22 04:10:11 2017 +0000
@@ -11,6 +11,39 @@
#include <stddef.h>
#include <stdint.h>
+
+class platformUart_Dummy {
+public:
+ int write(int data) { return 0; }
+ //int write(char* str);
+
+ size_t print(const char[]) { return 0; }
+ size_t print(char) { return 0; }
+ size_t print(unsigned char, int = DEC) { return 0; }
+ size_t print(int, int = DEC) { return 0; }
+ size_t print(unsigned int, int = DEC) { return 0; }
+ size_t print(long, int = DEC) { return 0; }
+ size_t print(unsigned long, int = DEC) { return 0; }
+ size_t print(double, int = 2) { return 0; }
+
+ size_t println(const char[]) { return 0; }
+ size_t println(char) { return 0; }
+ size_t println(unsigned char, int = DEC) { return 0; }
+ size_t println(int, int = DEC) { return 0; }
+ size_t println(unsigned int, int = DEC) { return 0; }
+ size_t println(long, int = DEC) { return 0; }
+ size_t println(unsigned long, int = DEC) { return 0; }
+ size_t println(double, int = 2) { return 0; }
+ size_t println(void) { return 0; }
+
+ unsigned char available() { return 0; }
+ unsigned char read() { return 0; }
+ void begin(int baudrate) {};
+
+ operator int() const { return 0; }
+
+};
+
class platformUart {
public:
int write(int data);
@@ -37,6 +70,7 @@
unsigned char available();
unsigned char read();
+ void begin(int baudrate) {}
platformUart();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/SerialBuffered.cpp Sun Jan 22 04:10:11 2017 +0000
@@ -0,0 +1,117 @@
+
+#include "mbed.h"
+#include "SerialBuffered.h"
+
+//extern Serial loggerSerial;
+
+SerialBuffered::SerialBuffered( size_t bufferSize, PinName tx, PinName rx, int baud ) : RawSerial( tx, rx, baud )
+{
+ m_buffSize = 0;
+ m_contentStart = 0;
+ m_contentEnd = 0;
+ m_timeout = 1.0;
+
+
+ attach( this, &SerialBuffered::handleInterrupt );
+
+ m_buff = (uint8_t *) malloc( bufferSize );
+ if( m_buff == NULL )
+ {
+ //loggerSerial.printf("SerialBuffered - failed to alloc buffer size %d\r\n", (int) bufferSize );
+ }
+ else
+ {
+ m_buffSize = bufferSize;
+ }
+}
+
+
+SerialBuffered::~SerialBuffered()
+{
+ if( m_buff )
+ free( m_buff );
+}
+
+void SerialBuffered::setTimeout( float seconds )
+{
+ m_timeout = seconds;
+}
+
+size_t SerialBuffered::readBytes( uint8_t *bytes, size_t requested )
+{
+ int i = 0;
+
+ for( ; i < requested; )
+ {
+ int c = getc();
+ if( c < 0 )
+ break;
+ bytes[i] = c;
+ i++;
+ }
+
+ return i;
+
+}
+
+
+int SerialBuffered::getc()
+{
+ m_timer.reset();
+ m_timer.start();
+ while( m_contentStart == m_contentEnd )
+ {
+
+
+ wait_ms( 1 );
+ if( m_timeout > 0 && m_timer.read() > m_timeout )
+ return EOF;
+ }
+
+ m_timer.stop();
+
+ uint8_t result = m_buff[m_contentStart++];
+ m_contentStart = m_contentStart % m_buffSize;
+
+
+ return result;
+}
+
+
+int SerialBuffered::readable()
+{
+ return m_contentStart != m_contentEnd ;
+}
+
+#include "stm32l4xx_hal_def.h"
+#include "stm32l4xx_hal_uart.h"
+
+void SerialBuffered::handleInterrupt()
+{
+
+ while( RawSerial::readable())
+ {
+ if( m_contentStart == (m_contentEnd +1) % m_buffSize)
+ {
+ //loggerSerial.printf("SerialBuffered - buffer overrun, data lost!\r\n" );
+ RawSerial::getc();
+ //UART_HandleTypeDef huart;
+ //huart.Instance = (USART_TypeDef *)USART1_BASE;
+ //__HAL_UART_CLEAR_FLAG(&huart, UART_FLAG_RXNE);
+ //volatile uint32_t tmpval = huart.Instance->RDR;
+
+ //break;
+
+ }
+ else
+ {
+
+ m_buff[ m_contentEnd ++ ] = RawSerial::getc();
+ m_contentEnd = m_contentEnd % m_buffSize;
+
+
+
+ }
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/SerialBuffered.h Sun Jan 22 04:10:11 2017 +0000
@@ -0,0 +1,39 @@
+#pragma once
+
+// This is a buffered serial reading class, using the serial interrupt introduced in mbed library version 18 on 17/11/09
+
+// In the simplest case, construct it with a buffer size at least equal to the largest message you
+// expect your program to receive in one go.
+
+class SerialBuffered : public RawSerial
+{
+public:
+ SerialBuffered( size_t bufferSize, PinName tx, PinName rx, int baud );
+ virtual ~SerialBuffered();
+
+ int getc(); // will block till the next character turns up, or return -1 if there is a timeout
+
+ int readable(); // returns 1 if there is a character available to read, 0 otherwise
+
+ void setTimeout( float seconds ); // maximum time in seconds that getc() should block
+ // while waiting for a character
+ // Pass -1 to disable the timeout.
+
+ size_t readBytes( uint8_t *bytes, size_t requested ); // read requested bytes into a buffer,
+ // return number actually read,
+ // which may be less than requested if there has been a timeout
+
+
+private:
+
+ void handleInterrupt();
+
+
+ uint8_t *m_buff; // points at a circular buffer, containing data from m_contentStart, for m_contentSize bytes, wrapping when you get to the end
+ uint16_t m_contentStart; // index of first bytes of content
+ uint16_t m_contentEnd; // index of bytes after last byte of content
+ uint16_t m_buffSize;
+ float m_timeout;
+ Timer m_timer;
+
+};
\ No newline at end of file
--- a/main.cpp Sun Dec 04 03:38:44 2016 +0000
+++ b/main.cpp Sun Jan 22 04:10:11 2017 +0000
@@ -5,551 +5,53 @@
DigitalOut led_blue(PB_5);
-
-#include "OpenBCI_32_Daisy.h"
-
-//------------------------------------------------------------------------------
-void setup(void);
-void loop();
-void loadChannelSettings(char c);
-void eventSerial();
-void getCommand(char token);
-void sendEOT();
-void loadChannelSettings(char c);
-void writeChannelSettings_maintainRunningState(char chan);
-void setChannelsToDefaultSetting();
-void loadLeadOffSettings(char c);
-char getChannelNumber(char n);
-void changeChannelState_maintainRunningState(byte chan, int start);
-void activateAllChannelsToTestCondition(byte testInputCode, byte amplitudeCode, byte freqCode);
-int changeChannelLeadOffDetect_maintainRunningState(char chan);
-void sendDefaultChannelSettings();
-boolean stopRunning(void);
-boolean startRunning(int OUT_TYPE);
-void printRegisters();
-void startFromScratch();
-
+//#include <DSPI.h>
+#include "OpenBCI_32bit_Library.h"
+#include "Definitions.h"
-//------------------------------------------------------------------------------
-// << SD CARD BUSINESS >>
-boolean SDfileOpen = false;
-char fileSize = '0'; // SD file size indicator
-int blockCounter = 0;
-//------------------------------------------------------------------------------
-// << OpenBCI BUSINESS >>
-boolean is_running = false; // this flag is set in serialEvent on reciept of ascii prompt
-OpenBCI_32_Daisy OBCI; //Uses SPI bus and pins to say data is ready.
-// these are used to change individual channel settings from PC
-char currentChannelToSet; // keep track of what channel we're loading settings for
-boolean getChannelSettings = false; // used to receive channel settings command
-int channelSettingsCounter; // used to retrieve channel settings from serial port
-int leadOffSettingsCounter;
-boolean getLeadOffSettings = false;
-// these are all subject to the radio requirements: 31byte max packet length (maxPacketLength - 1 for packet checkSum)
-#define OUTPUT_NOTHING (0) // quiet
-#define OUTPUT_8_CHAN (1) // not using Daisy module
-#define OUTPUT_16_CHAN (2) // using Daisy module
-int outputType = OUTPUT_8_CHAN; // default to 8 channels
-
-//------------------------------------------------------------------------------
-// << LIS3DH Accelerometer Business >>
-boolean addAccelToSD = false; // this flag get's set and cleared in the code below
-//------------------------------------------------------------------------------
-// << PUT FILTER STUFF HERE >>
-boolean useFilters = false; // add DSP if you like, and set this true to turn them on
-//------------------------------------------------------------------------------
-// << BASIC BOARD STUFF >>
-int LED = 11; // alias for the blue LED
-int PGCpin = 12; // PGC pin goes high when PIC is in bootloader mode
-//------------------------------------------------------------------------------
-// << AUXILIARY DATA STUFF >>
-boolean addAuxToSD = false; // use this to write auxiliary data to SD if you like
-//------------------------------------------------------------------------------
-void setup(void) {
-
- pinMode(LED, OUTPUT); digitalWrite(LED, HIGH); // blue LED
- pinMode(PGCpin, OUTPUT); digitalWrite(PGCpin, LOW); // used to tell RFduino if we are in bootloader mode NOT IMPLEMENTED
- delay(1000); // take a break
-
- startFromScratch(); // initialize OpenBCI, read device IDs
- // you can set EITHER useAccel or useAux to true
- // if you want both, you MUST set and clear one of the variables every sample
- OBCI.useAccel = true; // option to add/remove accelerometer data to stream
- OBCI.useAux = false; // option to add/remove auxiliary data to stream
-
-
+void setup() {
+ // Bring up the OpenBCI Board
+ board.begin();
}
-
-
void loop() {
- if (is_running) {
-
- while (!(OBCI.isDataAvailable())) {} // wait for DRDY pin...
-
- OBCI.updateChannelData(); // get the fresh ADS results
- if (OBCI.useAccel && OBCI.LIS3DH_DataAvailable()) {
- OBCI.LIS3DH_updateAxisData(); // fresh axis data goes into the X Y Z
- addAccelToSD = true;
- }
- if (SDfileOpen) {
- writeDataToSDcard(OBCI.sampleCounter); // store data locally
- }
-
- OBCI.sendChannelData(); // serial fire hose
- }
-
- eventSerial();
-
-}
-
-
-// some variables to help find 'burger protocol' commands
-int plusCounter = 0;
-char testChar;
-unsigned long commandTimer;
-
-void eventSerial() {
- while (Serial0.available()) {
- char inChar = (char)Serial0.read();
-
- //getCommand(inChar); // decode the command
-
- if (getChannelSettings) { // if we just got an 'x' expect channel setting parameters
- loadChannelSettings(inChar); // go get em!
- } else if (getLeadOffSettings) { // if we just got a 'z' expect lead-off setting parameters
- loadLeadOffSettings(inChar); // go get em!
- } else {
- getCommand(inChar); // decode the command
- }
-
-/*
- if (plusCounter == 1) { // if we have received the first 'bun'
- testChar = inChar; // this might be the 'patty', stop laughing
- plusCounter++; // get ready to look for another 'bun'
- commandTimer = millis(); // don't wait too long!
- }
-
- if (inChar == '+') { // if we see a 'bun' on the serial
- plusCounter++; // make a note of it
- if (plusCounter == 3) { // looks like we got a command character
- if (millis() - commandTimer < 5) { // if it's not too late,
- if (getChannelSettings) { // if we just got an 'x' expect channel setting parameters
- loadChannelSettings(testChar); // go get em!
- } else if (getLeadOffSettings) { // if we just got a 'z' expect lead-off setting parameters
- loadLeadOffSettings(testChar); // go get em!
- } else {
- getCommand(testChar); // decode the command
- }
- }
- plusCounter = 0; // get ready for the next one
- }
- }
-*/
- }
-}
-
+ if (board.streaming) {
+ if (board.channelDataAvailable) {
+ // Read from the ADS(s), store data, set channelDataAvailable flag to false
+ board.updateChannelData();
-void getCommand(char token) {
- switch (token) {
- //TURN CHANNELS ON/OFF COMMANDS
- 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 '!':
- changeChannelState_maintainRunningState(1, ACTIVATE); break;
- case '@':
- changeChannelState_maintainRunningState(2, ACTIVATE); break;
- case '#':
- changeChannelState_maintainRunningState(3, ACTIVATE); break;
- case '$':
- changeChannelState_maintainRunningState(4, ACTIVATE); break;
- case '%':
- changeChannelState_maintainRunningState(5, ACTIVATE); break;
- case '^':
- changeChannelState_maintainRunningState(6, ACTIVATE); break;
- case '&':
- changeChannelState_maintainRunningState(7, ACTIVATE); break;
- case '*':
- changeChannelState_maintainRunningState(8, ACTIVATE); break;
- case 'q':
- changeChannelState_maintainRunningState(9, DEACTIVATE); break;
- case 'w':
- changeChannelState_maintainRunningState(10, DEACTIVATE); break;
- case 'e':
- changeChannelState_maintainRunningState(11, DEACTIVATE); break;
- case 'r':
- changeChannelState_maintainRunningState(12, DEACTIVATE); break;
- case 't':
- changeChannelState_maintainRunningState(13, DEACTIVATE); break;
- case 'y':
- changeChannelState_maintainRunningState(14, DEACTIVATE); break;
- case 'u':
- changeChannelState_maintainRunningState(15, DEACTIVATE); break;
- case 'i':
- changeChannelState_maintainRunningState(16, DEACTIVATE); break;
- case 'Q':
- changeChannelState_maintainRunningState(9, ACTIVATE); break;
- case 'W':
- changeChannelState_maintainRunningState(10, ACTIVATE); break;
- case 'E':
- changeChannelState_maintainRunningState(11, ACTIVATE); break;
- case 'R':
- changeChannelState_maintainRunningState(12, ACTIVATE); break;
- case 'T':
- changeChannelState_maintainRunningState(13, ACTIVATE); break;
- case 'Y':
- changeChannelState_maintainRunningState(14, ACTIVATE); break;
- case 'U':
- changeChannelState_maintainRunningState(15, ACTIVATE); break;
- case 'I':
- changeChannelState_maintainRunningState(16, ACTIVATE); break;
-
- // TEST SIGNAL CONTROL COMMANDS
- 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 '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;
-
- // SD CARD COMMANDS
- // 5min 15min 30min 1hr 2hr 4hr 12hr 24hr 512blocks
- case 'A': case'S': case'F': case'G': case'H': case'J': case'K': case'L': case 'a':
- fileSize = token; SDfileOpen = setupSDcard(fileSize); //
- break;
- case 'j': // close the file, if it's open
- if (SDfileOpen) {
- SDfileOpen = closeSDfile();
- }
- break;
-
- // CHANNEL SETTING COMMANDS
- case 'x': // expect 6 parameters
- if (!is_running) {
- Serial0.println("ready to accept new channel settings");
- }
- channelSettingsCounter = 0;
- getChannelSettings = true; break;
- case 'X': // latch channel settings
- if (!is_running) {
- Serial0.println("updating channel settings");
- }
- writeChannelSettings_maintainRunningState(currentChannelToSet); break;
- case 'd': // reset all channel settings to default
- if (!is_running) {
- Serial0.println("updating channel settings to default");
- }
- setChannelsToDefaultSetting(); break;
- case 'D': // report the default settings
- sendDefaultChannelSettings(); break;
-
- // LEAD OFF IMPEDANCE DETECTION COMMANDS
- case 'z': // expect 2 parameters
- if (!is_running) {
- Serial0.println("ready to accept new impedance detect settings");
- }
- leadOffSettingsCounter = 0; // reset counter
- getLeadOffSettings = true;
- break;
- case 'Z': // latch impedance parameters
- if (!is_running) {
- Serial0.println("updating impedance detect settings");
- }
- changeChannelLeadOffDetect_maintainRunningState(currentChannelToSet);
- break;
-
- // DAISY MODULE COMMANDS
- case 'c': // use 8 channel mode
- if (OBCI.daisyPresent) {
- OBCI.removeDaisy();
- }
- outputType = OUTPUT_8_CHAN;
- break;
- case 'C': // use 16 channel mode
- if (OBCI.daisyPresent == false) {
- OBCI.attachDaisy();
- }
- if (OBCI.daisyPresent) {
- Serial0.print("16"); outputType = OUTPUT_16_CHAN;
+ if (board.timeSynced) {
+ // Send time synced packet with channel data, current board time, and an accel reading
+ // X axis is sent on sampleCounter % 10 == 7
+ // Y axis is sent on sampleCounter % 10 == 8
+ // Z axis is sent on sampleCounter % 10 == 9
+ board.sendChannelDataWithTimeAndAccel();
} else {
- Serial0.print("8"); outputType = OUTPUT_8_CHAN;
- }
- sendEOT();
- break;
-
- // STREAM DATA AND FILTER COMMANDS
- case 'b': // stream data
- if (SDfileOpen) stampSD(ACTIVATE); // time stamp the start time
- if (OBCI.useAccel) {
- OBCI.enable_accel(RATE_25HZ); // fire up the accelerometer if you want it
- }
- startRunning(outputType); // turn on the fire hose
- break;
- case 's': // stop streaming data
- if (SDfileOpen) stampSD(DEACTIVATE); // time stamp the stop time
- if (OBCI.useAccel) {
- OBCI.disable_accel(); // shut down the accelerometer if you're using it
+ // Send standard packet with channel data
+ board.sendChannelDataWithAccel();
}
- stopRunning();
- break;
- case 'f':
- useFilters = true;
- break;
- case 'g':
- useFilters = false;
- break;
-
- // INITIALIZE AND VERIFY
- case 'v':
- startFromScratch(); // initialize ADS and read device IDs
- break;
- // QUERY THE ADS AND ACCEL REGITSTERS
- case '?':
- printRegisters(); // print the ADS and accelerometer register values
- break;
- default:
- break;
- }
-}// end of getCommand
-
-void sendEOT() {
- Serial0.print("$$$"); // shake hands with the controlling program
-}
-
-void loadChannelSettings(char c) {
-
- if (channelSettingsCounter == 0) { // if it's the first byte in this channel's array, this byte is the channel number to set
- currentChannelToSet = getChannelNumber(c); // we just got the channel to load settings into (shift number down for array usage)
- channelSettingsCounter++;
- if (!is_running) {
- Serial0.print("load setting ");
- Serial0.print("for channel ");
- Serial0.println(currentChannelToSet + 1, DEC);
+ /*
+ if (board.timeSynced) {
+ board.sendChannelDataWithTimeAndRawAux();
+ } else {
+ // Send standard packet with channel data
+ board.sendChannelDataWithRawAux();
+ }
+ */
}
- return;
- }
- // setting bytes are in order: POWER_DOWN, GAIN_SET, INPUT_TYPE_SET, BIAS_SET, SRB2_SET, SRB1_SET
- if (!is_running) {
- Serial0.print(channelSettingsCounter - 1);
- Serial0.print(" with "); Serial0.println(c);
- }
- c -= '0';
- if (channelSettingsCounter - 1 == GAIN_SET) {
- c <<= 4;
- }
- OBCI.channelSettings[currentChannelToSet][channelSettingsCounter - 1] = c;
- channelSettingsCounter++;
- if (channelSettingsCounter == 7) { // 1 currentChannelToSet, plus 6 channelSetting parameters
- if (!is_running) Serial0.print("done receiving settings for channel "); Serial0.println(currentChannelToSet + 1, DEC);
- getChannelSettings = false;
- }
-}
-
-void writeChannelSettings_maintainRunningState(char chan) {
- boolean is_running_when_called = is_running;
- int cur_outputType = outputType;
- stopRunning(); //must stop running to change channel settings
-
- OBCI.writeChannelSettings(chan + 1); // change the channel settings on ADS
-
- if (is_running_when_called == true) {
- startRunning(cur_outputType); //restart, if it was running before
- }
-}
-
-void setChannelsToDefaultSetting() {
- boolean is_running_when_called = is_running;
- int cur_outputType = outputType;
- stopRunning(); //must stop running to change channel settings
-
- OBCI.setChannelsToDefault(); // default channel settings
-
- if (is_running_when_called == true) {
- startRunning(cur_outputType); //restart, if it was running before
- }
-}
-
-void loadLeadOffSettings(char c) {
- if (leadOffSettingsCounter == 0) { // if it's the first byte in this channel's array, this byte is the channel number to set
- currentChannelToSet = getChannelNumber(c); // we just got the channel to load settings into (shift number down for array usage)
- if (!is_running) Serial0.print("changing LeadOff settings for channel "); Serial0.println(currentChannelToSet + 1, DEC);
- leadOffSettingsCounter++;
- return;
- }
- // setting bytes are in order: PCHAN, NCHAN
- if (!is_running) {
- Serial0.print("load setting "); Serial0.print(leadOffSettingsCounter - 1);
- Serial0.print(" with "); Serial0.println(c);
- }
- c -= '0';
- OBCI.leadOffSettings[currentChannelToSet][leadOffSettingsCounter - 1] = c;
- leadOffSettingsCounter++;
- if (leadOffSettingsCounter == 3) { // 1 currentChannelToSet, plus 2 leadOff setting parameters
- if (!is_running) Serial0.print("done receiving leadOff settings for channel "); Serial0.println(currentChannelToSet + 1, DEC);
- getLeadOffSettings = false; // release the serial COM
- }
-}
-
-char getChannelNumber(char n) {
- if (n > '0' && n < '9') {
- n -= '1';
}
- switch (n) {
- case 'Q':
- n = 0x08; break;
- case 'W':
- n = 0x09; break;
- case 'E':
- n = 0x0A; break;
- case 'R':
- n = 0x0B; break;
- case 'T':
- n = 0x0C; break;
- case 'Y':
- n = 0x0D; break;
- case 'U':
- n = 0x0E; break;
- case 'I':
- n = 0x0F; break;
- default: break;
- }
- return n;
-}
-
-void changeChannelState_maintainRunningState(byte chan, int start)
-{
- boolean is_running_when_called = is_running;
- int cur_outputType = outputType;
-
- //must stop running to change channel settings
- stopRunning();
- if (start == 1) {
- OBCI.activateChannel(chan);
- } else if (start == 0) {
- OBCI.deactivateChannel(chan);
- }
- //restart, if it was running before
- if (is_running_when_called == true) {
- startRunning(cur_outputType);
- }
-}
-
-void activateAllChannelsToTestCondition(byte testInputCode, byte amplitudeCode, byte freqCode)
-{
- boolean is_running_when_called = is_running;
- int cur_outputType = outputType;
- //must stop running to change channel settings
- stopRunning(); delay(10);
-
- //set the test signal to the desired state
- OBCI.configureInternalTestSignal(amplitudeCode, freqCode);
- //change input type settings for all channels
- OBCI.changeInputType(testInputCode);
-
- //restart, if it was running before
- if (is_running_when_called == true) {
- startRunning(cur_outputType);
- }
-}
-
-int changeChannelLeadOffDetect_maintainRunningState(char chan)
-{
- boolean is_running_when_called = is_running;
- int cur_outputType = outputType;
-
- //must stop running to change channel settings
- stopRunning();
-
- OBCI.changeChannelLeadOffDetect(chan);
-
- //restart, if it was running before
- if (is_running_when_called == true) {
- startRunning(cur_outputType);
- }
-}
-
-void sendDefaultChannelSettings() {
- boolean is_running_when_called = is_running;
- int cur_outputType = outputType;
-
- OBCI.reportDefaultChannelSettings();
- sendEOT();
- delay(10);
-
- //restart, if it was running before
- if (is_running_when_called == true) {
- startRunning(cur_outputType);
- }
-}
-
-boolean stopRunning(void) {
- if (is_running) {
- OBCI.stopStreaming(); // stop the data acquisition, turn off accelerometer
- is_running = false;
- }
- return is_running;
-}
-
-boolean startRunning(int OUT_TYPE) {
- if (!is_running) {
- outputType = OUT_TYPE;
- OBCI.startStreaming(); // start the data acquisition, turn on accelerometer
- is_running = true;
- }
- return is_running;
-}
-
-void printRegisters() {
-
- if (!is_running) {
- // print the ADS and LIS3DH registers
- OBCI.printAllRegisters();
- sendEOT();
- delay(20);
- }
-
-}
-
-void startFromScratch() {
- if (!is_running) {
- OBCI.initialize(); // initializes accelerometer and on-board ADS and on-daisy ADS if present
- delay(500);
- Serial0.println("OpenBCI V3 16 channel");
- OBCI.configureLeadOffDetection(LOFF_MAG_6NA, LOFF_FREQ_31p2HZ);
- Serial0.print("On Board ADS1299 Device ID: 0x"); Serial0.println(OBCI.ADS_getDeviceID(ON_BOARD), HEX);
- if (OBCI.daisyPresent) { // library will set this in initialize() if daisy present and functional
- Serial0.print("On Daisy ADS1299 Device ID: 0x"); Serial0.println(OBCI.ADS_getDeviceID(ON_DAISY), HEX);
- }
- Serial0.print("LIS3DH Device ID: 0x"); Serial0.println(OBCI.LIS3DH_getDeviceID(), HEX);
- sendEOT();
+ // Check the serial port for new data
+ if (board.hasDataSerial0()) {
+ // Read one char and process it
+ board.processChar(board.getCharSerial0());
}
}
int main()
-{
+{
setup();
while (1) loop();