Added readback for peripheral info, 'who am i' and HW/FW versions

This commit is contained in:
Musa Mahmood 2025-04-12 20:30:55 -04:00
parent cf50064365
commit 3428fa968f
5 changed files with 77 additions and 48 deletions

View File

@ -121,19 +121,18 @@ bool ads1298_check_id(ads1298_info_t *p_info) {
#if ADS1298_LOG_DEBUG #if ADS1298_LOG_DEBUG
NRF_LOG_INFO("Checking ADS129xR? ID:"); NRF_LOG_INFO("Checking ADS129xR? ID:");
#endif #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}; uint8_t rx_buf[6] = {0,0,0,0,0,0};
spi_xfer_done = false; spi_xfer_done = false;
APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi0, tx_buf, 6, rx_buf, 6)); APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi0, tx_buf, 3, rx_buf, 3));
while(!spi_xfer_done) { while(!spi_xfer_done) { __WFE(); }
__WFE();
}
uint8_t register_data = rx_buf[2]; uint8_t register_data = rx_buf[2];
memcpy(p_info->id_buffer, rx_buf, 6);
#if ADS1298_LOG_DEBUG #if ADS1298_LOG_DEBUG
NRF_LOG_INFO("register_data[0] = 0x%X", register_data); NRF_LOG_INFO("register_data[0] = 0x%X", register_data);
NRF_LOG_INFO(">rx_buf dump:"); 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_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); // NRF_LOG_HEXDUMP_INFO(rx_buf, 6);
#endif #endif
@ -152,6 +151,7 @@ bool ads1298_check_id(ads1298_info_t *p_info) {
} }
// Check middle bits 0x[...]10[...] < always should be 10 // Check middle bits 0x[...]10[...] < always should be 10
if ((register_data & 0x10) != 0x10 || p_info->nChs == 0) { if ((register_data & 0x10) != 0x10 || p_info->nChs == 0) {
p_info->nChs = 8;
NRF_LOG_INFO("[ERROR] Expected ADS129xX not detected! E1"); NRF_LOG_INFO("[ERROR] Expected ADS129xX not detected! E1");
return false; 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]; return popcount_table[p_info->active_chs];
} }
// void ads1298_readback_registers
void ads1298_update_registers(ads1298_info_t *p_info) { void ads1298_update_registers(ads1298_info_t *p_info) {
NRF_LOG_INFO("Updating ADS1298 registers..."); NRF_LOG_INFO("Updating ADS1298 registers...");
ads1298_update_active_chs(p_info); 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 // Transaction size = 2 + number of registers to write
spi_xfer_done = false; spi_xfer_done = false;
APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi0, tx_data, ADS1298_REGISTER_COUNT + 2, rx_data, ADS1298_REGISTER_COUNT + 2)); APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi0, tx_data, ADS1298_REGISTER_COUNT + 2, rx_data, ADS1298_REGISTER_COUNT + 2));
while (!spi_xfer_done) while (!spi_xfer_done) { __WFE(); }
{
__WFE();
}
#if ADS1298_LOG_DEBUG #if ADS1298_LOG_DEBUG
NRF_LOG_INFO("[ADS1298] Registers updated!"); NRF_LOG_INFO("[ADS1298] Registers updated!");
#endif #endif
// #TODO: Readback registers?
} }
void ads1298_init_default_registers(void) { void ads1298_init_default_registers(void) {
@ -276,8 +277,9 @@ void ads1298_power_down(void) {
} }
void ads1298_power_up(void) { void ads1298_power_up(void) {
nrf_delay_ms(100); // wait for power supplies to stabilize
nrf_gpio_pin_set(ADS1298_PWDN_PIN); nrf_gpio_pin_set(ADS1298_PWDN_PIN);
nrf_delay_ms(80); nrf_delay_ms(100);
} }
// Standby/Wakeup controls: // Standby/Wakeup controls:
@ -418,6 +420,8 @@ void ads1298_set_data_buffer_length(ads1298_info_t* p_info) {
break; break;
} }
NRF_LOG_INFO("[ADS129x] Sampling rate is %d", sampling_rate); 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); NRF_LOG_INFO("[ADS129x] p_info->usb_buffer_size_max is %d", p_info->usb_buffer_size_max);
} }

View File

@ -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 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_CONFIG1 0x46 // Low power mode, Multiple readback mode, clk output disabled, LP: 250 SPS
#define ADS1298_REGDEFAULT_CONFIG2 0x00 // Test signals #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_LOFF 0x00
#define ADS1298_REGDEFAULT_CH1SET 0x00 #define ADS1298_REGDEFAULT_CH1SET 0x01 // Input Short (for startup)
#define ADS1298_REGDEFAULT_CH2SET 0x00 #define ADS1298_REGDEFAULT_CH2SET 0x01 // Input Short (for startup)
#define ADS1298_REGDEFAULT_CH3SET 0x00 #define ADS1298_REGDEFAULT_CH3SET 0x01 // Input Short (for startup)
#define ADS1298_REGDEFAULT_CH4SET 0x00 #define ADS1298_REGDEFAULT_CH4SET 0x01 // Input Short (for startup)
#define ADS1298_REGDEFAULT_CH5SET 0x00 #define ADS1298_REGDEFAULT_CH5SET 0x01 // Input Short (for startup)
#define ADS1298_REGDEFAULT_CH6SET 0x00 #define ADS1298_REGDEFAULT_CH6SET 0x01 // Input Short (for startup)
#define ADS1298_REGDEFAULT_CH7SET 0x00 #define ADS1298_REGDEFAULT_CH7SET 0x01 // Input Short (for startup)
#define ADS1298_REGDEFAULT_CH8SET 0x00 #define ADS1298_REGDEFAULT_CH8SET 0x01 // Input Short (for startup)
#define ADS1298_REGDEFAULT_RLD_SENSP 0x00 #define ADS1298_REGDEFAULT_RLD_SENSP 0x00
#define ADS1298_REGDEFAULT_RLD_SENSN 0x00 #define ADS1298_REGDEFAULT_RLD_SENSN 0x00
#define ADS1298_REGDEFAULT_LOFF_SENSP 0x00 #define ADS1298_REGDEFAULT_LOFF_SENSP 0x00
@ -106,6 +106,7 @@ typedef struct {
uint8_t active_chs; uint8_t active_chs;
uint8_t registers[ADS1298_REGISTER_COUNT]; uint8_t registers[ADS1298_REGISTER_COUNT];
char name[12]; char name[12];
uint8_t id_buffer[6];
char usb_buffer[USBD_MAX_SIZE]; char usb_buffer[USBD_MAX_SIZE];
uint8_t usb_buffer_count; uint8_t usb_buffer_count;
uint8_t usb_buffer_size_max; uint8_t usb_buffer_size_max;

64
main.c
View File

@ -36,8 +36,11 @@ static enum recording_mode_t recording_mode = RECORDING_MODE_DISABLED;
ads1298_info_t m_info; ads1298_info_t m_info;
#endif #endif
static bool send_peripheral_info = false; // #TEMP!
// static uint8_t message_length = 0; 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 volatile bool run_throughput_test = false;
static char usb_tx_buffer[NRF_DRV_USBD_EPSIZE]; 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 #define USBD_POWER_DETECTION true
#endif #endif
static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const * p_inst, 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);
@ -71,12 +73,33 @@ APP_USBD_CDC_ACM_GLOBAL_DEF(m_app_cdc_acm,
APP_USBD_CDC_COMM_PROTOCOL_AT_V250); 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` // length is always `READ_SIZE`
void write_ic_settings(uint8_t* new_packet) { void write_ic_settings(uint8_t* new_packet) {
switch (SECOND_NIBBLE(new_packet[0])) { switch (SECOND_NIBBLE(new_packet[0])) {
case TN_IC_ADS1298: { case TN_IC_ADS1298: {
// #TODO: &new_packet[1] // #TODO: &new_packet[1]
#if ADS1298 #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); memcpy(m_info.registers, &new_packet[1], ADS1298_REGISTER_COUNT);
ads1298_update_registers(&m_info); ads1298_update_registers(&m_info);
ads1298_set_data_buffer_length(&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) { void read_ic_settings(uint8_t* new_packet) {
switch (SECOND_NIBBLE(new_packet[0])) { switch (SECOND_NIBBLE(new_packet[0])) {
case TN_IC_ADS1298: { 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; } break;
default: default:
break; break;
@ -129,9 +158,9 @@ static void process_new_packet(uint8_t* new_packet) {
#endif #endif
} }
if (SECOND_NIBBLE(new_packet[0]) == TN_STREAM_REQUEST_INFO) { if (SECOND_NIBBLE(new_packet[0]) == TN_STREAM_REQUEST_INFO) {
// #TODO: Set peripheral info send flag usb_transmit_message(CTRL_STAT_INFO_PERIPHERALS, g_Peripheral_Info, strlen(g_Peripheral_Info));
// Can we just send it from here? usb_transmit_message(CTRL_STAT_INFO_WHO_AM_I, g_WhoAmI, strlen(g_WhoAmI));
send_peripheral_info = true; 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) { 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 // #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 (true) {
while (app_usbd_event_queue_process()) { /* Nothing to do */ } 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? // I think this check is totally irrelevant?
if (recording_mode == RECORDING_MODE_ALL) { if (recording_mode == RECORDING_MODE_ALL) {
@ -352,15 +372,7 @@ int main(void) {
}*/ }*/
if (run_throughput_test) { if (run_throughput_test) {
//NRF_LOG_INFO("Running throughput test!"); /*ret = */app_usbd_cdc_acm_write(&m_app_cdc_acm, usb_tx_buffer, NRF_DRV_USBD_EPSIZE);
// 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); }
} }
UNUSED_RETURN_VALUE(NRF_LOG_PROCESS()); 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);

View File

@ -10,6 +10,7 @@
#define ADS1298_MISO_PIN 12 #define ADS1298_MISO_PIN 12
#define ADS1298_SCK_PIN 13 #define ADS1298_SCK_PIN 13
#define ADS1298_CS_PIN 14 #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_PWDN_PIN 15
#define ADS1298_MOSI_PIN 16 #define ADS1298_MOSI_PIN 16
@ -33,10 +34,19 @@
#define TN_STREAM_REQUEST_BATTERY_LEVEL 0xB #define TN_STREAM_REQUEST_BATTERY_LEVEL 0xB
#define TN_STREAM_REQUEST_INFO 0xE #define TN_STREAM_REQUEST_INFO 0xE
// #TODO:
#define TN_MISC_THROUGHPUT_TEST 0xF #define TN_MISC_THROUGHPUT_TEST 0xF
#define TN_MISC_RTT_REQUEST 0x1 #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 FIRST_NIBBLE(x) ((x >> 4) & 0xF)
#define SECOND_NIBBLE(x) (x & 0xF) #define SECOND_NIBBLE(x) (x & 0xF)
// For IC controls, we want to prefix the registers with the length: [u16???] // For IC controls, we want to prefix the registers with the length: [u16???]

View File

@ -3092,7 +3092,7 @@
#ifndef SPI0_USE_EASY_DMA #ifndef SPI0_USE_EASY_DMA
#define SPI0_USE_EASY_DMA 1 #define SPI0_USE_EASY_DMA 0
#endif #endif
// </e> // </e>
@ -3114,7 +3114,7 @@
// <e> SPI2_ENABLED - Enable SPI2 instance // <e> SPI2_ENABLED - Enable SPI2 instance
//========================================================== //==========================================================
#ifndef SPI2_ENABLED #ifndef SPI2_ENABLED
#define SPI2_ENABLED 1 #define SPI2_ENABLED 0
#endif #endif
// <q> SPI2_USE_EASY_DMA - Use EasyDMA // <q> SPI2_USE_EASY_DMA - Use EasyDMA