Alex Borisevich
/
OpenBCI
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();