diff --git a/.gitignore b/.gitignore index 842cc48..cc0649c 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,13 @@ Meeting-Sean(Electrodes:Diagrams:Stores:More)/ # ODS Lock Files # ################## .~lock.* + +# Ignore `bin` dir +*/bin/* + +# Ignore `obj` dir +*/obj/* +*.o + +#Ignore log files +*.log diff --git a/code/software/ADS_1299_Embedded/scripts/run_neuro.sh b/code/software/ADS_1299_Embedded/scripts/run_neuro.sh index 04b980e..fabadb4 100755 --- a/code/software/ADS_1299_Embedded/scripts/run_neuro.sh +++ b/code/software/ADS_1299_Embedded/scripts/run_neuro.sh @@ -6,7 +6,7 @@ LOG_NAME=bootup_$CREATE_DATE.log LOG_FILE=$LOG_DIR/$LOG_NAME printf "\nRunning ./bin/neuro ...\n" -sudo ./bin/neuro > $LOG_FILE +sudo $BSB_EMBEDDED/bin/neuro "$@" > $LOG_FILE printf "Finished running ./bin/neuro\n" diff --git a/code/software/ADS_1299_Embedded/scripts/setup.sh b/code/software/ADS_1299_Embedded/scripts/setup.sh index 253e5b7..215fbb3 100755 --- a/code/software/ADS_1299_Embedded/scripts/setup.sh +++ b/code/software/ADS_1299_Embedded/scripts/setup.sh @@ -12,6 +12,8 @@ export BSB_GUI="$BSB_HOME/code/gui" export BSB_DIG="$BSB_HOME/code/digital" export BSB_PCB="$BSB_HOME/EAGLE" +alias run_neuro="sudo $BSB_EMBEDDED/bin/neuro" + #printf "Biosignals-Board Embedded Setup Complete\n\n" cd $CURR_DIR diff --git a/code/software/ADS_1299_Embedded/src/ADS1299_bcm2835.c b/code/software/ADS_1299_Embedded/src/ADS1299_bcm2835.c index b657f18..f198ebe 100644 --- a/code/software/ADS_1299_Embedded/src/ADS1299_bcm2835.c +++ b/code/software/ADS_1299_Embedded/src/ADS1299_bcm2835.c @@ -15,9 +15,11 @@ void ADS1299_init() { + delayMicroseconds(50000); + // Configure ADS1299 - specific interface pins - // Set the pin_DRDY to be the input + // Set the pin_DRDY to be the input bcm2835_gpio_fsel(PIN_DRDY, BCM2835_GPIO_FSEL_INPT); @@ -28,8 +30,11 @@ void ADS1299_init() { bcm2835_gpio_fsel(PIN_PWDN, BCM2835_GPIO_FSEL_OUTP); // Configure test pins as outputs - bcm2835_gpio_fsel(TEST_PIN_1, BCM2835_GPIO_FSEL_OUTP); - bcm2835_gpio_fsel(TEST_PIN_2, BCM2835_GPIO_FSEL_OUTP); + + // FIXME: Uncomment this line. Currently commented out since TEST_PIN_1 (GPIO_J8_03) has been repurposed as PIN_RESET + //bcm2835_gpio_fsel(TEST_PIN_1, BCM2835_GPIO_FSEL_OUTP); + + //bcm2835_gpio_fsel(TEST_PIN_2, BCM2835_GPIO_FSEL_OUTP); bcm2835_gpio_fsel(TEST_PIN_3, BCM2835_GPIO_FSEL_OUTP); // Configure BCM2835 SPI settings @@ -39,18 +44,18 @@ void ADS1299_init() { // Set bit order bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST); // The default - + // Set the spi mode - 4 modes // BCM2835_SPI_MODE1 = 1, // CPOL = 0, CPHA = 1, Clock idle low, data is clocked in on falling edge, output data (change) on rising edge bcm2835_spi_setDataMode(BCM2835_SPI_MODE1); // The default - + //Set SPI clock speed // BCM2835_SPI_CLOCK_DIVIDER_512 = 512, ///< 512 = 2.048us = 488.28125kHz bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_512); // The default // Chip select bcm2835_spi_chipSelect(BCM2835_SPI_CS0); - + // Select the polarity LOW // ADS1299 uses an active low chip select bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, LOW); @@ -59,10 +64,16 @@ void ADS1299_init() { // Do not try writing to the pin or setting it as an OUTPUT!! // Initialize pins to default values - bcm2835_gpio_write(PIN_RESET, HIGH); + + // FIXME: UNcomment + + bcm2835_gpio_write(PIN_RESET, LOW); bcm2835_gpio_write(PIN_PWDN, LOW); - - // PIN_CS (chip select CE0) will be held HIGH when an SPI transfer is not in progress since we + delayMicroseconds(50000); + + //bcm2835_gpio_write(PIN_DRDY, LOW); + + // PIN_CS (chip select CE0) will be held HIGH when an SPI transfer is not in progress since we // set the chip select polarity to LOW. #ifdef __DEBUG__ printf("After ADS1299 initialization\n"); @@ -74,19 +85,25 @@ void ADS1299_init() { void ADS1299_bootup(){ /* Function: Bootup Routine of the ADS1299 Return: None */ - + + + bcm2835_gpio_write(PIN_RESET, HIGH); + // Bring PWDN pin high to exit low-power standby mode. Delay 100 us bcm2835_gpio_write(PIN_PWDN, HIGH); - delayMicroseconds(100); + delayMicroseconds(pow(2, 18) * TCLK); + + // Delay 2 seconds for VCAP1 >= 1.1 V + delayMicroseconds(2000000); //Set the pin to low and delay for 2*TCLK us (tRST) as per datasheet bcm2835_gpio_write(PIN_RESET, LOW); - delayMicroseconds(2*TCLK); + delayMicroseconds(2 * TCLK); //set pin to high to reset and bootup; delay 16 TCLK after end of RESET pulse //or 18 TCLK after start of RESET pulse, as per Power Up Sequence in datasheet (pg. 70) bcm2835_gpio_write(PIN_RESET,HIGH); - delayMicroseconds(18*TCLK); + delayMicroseconds(16*TCLK); // Initialize some state variables @@ -95,16 +112,50 @@ void ADS1299_bootup(){ // The default PGA gain on bootup is 24 ADS1299_pga_gain = 24; + + printf("After ADS1299 bootup\n"); + display_all_pin_states(); + printf("End of ADS1299_bootup()\n"); + } void ADS1299_config() { - // We are using an internal reference, so set PD_REFBUF to 1 + // We are using an internal reference, so set PD_REFBUF to 1 printf("\nSetting PD_REFBUF bit of CONFIG3 to 1 \n"); - ADS1299_write_register_field(CONFIG3, 1, 7, 1); + ADS1299_write_register(CONFIG3, 0xE0); // Arbritrary delay to wait for internal reference to settle - bcm2835_delayMicroseconds(500); -} + bcm2835_delayMicroseconds(500); +} + +void ADS1299_power_down() { + printf("\n Powering down ADS1299...\n"); + bcm2835_gpio_write(PIN_PWDN, LOW); + bcm2835_gpio_write(PIN_RESET, LOW); + if (!bcm2835_gpio_lev(PIN_PWDN)) + printf("\n ADS1299 Powered down\n"); +} + +void ADS1299_reboot() { + bool powered_on = false; + + powered_on = bcm2835_gpio_lev(PIN_PWDN); + + if (powered_on) { + printf("\n ADS1299 is powered on. Rebooting ...\n"); + + ADS1299_power_down(); + + bcm2835_delayMicroseconds(2 * 1000000); // Wait for 2 seconds before powering up again + + ADS1299_init(); + ADS1299_bootup(); + + printf("\n ADS1299 Reboot Finished\n"); + } else { + printf("\n ADS1299 is already powered-down. Aborting reboot ...\n"); + } +} //////////////////////// Register interface functions ////////////////////// /* Function: Read a single register of the ADS1299 @@ -146,7 +197,7 @@ uint8_t ADS1299_read_register_field(uint8_t reg_addr, uint8_t fld_size, uint8_t BYTE_TO_BIN(fld_offset), BYTE_TO_BIN(rd_data), BYTE_TO_BIN(rd_fld_data)); - + #endif return rd_fld_data; @@ -172,7 +223,7 @@ void ADS1299_write_register_field(uint8_t reg_addr, uint8_t fld_size, uint8_t fl // fld_size : 3 // fld_offset : 3 // Field data : 0b010 - // + // // wr_mask = ~(((1 << 3) - 1) << 3) // = ~((0b00001000 - 1) << 3) // = ~(0b00000111 << 3) @@ -245,20 +296,20 @@ bool ADS1299_test_registers() { result &= register_check(CONFIG1, CONFIG1_DEFAULT, ®_config1); result &= register_check(CONFIG2, CONFIG2_DEFAULT, ®_config2); - + // FIXME: Might need to remove CONFIG3 from bootup test. We write to it before testing to enable the internal reference register_check(CONFIG3, CONFIG3_DEFAULT, ®_config3); if (result) printf("\n--- ADS1299 register defaults test PASSED ---\n"); - else + else printf("\n--- ADS1299 register defaults test FAILED ---\n"); - + return result; } bool ADS1299_test_registers_write() { - + uint8_t id_wr_data, config1_wr_data, config2_wr_data, config3_wr_data; uint8_t id_rd_data, config1_rd_data, config2_rd_data, config3_rd_data; @@ -278,23 +329,23 @@ bool ADS1299_test_registers_write() { ADS1299_write_register(CONFIG1, config1_wr_data); result &= register_check(CONFIG1, config1_wr_data, &config1_rd_data); - + ADS1299_write_register(CONFIG2, config2_wr_data); result &= register_check(CONFIG2, config2_wr_data, &config2_rd_data); - + // FIXME: Might need to remove CONFIG3 from test, do not want to clobber PD_REFBUF bit //ADS1299_write_register(CONFIG3, config3_wr_data); //result &= register_check(CONFIG3, config3_wr_data, &config3_rd_data); - + if (result) printf("\n--- ADS1299 register write test PASSED ---\n"); - else + else printf("\n--- ADS1299 register write test FAILED ---\n"); - - + + return result; -} - +} + ///////////////////////////////////////////////////////////////////////////// @@ -303,9 +354,9 @@ bool ADS1299_test_registers_write() { void output_square_wave(int _pin, double _frequency, double _test_duration) { double test_wave_frequency = _frequency; double test_wave_period_us = (1/test_wave_frequency) * 1000000; - + int elapsed_cycles; - int num_cycles_for_test = _test_duration * _frequency; + int num_cycles_for_test = _test_duration * _frequency; for (elapsed_cycles = 0; elapsed_cycles < num_cycles_for_test; elapsed_cycles++) { bcm2835_gpio_write(_pin, HIGH); @@ -362,21 +413,21 @@ void display_all_pin_states() { } void display_pin_state(int _pin) { - if (_pin == PIN_DRDY ) + if (_pin == PIN_DRDY ) printf("\tPIN_DRDY : %x\n", bcm2835_gpio_lev(PIN_DRDY)); - else if (_pin == PIN_RESET) + else if (_pin == PIN_RESET) printf("\tPIN_RESET : %x\n", bcm2835_gpio_lev(PIN_RESET)); - else if (_pin == PIN_PWDN) + else if (_pin == PIN_PWDN) printf("\tPIN_PWDN : %x\n", bcm2835_gpio_lev(PIN_PWDN)); - else if (_pin == PIN_MOSI) + else if (_pin == PIN_MOSI) printf("\tPIN_MOSI : %x\n", bcm2835_gpio_lev(PIN_MOSI)); - else if (_pin == PIN_MISO) + else if (_pin == PIN_MISO) printf("\tPIN_MISO : %x\n", bcm2835_gpio_lev(PIN_MISO)); - else if (_pin == PIN_SCLK) + else if (_pin == PIN_SCLK) printf("\tPIN_SCLK : %x\n", bcm2835_gpio_lev(PIN_SCLK)); - else if (_pin == PIN_CS) + else if (_pin == PIN_CS) printf("\tPIN_CS : %x\n", bcm2835_gpio_lev(PIN_CS)); - else + else printf("\tRPI_BPLUS_GPIO_J8_%d : %x\n", _pin, bcm2835_gpio_lev(_pin)); } @@ -385,4 +436,4 @@ void display_pin_state(int _pin) { - + diff --git a/code/software/ADS_1299_Embedded/src/ADS1299_bcm2835.h b/code/software/ADS_1299_Embedded/src/ADS1299_bcm2835.h index 59d1228..f0a2440 100644 --- a/code/software/ADS_1299_Embedded/src/ADS1299_bcm2835.h +++ b/code/software/ADS_1299_Embedded/src/ADS1299_bcm2835.h @@ -11,6 +11,10 @@ void ADS1299_init(); void ADS1299_bootup(); void ADS1299_config(); + +void ADS1299_power_down(); + +void ADS1299_reboot(); ///////////// Register Interface functions ////////////// uint8_t ADS1299_read_register(uint8_t reg_addr); diff --git a/code/software/ADS_1299_Embedded/src/ADS1299_definitions.h b/code/software/ADS_1299_Embedded/src/ADS1299_definitions.h index 6543eb5..2502a6c 100644 --- a/code/software/ADS_1299_Embedded/src/ADS1299_definitions.h +++ b/code/software/ADS_1299_Embedded/src/ADS1299_definitions.h @@ -24,20 +24,20 @@ // Control Pins #define PIN_DRDY RPI_BPLUS_GPIO_J8_15 // Make Pin 15 the DRDY pin (purple cable) -#define PIN_RESET RPI_BPLUS_GPIO_J8_16 // Make Pin 16 the RESET pin (brown cable) +#define PIN_RESET RPI_BPLUS_GPIO_J8_03 // FIXME: Temporarily make GPIO Pin 3 the reset pin. Original: Make Pin 16 the RESET pin (brown cable) #define PIN_PWDN RPI_BPLUS_GPIO_J8_22 // Make Pin 22 the !PWDN pin (red cable) // SPI pins (DO NOT CHANGE. These are defined in hardware!) #define PIN_MOSI RPI_BPLUS_GPIO_J8_19 // Pin 19 is the MOSI pin (green cable) #define PIN_MISO RPI_BPLUS_GPIO_J8_21 // Pin 21 is the MISO pin (blue cable) #define PIN_SCLK RPI_BPLUS_GPIO_J8_23 // Pin 23 is the SCLK pin (white cable) -#define PIN_CS RPI_BPLUS_GPIO_J8_24 // Pin 24 (CE0) is the CS pin (yellow cable) +#define PIN_CS RPI_BPLUS_GPIO_J8_24 // Pin 24 (CE0) is the CS pin (yellow cable // Use GPIO pin 20 as DGND. Pin 20 is not a GPIO pin and is not defined in bcm2835.h #define PIN_DGND 20 // black cable // Dedicated Test Pins -#define TEST_PIN_1 RPI_BPLUS_GPIO_J8_03 // Dedicated test pin #1 +//#define TEST_PIN_1 RPI_BPLUS_GPIO_J8_03 // FIXME: This definistion needs to be commented out to not conflict with the PIN_RESET redefine to GPIO_J8_03. Original: Dedicated test pin #1 #define TEST_PIN_2 RPI_BPLUS_GPIO_J8_05 // Dedicated test pin #2 #define TEST_PIN_3 RPI_BPLUS_GPIO_J8_07 // Dedicated test pin #3 diff --git a/code/software/ADS_1299_Embedded/src/main.c b/code/software/ADS_1299_Embedded/src/main.c index cc144dd..8c93b6e 100644 --- a/code/software/ADS_1299_Embedded/src/main.c +++ b/code/software/ADS_1299_Embedded/src/main.c @@ -3,58 +3,276 @@ #include "ADS1299_bcm2835.h" #include "ads1299.h" #include +#include +#include int main(int argc, char **argv) { - // If error in intializing bcm - if (!bcm2835_init()) { - printf("Failed to init the Raspberry PI"); - return 1; - } + int opt; + bool do_bootup = true, do_test = false, dry_run = false, output_wave = false, power_down = false; + + + char* test_name = NULL; bool bootup_success = false; int num_attempts = 1; + int output_test_pin_num = 2; + int test_pin = TEST_PIN_2; int attempt = 1; - //ADS1299_init(); - //output_square_wave(TEST_PIN_1, 10000, 100000); + // Parse command line options + // -b -> Perform bootup sequence: bcm2835_init() -> ADS1299_init() -> AS1299_bootup() + // -t -> Perform specific test + // -w -> Output wave on to one of the three test pins. + // -r -> Repeat test if failed. Default number of repeats is 1 + // -d -> Running dry_run mode (not on Raspberry Pi) + // -p -> Power down chip after testing + + while ((opt = getopt(argc, argv, "bdpt:r:w:")) != -1) { + switch (opt) { + case 'd': + dry_run = true; + printf("\ngetopt - received 'd'\n"); + break; + case 'r': + num_attempts = atoi(optarg); + printf("\ngetopt - received 'r'. num_attempts = %d\n", num_attempts); + break; + case 'b': + do_bootup = true; + printf("\ngetopt - received 'b'\n"); + break; + case 'w': + output_wave = true; + // Do not bootup the chip + do_bootup = false; - // Perform boot-up and test CONFIG registers for default values. - - while (attempt <= num_attempts && !bootup_success) { + output_test_pin_num = atoi(optarg); + if (output_test_pin_num == 2) + test_pin = TEST_PIN_2; + else if (output_test_pin_num == 3) + test_pin = TEST_PIN_3; + else { + fprintf(stderr, "Error: Invalid test pin. Must be 2 or 3"); + exit(EXIT_FAILURE); + } - // Initialize BCM Configuration to communicate with chip - ADS1299_init(); + printf("\ngetopt - received 'w'. test_pin = %d\n", output_test_pin_num); - // bootup sequence - ADS1299_bootup(); - - // Send SDATAC before reading/writing registers - transferCmd(_SDATAC); + break; + case 't': + do_test = true; + do_bootup = true; + test_name = optarg; + printf("\ngetopt - received 't'. test_name = %s\n", test_name); + break; + case 'p': + power_down = true; + printf("\ngetopt - received 'p'\n"); + break; + default: + fprintf(stderr, "Usage: %s [-bt] [file...]\n", argv[0]); + exit(EXIT_FAILURE); + } + } - // Write necessary registers/pins for our ADS1299 configuration - ADS1299_config(); - - printf("\nAttempt #%d\n", attempt); + if (!dry_run) { // If running on the Raspberry Pi + + // If error in intializing bcm + if (!bcm2835_init()) { + printf("Failed to init the Raspberry PI"); + return 1; + } - // Test registers' default values - bootup_success = ADS1299_test_registers(); + // Note: Disable other tests or sequences if testing with a test pin + if (output_wave) { + // set attempt = num_attempts + 1 so we don't enter the following loop + attempt = num_attempts + 1; - if (bootup_success) { - printf("\n-- ADS1299 Boot-up Successful --\n"); - } else { - printf("\n-- ADS1299 Boot-up Failed --\n"); + // Output a 100 kHz wave to test_pin for 300 seconds (5 minutes). + // Note: This is a blocking call. + output_square_wave(test_pin, 100000, 300); } - attempt++; - // Delay 500 us before moving on or reattempting bootup - bcm2835_delayMicroseconds(500); + while (attempt <= num_attempts && !bootup_success) { + + if (do_bootup) { + + printf("\n-- ADS1299 Boot-up --\n"); + + // Initialize BCM Configuration to communicate with chip + ADS1299_init(); + + delayMicroseconds(100); + + // bootup sequence + ADS1299_bootup(); + } + + // Tests: + // + // register_test - Bootup and read the 3 CONFIG registers and compare the read values against their default values + // sdatac_test - Bootup and send sdatac command + // pwrup_ref_buf_test - Bootup and write to 0xE0 to CONFIG3 register to power up the reference buffer. + // power_cycle_test - Do 5 cycles of bootup and power down + + if (do_test) { + + // Cannot do tests if ADS1299 was not boot-up + if (!do_bootup) { + printf("\nError: ADS1299 is not bootup!!!\n"); + return 1; + } + + if (!strcmp(test_name, "register_test")) { // Test registers' default values + + // Send SDATAC before reading/writing registers + transferCmd(_SDATAC); + + // Write PD_REFBUF = 1 + ADS1299_config(); + + // Set data rate + printf("Set data rate - start\n"); + ADS1299_write_register(CONFIG1, 0x96); + ADS1299_write_register(CONFIG2, 0xC0); + printf("Set data rate - done\n"); + + // Set all channels to input short + int i; + + printf("\nWrite all CHNSET to 0x01\n"); + for (i=0; i < NUM_CHANNELS; i++) { + printf("Write CH%0dSET to 0x01 - Start", i); + ADS1299_write_register(CH1SET+i, 0x01); + printf("\nWrite CH%0dSET to 0x01 - End", i); + } + + delayMicroseconds(50000); + // Send START command + printf("\nSending START commad\n"); + transferCmd(_START); + + // Put back in RDATAC + printf("\nSending RDATAC commad\n"); + transferCmd(_RDATAC); + + + // sET-UP TEST SGIANLS + ADS1299_write_register(CONFIG2, 0xD0); + for (i=0; i < NUM_CHANNELS; i++) { + printf("Write CH%0dSET to 0x05 - Start", i); + ADS1299_write_register(CH1SET+i, 0x05); + printf("\nWrite CH%0dSET to 0x05 - End", i); + } + + // Loop forever + /* + int recv_data = 0; + while(1) { + //if (!bcm2835_gpio_lev(PIN_DRDY)) { // conversion finished + // Issue 216 = 24 + 8 * 24 SCLKS + int j; + for (j = 0; j < NUM_CHANNELS + 1; j++) { + recv_data = transferData(0x00); + + printf("Packet %d, Recv Data %d\n", j, recv_data); + + // Delay 1/250 sec = 4 ms + delayMicroseconds(4000); + } + //} else + } + */ - } + /////////////////////////////////////////////// + + + bootup_success = ADS1299_test_registers(); + + if (bootup_success) { + printf("\n-- ADS1299 Boot-up Successful --\n"); + } else { + printf("\n-- ADS1299 Boot-up Failed --\n"); + } + + } else if (!strcmp(test_name, "sdatac_test")) { + + printf("\n--- ADS1299 SDATAC test ---\n"); + + transferCmd(_SDATAC); + + printf("\n--- ADS1299 SDATAC test Finished ---\n"); + + } else if (!strcmp(test_name, "pwrup_ref_buf_test")) { + + printf("\n--- ADS1299 Power-up reference buffer test ---\n"); + + transferCmd(_SDATAC); + + ADS1299_config(); + + printf("\n--- ADS1299 Power-up reference buffer test Finished ---\n"); + + } else if (!strcmp(test_name, "power_cycle_test")) { + + int cycle; + printf("\n--- ADS1299 power cycle test ---\n"); + + if (!do_bootup) { + + ADS1299_init(); + + delayMicroseconds(100); + + ADS1299_bootup(); + } + + for (cycle = 0; cycle < 5; cycle++) { + printf("\nReboot #%d\n", cycle + 1); + + // Power down the chip, wait 2 seconds, and reboot + ADS1299_reboot(); + } + + printf("\n--- ADS1299 power cycle test Finished ---\n"); + } else if (!strcmp(test_name, "data_test")) { + + printf("\n--- ADS1299 data test Started ---\n"); + transferCmd(_START); + delayMicroseconds(500); + display_all_pin_states(); + printf("\n--- ADS1299 data test Finished ---\n"); + } else if (!strcmp(test_name, "stop_test")) { + + printf("\n--- ADS1299 stop test Started ---\n"); + transferCmd(_STOP); + delayMicroseconds(500); + display_all_pin_states(); + printf("\n--- ADS1299 stop test Finished ---\n"); + } else { + fprintf(stderr, "Test %s not found\n", test_name); + exit(EXIT_FAILURE); + } + } + + attempt++; + // Delay 200 us before moving on or reattempting bootup + bcm2835_delayMicroseconds(200); + + // Only power down if we did bootup + if (do_bootup && power_down) { + ADS1299_power_down(); + } + + bcm2835_delayMicroseconds(200); + } + + if (!bootup_success ) { + printf("\nAttempts %d of %d to boot ADS1299 unsuccessful. Aborting...\n", num_attempts, num_attempts); + return 1; + } - if (!bootup_success) { - printf("\nAttempts %d of %d to boot ADS1299 unsuccessful. Aborting...\n", num_attempts, num_attempts); - return 1; } return 0;