Add build scripts, basic peripherial info response [WIP]
This commit is contained in:
parent
d2ffd09079
commit
cf50064365
216
ads1298.c
216
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 <string.h>
|
||||
#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
|
||||
46
ads1298.h
46
ads1298.h
@ -4,20 +4,14 @@
|
||||
#include <stdint.h>
|
||||
#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_
|
||||
|
||||
262
main.c
262
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();
|
||||
}
|
||||
|
||||
while (true) {
|
||||
while (app_usbd_event_queue_process()) {/* Nothing to do */}
|
||||
// Init peripherals:
|
||||
#if ADS1298
|
||||
ads1298_interrupt_setup();
|
||||
ads1298_initialize(&m_info);
|
||||
#endif
|
||||
|
||||
if(m_run_throughput_test) {
|
||||
memset(usb_tx_buffer, 0x41, NRF_DRV_USBD_EPSIZE); // #TEMP
|
||||
|
||||
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) {
|
||||
// #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());
|
||||
|
||||
57
pca10056/blank/config/custom_board.h
Normal file
57
pca10056/blank/config/custom_board.h
Normal file
@ -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
|
||||
@ -1771,7 +1771,7 @@
|
||||
// <e> 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
|
||||
// <o> NRF_LOG_BACKEND_RTT_TEMP_BUFFER_SIZE - Size of buffer for partially processed strings.
|
||||
// <i> Size of the buffer is a trade-off between RAM usage and processing.
|
||||
@ -1780,7 +1780,7 @@
|
||||
// <i> 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
|
||||
|
||||
// <o> NRF_LOG_BACKEND_RTT_TX_RETRY_DELAY_MS - Period before retrying writing to RTT
|
||||
|
||||
@ -44,6 +44,7 @@
|
||||
<folder Name="Application">
|
||||
<file file_name="../../../ads1298.c" />
|
||||
<file file_name="../../../ads1298.h" />
|
||||
<file file_name="../config/custom_board.h" />
|
||||
<file file_name="../../../main.c" />
|
||||
<file file_name="../config/sdk_config.h" />
|
||||
</folder>
|
||||
|
||||
24
pca10056/blank/ses/build_and_run.bat
Normal file
24
pca10056/blank/ses/build_and_run.bat
Normal file
@ -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 )
|
||||
24
pca10056/blank/ses/debug_build_and_run.bat
Normal file
24
pca10056/blank/ses/debug_build_and_run.bat
Normal file
@ -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
|
||||
)
|
||||
Loading…
Reference in New Issue
Block a user