diff --git a/ads1298.c b/ads1298.c index 5a5514c..07c6e97 100644 --- a/ads1298.c +++ b/ads1298.c @@ -11,12 +11,11 @@ #include "nrf_log_ctrl.h" #include "nrf_log_default_backends.h" #include "nrf_gpio.h" - #include "nrf_drv_gpiote.h" -#include +#include "custom_board.h" -//#include "usb_logging.h" +#if ADS1298 uint8_t ads1298_default_regs[] = { ADS1298_REGDEFAULT_CONFIG1, @@ -58,11 +57,11 @@ 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."); + NRF_LOG_INFO(" > SPI transfer completed."); #endif } -void ads1298_initialize(ble_exg_t *p_exg, ads1298_info_t *p_info) { +void ads1298_initialize(ads1298_info_t *p_info) { NRF_LOG_INFO("Initializing ADS1298..."); // 1. Power up the ADS1298: ads1298_power_up(); @@ -77,7 +76,9 @@ void ads1298_initialize(ble_exg_t *p_exg, ads1298_info_t *p_info) { 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.frequency = NRF_DRV_SPI_FREQ_500K; + //spi_config.frequency = NRF_DRV_SPI_FREQ_1M; + //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; @@ -89,9 +90,9 @@ void ads1298_initialize(ble_exg_t *p_exg, ads1298_info_t *p_info) { 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); + // Copy default registers into p_info->registers (first 25 bytes) + memset(p_info->registers, 0, sizeof(p_info->registers)); + memcpy(p_info->registers, ads1298_default_regs, ADS1298_REGISTER_COUNT); ads1298_init_default_registers(); #if ADS1298_LOG_DEBUG NRF_LOG_FLUSH(); @@ -99,14 +100,12 @@ void ads1298_initialize(ble_exg_t *p_exg, ads1298_info_t *p_info) { // 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); + ads1298_check_id(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 @@ -117,7 +116,7 @@ void ads1298_uninitialize(void) { nrf_drv_spi_uninit(&spi0); } -bool ads1298_check_id(ble_exg_t *p_exg, ads1298_info_t *p_info) { +bool ads1298_check_id(ads1298_info_t *p_info) { bool device_found = false; #if ADS1298_LOG_DEBUG NRF_LOG_INFO("Checking ADS129xR? ID:"); @@ -125,18 +124,21 @@ bool ads1298_check_id(ble_exg_t *p_exg, ads1298_info_t *p_info) { 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)); + APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi0, tx_buf, 6, rx_buf, 6)); while(!spi_xfer_done) { __WFE(); } + uint8_t register_data = rx_buf[2]; #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); + NRF_LOG_INFO("register_data[0] = 0x%X", register_data); + NRF_LOG_INFO(">rx_buf dump:"); + NRF_LOG_INFO(">rx_buf[0:5] = 0x[%X %X %X %X %X]", rx_buf[0], rx_buf[1], rx_buf[2], rx_buf[3], rx_buf[4], rx_buf[5]); + + // 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; + + // Check lower 3 bits 0x[...]..[xxx] + uint8_t nch_check = register_data & 0x07; // 0x.....111 p_info->nChs = 0; if (nch_check == ADS129x_4CH_BITMASK) { p_info->nChs = 4; // ADS1294 @@ -145,28 +147,26 @@ bool ads1298_check_id(ble_exg_t *p_exg, ads1298_info_t *p_info) { } else if (nch_check == ADS129x_8CH_BITMASK) { p_info->nChs = 8; // ADS1298 } else { - NRF_LOG_ERROR("Expected ADS129xX not detected! E0"); + NRF_LOG_INFO("[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"); + if ((register_data & 0x10) != 0x10 || p_info->nChs == 0) { + NRF_LOG_INFO("[ERROR] Expected ADS129xX not detected! E1"); return false; } - // Check first three bits: 0x[???]..[...] - uint8_t r_ver_chk = rx_buf[3] & 0xE0; + // Check first three bits: 0x[xxx]..[...] + uint8_t r_ver_chk = register_data & 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"); + NRF_LOG_INFO("[ERROR] Expected ADS129xX not detected! E2"); return false; } @@ -197,6 +197,29 @@ void ads1298_update_active_chs(ads1298_info_t *p_info) { if (ads1298_check_channel(p_info, 8)) p_info->active_chs |= 0x01; } +static const uint8_t popcount_table[256] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 +}; + +static inline uint8_t ads1298_channel_count(ads1298_info_t *p_info) { + return popcount_table[p_info->active_chs]; +} + void ads1298_update_registers(ads1298_info_t *p_info) { NRF_LOG_INFO("Updating ADS1298 registers..."); ads1298_update_active_chs(p_info); @@ -330,41 +353,142 @@ void ads1298_stop_rdatac(void) { // } // } -// 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; +uint16_t ads1298_sampling_rate(ads1298_info_t* p_info) { + // Check if we're in high precision or low power mode. + // We default to high precision. If LP, just div2. + uint16_t sampling_rate; + switch (p_info->registers[0] & 0x07) { + case 0: + sampling_rate = 32000; + case 1: + sampling_rate = 16000; + case 2: + sampling_rate = 8000; + case 3: + sampling_rate = 4000; + case 4: + sampling_rate = 2000; + case 5: + sampling_rate = 1000; + case 6: + sampling_rate = 500; + default: + sampling_rate = 500; + } + if (p_info->registers[0] & 0x80) { + sampling_rate /= sampling_rate; + } + + return sampling_rate; } +void ads1298_set_data_buffer_length(ads1298_info_t* p_info) { + uint16_t sampling_rate = ads1298_sampling_rate(p_info); + // Will depend not on sampling rate but on number of active channels + // #NOTE: Will need to update registers first. + uint8_t channel_count = ads1298_channel_count(p_info); + switch (channel_count) { + case 1: // Recall the max count is 64 + p_info->usb_buffer_size_max = (3 * 20) + ADS1298_PACKET_OFFSET; + break; + case 2: + p_info->usb_buffer_size_max = (3 * 20) + ADS1298_PACKET_OFFSET; + break; + case 3: + p_info->usb_buffer_size_max = (3 * 18) + ADS1298_PACKET_OFFSET; + break; + case 4: + p_info->usb_buffer_size_max = (3 * 20) + ADS1298_PACKET_OFFSET; + break; + case 5: + p_info->usb_buffer_size_max = (3 * 20) + ADS1298_PACKET_OFFSET; + break; + case 6: + p_info->usb_buffer_size_max = (3 * 18) + ADS1298_PACKET_OFFSET; + break; + case 7: + p_info->usb_buffer_size_max = (3 * 14) + ADS1298_PACKET_OFFSET; + break; + case 8: + p_info->usb_buffer_size_max = (3 * 16) + ADS1298_PACKET_OFFSET; + break; + default: + p_info->usb_buffer_size_max = (3 * 16) + ADS1298_PACKET_OFFSET; + // This should never happen! + break; + } + NRF_LOG_INFO("[ADS129x] Sampling rate is %d", sampling_rate); + NRF_LOG_INFO("[ADS129x] p_info->usb_buffer_size_max is %d", p_info->usb_buffer_size_max); +} + +__STATIC_INLINE void copy_relevant_data(ads1298_info_t* p_info) { + if ((p_info->active_chs & 0x80) == 0x80) { + memcpy(&p_info->usb_buffer[p_info->usb_buffer_count], &rx_buffer[3], 3); + p_info->usb_buffer_count += 3; + } + + if ((p_info->active_chs & 0x40) == 0x40) { + memcpy(&p_info->usb_buffer[p_info->usb_buffer_count], &rx_buffer[6], 3); + p_info->usb_buffer_count += 3; + } + + if ((p_info->active_chs & 0x20) == 0x20) { + memcpy(&p_info->usb_buffer[p_info->usb_buffer_count], &rx_buffer[9], 3); + p_info->usb_buffer_count += 3; + } + + if ((p_info->active_chs & 0x10) == 0x10) { + memcpy(&p_info->usb_buffer[p_info->usb_buffer_count], &rx_buffer[12], 3); + p_info->usb_buffer_count += 3; + } + + if ((p_info->active_chs & 0x08) == 0x08) { + memcpy(&p_info->usb_buffer[p_info->usb_buffer_count], &rx_buffer[15], 3); + p_info->usb_buffer_count += 3; + } + + if ((p_info->active_chs & 0x04) == 0x04) { + memcpy(&p_info->usb_buffer[p_info->usb_buffer_count], &rx_buffer[18], 3); + p_info->usb_buffer_count += 3; + } + + if ((p_info->active_chs & 0x02) == 0x02) { + memcpy(&p_info->usb_buffer[p_info->usb_buffer_count], &rx_buffer[21], 3); + p_info->usb_buffer_count += 3; + } + + if ((p_info->active_chs & 0x01) == 0x01) { + memcpy(&p_info->usb_buffer[p_info->usb_buffer_count], &rx_buffer[24], 3); + p_info->usb_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) { +void ads1298_get_data(ads1298_info_t* p_info) { spi_xfer_done = false; + // necessary? 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); + copy_relevant_data(p_info); } -void ads1296_get_data(ble_exg_t *p_exg, uint8_t active_chs) { +void ads1296_get_data(ads1298_info_t* p_info) { 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); + copy_relevant_data(p_info); } -void ads1294_get_data(ble_exg_t *p_exg, uint8_t active_chs) { +void ads1294_get_data(ads1298_info_t* p_info) { 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); + copy_relevant_data(p_info); } + +#endif // ADS1298 \ No newline at end of file diff --git a/ads1298.h b/ads1298.h index 14d67ec..dd5ac5f 100644 --- a/ads1298.h +++ b/ads1298.h @@ -4,20 +4,14 @@ #include #include "nrf_drv_spi.h" +#include "custom_board.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 +#define ADS1298_PACKET_OFFSET 2 // [device id][serial id][..data] /** REGISTER ADDRESSES **/ #define ADS1298_REGADDR_ID 0x00 @@ -101,22 +95,7 @@ #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; +#define USBD_MAX_SIZE 64 typedef struct { uint8_t nChs; // 4, 6, or 8 channels depending on variant. @@ -127,14 +106,17 @@ typedef struct { uint8_t active_chs; uint8_t registers[ADS1298_REGISTER_COUNT]; char name[12]; + char usb_buffer[USBD_MAX_SIZE]; + uint8_t usb_buffer_count; + uint8_t usb_buffer_size_max; } ads1298_info_t; /** FUNCTION PROTOTYPES **/ -void ads1298_initialize(ble_exg_t *p_exg, ads1298_info_t *p_info); +void ads1298_initialize(ads1298_info_t *p_info); void ads1298_uninitialize(void); -bool ads1298_check_id(ble_exg_t *p_exg, ads1298_info_t *p_info); +bool ads1298_check_id(ads1298_info_t *p_info); void ads1298_update_registers(ads1298_info_t *p_info); @@ -154,10 +136,14 @@ void ads1298_start_rdatac(void); void ads1298_stop_rdatac(void); -void ads1294_get_data(ble_exg_t *p_exg, uint8_t active_chs); +void ads1294_get_data(ads1298_info_t* p_info); -void ads1296_get_data(ble_exg_t *p_exg, uint8_t active_chs); +void ads1296_get_data(ads1298_info_t* p_info); -void ads1298_get_data(ble_exg_t *p_exg, uint8_t active_chs); +void ads1298_get_data(ads1298_info_t* p_info); + +uint16_t ads1298_sampling_rate(ads1298_info_t* p_info); + +void ads1298_set_data_buffer_length(ads1298_info_t* p_info); #endif // ADS1298_H_ diff --git a/main.c b/main.c index ebc6059..e663d0e 100644 --- a/main.c +++ b/main.c @@ -24,11 +24,27 @@ #include "nrf_log_ctrl.h" #include "nrf_log_default_backends.h" -/** - * @brief Enable power USB detection - * - * Configure if example supports USB port connection - */ +#include "custom_board.h" + +static enum recording_mode_t recording_mode = RECORDING_MODE_DISABLED; + +#if ADS1298 + #include "ads1298.h" + #include "nrf_drv_gpiote.h" + + static bool drdy_flag = false; + ads1298_info_t m_info; +#endif + +static bool send_peripheral_info = false; +// static uint8_t message_length = 0; +static volatile bool run_throughput_test = false; +static char usb_tx_buffer[NRF_DRV_USBD_EPSIZE]; + +#define READ_SIZE 64 +static char usb_read_buffer[READ_SIZE]; + + #ifndef USBD_POWER_DETECTION #define USBD_POWER_DETECTION true #endif @@ -45,9 +61,6 @@ static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const * p_inst, #define CDC_ACM_DATA_EPOUT NRF_DRV_USBD_EPOUT1 -/** - * @brief CDC_ACM class instance - * */ APP_USBD_CDC_ACM_GLOBAL_DEF(m_app_cdc_acm, cdc_acm_user_ev_handler, CDC_ACM_COMM_INTERFACE, @@ -55,33 +68,101 @@ APP_USBD_CDC_ACM_GLOBAL_DEF(m_app_cdc_acm, CDC_ACM_COMM_EPIN, CDC_ACM_DATA_EPIN, CDC_ACM_DATA_EPOUT, - APP_USBD_CDC_COMM_PROTOCOL_AT_V250 -); + APP_USBD_CDC_COMM_PROTOCOL_AT_V250); -#define READ_SIZE 64 -static char m_rx_buffer[READ_SIZE]; -static char m_tx_buffer[NRF_DRV_USBD_EPSIZE]; -static bool m_run_throughput_test = false; -static bool m_send_flag = false; +// length is always `READ_SIZE` +void write_ic_settings(uint8_t* new_packet) { + switch (SECOND_NIBBLE(new_packet[0])) { + case TN_IC_ADS1298: { + // #TODO: &new_packet[1] + #if ADS1298 + memcpy(m_info.registers, &new_packet[1], ADS1298_REGISTER_COUNT); + ads1298_update_registers(&m_info); + ads1298_set_data_buffer_length(&m_info); + #endif + } break; + default: + break; + } +} + +void read_ic_settings(uint8_t* new_packet) { + switch (SECOND_NIBBLE(new_packet[0])) { + case TN_IC_ADS1298: { + // #TODO: + } break; + default: + break; + } +} + +// length is always `READ_SIZE` +static void process_new_packet(uint8_t* new_packet) { + switch (FIRST_NIBBLE(new_packet[0])) { + case CN_WRITE_IC_REGS: { + write_ic_settings(new_packet); + } break; + case CN_READ_IC_REGS: { + read_ic_settings(new_packet); + } break; + case CN_STREAM_CONTROL: { + if (SECOND_NIBBLE(new_packet[0]) == TN_STREAM_START) { + recording_mode = RECORDING_MODE_ALL; + #if ADS1298 + if (m_info.state == 0) { + m_info.state = 1; + // ads1298_update_registers(&m_info); + // ads1298_set_data_buffer_length(&m_info); + ads1298_wakeup(); + NRF_LOG_INFO("[ADS129x] Active channels: 0x%X", m_info.active_chs); + } + #endif + } + if (SECOND_NIBBLE(new_packet[0]) == TN_STREAM_STOP) { + recording_mode = RECORDING_MODE_DISABLED; + #if ADS1298 + if (m_info.state == 1) { + m_info.state = 0; + ads1298_standby(); + } + #endif + } + if (SECOND_NIBBLE(new_packet[0]) == TN_STREAM_REQUEST_INFO) { + // #TODO: Set peripheral info send flag + // Can we just send it from here? + send_peripheral_info = true; + } + if (SECOND_NIBBLE(new_packet[0]) == TN_STREAM_REQUEST_BATTERY_LEVEL) { + // #NOTE: Will not use. This is not a battery-powered device. (I mean, it can + // be, but it's also wired, so who cares.) + // Just return some constant. + } + + } break; + case CN_MISC_CONTROLS: { + if (SECOND_NIBBLE(new_packet[0]) == TN_MISC_THROUGHPUT_TEST) { // 0xEF + NRF_LOG_INFO("Starting throughput test!"); + run_throughput_test = true; + } + if (SECOND_NIBBLE(new_packet[0]) == TN_MISC_RTT_REQUEST) { + // [↓] #TODO [Later] + } + } break; + default: + break; + } +} -/** - * @brief User event handler @ref app_usbd_cdc_acm_user_ev_handler_t (headphones) - * */ static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const * p_inst, - app_usbd_cdc_acm_user_event_t event) -{ + app_usbd_cdc_acm_user_event_t event) { app_usbd_cdc_acm_t const * p_cdc_acm = app_usbd_cdc_acm_class_get(p_inst); - switch (event) - { - case APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN: - { + switch (event) { + case APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN: { /*Setup first transfer*/ - ret_code_t ret = app_usbd_cdc_acm_read(&m_app_cdc_acm, - m_rx_buffer, - READ_SIZE); + ret_code_t ret = app_usbd_cdc_acm_read(&m_app_cdc_acm, usb_read_buffer, READ_SIZE); UNUSED_VARIABLE(ret); break; } @@ -89,29 +170,31 @@ static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const * p_inst, break; case APP_USBD_CDC_ACM_USER_EVT_TX_DONE: break; - case APP_USBD_CDC_ACM_USER_EVT_RX_DONE: - { + case APP_USBD_CDC_ACM_USER_EVT_RX_DONE: { ret_code_t ret; NRF_LOG_INFO("Bytes waiting: %d", app_usbd_cdc_acm_bytes_stored(p_cdc_acm)); - do - { + do { /*Get amount of data transfered*/ size_t size = app_usbd_cdc_acm_rx_size(p_cdc_acm); - NRF_LOG_INFO("RX: size: %lu char: %c", size, m_rx_buffer[0]); - if (m_rx_buffer[0] == 0xFF) { - m_run_throughput_test = true; - } - if (m_rx_buffer[0] == 1) { - m_send_flag = false; - } - if (m_rx_buffer[0] == 2) { - m_send_flag = true; - } + + NRF_LOG_INFO("RX[size:%lu] [0]: 0x%X", size, usb_read_buffer[0]); + + process_new_packet(usb_read_buffer); + + // if (usb_read_buffer[0] == 0xBE) { + + // } + + // if (usb_read_buffer[0] == 0xEF) { + // run_throughput_test = true; + // } + // if (usb_read_buffer[0] == 0xE1) { + // run_throughput_test = false; + // } + // NRF_LOG_INFO("Received packet; first byte: 0x%X", new_packet[0]); /* Fetch data until internal buffer is empty */ - ret = app_usbd_cdc_acm_read(&m_app_cdc_acm, - m_rx_buffer, - READ_SIZE); + ret = app_usbd_cdc_acm_read(&m_app_cdc_acm, usb_read_buffer, READ_SIZE); } while (ret == NRF_SUCCESS); break; @@ -121,10 +204,8 @@ static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const * p_inst, } } -static void usbd_user_ev_handler(app_usbd_event_type_t event) -{ - switch (event) - { +static void usbd_user_ev_handler(app_usbd_event_type_t event) { + switch (event) { case APP_USBD_EVT_DRV_SUSPEND: break; case APP_USBD_EVT_DRV_RESUME: @@ -137,8 +218,7 @@ static void usbd_user_ev_handler(app_usbd_event_type_t event) case APP_USBD_EVT_POWER_DETECTED: NRF_LOG_INFO("USB power detected"); - if (!nrf_drv_usbd_is_enabled()) - { + if (!nrf_drv_usbd_is_enabled()) { app_usbd_enable(); } break; @@ -155,6 +235,38 @@ static void usbd_user_ev_handler(app_usbd_event_type_t event) } } +void idle_state_handle(void) { + +} + +#if ADS1298 +void drdy_pin_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { + UNUSED_PARAMETER(pin); + UNUSED_PARAMETER(action); + drdy_flag = true; +} + +void ads1298_interrupt_setup(void) { + nrf_gpio_cfg_output(ADS1298_PWDN_PIN); + nrf_gpio_pin_clear(ADS1298_PWDN_PIN); + nrf_gpio_cfg_input(ADS1298_DRDY_PIN, NRF_GPIO_PIN_PULLUP); + // Initialize GPIOTE: + ret_code_t err_code = NRF_SUCCESS; + if (!nrf_drv_gpiote_is_init()) { + err_code = nrf_drv_gpiote_init(); + } + NRF_LOG_INFO("GPIOTE error code: %d", err_code); + APP_ERROR_CHECK(err_code); + nrfx_gpiote_in_config_t in_config = NRFX_GPIOTE_CONFIG_IN_SENSE_HITOLO(true); + in_config.is_watcher = true; + in_config.pull = NRF_GPIO_PIN_NOPULL; + err_code = nrf_drv_gpiote_in_init(ADS1298_DRDY_PIN, &in_config, drdy_pin_handler); + APP_ERROR_CHECK(err_code); + nrf_drv_gpiote_in_event_enable(ADS1298_DRDY_PIN, true); + ads1298_power_down(); +} +#endif + int main(void) { ret_code_t ret; static const app_usbd_config_t usbd_config = { @@ -197,18 +309,58 @@ int main(void) { app_usbd_start(); } + // Init peripherals: +#if ADS1298 + ads1298_interrupt_setup(); + ads1298_initialize(&m_info); +#endif + + memset(usb_tx_buffer, 0x41, NRF_DRV_USBD_EPSIZE); // #TEMP + while (true) { - while (app_usbd_event_queue_process()) {/* Nothing to do */} + while (app_usbd_event_queue_process()) { /* Nothing to do */ } - if(m_run_throughput_test) { + if (send_peripheral_info) { + send_peripheral_info = false; + // #TODO: Prefix relevant correct bytes; copy into static buffer. + // should this be a static buffer? + char info_buffer[] = "ADS1298|"; + memset(usb_tx_buffer, 0, NRF_DRV_USBD_EPSIZE); + memcpy(usb_tx_buffer, info_buffer, strlen(info_buffer)); + app_usbd_cdc_acm_write(&m_app_cdc_acm, usb_tx_buffer, strlen(info_buffer)); + } + /* + // I think this check is totally irrelevant? + if (recording_mode == RECORDING_MODE_ALL) { + // #TODO: Count samples + #if ADS1298 + switch (m_info.nChs) { + case 4: + ads1294_get_data(&m_info); + break; + case 6: + ads1296_get_data(&m_info); + break; + case 8: + ads1298_get_data(&m_info); + break; + default: + break; + } + #endif + // #TODO: if buffer full transfer via `app_usbd_cdc_acm_write` + }*/ + + if (run_throughput_test) { + //NRF_LOG_INFO("Running throughput test!"); // static int frame_counter; - + // size_t size = sprintf(m_tx_buffer, "Hello USB CDC FA demo: %u\r\n", frame_counter); - + // ret = app_usbd_cdc_acm_write(&m_app_cdc_acm, m_tx_buffer, size); // if (ret == NRF_SUCCESS) { ++frame_counter; } - - app_usbd_cdc_acm_write(&m_app_cdc_acm, m_tx_buffer, NRF_DRV_USBD_EPSIZE); + app_usbd_cdc_acm_write(&m_app_cdc_acm, usb_tx_buffer, NRF_DRV_USBD_EPSIZE); + // if (rc != NRF_SUCCESS) { NRF_LOG_INFO("rc: %d", rc); } } UNUSED_RETURN_VALUE(NRF_LOG_PROCESS()); diff --git a/pca10056/blank/config/custom_board.h b/pca10056/blank/config/custom_board.h new file mode 100644 index 0000000..069df3c --- /dev/null +++ b/pca10056/blank/config/custom_board.h @@ -0,0 +1,57 @@ +#ifndef CUSTOM_BOARD_H +#define CUSTOM_BOARD_H + +#define NRF52840_BREAKOUT_BOARD 1 +#define ADS1298 1 + +// Testing with nRF52840: +#if NRF52840_BREAKOUT_BOARD + #define ADS1298_DRDY_PIN 11 + #define ADS1298_MISO_PIN 12 + #define ADS1298_SCK_PIN 13 + #define ADS1298_CS_PIN 14 + #define ADS1298_PWDN_PIN 15 + #define ADS1298_MOSI_PIN 16 + + // This is the packet format for data received over USB: + // [CN:4bit][TN:4bit][..data] + + // COMMAND NIBBLES (4-bit definitions), CN_ + #define CN_WRITE_IC_REGS 0x8 // 0b1000 + #define CN_READ_IC_REGS 0x4 // 0b0100 + #define CN_STREAM_CONTROL 0xB // 0b1011 + #define CN_MISC_CONTROLS 0xE // 0b1110 + + // CTRL_REQUEST_BATTERY_LEVEL :: 0xBB + + // TARGET NIBBLES (4-bit definitions) + #define TN_IC_ADS1298 0x1 + #define TN_IC_EXT 0xF // Extended .. check the next byte! + + #define TN_STREAM_START 0x2 + #define TN_STREAM_STOP 0xF + #define TN_STREAM_REQUEST_BATTERY_LEVEL 0xB + #define TN_STREAM_REQUEST_INFO 0xE + + // #TODO: + #define TN_MISC_THROUGHPUT_TEST 0xF + #define TN_MISC_RTT_REQUEST 0x1 + + #define FIRST_NIBBLE(x) ((x >> 4) & 0xF) + #define SECOND_NIBBLE(x) (x & 0xF) + // For IC controls, we want to prefix the registers with the length: [u16???] + // Data format will be different for each device. + // For ADS1298 + // [CN:4bit][TN:4bit][length:u8][..data] + // For other device with 1 register read/write at a time + // [CN:4bit][TN:4bit][RegisterID][RegisterData] for single register + +#endif // NRF52840_BREAKOUT_BOARD + +enum recording_mode_t { + RECORDING_MODE_ALL, + RECORDING_MODE_DISABLED +}; + + +#endif // CUSTOM_BOARD_H \ No newline at end of file diff --git a/pca10056/blank/config/sdk_config.h b/pca10056/blank/config/sdk_config.h index 2e0dc72..4b0a3a3 100644 --- a/pca10056/blank/config/sdk_config.h +++ b/pca10056/blank/config/sdk_config.h @@ -1771,7 +1771,7 @@ // NRF_LOG_BACKEND_RTT_ENABLED - nrf_log_backend_rtt - Log RTT backend //========================================================== #ifndef NRF_LOG_BACKEND_RTT_ENABLED -#define NRF_LOG_BACKEND_RTT_ENABLED 0 +#define NRF_LOG_BACKEND_RTT_ENABLED 1 #endif // NRF_LOG_BACKEND_RTT_TEMP_BUFFER_SIZE - Size of buffer for partially processed strings. // Size of the buffer is a trade-off between RAM usage and processing. @@ -1780,7 +1780,7 @@ // longer one will be fragmented. #ifndef NRF_LOG_BACKEND_RTT_TEMP_BUFFER_SIZE -#define NRF_LOG_BACKEND_RTT_TEMP_BUFFER_SIZE 64 +#define NRF_LOG_BACKEND_RTT_TEMP_BUFFER_SIZE 256 #endif // NRF_LOG_BACKEND_RTT_TX_RETRY_DELAY_MS - Period before retrying writing to RTT diff --git a/pca10056/blank/ses/Multimodal_CV_USB_ADS1298R_pca10056.emProject b/pca10056/blank/ses/Multimodal_CV_USB_ADS1298R_pca10056.emProject index 7a6d544..2b19a8e 100644 --- a/pca10056/blank/ses/Multimodal_CV_USB_ADS1298R_pca10056.emProject +++ b/pca10056/blank/ses/Multimodal_CV_USB_ADS1298R_pca10056.emProject @@ -44,6 +44,7 @@ + diff --git a/pca10056/blank/ses/build_and_run.bat b/pca10056/blank/ses/build_and_run.bat new file mode 100644 index 0000000..d986c9c --- /dev/null +++ b/pca10056/blank/ses/build_and_run.bat @@ -0,0 +1,24 @@ +@echo off +echo building project with emBuild: +emBuild -time -rebuild -nostderr -config "Release" -solution "Multimodal_CV_USB_ADS1298R_pca10056" Multimodal_CV_USB_ADS1298R_pca10056.emProject +IF ERRORLEVEL 1 ( + echo Building solution failed. + echo. + exit /b 1 +) +echo build success. + +nrfjprog --program Output\Release\Exe\Multimodal_CV_USB_ADS1298R_pca10056.hex --chiperase --verify --reset +IF ERRORLEVEL 1 ( + echo Flashing target device failed. + echo. + exit /b 1 +) +echo flash success. + +rem "C:\Program Files\SEGGER\JLink_V810f\JLinkRTTViewer.exe" --autoconnect -d "NRF52840_XXAA" +rem IF ERRORLEVEL 1 ( +rem echo J-Link RTT Viewer failed to launch. +rem echo. +rem exit /b 1 +rem ) diff --git a/pca10056/blank/ses/debug_build_and_run.bat b/pca10056/blank/ses/debug_build_and_run.bat new file mode 100644 index 0000000..7d1905d --- /dev/null +++ b/pca10056/blank/ses/debug_build_and_run.bat @@ -0,0 +1,24 @@ +@echo off +echo building project with emBuild: +emBuild -time -rebuild -nostderr -config "Debug" -solution "Multimodal_CV_USB_ADS1298R_pca10056" Multimodal_CV_USB_ADS1298R_pca10056.emProject +IF ERRORLEVEL 1 ( + echo Building solution failed. + echo. + exit /b 1 +) +echo build success. + +nrfjprog --program Output\Debug\Exe\Multimodal_CV_USB_ADS1298R_pca10056.hex --chiperase --verify --reset +IF ERRORLEVEL 1 ( + echo Flashing target device failed. + echo. + exit /b 1 +) +echo flash success. + +"C:\Program Files\SEGGER\JLink_V810f\JLinkRTTViewer.exe" --autoconnect -d "NRF52840_XXAA" +IF ERRORLEVEL 1 ( + echo J-Link RTT Viewer failed to launch. + echo. + exit /b 1 +)