Allow buffering of small messages (e.g. peripheral info, who-am-i, and hw/fw version) over USB
This commit is contained in:
parent
3688db710a
commit
919523a465
14
ads1298.c
14
ads1298.c
@ -76,10 +76,11 @@ void ads1298_initialize(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_125K;
|
||||
spi_config.frequency = NRF_DRV_SPI_FREQ_250K;
|
||||
//spi_config.frequency = NRF_DRV_SPI_FREQ_500K;
|
||||
spi_config.frequency = NRF_DRV_SPI_FREQ_1M;
|
||||
//spi_config.frequency = NRF_DRV_SPI_FREQ_1M;
|
||||
//spi_config.frequency = NRF_DRV_SPI_FREQ_2M;
|
||||
spi_config.irq_priority = APP_IRQ_PRIORITY_HIGH;
|
||||
//spi_config.irq_priority = APP_IRQ_PRIORITY_HIGHEST;
|
||||
spi_config.mode = NRF_DRV_SPI_MODE_1;
|
||||
spi_config.orc = 0x55;
|
||||
@ -487,6 +488,15 @@ __STATIC_INLINE void copy_relevant_data(ads1298_info_t* p_info) {
|
||||
}
|
||||
}
|
||||
|
||||
void ads1298_get_data_fast(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(); }
|
||||
memcpy(&p_info->usb_buffer[p_info->usb_buffer_count], &rx_buffer[3], 8 * 3);
|
||||
p_info->usb_buffer_count += 3 * 8;
|
||||
}
|
||||
|
||||
// Buffer size depends on version (27 bytes for ADS1298, 21 for ADS1296, and 15 for ADS1294)
|
||||
void ads1298_get_data(ads1298_info_t* p_info) {
|
||||
|
||||
@ -65,7 +65,8 @@
|
||||
#define ADS129x_8CH_BITMASK 0x02 // 0x[...]10[010]
|
||||
|
||||
/** DEFAULT REGISTER VALUES **/
|
||||
#define ADS1298_REGDEFAULT_CONFIG1 0xC6 // High-res mode, Multiple readback mode, clk output disabled, LP: 250 SPS
|
||||
//
|
||||
#define ADS1298_REGDEFAULT_CONFIG1 0xC5 // High-res mode, Multiple readback mode, clk output disabled, LP: 250 SPS
|
||||
#define ADS1298_REGDEFAULT_CONFIG2 0x00 // Test signals
|
||||
#define ADS1298_REGDEFAULT_CONFIG3 0xCE //
|
||||
#define ADS1298_REGDEFAULT_LOFF 0x00
|
||||
@ -112,6 +113,7 @@ typedef struct {
|
||||
#if ADS1298_STATS
|
||||
uint32_t drdy_trigger_count;
|
||||
uint32_t seconds_elapsed;
|
||||
uint32_t bytes_sent_usb;
|
||||
#endif
|
||||
} ads1298_info_t;
|
||||
|
||||
@ -147,6 +149,7 @@ void ads1294_get_data(ads1298_info_t* p_info);
|
||||
void ads1296_get_data(ads1298_info_t* p_info);
|
||||
|
||||
void ads1298_get_data(ads1298_info_t* p_info);
|
||||
void ads1298_get_data_fast(ads1298_info_t* p_info);
|
||||
|
||||
uint16_t ads1298_sampling_rate(ads1298_info_t* p_info);
|
||||
|
||||
|
||||
136
main.c
136
main.c
@ -42,7 +42,8 @@ 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];
|
||||
static char usb_send_buffer[NRF_DRV_USBD_EPSIZE * 2]; // * 2 is just for safety margin in case we overrun!
|
||||
static uint8_t usb_send_buffer_offset = 0;
|
||||
|
||||
#define READ_SIZE 64
|
||||
static char usb_read_buffer[READ_SIZE];
|
||||
@ -84,30 +85,55 @@ void reset_counters(void) {
|
||||
#if ADS1298
|
||||
m_info.usb_buffer_count = ADS1298_PACKET_OFFSET;
|
||||
reset_buffer_count(m_info.usb_buffer);
|
||||
// #TODO: Clear stats:
|
||||
#if ADS1298_STATS
|
||||
m_info.drdy_trigger_count = 0;
|
||||
m_info.seconds_elapsed = 0;
|
||||
m_info.bytes_sent_usb = 0;
|
||||
#endif
|
||||
// #TODO: elapsed time Milliseconds (need last second timer).
|
||||
#endif
|
||||
}
|
||||
|
||||
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);
|
||||
// For sending two-byte prefixed messages
|
||||
void usb_send_push_ex(uint8_t message_prefix, uint8_t message_part_two, uint8_t* message, uint8_t message_length) {
|
||||
usb_send_buffer[0] = message_prefix;
|
||||
usb_send_buffer[1] = message_part_two;
|
||||
usb_send_buffer[2] = message_length + 3;
|
||||
memcpy(&usb_send_buffer[3], message, message_length);
|
||||
ret_code_t ret = app_usbd_cdc_acm_write(&m_app_cdc_acm, usb_send_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);
|
||||
// void usb_transmit_message(uint8_t message_prefix, uint8_t* message, uint8_t message_length) {
|
||||
// usb_send_buffer[0] = message_prefix;
|
||||
// usb_send_buffer[1] = message_length + 2;
|
||||
// memcpy(&usb_send_buffer[2], message, message_length);
|
||||
// ret_code_t ret = app_usbd_cdc_acm_write(&m_app_cdc_acm, usb_send_buffer, message_length + 2);
|
||||
|
||||
NRF_LOG_INFO("[0]Writing message of length %d, ret: %d", message_length + 2, ret);
|
||||
// NRF_LOG_INFO("[0]Writing message of length %d, ret: %d", message_length + 2, ret);
|
||||
// }
|
||||
|
||||
void usb_send_push(void) {
|
||||
ret_code_t ret = app_usbd_cdc_acm_write(&m_app_cdc_acm, usb_send_buffer, usb_send_buffer_offset);
|
||||
|
||||
NRF_LOG_INFO("[1]Writing message of length %d, ret: %d", usb_send_buffer_offset, ret);
|
||||
|
||||
usb_send_buffer_offset = 0; // reset.
|
||||
}
|
||||
|
||||
// For mushing together small messages into a 64-byte packet:
|
||||
void usb_send_append_message(uint8_t message_prefix, uint8_t* message, uint8_t message_length) {
|
||||
usb_send_buffer[usb_send_buffer_offset] = message_prefix;
|
||||
usb_send_buffer[usb_send_buffer_offset + 1] = message_length + 2;
|
||||
memcpy(&usb_send_buffer[usb_send_buffer_offset + 2], message, message_length);
|
||||
|
||||
usb_send_buffer_offset += (2 + message_length);
|
||||
|
||||
if (usb_send_buffer_offset >= 64) { // end of buffer
|
||||
NRF_LOG_INFO("[WARNING] exceeded limit of usb_send_buffer\n");
|
||||
usb_send_buffer_offset = 64;
|
||||
}
|
||||
}
|
||||
|
||||
// length is always `READ_SIZE`
|
||||
@ -142,11 +168,8 @@ void read_ic_settings(uint8_t* new_packet) {
|
||||
// read all registers into m_info.registers
|
||||
ads1298_readback_registers(&m_info);
|
||||
// Send back over USB.
|
||||
usb_transmit_message_ex(REGISTER_READBACK_PREFIX, REGISTER_READBACK_ADS1298,
|
||||
usb_send_push_ex(REGISTER_READBACK_PREFIX, REGISTER_READBACK_ADS1298,
|
||||
m_info.registers, ADS1298_REGISTER_COUNT);
|
||||
// This is totally unnecessary:
|
||||
// usb_transmit_message_ex(ID_REGISTER_READBACK_PREFIX, REGISTER_READBACK_ADS1298,
|
||||
// m_info.id_buffer, sizeof(m_info.id_buffer));
|
||||
ads1298_start_rdatac();
|
||||
ads1298_standby();
|
||||
} break;
|
||||
@ -180,18 +203,24 @@ static void process_new_packet(uint8_t* new_packet) {
|
||||
}
|
||||
if (SECOND_NIBBLE(new_packet[0]) == TN_STREAM_STOP) {
|
||||
recording_mode = RECORDING_MODE_DISABLED;
|
||||
#if ADS1298
|
||||
#if ADS1298
|
||||
if (m_info.state == 1) {
|
||||
m_info.state = 0;
|
||||
ads1298_standby();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#if ADS1298_STATS
|
||||
NRF_LOG_INFO("Bytes sent via USB: %lu\n", m_info.bytes_sent_usb);
|
||||
#endif
|
||||
reset_counters();
|
||||
}
|
||||
if (SECOND_NIBBLE(new_packet[0]) == TN_STREAM_REQUEST_INFO) {
|
||||
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_PERIPHERAL_INFO) {
|
||||
// #TODO: we should assert that the length of these messages does not exceed the packet
|
||||
// size!
|
||||
usb_send_append_message(CTRL_STAT_INFO_PERIPHERALS, g_Peripheral_Info, strlen(g_Peripheral_Info));
|
||||
usb_send_append_message(CTRL_STAT_INFO_WHO_AM_I, g_WhoAmI, strlen(g_WhoAmI));
|
||||
usb_send_append_message(CTRL_STAT_INFO_HW_FW_VERSION, g_HWFW_Ver, sizeof(g_HWFW_Ver));
|
||||
usb_send_push();
|
||||
}
|
||||
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
|
||||
@ -289,7 +318,9 @@ void drdy_pin_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) {
|
||||
UNUSED_PARAMETER(pin);
|
||||
UNUSED_PARAMETER(action);
|
||||
drdy_flag = true;
|
||||
#if ADS1298_STATS
|
||||
m_info.drdy_trigger_count += 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ads1298_interrupt_setup(void) {
|
||||
@ -393,15 +424,29 @@ int main(void) {
|
||||
ads1298_initialize(&m_info);
|
||||
#endif
|
||||
|
||||
memset(usb_tx_buffer, 0x41, NRF_DRV_USBD_EPSIZE); // #TEMP
|
||||
memset(usb_send_buffer, 0x41, NRF_DRV_USBD_EPSIZE); // #TEMP
|
||||
|
||||
reset_counters();
|
||||
|
||||
// #TEMP: application_timers_start
|
||||
application_timers_start();
|
||||
|
||||
#if AUTO_START_ADS1298 // for debugging
|
||||
ads1298_stop_rdatac();
|
||||
NRF_LOG_INFO("Writing new ADS1298 registers:");
|
||||
uint8_t new_registers[] = {0xC5,0x00,0xCE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00};
|
||||
memcpy(m_info.registers, new_registers, ADS1298_REGISTER_COUNT);
|
||||
ads1298_update_registers(&m_info);
|
||||
ads1298_set_data_buffer_length(&m_info);
|
||||
ads1298_start_rdatac();
|
||||
ads1298_wakeup();
|
||||
recording_mode = RECORDING_MODE_ALL;
|
||||
#endif
|
||||
|
||||
while (true) {
|
||||
#if !DISABLE_USBD_IN_MAIN_LOOP
|
||||
while (app_usbd_event_queue_process()) { /* Nothing to do */ }
|
||||
#endif
|
||||
|
||||
if (recording_mode == RECORDING_MODE_ALL) {
|
||||
// if (recording_mode & drdy_flag) { // may be faster if we're just using ADS1298
|
||||
@ -417,23 +462,30 @@ int main(void) {
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
// :ADS1298_FAST_PATH
|
||||
ads1298_get_data_fast(&m_info);
|
||||
// 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;
|
||||
// }
|
||||
|
||||
if (m_info.usb_buffer_count >= m_info.usb_buffer_size_max) {
|
||||
m_info.usb_buffer_count = ADS1298_PACKET_OFFSET;
|
||||
#if !DISABLE_USBD_IN_MAIN_LOOP
|
||||
app_usbd_cdc_acm_write(&m_app_cdc_acm, m_info.usb_buffer, m_info.usb_buffer_size_max);
|
||||
#if ADS1298_STATS
|
||||
m_info.bytes_sent_usb += m_info.usb_buffer_size_max;
|
||||
#endif
|
||||
#endif
|
||||
increment_packet(m_info.usb_buffer);
|
||||
|
||||
// NRF_LOG_INFO("Current time tick: %lu", app_timer_cnt_get());
|
||||
@ -441,14 +493,16 @@ int main(void) {
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !DISABLE_USBD_IN_MAIN_LOOP
|
||||
if (run_throughput_test) {
|
||||
/*ret = */app_usbd_cdc_acm_write(&m_app_cdc_acm, usb_tx_buffer, NRF_DRV_USBD_EPSIZE);
|
||||
/*ret = */app_usbd_cdc_acm_write(&m_app_cdc_acm, usb_send_buffer, NRF_DRV_USBD_EPSIZE);
|
||||
}
|
||||
|
||||
#endif
|
||||
UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
|
||||
/* Sleep CPU only if there was no interrupt since last loop processing */
|
||||
#if !DISABLE_USBD_IN_MAIN_LOOP
|
||||
__WFE();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -4,9 +4,13 @@
|
||||
#define NRF52840_BREAKOUT_BOARD 1
|
||||
#define ADS1298 1
|
||||
#if ADS1298
|
||||
#define ADS1298_STATS 1
|
||||
#define AUTO_START_ADS1298 0
|
||||
#define ADS1298_STATS 0
|
||||
#endif
|
||||
|
||||
// Debugging flags
|
||||
#define DISABLE_USBD_IN_MAIN_LOOP 0
|
||||
|
||||
// Testing with nRF52840:
|
||||
#if NRF52840_BREAKOUT_BOARD
|
||||
#define ADS1298_DRDY_PIN 11
|
||||
@ -35,7 +39,8 @@
|
||||
#define TN_STREAM_START 0x2
|
||||
#define TN_STREAM_STOP 0xF
|
||||
#define TN_STREAM_REQUEST_BATTERY_LEVEL 0xB
|
||||
#define TN_STREAM_REQUEST_INFO 0xE
|
||||
// #define TN_STREAM_REQUEST_WHO_AM_I 0xD
|
||||
#define TN_STREAM_REQUEST_PERIPHERAL_INFO 0xE
|
||||
|
||||
#define TN_MISC_THROUGHPUT_TEST 0xF
|
||||
#define TN_MISC_RTT_REQUEST 0x1
|
||||
|
||||
@ -1628,7 +1628,7 @@
|
||||
// <i> This may limit throughput if a lot of binary data is sent, but in terminal mode operation it makes sure that the data is always displayed right after it is sent.
|
||||
|
||||
#ifndef APP_USBD_CDC_ACM_ZLP_ON_EPSIZE_WRITE
|
||||
#define APP_USBD_CDC_ACM_ZLP_ON_EPSIZE_WRITE 1
|
||||
#define APP_USBD_CDC_ACM_ZLP_ON_EPSIZE_WRITE 0
|
||||
#endif
|
||||
|
||||
// </h>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user