From 3428fa968f77e2116f8161d768fc7737102f8168 Mon Sep 17 00:00:00 2001 From: Musa Mahmood Date: Sat, 12 Apr 2025 20:30:55 -0400 Subject: [PATCH] Added readback for peripheral info, 'who am i' and HW/FW versions --- ads1298.c | 26 ++++++----- ads1298.h | 19 +++++---- main.c | 64 +++++++++++++++++----------- pca10056/blank/config/custom_board.h | 12 +++++- pca10056/blank/config/sdk_config.h | 4 +- 5 files changed, 77 insertions(+), 48 deletions(-) diff --git a/ads1298.c b/ads1298.c index 07c6e97..cd0037a 100644 --- a/ads1298.c +++ b/ads1298.c @@ -121,19 +121,18 @@ bool ads1298_check_id(ads1298_info_t *p_info) { #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}; + // Read two registers starting from ID register + uint8_t tx_buf[6] = {ADS1298_OPC_RREG|ADS1298_REGADDR_ID, 0x00, 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, 6, rx_buf, 6)); - while(!spi_xfer_done) { - __WFE(); - } + APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi0, tx_buf, 3, rx_buf, 3)); + while(!spi_xfer_done) { __WFE(); } uint8_t register_data = rx_buf[2]; + memcpy(p_info->id_buffer, rx_buf, 6); #if ADS1298_LOG_DEBUG 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 @@ -152,6 +151,7 @@ bool ads1298_check_id(ads1298_info_t *p_info) { } // Check middle bits 0x[...]10[...] < always should be 10 if ((register_data & 0x10) != 0x10 || p_info->nChs == 0) { + p_info->nChs = 8; NRF_LOG_INFO("[ERROR] Expected ADS129xX not detected! E1"); return false; } @@ -220,6 +220,8 @@ static inline uint8_t ads1298_channel_count(ads1298_info_t *p_info) { return popcount_table[p_info->active_chs]; } +// void ads1298_readback_registers + void ads1298_update_registers(ads1298_info_t *p_info) { NRF_LOG_INFO("Updating ADS1298 registers..."); ads1298_update_active_chs(p_info); @@ -236,13 +238,12 @@ void ads1298_update_registers(ads1298_info_t *p_info) { // 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(); - } + while (!spi_xfer_done) { __WFE(); } #if ADS1298_LOG_DEBUG NRF_LOG_INFO("[ADS1298] Registers updated!"); #endif + + // #TODO: Readback registers? } void ads1298_init_default_registers(void) { @@ -276,8 +277,9 @@ void ads1298_power_down(void) { } void ads1298_power_up(void) { + nrf_delay_ms(100); // wait for power supplies to stabilize nrf_gpio_pin_set(ADS1298_PWDN_PIN); - nrf_delay_ms(80); + nrf_delay_ms(100); } // Standby/Wakeup controls: @@ -418,6 +420,8 @@ void ads1298_set_data_buffer_length(ads1298_info_t* p_info) { break; } NRF_LOG_INFO("[ADS129x] Sampling rate is %d", sampling_rate); + NRF_LOG_INFO("[ADS129x] p_info->nChs is %d", p_info->nChs); + NRF_LOG_INFO("[ADS129x] Channel count is %d, active_channels: 0x%X", channel_count, p_info->active_chs); NRF_LOG_INFO("[ADS129x] p_info->usb_buffer_size_max is %d", p_info->usb_buffer_size_max); } diff --git a/ads1298.h b/ads1298.h index dd5ac5f..68386a8 100644 --- a/ads1298.h +++ b/ads1298.h @@ -68,16 +68,16 @@ //#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_CONFIG3 0xCC // #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_CH1SET 0x01 // Input Short (for startup) +#define ADS1298_REGDEFAULT_CH2SET 0x01 // Input Short (for startup) +#define ADS1298_REGDEFAULT_CH3SET 0x01 // Input Short (for startup) +#define ADS1298_REGDEFAULT_CH4SET 0x01 // Input Short (for startup) +#define ADS1298_REGDEFAULT_CH5SET 0x01 // Input Short (for startup) +#define ADS1298_REGDEFAULT_CH6SET 0x01 // Input Short (for startup) +#define ADS1298_REGDEFAULT_CH7SET 0x01 // Input Short (for startup) +#define ADS1298_REGDEFAULT_CH8SET 0x01 // Input Short (for startup) #define ADS1298_REGDEFAULT_RLD_SENSP 0x00 #define ADS1298_REGDEFAULT_RLD_SENSN 0x00 #define ADS1298_REGDEFAULT_LOFF_SENSP 0x00 @@ -106,6 +106,7 @@ typedef struct { uint8_t active_chs; uint8_t registers[ADS1298_REGISTER_COUNT]; char name[12]; + uint8_t id_buffer[6]; char usb_buffer[USBD_MAX_SIZE]; uint8_t usb_buffer_count; uint8_t usb_buffer_size_max; diff --git a/main.c b/main.c index e663d0e..6ff370d 100644 --- a/main.c +++ b/main.c @@ -36,8 +36,11 @@ static enum recording_mode_t recording_mode = RECORDING_MODE_DISABLED; ads1298_info_t m_info; #endif -static bool send_peripheral_info = false; -// static uint8_t message_length = 0; +// #TEMP! +char g_Peripheral_Info[] = "ADS1298|"; +char g_WhoAmI[] = "multimodal_cv_dev0_ecg"; +uint8_t g_HWFW_Ver[] = {1,0,0,1}; // HW Maj, HW Min, FW Maj, FW Min + static volatile bool run_throughput_test = false; static char usb_tx_buffer[NRF_DRV_USBD_EPSIZE]; @@ -49,7 +52,6 @@ static char usb_read_buffer[READ_SIZE]; #define USBD_POWER_DETECTION true #endif - static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const * p_inst, app_usbd_cdc_acm_user_event_t event); @@ -71,12 +73,33 @@ APP_USBD_CDC_ACM_GLOBAL_DEF(m_app_cdc_acm, APP_USBD_CDC_COMM_PROTOCOL_AT_V250); +void usb_transmit_message_ex(uint8_t message_prefix, uint8_t message_part_two, uint8_t* message, uint8_t message_length) { + usb_tx_buffer[0] = message_prefix; + usb_tx_buffer[1] = message_part_two; + usb_tx_buffer[2] = message_length + 3; + memcpy(&usb_tx_buffer[3], message, message_length); + ret_code_t ret = app_usbd_cdc_acm_write(&m_app_cdc_acm, usb_tx_buffer, message_length + 3); + + NRF_LOG_INFO("[ex]Writing message of length %d, ret: %d", message_length + 3, ret); +} + +void usb_transmit_message(uint8_t message_prefix, uint8_t* message, uint8_t message_length) { + usb_tx_buffer[0] = message_prefix; + usb_tx_buffer[1] = message_length + 2; + memcpy(&usb_tx_buffer[2], message, message_length); + ret_code_t ret = app_usbd_cdc_acm_write(&m_app_cdc_acm, usb_tx_buffer, message_length + 2); + + NRF_LOG_INFO("[0]Writing message of length %d, ret: %d", message_length + 2, ret); +} + // 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 + NRF_LOG_INFO("Writing new ADS1298 registers:"); + NRF_LOG_HEXDUMP_INFO(&new_packet[1], ADS1298_REGISTER_COUNT); memcpy(m_info.registers, &new_packet[1], ADS1298_REGISTER_COUNT); ads1298_update_registers(&m_info); ads1298_set_data_buffer_length(&m_info); @@ -90,7 +113,13 @@ void write_ic_settings(uint8_t* new_packet) { void read_ic_settings(uint8_t* new_packet) { switch (SECOND_NIBBLE(new_packet[0])) { case TN_IC_ADS1298: { - // #TODO: + // #NOTE: you will not be able to read registers while in RDATAC mode. + ads1298_stop_rdatac(); + ads1298_check_id(&m_info); + usb_transmit_message_ex(ID_REGISTER_READBACK_PREFIX, REGISTER_READBACK_ADS1298, + m_info.id_buffer, sizeof(m_info.id_buffer)); + usb_transmit_message_ex(REGISTER_READBACK_PREFIX, REGISTER_READBACK_ADS1298, + m_info.registers, ADS1298_REGISTER_COUNT); } break; default: break; @@ -129,9 +158,9 @@ static void process_new_packet(uint8_t* new_packet) { #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; + usb_transmit_message(CTRL_STAT_INFO_PERIPHERALS, g_Peripheral_Info, strlen(g_Peripheral_Info)); + usb_transmit_message(CTRL_STAT_INFO_WHO_AM_I, g_WhoAmI, strlen(g_WhoAmI)); + usb_transmit_message(CTRL_STAT_INFO_HW_FW_VERSION, g_HWFW_Ver, sizeof(g_HWFW_Ver)); } 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 @@ -320,15 +349,6 @@ int main(void) { while (true) { while (app_usbd_event_queue_process()) { /* Nothing to do */ } - 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) { @@ -352,15 +372,7 @@ int main(void) { }*/ 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, usb_tx_buffer, NRF_DRV_USBD_EPSIZE); - // if (rc != NRF_SUCCESS) { NRF_LOG_INFO("rc: %d", rc); } + /*ret = */app_usbd_cdc_acm_write(&m_app_cdc_acm, usb_tx_buffer, NRF_DRV_USBD_EPSIZE); } UNUSED_RETURN_VALUE(NRF_LOG_PROCESS()); @@ -370,3 +382,5 @@ int main(void) { } /** @} */ +// size_t size = sprintf(m_tx_buffer, "Hello USB CDC FA demo: %u\r\n", frame_counter); + diff --git a/pca10056/blank/config/custom_board.h b/pca10056/blank/config/custom_board.h index 069df3c..804a938 100644 --- a/pca10056/blank/config/custom_board.h +++ b/pca10056/blank/config/custom_board.h @@ -10,6 +10,7 @@ #define ADS1298_MISO_PIN 12 #define ADS1298_SCK_PIN 13 #define ADS1298_CS_PIN 14 + // I don't think you're supposed to tie PWDN and reset together on ADS1298 #define ADS1298_PWDN_PIN 15 #define ADS1298_MOSI_PIN 16 @@ -33,10 +34,19 @@ #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 + // #################### RESPONSE CODES #################### + + #define CTRL_STAT_INFO_PERIPHERALS 0x03 + #define CTRL_STAT_INFO_HW_FW_VERSION 0x04 + #define CTRL_STAT_INFO_WHO_AM_I 0x05 + + #define REGISTER_READBACK_PREFIX 0xC8 + #define ID_REGISTER_READBACK_PREFIX 0xC9 + #define REGISTER_READBACK_ADS1298 TN_IC_ADS1298 + #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???] diff --git a/pca10056/blank/config/sdk_config.h b/pca10056/blank/config/sdk_config.h index 4b0a3a3..c8a4d1b 100644 --- a/pca10056/blank/config/sdk_config.h +++ b/pca10056/blank/config/sdk_config.h @@ -3092,7 +3092,7 @@ #ifndef SPI0_USE_EASY_DMA -#define SPI0_USE_EASY_DMA 1 +#define SPI0_USE_EASY_DMA 0 #endif // @@ -3114,7 +3114,7 @@ // SPI2_ENABLED - Enable SPI2 instance //========================================================== #ifndef SPI2_ENABLED -#define SPI2_ENABLED 1 +#define SPI2_ENABLED 0 #endif // SPI2_USE_EASY_DMA - Use EasyDMA