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

Try to transfert ADC sampling signal by BLE.

Hello,

I am trying to transfer a signal sampled on AN0 (P0.02)  at 16kHz via Bluetooth using an ATT MTU of 247 and a 2MBPS PHY speed. The basis project used is  examples \ ble_central_and_peripheral \ experimental \ ble_app_att_mtu_throughput.

I also used  examples \ peripheral \ saadc for sampling trigger based on a timer 2 configuration.

  • If I test the signal sampling and disable the BLE pairing +vdata transfer, i can notice a good sampling.
  • When I disable the ADC sampling T(bsaadc_sampling_event_enable ()  )and test the pairing and data transfer, the operation is correct.
  • If I enable sampling and data transfer by BLE, the Bluetooth stack no longer works (the pairing does not run). I tried to use SAADC sampling using other Timers and the problem is not solved.I notice that the timer activation generates a conflict with the bluetooth stack.

I hope you can help me with the code I am writing below.

Thanks in advance, 

/**
* Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@cond To Make Doxygen skip documentation generation for this file.
* @{
*/

#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "nordic_common.h"
#include "nrf.h"

#include "sdk_config.h"
#include "nrf_drv_saadc.h"
#include "nrf_drv_ppi.h"
#include "nrf_drv_timer.h"
#include "amt.h"
#include "counter.h"

#include "ble.h"
#include "ble_gatt.h"
#include "ble_hci.h"

#include "nrf_gpio.h"
#include "bsp_btn_ble.h"
#include "ble_srv_common.h"
#include "nrf_sdh.h"
#include "nrf_sdh_ble.h"
#include "nrf_ble_gatt.h"
#include "nrf_ble_qwr.h"
#include "ble_advdata.h"
#include "app_timer.h"
#include "app_error.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_ble_scan.h"
#include "app_uart.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "nrf_delay.h"
#include "iirfilter.h"

#if defined (UART_PRESENT)
#include "nrf_uart.h"
#endif
#if defined (UARTE_PRESENT)
#include "nrf_uarte.h"
#endif

#define UART_TX_BUF_SIZE 256 /**< UART TX buffer size. */
#define UART_RX_BUF_SIZE 256 /**< UART RX buffer size. */


#define DATA_LENGTH_DEFAULT 27 /**< The stack default data length. */
#define DATA_LENGTH_MAX 251 /**< The stack maximum data length. */

#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 CONN_INTERVAL_MIN (uint16_t)(MSEC_TO_UNITS(7.5, UNIT_1_25_MS)) /**< Minimum acceptable connection interval, in units of 1.25 ms. */
#define CONN_INTERVAL_MAX (uint16_t)(MSEC_TO_UNITS(500, UNIT_1_25_MS)) /**< Maximum acceptable connection interval, in units of 1.25 ms. */
#define CONN_SUP_TIMEOUT (uint16_t)(MSEC_TO_UNITS(4000, UNIT_10_MS)) /**< Connection supervisory timeout (4 seconds). */
#define SLAVE_LATENCY 0 /**< Slave latency. */

#define SCAN_ADV_LED BSP_BOARD_LED_0
#define READY_LED BSP_BOARD_LED_1
#define PROGRESS_LED BSP_BOARD_LED_2
#define DONE_LED BSP_BOARD_LED_3

#define START_BUTTON BSP_BUTTON_2 /**< Button to press at the beginning of the test to indicate that this board is connected to the PC and takes input from it via the UART. */
//#define BOARD_DUMMY_BUTTON BSP_BUTTON_3 /**< Button to press at the beginning of the test to indicate that this board is standalone (automatic behavior). */
#define BUTTON_DETECTION_DELAY APP_TIMER_TICKS(50) /**< Delay from a GPIOTE event until a button is reported as pushed (in number of timer ticks). */

#define APP_BLE_CONN_CFG_TAG 1 /**< Tag that refers to the BLE stack configuration. */
#define APP_BLE_OBSERVER_PRIO 3 /**< BLE observer priority of the application. There is no need to modify this value. */

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. */


#define SAADC_SAMPLE_RATE 80 /**< SAADC sample rate in us. */

static const nrf_drv_timer_t m_timer = NRF_DRV_TIMER_INSTANCE(2);
static nrf_saadc_value_t m_buffer_pool[2];
static nrf_ppi_channel_t m_ppi_channel;
static uint32_t m_adc_evt_counter;
static uint32_t wait_filter_time_const = 0;

int16_t adc_buffer[2000];
static char flagsend = 1;
//static nrf_saadc_value_t adc_buf[2];

/**@brief Struct that contains pointers to the encoded advertising data. */
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 = NULL,
.len = 0

}
};


//typedef enum
//{
// NOT_SELECTED = 0x00,
// BOARD_TESTER,
// BOARD_DUMMY,
//} board_role_t;

typedef struct
{
uint16_t att_mtu; /**< GATT ATT MTU, in bytes. */
uint16_t conn_interval; /**< Connection interval expressed in units of 1.25 ms. */
ble_gap_phys_t phys; /**< Preferred PHYs. */
uint8_t data_len; /**< Data length. */
bool conn_evt_len_ext_enabled; /**< Connection event length extension status. */
} test_params_t;


NRF_BLE_GATT_DEF(m_gatt); /**< GATT module instance. */
NRF_BLE_QWR_DEF(m_qwr); /**< Context for the Queued Write module.*/
BLE_DB_DISCOVERY_DEF(m_ble_db_discovery); /**< Database discovery module instance. */
NRF_BLE_SCAN_DEF(m_scan); /**< Scanning Module instance. */

static nrf_ble_amtc_t m_amtc;
static nrf_ble_amts_t m_amts;
NRF_SDH_BLE_OBSERVER(m_amtc_ble_obs, BLE_AMTC_BLE_OBSERVER_PRIO, nrf_ble_amtc_on_ble_evt, &m_amtc);
NRF_SDH_BLE_OBSERVER(m_amts_ble_obs, BLE_AMTS_BLE_OBSERVER_PRIO, nrf_ble_amts_on_ble_evt, &m_amts);


static bool volatile m_run_test;
static bool volatile m_notif_enabled;
static bool volatile m_mtu_exchanged;
static bool volatile m_data_length_updated;
static bool volatile m_phy_updated;
static bool volatile m_conn_interval_configured;

static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID; /**< Handle of the current BLE connection .*/
static uint8_t m_gap_role = BLE_GAP_ROLE_INVALID; /**< BLE role for this connection, see @ref BLE_GAP_ROLES */

//// Name to use for advertising and connection.
static char const m_target_periph_name[] = DEVICE_NAME;
void test_begin(void);
// Test parameters.
// Settings like ATT MTU size are set only once, on the dummy board.
// Make sure that defaults are sensible.
static test_params_t m_test_params =
{
.att_mtu = NRF_SDH_BLE_GATT_MAX_MTU_SIZE,
.data_len = NRF_SDH_BLE_GAP_DATA_LENGTH,
.conn_interval = CONN_INTERVAL_DEFAULT,
.conn_evt_len_ext_enabled = true,
// Only symmetric PHYs are supported.
#if defined(S140)
.phys.tx_phys = BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_CODED,
.phys.rx_phys = BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_CODED,
#else
.phys.tx_phys = BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_1MBPS,
.phys.rx_phys = BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_1MBPS,
#endif
};


// Connection parameters requested for connection.
static ble_gap_conn_params_t m_conn_param =
{
.min_conn_interval = CONN_INTERVAL_MIN, // Minimum connection interval.
.max_conn_interval = CONN_INTERVAL_MAX, // Maximum connection interval.
.slave_latency = SLAVE_LATENCY, // Slave latency.
.conn_sup_timeout = CONN_SUP_TIMEOUT // Supervisory timeout.
};


static void test_terminate(void);
void data_len_set(uint8_t value);


static bool is_test_ready()
{
return ( m_conn_interval_configured
&& m_notif_enabled
&& m_mtu_exchanged
&& (m_data_length_updated || m_test_params.data_len == DATA_LENGTH_DEFAULT)
&& m_phy_updated
&& !m_run_test);
}


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;
float adc_value,adc_value_filered;
uint8_t value[2];
uint8_t bytes_to_send;

// set buffers
err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, 1);
APP_ERROR_CHECK(err_code);

// print samples on hardware UART and parse data for BLE transmission
// printf("ADC event number: %d\r\n",(int)m_adc_evt_counter);
bsp_board_led_invert(PROGRESS_LED);

// printf("%d\r\n", p_event->data.done.p_buffer[0]);
adc_value = (float)p_event->data.done.p_buffer[0];
IRBiquadForm1PS(&adc_value, &adc_value_filered);
adc_buffer[m_adc_evt_counter] = (int16_t)adc_value_filered;

// value[0] = adc_value;
// value[1] = adc_value >> 8;


// Send data over BLE via NUS service. Makes sure not to send more than 20 bytes.
if((1*2) <= 20)
{
bytes_to_send = (1*2);
}
else
{
bytes_to_send = 20;
}
// err_code = ble_nus_string_send(&m_nus, value, bytes_to_send);
// if (err_code != NRF_ERROR_INVALID_STATE)
// {
// APP_ERROR_CHECK(err_code);
// }
if((m_adc_evt_counter < 2000) && (wait_filter_time_const > 1000 ))
m_adc_evt_counter++;

else
wait_filter_time_const++;
}
}

void timer_handler(nrf_timer_event_t event_type, void* p_context)
{

}

void saadc_sampling_event_init(void)
{
ret_code_t err_code;
err_code = nrf_drv_ppi_init();
APP_ERROR_CHECK(err_code);

nrf_drv_timer_config_t timer_config = NRF_DRV_TIMER_DEFAULT_CONFIG;
timer_config.frequency = NRF_TIMER_FREQ_31250Hz;
err_code = nrf_drv_timer_init(&m_timer, &timer_config, timer_handler);
APP_ERROR_CHECK(err_code);

/* setup m_timer for compare event */
uint32_t ticks = nrf_drv_timer_us_to_ticks(&m_timer,SAADC_SAMPLE_RATE);
// printf("get tick %ld \n", ticks );
nrf_drv_timer_extended_compare(&m_timer, NRF_TIMER_CC_CHANNEL0, ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);
nrf_drv_timer_enable(&m_timer);

uint32_t timer_compare_event_addr = nrf_drv_timer_compare_event_address_get(&m_timer, NRF_TIMER_CC_CHANNEL0);
uint32_t saadc_sample_event_addr = nrf_drv_saadc_sample_task_get();

/* 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);

err_code = nrf_drv_ppi_channel_assign(m_ppi_channel, timer_compare_event_addr, saadc_sample_event_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_init(void)
{
ret_code_t err_code;
nrf_drv_saadc_config_t saadc_config = NRF_DRV_SAADC_DEFAULT_CONFIG;
saadc_config.resolution = NRF_SAADC_RESOLUTION_12BIT;

err_code = nrf_drv_saadc_init(&saadc_config, saadc_callback);
APP_ERROR_CHECK(err_code);

//Configure SAADC channel
nrf_saadc_channel_config_t config =
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN0); //Disable pulldown resistor on the input pin
err_code = nrf_drv_saadc_channel_init(0, &config);
APP_ERROR_CHECK(err_code);

err_code = nrf_drv_saadc_buffer_convert(&m_buffer_pool[0],1);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_saadc_buffer_convert(&m_buffer_pool[1],1);
APP_ERROR_CHECK(err_code);
}


char const * phy_str(ble_gap_phys_t phys)
{
static char const * str[] =
{
"1 Mbps",
"2 Mbps",
"Coded",
"Unknown"
};

switch (phys.tx_phys)
{
case BLE_GAP_PHY_1MBPS:
return str[0];

case BLE_GAP_PHY_2MBPS:
case BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_1MBPS:
case BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_CODED:
return str[1];

case BLE_GAP_PHY_CODED:
return str[2];

default:
return str[3];
}
}


//static void instructions_print(void)
//{
// printf("Type 'config' to change the configuration parameters.");
// printf("You can use the Tab key to autocomplete your input.");
// printf("Type 'run' when you are ready to run the test.");
//}


/**@brief Function for handling BLE_GAP_EVT_CONNECTED events.
* Save the connection handle and GAP role, then discover the peer DB.
*/
static void on_ble_gap_evt_connected(ble_gap_evt_t const * p_gap_evt)
{
ret_code_t err_code;

m_conn_handle = p_gap_evt->conn_handle;
m_gap_role = p_gap_evt->params.connected.role;

if (m_gap_role == BLE_GAP_ROLE_PERIPH)
{
printf("Connected as a peripheral.\n");
}
else if (m_gap_role == BLE_GAP_ROLE_CENTRAL)
{
printf("Connected as a central.\n");
}

// Stop scanning and advertising.
nrf_ble_scan_stop();
(void) sd_ble_gap_adv_stop(m_adv_handle);

bsp_board_leds_off();

// Assign connection handle to the Queued Write module.
err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_conn_handle);
APP_ERROR_CHECK(err_code);

printf("Discovering GATT database...\n");
err_code = ble_db_discovery_start(&m_ble_db_discovery, p_gap_evt->conn_handle);
APP_ERROR_CHECK(err_code);

if (m_gap_role == BLE_GAP_ROLE_PERIPH)
{
printf("Sending PHY Update, %s \n.", phy_str(m_test_params.phys));

err_code = sd_ble_gap_phy_update(p_gap_evt->conn_handle, &m_test_params.phys);
APP_ERROR_CHECK(err_code);
}
}


/**@brief Function for handling BLE_GAP_EVT_DISCONNECTED events.
* Unset the connection handle and terminate the test.
*/
static void on_ble_gap_evt_disconnected(ble_gap_evt_t const * p_gap_evt)
{
m_conn_handle = BLE_CONN_HANDLE_INVALID;

printf("Disconnected: reason 0x%x. \n", p_gap_evt->params.disconnected.reason);
// bsp_board_leds_off();

if (m_run_test)
{
NRF_LOG_WARNING("GAP disconnection event received while test was running.")
}

test_terminate();
}


/**@brief Function for handling BLE Stack events.
*
* @param[in] p_ble_evt Bluetooth stack event.
*/
static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
{
uint32_t err_code;
ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt;

switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
on_ble_gap_evt_connected(p_gap_evt);
break;

case BLE_GAP_EVT_DISCONNECTED:
on_ble_gap_evt_disconnected(p_gap_evt);
break;

case BLE_GAP_EVT_CONN_PARAM_UPDATE:
{
m_conn_interval_configured = true;
printf("Connection interval updated: 0x%x, 0x%x. \n",
p_gap_evt->params.conn_param_update.conn_params.min_conn_interval,
p_gap_evt->params.conn_param_update.conn_params.max_conn_interval);
} break;

case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST:
{
// Accept parameters requested by the peer.
ble_gap_conn_params_t params;
params = p_gap_evt->params.conn_param_update_request.conn_params;
err_code = sd_ble_gap_conn_param_update(p_gap_evt->conn_handle, &params);
APP_ERROR_CHECK(err_code);

printf("Connection interval updated (upon request): 0x%x, 0x%x.\n",
p_gap_evt->params.conn_param_update_request.conn_params.min_conn_interval,
p_gap_evt->params.conn_param_update_request.conn_params.max_conn_interval);
} break;

case BLE_GATTS_EVT_SYS_ATTR_MISSING:
{
err_code = sd_ble_gatts_sys_attr_set(p_gap_evt->conn_handle, NULL, 0, 0);
APP_ERROR_CHECK(err_code);
} break;

case BLE_GATTC_EVT_TIMEOUT: // Fall through.
case BLE_GATTS_EVT_TIMEOUT:
{
NRF_LOG_DEBUG("GATT timeout, disconnecting.");
err_code = sd_ble_gap_disconnect(m_conn_handle,
BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
APP_ERROR_CHECK(err_code);
} break;

case BLE_GAP_EVT_PHY_UPDATE:
{
ble_gap_evt_phy_update_t const * p_phy_evt = &p_ble_evt->evt.gap_evt.params.phy_update;

if (p_phy_evt->status == BLE_HCI_STATUS_CODE_LMP_ERROR_TRANSACTION_COLLISION)
{
// Ignore LL collisions.
NRF_LOG_DEBUG("LL transaction collision during PHY update.");
break;
}

m_phy_updated = true;

ble_gap_phys_t phys = {0};
phys.tx_phys = p_phy_evt->tx_phy;
phys.rx_phys = p_phy_evt->rx_phy;
printf("PHY update %s. PHY set to %s. \n",
(p_phy_evt->status == BLE_HCI_STATUS_CODE_SUCCESS) ?
"accepted" : "rejected",
phy_str(phys));
} break;

case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
{
err_code = sd_ble_gap_phy_update(p_gap_evt->conn_handle, &m_test_params.phys);
APP_ERROR_CHECK(err_code);
} break;

default:
// No implementation needed.
break;
}
}


/**@brief AMT server event handler. */
static void amts_evt_handler(nrf_ble_amts_evt_t evt)
{
ret_code_t err_code;

switch (evt.evt_type)
{
case NRF_BLE_AMTS_EVT_NOTIF_ENABLED:
{
printf("Notifications enabled. \n");

// bsp_board_led_on(READY_LED);
m_notif_enabled = true;

if (m_test_params.conn_interval != CONN_INTERVAL_DEFAULT)
{
NRF_LOG_DEBUG("Updating connection parameters..");
m_conn_param.min_conn_interval = m_test_params.conn_interval;
m_conn_param.max_conn_interval = m_test_params.conn_interval;
err_code = sd_ble_gap_conn_param_update(m_conn_handle, &m_conn_param);

if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("sd_ble_gap_conn_param_update() failed: 0x%x.", err_code);
}
}
else
{
m_conn_interval_configured = true;
}
} break;

case NRF_BLE_AMTS_EVT_NOTIF_DISABLED:
{
printf("Notifications disabled.\n");
// bsp_board_led_off(READY_LED);
} break;

case NRF_BLE_AMTS_EVT_TRANSFER_1KB:
{
printf("Sent %u KBytes \n", (evt.bytes_transfered_cnt / 1024));
// bsp_board_led_invert(PROGRESS_LED);
} break;

case NRF_BLE_AMTS_EVT_TRANSFER_FINISHED:
{
counter_stop();

// bsp_board_led_off(PROGRESS_LED);
// bsp_board_led_on(DONE_LED);

uint32_t time_ms = counter_get();
uint32_t bit_count = (evt.bytes_transfered_cnt * 8);
float throughput_kbps = ((bit_count / (time_ms / 1000.f)) / 1000.f);

printf("Done.\n");
printf("=============================\n");
printf("Time: %u.%.2u seconds elapsed.\n", (time_ms / 1000), (time_ms % 1000));
printf("Throughput: " NRF_LOG_FLOAT_MARKER " Kbps.\n",
NRF_LOG_FLOAT(throughput_kbps));
printf("=============================");
printf("Sent %u bytes of ATT payload.\n", evt.bytes_transfered_cnt);
printf("Retrieving amount of bytes received from peer...\n");

err_code = nrf_ble_amtc_rcb_read(&m_amtc);
// if (err_code != NRF_SUCCESS)
// {
// NRF_LOG_ERROR("nrf_ble_amtc_rcb_read() failed: 0x%x.", err_code);
test_terminate();
// }
} break;
}
}

static void adc_handler(void * p_context)
{

// bsp_board_led_invert(PROGRESS_LED);
}

/**@brief AMT Client event handler. */
static void amtc_evt_handler(nrf_ble_amtc_t * p_amt_c, nrf_ble_amtc_evt_t * p_evt)
{
char i;
ret_code_t err_code;

switch (p_evt->evt_type)
{
case NRF_BLE_AMT_C_EVT_DISCOVERY_COMPLETE:
{
printf("AMT service discovered at peer.\n");

err_code = nrf_ble_amtc_handles_assign(p_amt_c,
p_evt->conn_handle,
&p_evt->params.peer_db);
APP_ERROR_CHECK(err_code);

// Enable notifications.
err_code = nrf_ble_amtc_notif_enable(p_amt_c);
APP_ERROR_CHECK(err_code);
} break;

case NRF_BLE_AMT_C_EVT_NOTIFICATION:
{
static uint32_t bytes_cnt = 0;
static uint32_t kbytes_cnt = 0;

if (p_evt->params.hvx.bytes_sent == 0)
{
bytes_cnt = 0;
kbytes_cnt = 0;
}
bytes_cnt += p_evt->params.hvx.notif_len;

if (bytes_cnt > 1024)
{
// bsp_board_led_invert(PROGRESS_LED);

bytes_cnt -= 1024;
kbytes_cnt++;

printf("Received %u kbytes\n", kbytes_cnt);

nrf_ble_amts_rbc_set(&m_amts, p_evt->params.hvx.bytes_rcvd);
}

if (p_evt->params.hvx.bytes_rcvd >= AMT_BYTE_TRANSFER_CNT)
{
// bsp_board_led_off(PROGRESS_LED);

bytes_cnt = 0;
kbytes_cnt = 0;

printf("Transfer complete, received %u bytes of ATT payload.\n",
p_evt->params.hvx.bytes_rcvd);


// for(i=0; i<244; i++)
// printf("[%d]-%x",i, Mybuffer[i]);

nrf_ble_amts_rbc_set(&m_amts, p_evt->params.hvx.bytes_rcvd);
}
} break;

case NRF_BLE_AMT_C_EVT_RBC_READ_RSP:
{
printf("Peer received %u bytes of ATT payload.\n", (p_evt->params.rcv_bytes_cnt));
test_terminate();
} break;

default:
break;
}
}


/**@brief Function for handling database discovery events.
*
* @details This function is a callback function to handle events from the database discovery module.
* Depending on the UUIDs that are discovered, this function forwards the events
* to their respective service instances.
*
* @param[in] p_evt Pointer to the database discovery event.
*/
static void db_disc_evt_handler(ble_db_discovery_evt_t * p_evt)
{
nrf_ble_amtc_on_db_disc_evt(&m_amtc, p_evt);
}


/**@brief Function for handling events from the GATT library. */
static void gatt_evt_handler(nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_t const * p_evt)
{
switch (p_evt->evt_id)
{
case NRF_BLE_GATT_EVT_ATT_MTU_UPDATED:
{
m_mtu_exchanged = true;
printf("ATT MTU exchange completed. MTU set to %u bytes.\n",
p_evt->params.att_mtu_effective);
} break;

case NRF_BLE_GATT_EVT_DATA_LENGTH_UPDATED:
{
m_data_length_updated = true;
printf("Data length updated to %u bytes.\n", p_evt->params.data_length);
} break;
}

nrf_ble_amts_on_gatt_evt(&m_amts, p_evt);
}


/**@brief Function for setting up advertising data. */
static void advertising_data_set(void)
{
ret_code_t ret;

ble_gap_adv_params_t const adv_params =
{
.properties =
{
.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED,
},
.p_peer_addr = NULL,
.filter_policy = BLE_GAP_ADV_FP_ANY,
.interval = ADV_INTERVAL,
.duration = 0,

.primary_phy = BLE_GAP_PHY_1MBPS, // Must be changed to connect in long range. (BLE_GAP_PHY_CODED)
.secondary_phy = BLE_GAP_PHY_1MBPS,
};

ble_advdata_t const adv_data =
{
.name_type = BLE_ADVDATA_FULL_NAME,
.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE,
.include_appearance = false,
};

ret = ble_advdata_encode(&adv_data, m_adv_data.adv_data.p_data, &m_adv_data.adv_data.len);
APP_ERROR_CHECK(ret);

ret = sd_ble_gap_adv_set_configure(&m_adv_handle, &m_adv_data, &adv_params);
APP_ERROR_CHECK(ret);
}


/**@brief Function for starting advertising. */
static void advertising_start(void)
{
printf("Starting advertising.\n");

// bsp_board_led_on(SCAN_ADV_LED);
ret_code_t err_code = sd_ble_gap_adv_start(m_adv_handle, APP_BLE_CONN_CFG_TAG);
APP_ERROR_CHECK(err_code);
}


/**@brief Function for handling Scanning Module events.
*/
static void scan_evt_handler(scan_evt_t const * p_scan_evt)
{
ret_code_t err_code;
ble_gap_evt_adv_report_t const * p_adv =
p_scan_evt->params.filter_match.p_adv_report;
ble_gap_scan_params_t const * p_scan_param =
p_scan_evt->p_scan_params;

switch(p_scan_evt->scan_evt_id)
{
case NRF_BLE_SCAN_EVT_FILTER_MATCH:
{
printf("Device \"%s\" found, sending a connection request.\n",
(uint32_t) m_target_periph_name);

// Stop advertising.
err_code = sd_ble_gap_adv_stop(m_adv_handle);
if (err_code != NRF_ERROR_INVALID_STATE)
{
APP_ERROR_CHECK(err_code);
}

// Initiate connection.
m_conn_param.min_conn_interval = CONN_INTERVAL_DEFAULT;
m_conn_param.max_conn_interval = CONN_INTERVAL_DEFAULT;

err_code = sd_ble_gap_connect(&p_adv->peer_addr,
p_scan_param,
&m_conn_param,
APP_BLE_CONN_CFG_TAG);

if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("sd_ble_gap_connect() failed: 0x%x.", err_code);
}
} break;

default:
break;
}
}


/**@brief Function for initialization the scanning and setting the filters.
*/
static void scan_init(void)
{
ret_code_t err_code;

err_code = nrf_ble_scan_init(&m_scan, NULL, scan_evt_handler);
APP_ERROR_CHECK(err_code);

err_code = nrf_ble_scan_filter_set(&m_scan,
SCAN_NAME_FILTER,
m_target_periph_name);
APP_ERROR_CHECK(err_code);

err_code = nrf_ble_scan_filters_enable(&m_scan,
NRF_BLE_SCAN_NAME_FILTER,
false);
APP_ERROR_CHECK(err_code);
}


/**@brief Function for starting the scanning. */
static void scan_start(void)
{
printf("Starting scanning.\n");

// bsp_board_led_on(SCAN_ADV_LED);

ret_code_t err_code = nrf_ble_scan_start(&m_scan);
APP_ERROR_CHECK(err_code);
}

/**@brief Function for initializing the LEDs.
*
* @details Initializes all LEDs used by the application.
*/
static void leds_init(void)
{
bsp_board_init(BSP_INIT_LEDS);
}

/**@brief Function for enabling button input.
*/
static void buttons_enable(void)
{
ret_code_t err_code = app_button_enable();
APP_ERROR_CHECK(err_code);
}


/**@brief Function for disabling button input. */
static void buttons_disable(void)
{
ret_code_t err_code = app_button_disable();
APP_ERROR_CHECK(err_code);
}

/**@brief Function for handling events from the button handler module.
*
* @param[in] pin_no The pin that the event applies to.
* @param[in] button_action The button action (press or release).
*/
static void button_evt_handler(uint8_t pin_no, uint8_t button_action)
{
switch (pin_no)
{
case START_BUTTON:
{
printf("Button start Pressed !");
if(!m_run_test)
test_begin();

} break;
default:
break;
}
buttons_disable();
}


/**@brief Function for initializing the button library.
*/
static void buttons_init(void)
{
// The array must be static because a pointer to it will be saved in the button library.
static app_button_cfg_t buttons[] =
{
{START_BUTTON, false, BUTTON_PULL, button_evt_handler}
};

ret_code_t err_code = app_button_init(buttons, ARRAY_SIZE(buttons), BUTTON_DETECTION_DELAY);
APP_ERROR_CHECK(err_code);
}


static void client_init(void)
{
ret_code_t err_code = ble_db_discovery_init(db_disc_evt_handler);
APP_ERROR_CHECK(err_code);

err_code = nrf_ble_amtc_init(&m_amtc, amtc_evt_handler);
APP_ERROR_CHECK(err_code);
}


/**@brief Function for handling Queued Write module errors.
*
* @details A pointer to this function is passed to each service that may need to inform the
* application about an error.
*
* @param[in] nrf_error Error code that contains information about what went wrong.
*/
static void nrf_qwr_error_handler(uint32_t nrf_error)
{
APP_ERROR_HANDLER(nrf_error);
}


/**@brief Function for initializing the Queued Write module.
*/
static void qwr_init(void)
{
ret_code_t err_code;
nrf_ble_qwr_init_t qwr_init_obj = {0};

// Initialize Queued Write Module.
qwr_init_obj.error_handler = nrf_qwr_error_handler;

err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init_obj);
APP_ERROR_CHECK(err_code);
}


static void server_init(void)
{
qwr_init();
nrf_ble_amts_init(&m_amts, amts_evt_handler);
}


/**@brief Function for initializing the BLE stack.
*
* @details Initializes the SoftDevice and the BLE event interrupt.
*/
static void ble_stack_init(void)
{
ret_code_t err_code;

err_code = nrf_sdh_enable_request();
APP_ERROR_CHECK(err_code);

// Configure the BLE stack using the default settings.
// Fetch the start address of the application RAM.
uint32_t ram_start = 0;
err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
APP_ERROR_CHECK(err_code);

// Enable BLE stack.
err_code = nrf_sdh_ble_enable(&ram_start);
APP_ERROR_CHECK(err_code);

// Register a handler for BLE events.
NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
}


/**@brief Function for initializing GAP parameters.
*
* @details This function sets up all the necessary GAP (Generic Access Profile) parameters of the
* device, including the device name and the preferred connection parameters.
*/
static void gap_params_init(void)
{
ret_code_t err_code;
ble_gap_conn_sec_mode_t sec_mode;

BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);

err_code = sd_ble_gap_device_name_set(&sec_mode,
(uint8_t const *)DEVICE_NAME,
strlen(DEVICE_NAME));
APP_ERROR_CHECK(err_code);

err_code = sd_ble_gap_ppcp_set(&m_conn_param);
APP_ERROR_CHECK(err_code);
}


/**@brief Function for initializing the GATT library. */
static void gatt_init(void)
{
ret_code_t err_code = nrf_ble_gatt_init(&m_gatt, gatt_evt_handler);
APP_ERROR_CHECK(err_code);
}

//void preferred_phy_set(ble_gap_phys_t * p_phy)
//{
// memcpy(&m_test_params.phys, p_phy, sizeof(ble_gap_phys_t));
//}


void gatt_mtu_set(uint16_t att_mtu)
{
ret_code_t err_code;

m_test_params.att_mtu = att_mtu;

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

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


//void connection_interval_set(uint16_t value)
//{
// m_test_params.conn_interval = value;
//}


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);

m_test_params.conn_evt_len_ext_enabled = status;
}


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);

m_test_params.data_len = value;
}

void test_begin(void)
{
printf("Preparing the test.\n");
NRF_LOG_FLUSH();

#if defined(S132)
// PHY does not need to be updated for s132.
m_phy_updated = true;
#endif

switch (m_gap_role)
{
default:
// If no connection was established, the role is not established either.
// In this case, start both the advertising and the scanning.
advertising_start();
scan_start();
break;

case BLE_GAP_ROLE_PERIPH:
advertising_start();
m_test_params.phys.tx_phys = BLE_GAP_PHY_2MBPS;
break;

case BLE_GAP_ROLE_CENTRAL:
scan_start();
break;
}


}


static void test_run(void)
{
counter_start();
nrf_ble_amts_notif_spam(&m_amts);
}


//void cli_process(void)
//{
// nrf_cli_process(&m_cli_uart);
//}


/**@brief Function for handling the idle state (main loop).
*
* @details Handles any pending operations, then sleeps until the next event occurs.
*/
static void idle_state_handle(void)
{
// cli_process();
int ret;

if (is_test_ready())
{
printf("Test started\n");
m_run_test = true;
test_run();
}

if (NRF_LOG_PROCESS() == false)
{
nrf_pwr_mgmt_run();
}
}


static void test_terminate(void)
{
m_run_test = false;
m_notif_enabled = false;
m_mtu_exchanged = false;
m_data_length_updated = false;
m_phy_updated = false;
m_conn_interval_configured = false;

if (m_conn_handle != BLE_CONN_HANDLE_INVALID)
{
printf("Disconnecting... \n");

ret_code_t err_code;
err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);

if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("sd_ble_gap_disconnect() failed: 0x%0x.", err_code);
}

buttons_enable();
}
// else
// {
// if (m_board_role == BOARD_DUMMY)
// {
// if (m_gap_role == BLE_GAP_ROLE_PERIPH)
// {
// advertising_start();
// }
// else
// {
// scan_start();
// }
// }
// }
}


//void cli_init(void)
//{
// if (CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk)
// {
// ret_code_t err_code = nrf_cli_init(&m_cli_rtt, NULL, true, true, NRF_LOG_SEVERITY_INFO);
// APP_ERROR_CHECK(err_code);
// }

// nrf_drv_uart_config_t uart_config = NRF_DRV_UART_DEFAULT_CONFIG;
// uart_config.pseltxd = TX_PIN_NUMBER;
// uart_config.pselrxd = RX_PIN_NUMBER;
// uart_config.hwfc = NRF_UART_HWFC_DISABLED;

// ret_code_t err_code = nrf_cli_init(&m_cli_uart, &uart_config, true, true, NRF_LOG_SEVERITY_INFO);
// APP_ERROR_CHECK(err_code);
//}


//void cli_start(void)
//{
// ret_code_t err_code = nrf_cli_start(&m_cli_uart);
// APP_ERROR_CHECK(err_code);
//}


/**@brief Function for initializing the timer.
*
* @details Initializes the timer module. This creates and starts application timers.
*/
static void timer_init(void)
{
ret_code_t err_code = app_timer_init();
APP_ERROR_CHECK(err_code);
}


/**@brief Function for initializing power management.
*/
static void power_management_init(void)
{
ret_code_t ret;
ret = nrf_pwr_mgmt_init();
APP_ERROR_CHECK(ret);
}

/**@brief Function for handling app_uart events.
*
* @details This function will receive a single character from the app_uart module and append it to
* a string. The string will be be sent over BLE when the last character received was a
* 'new line' '\n' (hex 0x0A) or if the string has reached the maximum data length.
*/
/**@snippet [Handling the data received over UART] */
void uart_event_handle(app_uart_evt_t * p_event)
{
static uint8_t data_array[100];
static uint8_t index = 0;
// uint32_t err_code;

switch (p_event->evt_type)
{
case APP_UART_DATA_READY:
UNUSED_VARIABLE(app_uart_get(&data_array[index]));
index++;

if ((data_array[index - 1] == '\n') || (data_array[index - 1] == '\r'))
{
if (index > 1)
{
// NRF_LOG_DEBUG("Ready to send data over BLE NUS");
printf("Ready to send data over BLE NUS \n");
if( strstr(data_array, "RUN") != NULL)
{
printf("Get DATA %s \n",data_array);
test_begin();
}
// NRF_LOG_HEXDUMP_DEBUG(data_array, index);

// do
// {
// uint16_t length = (uint16_t)index;
// err_code = ble_nus_data_send(&m_nus, data_array, &length, m_conn_handle);
// if ((err_code != NRF_ERROR_INVALID_STATE) &&
// (err_code != NRF_ERROR_RESOURCES) &&
// (err_code != NRF_ERROR_NOT_FOUND))
// {
// APP_ERROR_CHECK(err_code);
// }
// } while (err_code == NRF_ERROR_RESOURCES);
}

index = 0;
}
break;

case APP_UART_COMMUNICATION_ERROR:
APP_ERROR_HANDLER(p_event->data.error_communication);
break;

case APP_UART_FIFO_ERROR:
APP_ERROR_HANDLER(p_event->data.error_code);
break;

default:
break;
}
}

/**@snippet [Handling the data received over UART] */


/**@brief Function for initializing the UART module.
*/
/**@snippet [UART Initialization] */
static void uart_init(void)
{
uint32_t err_code;
app_uart_comm_params_t const comm_params =
{
.rx_pin_no = RX_PIN_NUMBER,
.tx_pin_no = TX_PIN_NUMBER,
.rts_pin_no = RTS_PIN_NUMBER,
.cts_pin_no = CTS_PIN_NUMBER,
.flow_control = APP_UART_FLOW_CONTROL_DISABLED,
.use_parity = false,
#if defined (UART_PRESENT)
.baud_rate = NRF_UART_BAUDRATE_115200
#else
.baud_rate = NRF_UARTE_BAUDRATE_115200
#endif
};

APP_UART_FIFO_INIT(&comm_params,
UART_RX_BUF_SIZE,
UART_TX_BUF_SIZE,
uart_event_handle,
APP_IRQ_PRIORITY_LOWEST,
err_code);
APP_ERROR_CHECK(err_code);
}
/**@snippet [UART Initialization] */


static void log_init(void)
{
ret_code_t err_code = NRF_LOG_INIT(app_timer_cnt_get);
APP_ERROR_CHECK(err_code);
}

int main(void)
{
// Initialize.
int count_buffet;
uart_init();
log_init();
// cli_init();
leds_init();
timer_init();
counter_init();
buttons_init();
power_management_init();
ble_stack_init(); // nitializes the SoftDevice and the BLE event interrupt
gap_params_init(); //sets up all the necessary GAP (Name , Min & Max connection latency )
gatt_init(); // Sets up Gap parameters (MTU size : 247, Gap Data length : 251 ..... )
advertising_data_set();
scan_init();
server_init();
client_init();

gatt_mtu_set(m_test_params.att_mtu);
conn_evt_len_ext_set(m_test_params.conn_evt_len_ext_enabled);


// Start execution.
// cli_start();
buttons_enable();
iir_loadcoeff_250_2k5_16ksps();
data_len_set(DATA_LENGTH_DEFAULT);

saadc_sampling_event_init();
saadc_init();
//saadc_sampling_event_enable();
printf("\r\nUART started.\r\n");

for (;;)
{
nrf_delay_ms(1000);
// if((m_adc_evt_counter >= 2000) && flagsend )
// {
// flagsend = 0;
// for(count_buffet=0; count_buffet<2000; count_buffet++)
// {
// nrf_delay_ms(10);
// printf("%d \r\n",adc_buffer[count_buffet]);
// }
//
// }

idle_state_handle();
printf("get status ready = %d, %d, %d, %d, %d, %d \r\n",
m_conn_interval_configured,
m_notif_enabled,
m_mtu_exchanged,
m_data_length_updated || m_test_params.data_len == DATA_LENGTH_DEFAULT,
m_phy_updated,
m_run_test);
}
}


/**
* @}
*/

Parents
  • when the event to activate the timer for sampling SAADC is enabled (saadc_sampling_event_enable() ) , AMT server event handler is no longer executes.

    You must disable the timer event for sampling SAADC, so  the AMT server event  works properly.

    Best regards, 

  • I have not found a root cause, but I did find something that will be an issue.

    You're using SAADC buffer sizes of 1, ie. one sample taken and processed every 80µs, and that's not possible with a BLE stack running. You need to use larger buffer sizes for your ADC sampling and process them far less often. 
    What will happen now is that the SoftDevice will block the SAADC driver's IRQ from executing whenever there's some BLE activity or stack processing to be done, and your SAADC sampling will halt. 

    I suggest you double buffer your SAADC buffers, like our example does, and choose a size so that you will get a callback every few milliseconds (the longer the better). 

    This issue might be related to your original issue, what IRQ priority have you set the SAADC driver to use?

  • Hello,

    Thanks for your reply.

    I changed the callback time to a few milliseconds and the problem is solved. I just did a test by changing the Callback timer to 10ms and it works.

    If I want to sample my signal at 16ksps, so with a buffer of 200 samples I can set a Callback every 12.5ms. Can you help me configure my timer and the SAADC ?

    Best regards, 

  • If you just set your buffer size to 200 samples, you'll get a callback once those are done. The saadc example uses the define SAMPLES_IN_BUFFER or something similar to set the buffer sizes. 


  • I understood that I could initialize the Buffer size to 200 samples by changing define SAMPLES_IN_BUFFER. What I do not understand is how to configure my sampling frequency at 16kHz to have a Callback every 12.5ms.

    In order to perform the tests, I set the sampling time to 125us (8kHz) with a SAMPLES_IN_BUFFER 200. According to the code below, I hoped that my Callback would be called every 25mS. I can see that my Callback is called every 125uS and I do not understand.

    Please see the source code below : 

    #define SAADC_SAMPLE_RATE		        125                                         /**< SAADC sample rate in us. */      
    #define SAMPLES_IN_BUFFER 200 
    
    
    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;
            float adc_value,adc_value_filered;
            uint8_t value[2];
            uint8_t bytes_to_send;
         
            // set buffers
            err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, 1);
            APP_ERROR_CHECK(err_code);
    						
    			  bsp_board_led_invert(PROGRESS_LED);
     
        }
    }
    
    
    
    void saadc_sampling_event_init(void)
    {
        ret_code_t err_code;
        err_code = nrf_drv_ppi_init();
        APP_ERROR_CHECK(err_code);
        
        nrf_drv_timer_config_t timer_config = NRF_DRV_TIMER_DEFAULT_CONFIG;
      //  timer_config.frequency = NRF_TIMER_FREQ_31250Hz;
    	  timer_config.frequency = NRF_TIMER_FREQ_1MHz;
        err_code = nrf_drv_timer_init(&m_timer, &timer_config, timer_handler);
        APP_ERROR_CHECK(err_code);
    
        /* setup m_timer for compare event */
        uint32_t ticks = nrf_drv_timer_us_to_ticks(&m_timer,SAADC_SAMPLE_RATE);
        nrf_drv_timer_extended_compare(&m_timer, NRF_TIMER_CC_CHANNEL0, ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);
        nrf_drv_timer_enable(&m_timer);
    
        uint32_t timer_compare_event_addr = nrf_drv_timer_compare_event_address_get(&m_timer, NRF_TIMER_CC_CHANNEL0);
        uint32_t saadc_sample_event_addr = nrf_drv_saadc_sample_task_get();
    
        /* 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);
        
        err_code = nrf_drv_ppi_channel_assign(m_ppi_channel, timer_compare_event_addr, saadc_sample_event_addr);
        APP_ERROR_CHECK(err_code);
    }
    
    
    void saadc_init(void)
    {
        ret_code_t err_code;
        nrf_drv_saadc_config_t saadc_config = NRF_DRV_SAADC_DEFAULT_CONFIG;
        saadc_config.resolution = NRF_SAADC_RESOLUTION_12BIT;
    	
    
        err_code = nrf_drv_saadc_init(&saadc_config, saadc_callback);
        APP_ERROR_CHECK(err_code);
    
    	    //Configure SAADC channel
        nrf_saadc_channel_config_t config =
            NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN0);                           //Disable pulldown resistor on the input pin
        err_code = nrf_drv_saadc_channel_init(0, &config);
        APP_ERROR_CHECK(err_code);
    
    	
        err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0],SAMPLES_IN_BUFFER);
        APP_ERROR_CHECK(err_code);   
        err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1],SAMPLES_IN_BUFFER);
        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);
    }
    

  • In your callback:

    // set buffers
    err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, 1);
    APP_ERROR_CHECK(err_code);

    Set the length to SAMPLES_IN_BUFFER and you should be good.

  • Dear Sir,

    I thank you for this remark. I can indeed see that  SAADC Callback is called after 100 samples since SAMPLE_IN_BUFFER  is set to 100.

    To make sure that I get into the callback, I toggle a pin out of the chip to ensure that the duration of taking measurements is constant and therefore my samples are synchronized.

    If I activate a Bluetooth transmission in parallel, during the transfer, I can notice a timing error in the SAADC Callback . There is therefore an error in the discretization of my signal.
    How can I set a priority on my ADC timer or correct the timing problem when the handles on Bluetooth events are called ?

Reply
  • Dear Sir,

    I thank you for this remark. I can indeed see that  SAADC Callback is called after 100 samples since SAMPLE_IN_BUFFER  is set to 100.

    To make sure that I get into the callback, I toggle a pin out of the chip to ensure that the duration of taking measurements is constant and therefore my samples are synchronized.

    If I activate a Bluetooth transmission in parallel, during the transfer, I can notice a timing error in the SAADC Callback . There is therefore an error in the discretization of my signal.
    How can I set a priority on my ADC timer or correct the timing problem when the handles on Bluetooth events are called ?

Children
Related