This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

[nRF52] ADC and BLE send

#define DEVICE_NAME                     "fast sampling"                  

#define APP_BLE_OBSERVER_PRIO           3                                       /**< Application's BLE observer priority. You shouldn't need to modify this value. */
#define APP_BLE_CONN_CFG_TAG            1                                       /**< A tag identifying the SoftDevice BLE configuration. */

#define APP_ADV_INTERVAL                64                                      /**< The advertising interval (in units of 0.625 ms; this value corresponds to 40 ms). */
#define APP_ADV_DURATION                BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED   /**< The advertising time-out (in units of seconds). When set to 0, we will never time out. */

#define CONN_INTERVAL_DEFAULT           (uint16_t)(MSEC_TO_UNITS(7.5, UNIT_1_25_MS))    /**< Default connection interval used at connection establishment by central side. */

#define MIN_CONN_INTERVAL               MSEC_TO_UNITS(7.5, UNIT_1_25_MS)        /**< Minimum acceptable connection interval (7.5 mseconds). */
#define MAX_CONN_INTERVAL               MSEC_TO_UNITS(500, UNIT_1_25_MS)        /**< Maximum acceptable connection interval (0.5 second). */
#define SLAVE_LATENCY                   0                                       /**< Slave latency. */
#define CONN_SUP_TIMEOUT                MSEC_TO_UNITS(4000, UNIT_10_MS)         /**< Connection supervisory time-out (4 seconds). */

#define FIRST_CONN_PARAMS_UPDATE_DELAY  APP_TIMER_TICKS(20000)                  /**< Time from initiating event (connect or start of notification) to first time sd_ble_gap_conn_param_update is called (15 seconds). */
#define NEXT_CONN_PARAMS_UPDATE_DELAY   APP_TIMER_TICKS(5000)                   /**< Time between each call to sd_ble_gap_conn_param_update after the first call (5 seconds). */
#define MAX_CONN_PARAMS_UPDATE_COUNT    3                                       /**< Number of attempts before giving up the connection parameter negotiation. */

#define DEAD_BEEF                       0xDEADBEEF                              /**< Value used as error code on stack dump, can be used to identify stack location on stack unwind. */

#define SAMPLES_IN_BUFFER 123
#define NO_OF_SAADC_BUFFER 2
#define TIMER_ADC_TIMEOUT_US      13  //80kHz sampling
#define MUX_OUTPUT  NRF_SAADC_INPUT_AIN4 // PA28

BLE_FS_DEF(m_ble_fs);                                                             /**< LED Button Service instance. */
NRF_BLE_GATT_DEF(m_gatt);                                                       /**< GATT module instance. */
NRF_BLE_QWR_DEF(m_qwr);                                                         /**< Context for the Queued Write module.*/
static const nrf_drv_timer_t m_timer_2 = NRF_DRV_TIMER_INSTANCE(2);

static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID;                        /**< Handle of the current connection. */

static uint8_t m_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET;                   /**< Advertising handle used to identify an advertising set. */
static uint8_t m_enc_advdata[BLE_GAP_ADV_SET_DATA_SIZE_MAX];                    /**< Buffer for storing an encoded advertising set. */
static uint8_t m_enc_scan_response_data[BLE_GAP_ADV_SET_DATA_SIZE_MAX];          /**< Buffer for storing an encoded scan data. */
static nrf_ppi_channel_t     m_ppi_channel // ppi channels
static uint32_t              m_adc_evt_counter; // adc event counter
volatile uint8_t buffer_number = 0x01;// vairable to change the buffer in adc event and ble send notification
volatile bool saadc_event_callback = false; // callback flag
static uint8_t adc_ble_notify_size = SAMPLES_IN_BUFFER * sizeof(uint16_t); // variable of keeping track of size of ble buffer

typedef union {
	struct {
		nrf_saadc_value_t m_buffer_pool[NO_OF_SAADC_BUFFER][SAMPLES_IN_BUFFER]; //uint16_t
	}adc_buffer_saadc_t;
	uint8_t m_buffer_ble[NO_OF_SAADC_BUFFER * SAMPLES_IN_BUFFER];
}adc_buffer_t;

adc_buffer_t adc_buffer; // structure instance

static ble_gap_adv_data_t m_adv_data =
{
	.adv_data ={.p_data = m_enc_advdata,.len = BLE_GAP_ADV_SET_DATA_SIZE_MAX},
.scan_rsp_data ={.p_data = m_enc_scan_response_data,.len = BLE_GAP_ADV_SET_DATA_SIZE_MAX}
};

void timer_handler(nrf_timer_event_t event_type, void * p_context)
{
}

static void timer_init(void)
{
	ret_code_t err_code;

	nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
	timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;

	err_code = nrf_drv_timer_init(&m_timer_2, &timer_cfg, timer_handler);
	APP_ERROR_CHECK(err_code);

	uint32_t ticks_input_adc = nrf_drv_timer_us_to_ticks(&m_timer_2, TIMER_ADC_TIMEOUT_US);

	nrf_drv_timer_extended_compare(&m_timer_2,
		NRF_TIMER_CC_CHANNEL0,
		ticks_input_adc,
		NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
		false);

}

static void enable_timers(void)
{
	nrf_drv_timer_enable(&m_timer_2);
}

static void disable_timers(void)
{
	nrf_drv_timer_disable(&m_timer_2);
}

static void ppi_init(void)
{
	ret_code_t err_code;

	err_code = nrf_drv_ppi_init();
	APP_ERROR_CHECK(err_code);

	/* setup ppi channel so that timer compare event is triggering sample task in SAADC */
	err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel);
	APP_ERROR_CHECK(err_code);
}

static void saadc_sampling_event_init(void)
{
	ret_code_t err_code;
	uint32_t timer_compare_event_addr = nrf_drv_timer_event_address_get(&m_timer_2, NRF_TIMER_EVENT_COMPARE0);
	uint32_t saadc_sample_task_addr = nrf_drv_saadc_sample_task_get();

	err_code = nrf_drv_ppi_channel_assign(m_ppi_channel, timer_compare_event_addr, saadc_sample_task_addr);
	APP_ERROR_CHECK(err_code);
}

void saadc_sampling_event_enable(void)
{
	ret_code_t err_code = nrf_drv_ppi_channel_enable(m_ppi_channel);

	APP_ERROR_CHECK(err_code);
}

void saadc_sampling_event_disable(void)
{
	ret_code_t err_code = nrf_drv_ppi_channel_disable(m_ppi_channel);

	APP_ERROR_CHECK(err_code);
}

void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
	if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
	{
		ret_code_t err_code;
		buffer_number ^= 0x01;
		saadc_event_callback = true;
		err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER-2);
		APP_ERROR_CHECK(err_code);
	}
}

void saadc_init(void)
{
	ret_code_t err_code;
	nrf_saadc_channel_config_t channel_config =
		NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(MUX_OUTPUT);

	err_code = nrf_drv_saadc_init(NULL, saadc_callback);
	APP_ERROR_CHECK(err_code);

	err_code = nrf_drv_saadc_channel_init(0, &channel_config);
	APP_ERROR_CHECK(err_code);
	for (uint8_t i = 0; i < NO_OF_SAADC_BUFFER; i++) {
		err_code = nrf_drv_saadc_buffer_convert(&adc_buffer.adc_buffer_saadc_t.m_buffer_pool[i], SAMPLES_IN_BUFFER);
		APP_ERROR_CHECK(err_code);
	}
}

static void ui_write_handler(uint16_t conn_handle, ble_fs_t * p_ble_fs, uint8_t* p_data, uint8_t len)
{
	ret_code_t err_code;
	uint8_t cmd = p_data[0];

	switch (cmd)
	{
	case 0x31: // start ADC data, when send 1
	{
		saadc_sampling_event_enable();
		enable_timers();
	}
	break;
	case 0x32: // stop ADC data, when send 2
	{
		disable_timers();
		saadc_sampling_event_disable();
	}
	break;
	}
}

static void gatt_mtu_set(uint16_t att_mtu)
{
	ret_code_t err_code;

	err_code = nrf_ble_gatt_att_mtu_periph_set(&m_gatt, att_mtu);
	APP_ERROR_CHECK(err_code);
}

static void conn_evt_len_ext_set(bool status)
{
	ret_code_t err_code;
	ble_opt_t  opt;

	memset(&opt, 0x00, sizeof(opt));
	opt.common_opt.conn_evt_ext.enable = status ? 1 : 0;

	err_code = sd_ble_opt_set(BLE_COMMON_OPT_CONN_EVT_EXT, &opt);
	APP_ERROR_CHECK(err_code);

}

static void data_len_set(uint8_t value)
{
	ret_code_t err_code;
	err_code = nrf_ble_gatt_data_length_set(&m_gatt, BLE_CONN_HANDLE_INVALID, value);
	APP_ERROR_CHECK(err_code);
}

static void idle_state_handle(void)
{
	if (NRF_LOG_PROCESS() == false)
	{
		nrf_pwr_mgmt_run();
	}
}

int main(void)
{
	ret_code_t err_code;

	timer_init();
	ppi_init();

	saadc_init();
	saadc_sampling_event_init();

	gatt_mtu_set(adc_ble_notify_size);
	conn_evt_len_ext_set(true);
	data_len_set(adc_ble_notify_size);

	advertising_start();

	for (;;)
	{
		if (saadc_event_callback) {
			ble_fs_send_adc_data(m_conn_handle, &m_ble_fs, &(adc_buffer.m_buffer_ble[buffer_number * adc_ble_notify_size]), adc_ble_notify_size);
			ble_fs_send_adc_data(m_conn_handle, &m_ble_fs, &(adc_buffer.m_buffer_ble[(buffer_number * adc_ble_notify_size) + (adc_ble_notify_size)]), adc_ble_notify_size); //sizeof(m_buffer_ble)=246
			saadc_event_callback = false;			
		}
		idle_state_handle();
	}
}

Hello all, I'm working on ADC and data transmission.

Device do ADC first, and send those values.

Sampling frequency of ADC is ~80 kHz (sampling per 13 microseconds), and using 2 Mbps transmission mode.

An array is sent to nRF52 app (smartphone) per one transmission, and that array contains 121 numbers. Numbers are 16 bits (ADC is done in 10 bits, but to send numbers, it converted into 16 bits).

So theoretically, transmission speed is lower than 1.3Mbps.

I attached my codes here. I removed some parts which are unimportant in my thoughts.

Anyway, my question is, how can I speed up the transmission speed? 

This graph is the result when I put ramp function to nRF52 board. (linearly increasing)

As you can see, there are some points that values are increasing suddenly. It means that some values are missing.

I think it is because of delay between transmission. I've checked in wired communication that ADC function is OK.

Any advice will be appreciated.

Thanks everyone and happy new year.

Parents
  • uint32_t ble_fs_send_adc_data(uint16_t conn_handle, ble_fs_t * p_fs, uint8_t *  p_data, uint16_t length)
    {
        ble_gatts_hvx_params_t params;
        uint16_t len = length;
        //p_fs->bytes_sent += len; // keep track of how many lengths have been sent!
        memset(&params, 0, sizeof(params));
        params.type   = BLE_GATT_HVX_NOTIFICATION;
        params.handle = p_fs->adc_char_handles.value_handle;
        params.p_data = p_data;
        params.p_len  = &len;
        return sd_ble_gatts_hvx(conn_handle, &params);
    }

    I added one more function here. Thanks!

Reply
  • uint32_t ble_fs_send_adc_data(uint16_t conn_handle, ble_fs_t * p_fs, uint8_t *  p_data, uint16_t length)
    {
        ble_gatts_hvx_params_t params;
        uint16_t len = length;
        //p_fs->bytes_sent += len; // keep track of how many lengths have been sent!
        memset(&params, 0, sizeof(params));
        params.type   = BLE_GATT_HVX_NOTIFICATION;
        params.handle = p_fs->adc_char_handles.value_handle;
        params.p_data = p_data;
        params.p_len  = &len;
        return sd_ble_gatts_hvx(conn_handle, &params);
    }

    I added one more function here. Thanks!

Children
No Data
Related