diff --git a/.gitignore b/.gitignore index a1afc49..dbefb3d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ Output/ *.jlink -*.eww \ No newline at end of file +*.eww +*.emSession \ No newline at end of file diff --git a/ads1298.c b/ads1298.c new file mode 100644 index 0000000..a0a76cf --- /dev/null +++ b/ads1298.c @@ -0,0 +1,369 @@ +/* Author: Musa Mahmood - JIIM, Inc. + * Date: 11/11/2023 + * License: This is proprietary code and may not be used without express written permission. + */ + +#include "ads1298.h" +#include "app_util_platform.h" +#include "nrf_delay.h" +#include "app_error.h" +#include "nrf_log.h" +#include "nrf_log_ctrl.h" +#include "nrf_log_default_backends.h" +#include "nrf_gpio.h" + +#include "nrf_drv_gpiote.h" + +#include + + +uint8_t ads1298_default_regs[] = { + ADS1298_REGDEFAULT_CONFIG1, + ADS1298_REGDEFAULT_CONFIG2, + ADS1298_REGDEFAULT_CONFIG3, + ADS1298_REGDEFAULT_LOFF, + ADS1298_REGDEFAULT_CH1SET, + ADS1298_REGDEFAULT_CH2SET, + ADS1298_REGDEFAULT_CH3SET, + ADS1298_REGDEFAULT_CH4SET, + ADS1298_REGDEFAULT_CH5SET, + ADS1298_REGDEFAULT_CH6SET, + ADS1298_REGDEFAULT_CH7SET, + ADS1298_REGDEFAULT_CH8SET, + ADS1298_REGDEFAULT_RLD_SENSP, + ADS1298_REGDEFAULT_RLD_SENSN, + ADS1298_REGDEFAULT_LOFF_SENSP, + ADS1298_REGDEFAULT_LOFF_SENSN, + ADS1298_REGDEFAULT_LOFF_FLIP, + ADS1298_REGDEFAULT_LOFF_STATP, + ADS1298_REGDEFAULT_LOFF_STATN, + ADS1298_REGDEFAULT_GPIO, + ADS1298_REGDEFAULT_PACE, + ADS1298_REGDEFAULT_RESP, + ADS1298_REGDEFAULT_CONFIG4, + ADS1298_REGDEFAULT_WCT1, + ADS1298_REGDEFAULT_WCT2 +}; + +// SPI flags: +static volatile bool spi_xfer_done; +static uint8_t rx_buffer[27+2]; + +// SPI Instance: +static const nrf_drv_spi_t spi0 = NRF_DRV_SPI_INSTANCE(0); + +// SPI Event Handler: +static void spi_event_handler(nrf_drv_spi_evt_t const *p_event, void *p_context) +{ + spi_xfer_done = true; +#if ADS1298_LOG_DEBUG + NRF_LOG_DEBUG("SPI transfer completed."); +#endif +} + +void ads1298_initialize(ble_exg_t *p_exg, ads1298_info_t *p_info) { + NRF_LOG_INFO("Initializing ADS1298..."); + // 1. Power up the ADS1298: + ads1298_power_up(); + #if ADS1298_LOG_DEBUG + NRF_LOG_FLUSH(); + #endif + nrf_drv_spi_config_t spi_config; + memset(&spi_config, 0, sizeof(spi_config)); + // 2. Initialize SPI + spi_config.bit_order = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST; + spi_config.ss_pin = ADS1298_CS_PIN; + spi_config.miso_pin = ADS1298_MISO_PIN; + spi_config.mosi_pin = ADS1298_MOSI_PIN; + spi_config.sck_pin = ADS1298_SCK_PIN; + spi_config.frequency = NRF_DRV_SPI_FREQ_2M; + spi_config.irq_priority = APP_IRQ_PRIORITY_HIGHEST; + spi_config.mode = NRF_DRV_SPI_MODE_1; + spi_config.orc = 0x55; + + APP_ERROR_CHECK(nrf_drv_spi_init(&spi0, &spi_config, spi_event_handler, NULL)); + // 3. Stop read data continuous mode (rdatac) + ads1298_stop_rdatac(); + #if ADS1298_LOG_DEBUG + NRF_LOG_FLUSH(); + #endif + // 4. Init registers: + // Copy default registers into p_exg->ads1298_settings (first 25 bytes) + memset(p_exg->ads1298_settings, 0, ADS1298_SETTINGS_SIZE); + memcpy(p_exg->ads1298_settings, ads1298_default_regs, ADS1298_REGISTER_COUNT); + ads1298_init_default_registers(); + #if ADS1298_LOG_DEBUG + NRF_LOG_FLUSH(); + #endif + // 5. Soft start: + ads1298_soft_start_conversion(); + // 6. Check ID: (sets lower 3 bits of ads1298_settings[25]) + ads1298_check_id(p_exg, p_info); + // 7. Start read data continuous mode (rdatac): + ads1298_start_rdatac(); + // 8. Place on standby mode: + ads1298_standby(); + // 9. Set remainder of ads1298_settings[25]: + p_exg->ads1298_settings[25] |= 0x80; // 16-bit mode + // ads1298_settings[25] &= 0b10011111; // TODO: sets downsample to zero + #if ADS1298_LOG_DEBUG + NRF_LOG_FLUSH(); + #endif +} + +void ads1298_uninitialize(void) { + NRF_LOG_INFO("Uninitializing ADS1298..."); + nrf_drv_spi_uninit(&spi0); +} + +bool ads1298_check_id(ble_exg_t *p_exg, ads1298_info_t *p_info) { + bool device_found = false; + #if ADS1298_LOG_DEBUG + NRF_LOG_INFO("Checking ADS129xR? ID:"); + #endif + uint8_t tx_buf[6] = {ADS1298_OPC_RREG|ADS1298_REGADDR_ID, 0x01, 0, 0, 0, 0}; + uint8_t rx_buf[6] = {0,0,0,0,0,0}; + spi_xfer_done = false; + APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi0, tx_buf, 2, rx_buf, 6)); + while(!spi_xfer_done) { + __WFE(); + } + #if ADS1298_LOG_DEBUG + NRF_LOG_INFO("rx_buf[3] = 0x%X", rx_buf[3]); + NRF_LOG_INFO("rx_buf dump:"); + NRF_LOG_HEXDUMP_INFO(rx_buf, 6); + #endif + // Check lower 3 bits 0x[...]..[???] + uint8_t nch_check = rx_buf[3] & 0x07; // 0x.....111 + p_exg->ads1298_settings[25] |= nch_check; + p_info->nChs = 0; + if (nch_check == ADS129x_4CH_BITMASK) { + p_info->nChs = 4; // ADS1294 + } else if (nch_check == ADS129x_6CH_BITMASK) { + p_info->nChs = 6; // ADS1296 + } else if (nch_check == ADS129x_8CH_BITMASK) { + p_info->nChs = 8; // ADS1298 + } else { + NRF_LOG_ERROR("Expected ADS129xX not detected! E0"); + return false; + } + // Check middle bits 0x[...]10[...] < always should be 10 + if ((rx_buf[3] & 0x10) != 0x10 || p_info->nChs == 0) { + NRF_LOG_ERROR("Expected ADS129xX not detected! E1"); + return false; + } + // Check first three bits: 0x[???]..[...] + uint8_t r_ver_chk = rx_buf[3] & 0xE0; + if (r_ver_chk == ADS129x_DEVICE_FAMILY_BITMASK) { + p_info->name_len = sprintf(p_info->name, "ADS129%d", p_info->nChs); + NRF_LOG_INFO("%s detected! (name_len: %d)", p_info->name, p_info->name_len); + device_found = true; + p_exg->ads1298_settings[25] &= (~0x08); + } else if (r_ver_chk == ADS129xR_DEVICE_FAMILY_BITMASK) { + p_info->name_len = sprintf(p_info->name, "ADS129%dR", p_info->nChs); + NRF_LOG_INFO("%s detected! (name_len: %d)", p_info->name, p_info->name_len); + p_exg->ads1298_settings[25] |= 0x08; + device_found = true; + } else { + NRF_LOG_ERROR("Expected ADS129xX not detected! E2"); + return false; + } + + return device_found; +} + +// chNumber = 1:8 +__STATIC_INLINE bool ads1298_check_channel(ads1298_info_t *p_info, uint8_t chNumber) { + if (chNumber > p_info->nChs) return false; + if (chNumber > 8) { + NRF_LOG_INFO("[ads1298_check_channel] INVALID CHANNEL NUMBER: %d!", chNumber); + return false; + } + return !((p_info->registers[3 + chNumber] & 0x80) == 0x80); +} + +void ads1298_update_active_chs(ads1298_info_t *p_info) { + p_info->active_chs = 0; + if (ads1298_check_channel(p_info, 1)) p_info->active_chs |= 0x80; + if (ads1298_check_channel(p_info, 2)) p_info->active_chs |= 0x40; + if (ads1298_check_channel(p_info, 3)) p_info->active_chs |= 0x20; + if (ads1298_check_channel(p_info, 4)) p_info->active_chs |= 0x10; + if (p_info->nChs == 4) return; + if (ads1298_check_channel(p_info, 5)) p_info->active_chs |= 0x08; + if (ads1298_check_channel(p_info, 6)) p_info->active_chs |= 0x04; + if (p_info->nChs == 6) return; + if (ads1298_check_channel(p_info, 7)) p_info->active_chs |= 0x02; + if (ads1298_check_channel(p_info, 8)) p_info->active_chs |= 0x01; +} + +void ads1298_update_registers(ads1298_info_t *p_info) { + NRF_LOG_INFO("Updating ADS1298 registers..."); + ads1298_update_active_chs(p_info); + uint8_t i = 0; // Register index + uint8_t tx_data[ADS1298_REGISTER_COUNT + 2]; // plus 2 for opcodes + uint8_t rx_data[ADS1298_REGISTER_COUNT + 2]; + memset(tx_data, 0, ADS1298_REGISTER_COUNT + 2); + memset(rx_data, 0, ADS1298_REGISTER_COUNT + 2); + // Write Register Opcode | Register Address: + tx_data[0] = ADS1298_OPC_WREG | ADS1298_REGADDR_CONFIG1; + tx_data[1] = ADS1298_REGISTER_COUNT; + // Copy default register values: + memcpy(&tx_data[2], p_info->registers, ADS1298_REGISTER_COUNT); + // Transaction size = 2 + number of registers to write + spi_xfer_done = false; + APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi0, tx_data, ADS1298_REGISTER_COUNT + 2, rx_data, ADS1298_REGISTER_COUNT + 2)); + while (!spi_xfer_done) + { + __WFE(); + } +#if ADS1298_LOG_DEBUG + NRF_LOG_INFO("[ADS1298] Registers updated!"); +#endif +} + +void ads1298_init_default_registers(void) { + NRF_LOG_INFO("Initializing ADS1298 registers..."); + uint8_t i = 0; // Register index + uint8_t tx_data[ADS1298_REGISTER_COUNT + 2]; // plus 2 for opcodes + uint8_t rx_data[ADS1298_REGISTER_COUNT + 2]; + memset(tx_data, 0, ADS1298_REGISTER_COUNT + 2); + memset(rx_data, 0, ADS1298_REGISTER_COUNT + 2); + // Write Register Opcode | Register Address: + tx_data[0] = ADS1298_OPC_WREG | ADS1298_REGADDR_CONFIG1; + tx_data[1] = ADS1298_REGISTER_COUNT; + // Copy default register values: + memcpy(&tx_data[2], ads1298_default_regs, ADS1298_REGISTER_COUNT); + // Transaction size = 2 + number of registers to write + spi_xfer_done = false; + APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi0, tx_data, ADS1298_REGISTER_COUNT + 2, rx_data, ADS1298_REGISTER_COUNT + 2)); + while (!spi_xfer_done) + { + __WFE(); + } +#if ADS1298_LOG_DEBUG + NRF_LOG_INFO("[ADS1298] Registers initialized."); +#endif +} + +// Power controls: +void ads1298_power_down(void) { + nrf_gpio_pin_clear(ADS1298_PWDN_PIN); + nrf_delay_ms(5); +} + +void ads1298_power_up(void) { + nrf_gpio_pin_set(ADS1298_PWDN_PIN); + nrf_delay_ms(80); +} + +// Standby/Wakeup controls: +void ads1298_wakeup(void) { + NRF_LOG_INFO("Waking up ADS1298..."); + uint8_t cmd = ADS1298_OPC_WAKEUP; + uint8_t rx_buf; + spi_xfer_done = false; + APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi0, &cmd, 1, &rx_buf, 1)); + while (!spi_xfer_done) + { + __WFE(); + } +} + +void ads1298_standby(void) { + NRF_LOG_INFO("Placing ADS1298 in standby mode..."); + uint8_t cmd = ADS1298_OPC_STANDBY; + uint8_t rx_buf; + spi_xfer_done = false; + APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi0, &cmd, 1, &rx_buf, 1)); + while (!spi_xfer_done) + { + __WFE(); + } +} + +// Start/stop conversions +void ads1298_soft_start_conversion(void) { + NRF_LOG_INFO("[ADS1298] Starting conversion..."); + uint8_t cmd = ADS1298_OPC_START; + uint8_t rx_buf; + spi_xfer_done = false; + APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi0, &cmd, 1, &rx_buf, 1)); + while (!spi_xfer_done) + { + __WFE(); + } +} + +void ads1298_start_rdatac(void) { + NRF_LOG_INFO("[ADS1298] Starting Read Data Continuous Mode..."); + uint8_t cmd = ADS1298_OPC_RDATAC; + uint8_t rx_buf; + spi_xfer_done = false; + APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi0, &cmd, 1, &rx_buf, 1)); + while (!spi_xfer_done) + { + __WFE(); + } +} + +void ads1298_stop_rdatac(void) { + NRF_LOG_INFO("[ADS1298] Stopping Read Data Continuous Mode..."); + uint8_t cmd = ADS1298_OPC_SDATAC; + uint8_t rx_buf; + spi_xfer_done = false; + APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi0, &cmd, 1, &rx_buf, 1)); + while (!spi_xfer_done) + { + __WFE(); + } +} + +// __STATIC_INLINE uint8_t get_channel_count_from_settings(uint8_t settings) { +// uint8_t lower_bits = settings & 0x07; +// if (lower_bits == ADS129x_4CH_BITMASK) { +// return 4; +// } else if (lower_bits == ADS129x_6CH_BITMASK) { +// return 6; +// } else if (lower_bits == ADS129x_8CH_BITMASK) { +// return 8; +// } +// } + +// TODO: Add option for 2 bytes (low resolution) +__STATIC_INLINE void copy_relevant_data(ble_exg_t *p_exg, uint8_t active_chs/*, bool hi_res*/) { + if ((active_chs & 0x80) == 0x80) memcpy(&p_exg->exg_ch1_buffer[p_exg->data_buffer_count], &rx_buffer[3], 3); + if ((active_chs & 0x40) == 0x40) memcpy(&p_exg->exg_ch2_buffer[p_exg->data_buffer_count], &rx_buffer[6], 3); + if ((active_chs & 0x20) == 0x20) memcpy(&p_exg->exg_ch3_buffer[p_exg->data_buffer_count], &rx_buffer[9], 3); + if ((active_chs & 0x10) == 0x10) memcpy(&p_exg->exg_ch4_buffer[p_exg->data_buffer_count], &rx_buffer[12], 3); + if ((active_chs & 0x08) == 0x08) memcpy(&p_exg->exg_ch5_buffer[p_exg->data_buffer_count], &rx_buffer[15], 3); + if ((active_chs & 0x04) == 0x04) memcpy(&p_exg->exg_ch6_buffer[p_exg->data_buffer_count], &rx_buffer[18], 3); + if ((active_chs & 0x02) == 0x02) memcpy(&p_exg->exg_ch7_buffer[p_exg->data_buffer_count], &rx_buffer[21], 3); + if ((active_chs & 0x01) == 0x01) memcpy(&p_exg->exg_ch8_buffer[p_exg->data_buffer_count], &rx_buffer[24], 3); + p_exg->data_buffer_count += 3; +} + +// Buffer size depends on version (27 bytes for ADS1298, 21 for ADS1296, and 15 for ADS1294) +void ads1298_get_data(ble_exg_t *p_exg, uint8_t active_chs) { + spi_xfer_done = false; + memset(rx_buffer, 0, 27); + nrf_drv_spi_transfer(&spi0, rx_buffer, 27, rx_buffer, 27); + while (!spi_xfer_done) { __WFE(); } + copy_relevant_data(p_exg, active_chs); +} + +void ads1296_get_data(ble_exg_t *p_exg, uint8_t active_chs) { + spi_xfer_done = false; + memset(rx_buffer, 0, 21); + nrf_drv_spi_transfer(&spi0, rx_buffer, 21, rx_buffer, 21); + while (!spi_xfer_done) { __WFE(); } + copy_relevant_data(p_exg, active_chs); +} + +void ads1294_get_data(ble_exg_t *p_exg, uint8_t active_chs) { + spi_xfer_done = false; + memset(rx_buffer, 0, 15); + nrf_drv_spi_transfer(&spi0, rx_buffer, 15, rx_buffer, 15); + while (!spi_xfer_done) { __WFE(); } + // Check mode p_exg->ads1298_settings[26] b0 + copy_relevant_data(p_exg, active_chs); +} diff --git a/ads1298.h b/ads1298.h new file mode 100644 index 0000000..14d67ec --- /dev/null +++ b/ads1298.h @@ -0,0 +1,163 @@ +#ifndef ADS1298_H_ +#define ADS1298_H_ + +#include +#include "nrf_drv_spi.h" + +// Debug flag for logging: +#define ADS1298_LOG_DEBUG 1 + +// Testing with nRF52840-DK: +#define ADS1298_MISO_PIN 29 +#define ADS1298_DRDY_PIN 12 +#define ADS1298_CS_PIN 19 +#define ADS1298_SCK_PIN 11 +#define ADS1298_MOSI_PIN 26 +#define ADS1298_PWDN_PIN 03 + + +// Number of WRITABLE registers (Not inc. ID register) +#define ADS1298_REGISTER_COUNT 25 + +/** REGISTER ADDRESSES **/ +#define ADS1298_REGADDR_ID 0x00 +#define ADS1298_REGADDR_CONFIG1 0x01 +#define ADS1298_REGADDR_CONFIG2 0x02 +#define ADS1298_REGADDR_CONFIG3 0x03 +#define ADS1298_REGADDR_LOFF 0x04 +#define ADS1298_REGADDR_CH1SET 0x05 +#define ADS1298_REGADDR_CH2SET 0x06 +#define ADS1298_REGADDR_CH3SET 0x07 +#define ADS1298_REGADDR_CH4SET 0x08 +#define ADS1298_REGADDR_CH5SET 0x09 +#define ADS1298_REGADDR_CH6SET 0x0A +#define ADS1298_REGADDR_CH7SET 0x0B +#define ADS1298_REGADDR_CH8SET 0x0C +#define ADS1298_REGADDR_RLD_SENSP 0x0D +#define ADS1298_REGADDR_RLD_SENSN 0x0E +#define ADS1298_REGADDR_LOFF_SENSP 0x0F +#define ADS1298_REGADDR_LOFF_SENSN 0x10 +#define ADS1298_REGADDR_LOFF_FLIP 0x11 +#define ADS1298_REGADDR_LOFF_STATP 0x12 +#define ADS1298_REGADDR_LOFF_STATN 0x13 +#define ADS1298_REGADDR_GPIO 0x14 +#define ADS1298_REGADDR_PACE 0x15 +#define ADS1298_REGADDR_RESP 0x16 +#define ADS1298_REGADDR_CONFIG4 0x17 +#define ADS1298_REGADDR_WCT1 0x18 +#define ADS1298_REGADDR_WCT2 0x19 + +/** SPI OPCODES **/ +// TODO: Double check! +#define ADS1298_OPC_WAKEUP 0x02 // Wake up from standby. +#define ADS1298_OPC_STANDBY 0x04 // Enter standby. +#define ADS1298_OPC_RESET 0x06 // Reset all registers. +#define ADS1298_OPC_START 0x08 // Start data conversions. +#define ADS1298_OPC_STOP 0x0A // Stop data conversions. + +#define ADS1298_OPC_RDATAC 0x10 // Read data continuously (registers cannot be read or written in this mode). +#define ADS1298_OPC_SDATAC 0x11 // Stop continuous data read. +#define ADS1298_OPC_RDATA 0x12 // Read single data value. + +#define ADS1298_OPC_RREG 0x20 // Read register value. System must not be in RDATAC mode. +#define ADS1298_OPC_WREG 0x40 // Write register value. System must not be in RDATAC mode. + +/** FACTORY IDs FOR ADS129x **/ +#define ADS129x_DEVICE_FAMILY_BITMASK 0x80 // 0x[100]10[...] +#define ADS129xR_DEVICE_FAMILY_BITMASK 0xC0 // 0x[110]10[...] + +#define ADS129x_4CH_BITMASK 0x00 // 0x[...]10[000] +#define ADS129x_6CH_BITMASK 0x01 // 0x[...]10[001] +#define ADS129x_8CH_BITMASK 0x02 // 0x[...]10[010] + +/** DEFAULT REGISTER VALUES **/ +//#define ADS1298_REGDEFAULT_CONFIG1 0x05 // Low power mode, Daisy-chain mode, clk output disabled, LP: 250 SPS +#define ADS1298_REGDEFAULT_CONFIG1 0x46 // Low power mode, Multiple readback mode, clk output disabled, LP: 250 SPS +#define ADS1298_REGDEFAULT_CONFIG2 0x00 // Test signals +#define ADS1298_REGDEFAULT_CONFIG3 0x40 // +#define ADS1298_REGDEFAULT_LOFF 0x00 +#define ADS1298_REGDEFAULT_CH1SET 0x00 +#define ADS1298_REGDEFAULT_CH2SET 0x00 +#define ADS1298_REGDEFAULT_CH3SET 0x00 +#define ADS1298_REGDEFAULT_CH4SET 0x00 +#define ADS1298_REGDEFAULT_CH5SET 0x00 +#define ADS1298_REGDEFAULT_CH6SET 0x00 +#define ADS1298_REGDEFAULT_CH7SET 0x00 +#define ADS1298_REGDEFAULT_CH8SET 0x00 +#define ADS1298_REGDEFAULT_RLD_SENSP 0x00 +#define ADS1298_REGDEFAULT_RLD_SENSN 0x00 +#define ADS1298_REGDEFAULT_LOFF_SENSP 0x00 +#define ADS1298_REGDEFAULT_LOFF_SENSN 0x00 +#define ADS1298_REGDEFAULT_LOFF_FLIP 0x00 +#define ADS1298_REGDEFAULT_LOFF_STATP 0x00 +#define ADS1298_REGDEFAULT_LOFF_STATN 0x00 +#define ADS1298_REGDEFAULT_GPIO 0x0F +#define ADS1298_REGDEFAULT_PACE 0x00 +#define ADS1298_REGDEFAULT_RESP 0x00 +#define ADS1298_REGDEFAULT_CONFIG4 0x00 +#define ADS1298_REGDEFAULT_WCT1 0x00 +#define ADS1298_REGDEFAULT_WCT2 0x00 + +#define ADS1298_BUFFER_SIZE 64 +#define ADS1298_SETTINGS_SIZE 26 + +typedef struct { + uint16_t service_handle; /**< Handle of ble_exg Service (as provided by the BLE stack). */ + uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */ + uint8_t uuid_type; /**< UUID type for the ble_exg Service. */ + uint8_t exg_ch1_buffer[ADS1298_BUFFER_SIZE]; /**< Buffer for sending data to the peer device. */ + uint8_t exg_ch2_buffer[ADS1298_BUFFER_SIZE]; + uint8_t exg_ch3_buffer[ADS1298_BUFFER_SIZE]; + uint8_t exg_ch4_buffer[ADS1298_BUFFER_SIZE]; + uint8_t exg_ch5_buffer[ADS1298_BUFFER_SIZE]; + uint8_t exg_ch6_buffer[ADS1298_BUFFER_SIZE]; + uint8_t exg_ch7_buffer[ADS1298_BUFFER_SIZE]; + uint8_t exg_ch8_buffer[ADS1298_BUFFER_SIZE]; + uint8_t ads1298_settings[ADS1298_SETTINGS_SIZE]; + uint16_t data_buffer_count; /**< Counter for data buffer. */ + uint16_t data_buffer_length; /**< Length of the data buffer. */ +} ble_exg_t; + +typedef struct { + uint8_t nChs; // 4, 6, or 8 channels depending on variant. + uint8_t state; // Powered on or off! + uint8_t name_len; // does not include null terminator + // [active_chs] bit-packed array of active channels 1:8: + // Chs: [1,2,3,4,5,6,7,8]. Ch1 active |= 0x80, ch2 |= 0x40 and so on.. + uint8_t active_chs; + uint8_t registers[ADS1298_REGISTER_COUNT]; + char name[12]; +} ads1298_info_t; + +/** FUNCTION PROTOTYPES **/ +void ads1298_initialize(ble_exg_t *p_exg, ads1298_info_t *p_info); + +void ads1298_uninitialize(void); + +bool ads1298_check_id(ble_exg_t *p_exg, ads1298_info_t *p_info); + +void ads1298_update_registers(ads1298_info_t *p_info); + +void ads1298_init_default_registers(void); + +void ads1298_power_down(void); + +void ads1298_power_up(void); + +void ads1298_standby(void); + +void ads1298_wakeup(void); + +void ads1298_soft_start_conversion(void); + +void ads1298_start_rdatac(void); + +void ads1298_stop_rdatac(void); + +void ads1294_get_data(ble_exg_t *p_exg, uint8_t active_chs); + +void ads1296_get_data(ble_exg_t *p_exg, uint8_t active_chs); + +void ads1298_get_data(ble_exg_t *p_exg, uint8_t active_chs); + +#endif // ADS1298_H_ diff --git a/main.c b/main.c index 63016c9..abe1179 100644 --- a/main.c +++ b/main.c @@ -1,9 +1,3 @@ -// ~TODO -// [ ] Add SPI files (see: fw-mvp), enable SPI interface. -// [ ] Add ADS1292 driver, and test (just print for now) -// [ ] Increase size of USB receive buffer, and see if we can program the ADS1292 via USB. -// - #include #include #include diff --git a/pca10056/blank/config/sdk_config.h b/pca10056/blank/config/sdk_config.h index 564d9a4..2e0dc72 100644 --- a/pca10056/blank/config/sdk_config.h +++ b/pca10056/blank/config/sdk_config.h @@ -2881,6 +2881,123 @@ #define SAADC_CONFIG_DEBUG_COLOR 0 #endif +// +// NRFX_SPIM_ENABLED - nrfx_spim - SPIM peripheral driver +//========================================================== +#ifndef NRFX_SPIM_ENABLED +#define NRFX_SPIM_ENABLED 0 +#endif +// NRFX_SPIM0_ENABLED - Enable SPIM0 instance + + +#ifndef NRFX_SPIM0_ENABLED +#define NRFX_SPIM0_ENABLED 0 +#endif + +// NRFX_SPIM1_ENABLED - Enable SPIM1 instance + + +#ifndef NRFX_SPIM1_ENABLED +#define NRFX_SPIM1_ENABLED 0 +#endif + +// NRFX_SPIM2_ENABLED - Enable SPIM2 instance + + +#ifndef NRFX_SPIM2_ENABLED +#define NRFX_SPIM2_ENABLED 0 +#endif + +// NRFX_SPIM_MISO_PULL_CFG - MISO pin pull configuration. + +// <0=> NRF_GPIO_PIN_NOPULL +// <1=> NRF_GPIO_PIN_PULLDOWN +// <3=> NRF_GPIO_PIN_PULLUP + +#ifndef NRFX_SPIM_MISO_PULL_CFG +#define NRFX_SPIM_MISO_PULL_CFG 1 +#endif + +// NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY - Interrupt priority + +// <0=> 0 (highest) +// <1=> 1 +// <2=> 2 +// <3=> 3 +// <4=> 4 +// <5=> 5 +// <6=> 6 +// <7=> 7 + +#ifndef NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY 6 +#endif + +// NRFX_SPIM_CONFIG_LOG_ENABLED - Enables logging in the module. +//========================================================== +#ifndef NRFX_SPIM_CONFIG_LOG_ENABLED +#define NRFX_SPIM_CONFIG_LOG_ENABLED 0 +#endif +// NRFX_SPIM_CONFIG_LOG_LEVEL - Default Severity level + +// <0=> Off +// <1=> Error +// <2=> Warning +// <3=> Info +// <4=> Debug + +#ifndef NRFX_SPIM_CONFIG_LOG_LEVEL +#define NRFX_SPIM_CONFIG_LOG_LEVEL 3 +#endif + +// NRFX_SPIM_CONFIG_INFO_COLOR - ANSI escape code prefix. + +// <0=> Default +// <1=> Black +// <2=> Red +// <3=> Green +// <4=> Yellow +// <5=> Blue +// <6=> Magenta +// <7=> Cyan +// <8=> White + +#ifndef NRFX_SPIM_CONFIG_INFO_COLOR +#define NRFX_SPIM_CONFIG_INFO_COLOR 0 +#endif + +// NRFX_SPIM_CONFIG_DEBUG_COLOR - ANSI escape code prefix. + +// <0=> Default +// <1=> Black +// <2=> Red +// <3=> Green +// <4=> Yellow +// <5=> Blue +// <6=> Magenta +// <7=> Cyan +// <8=> White + +#ifndef NRFX_SPIM_CONFIG_DEBUG_COLOR +#define NRFX_SPIM_CONFIG_DEBUG_COLOR 0 +#endif + +// + +// NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED - Enables nRF52 anomaly 109 workaround for SPIM. + + +// The workaround uses interrupts to wake up the CPU by catching +// a start event of zero-length transmission to start the clock. This +// ensures that the DMA transfer will be executed without issues and +// that the proper transfer will be started. See more in the Errata +// document or Anomaly 109 Addendum located at +// https://infocenter.nordicsemi.com/ + +#ifndef NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED +#define NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED 0 +#endif + // // SPIS_CONFIG_LOG_ENABLED - Enables logging in the module. @@ -2934,6 +3051,80 @@ // +// SPI_ENABLED - nrf_drv_spi - SPI/SPIM peripheral driver - legacy layer +//========================================================== +#ifndef SPI_ENABLED +#define SPI_ENABLED 1 +#endif +// SPI_DEFAULT_CONFIG_IRQ_PRIORITY - Interrupt priority + + +// Priorities 0,2 (nRF51) and 0,1,4,5 (nRF52) are reserved for SoftDevice +// <0=> 0 (highest) +// <1=> 1 +// <2=> 2 +// <3=> 3 +// <4=> 4 +// <5=> 5 +// <6=> 6 +// <7=> 7 + +#ifndef SPI_DEFAULT_CONFIG_IRQ_PRIORITY +#define SPI_DEFAULT_CONFIG_IRQ_PRIORITY 6 +#endif + +// NRF_SPI_DRV_MISO_PULLUP_CFG - MISO PIN pull-up configuration. + +// <0=> NRF_GPIO_PIN_NOPULL +// <1=> NRF_GPIO_PIN_PULLDOWN +// <3=> NRF_GPIO_PIN_PULLUP + +#ifndef NRF_SPI_DRV_MISO_PULLUP_CFG +#define NRF_SPI_DRV_MISO_PULLUP_CFG 1 +#endif + +// SPI0_ENABLED - Enable SPI0 instance +//========================================================== +#ifndef SPI0_ENABLED +#define SPI0_ENABLED 1 +#endif +// SPI0_USE_EASY_DMA - Use EasyDMA + + +#ifndef SPI0_USE_EASY_DMA +#define SPI0_USE_EASY_DMA 1 +#endif + +// + +// SPI1_ENABLED - Enable SPI1 instance +//========================================================== +#ifndef SPI1_ENABLED +#define SPI1_ENABLED 0 +#endif +// SPI1_USE_EASY_DMA - Use EasyDMA + + +#ifndef SPI1_USE_EASY_DMA +#define SPI1_USE_EASY_DMA 1 +#endif + +// + +// SPI2_ENABLED - Enable SPI2 instance +//========================================================== +#ifndef SPI2_ENABLED +#define SPI2_ENABLED 1 +#endif +// SPI2_USE_EASY_DMA - Use EasyDMA + + +#ifndef SPI2_USE_EASY_DMA +#define SPI2_USE_EASY_DMA 1 +#endif + +// + // SPI_CONFIG_LOG_ENABLED - Enables logging in the module. //========================================================== #ifndef SPI_CONFIG_LOG_ENABLED diff --git a/pca10056/blank/ses/usbd_cdc_acm_pca10056.emProject b/pca10056/blank/ses/Multimodal_CV_USB_ADS1298R_pca10056.emProject similarity index 95% rename from pca10056/blank/ses/usbd_cdc_acm_pca10056.emProject rename to pca10056/blank/ses/Multimodal_CV_USB_ADS1298R_pca10056.emProject index 1399917..7a6d544 100644 --- a/pca10056/blank/ses/usbd_cdc_acm_pca10056.emProject +++ b/pca10056/blank/ses/Multimodal_CV_USB_ADS1298R_pca10056.emProject @@ -1,5 +1,5 @@ - + - + + + @@ -60,6 +62,7 @@ + @@ -68,6 +71,8 @@ + + diff --git a/pca10056/blank/ses/usbd_cdc_acm_pca10056.emSession b/pca10056/blank/ses/usbd_cdc_acm_pca10056.emSession deleted file mode 100644 index b40f1df..0000000 --- a/pca10056/blank/ses/usbd_cdc_acm_pca10056.emSession +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -