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

Combining BLE and SAADC

Hi everyone,

I have written a code that sends data over BLE notifications (IMU data). It works great so far and now I want to read the analog values from eight force sensors and send them also as well.

Using the SAADC,PPI AND TIMER drivers I wrote a code that works great. I am using an eight-channel multiplexer in order to read the 8 analog sensors

Due to the fact that I am trying to design a low power application I want to use the app_timer (RTC) rather than the TIMER driver. I am trying to combine my BLE and SAADC codes but I fail.

In the BLE code, I have created an app_timer that starts as soon as notification is enabled. When the timer expires the notification_timeout_handler function is called

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static void timers_init(void) {
// Initialize timer module.
ret_code_t err_code = app_timer_init();
APP_ERROR_CHECK(err_code);
// Create timers.
err_code = app_timer_create(&m_notification_timer_id, APP_TIMER_MODE_REPEATED, notification_timeout_handler);
APP_ERROR_CHECK(err_code);
}
// This is the handler function
static void on_cus_evt(ble_cus_t *p_cus_service,
ble_cus_evt_t *p_evt) {
ret_code_t err_code;
switch (p_evt->evt_type) {
case BLE_CUS_EVT_NOTIFICATION_ENABLED:
err_code = app_timer_start(m_notification_timer_id, NOTIFICATION_INTERVAL, NULL);
APP_ERROR_CHECK(err_code);
break;
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Inside the notification_timeout_handler function, I read the data from the IMU and I update the payload that will be sent through BLE notification.

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static void notification_timeout_handler(void *p_context) {
UNUSED_PARAMETER(p_context);
ret_code_t err_code;
m_xfer_done = false;
bmi160_get_sensor_data((BMI160_ACCEL_SEL | BMI160_GYRO_SEL | BMI160_TIME_SEL), &accel, &gyro, &sensor);
bmi160_read_aux_data_auto_mode(mag_data, &sensor);
bmm150_aux_mag_data(mag_data, &bmm150);
NRF_LOG_INFO("AccelX:%d , AccelY:%d , AccelZ:%d", accel.x, accel.y, accel.z);
NRF_LOG_INFO("GyroX:%d , GyroY:%d , GyroZ:%d", gyro.x, gyro.y, gyro.z);
NRF_LOG_INFO("MagX:%d , MagY:%d , MagZ:%d", bmm150.data.x, bmm150.data.y, bmm150.data.z);
// Passing an array of data through notification to the central
int16_t m_array[] = {accel.x, accel.y, accel.z,
gyro.x, gyro.y, gyro.z,
bmm150.data.x, bmm150.data.y, bmm150.data.z}; // you can set either decimal or hex values until 20bytes!!
err_code = ble_cus_custom_value_update(&m_cus, m_array);
APP_ERROR_CHECK(err_code);
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Until this point, everything works fine.

Now inside the notification_timeout_handler() function I want to read also the analog sensors...

I tried to call the nrf_drv_saadc_sample() inside a for loop in order to read the 8 sensors but it fails :

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
static void notification_timeout_handler(void *p_context) {
UNUSED_PARAMETER(p_context);
ret_code_t err_code;
// na - read flexi forces
for (int i = 0; i < NO_SENSORS; i++) {
nrf_drv_saadc_sample(); // na - trigger sampling
NRF_LOG_INFO("i = %d", i);
}
..........rest of code......
}
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

This is the callback function as well the function to switch the channels of the multiplexer:

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void saadc_callback(nrf_drv_saadc_evt_t const *p_event) {
if (p_event->type == NRF_DRV_SAADC_EVT_DONE) { // na - when the buffer is filled then the NRF_DRV_SAADC_EVT_DONE is generated
ret_code_t err_code;
err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code);
ADC_RawData[callback_counter] = p_event->data.done.p_buffer[0]; // na - Store the ADC values from flexi force
NRF_LOG_INFO("ADC_Sensor%d: %d ", callback_counter + 1, ADC_RawData[callback_counter]);
NRF_LOG_INFO("Callback_counter %d ", callback_counter);
if (callback_counter == NO_SENSORS - 1) {
memset(ADC_RawData, 0, sizeof(ADC_RawData)); // na - Initialize ADC_RawData to 0
callback_counter = 0;
}
else {
callback_counter++;
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

My problem is that the nrf_drv_saadc_sample() function inside the for loop does not work. I was expecting to call nrf_drv_saadc_sample() function eight times, store the data in ADC_RawData[] array, and then send the data over BLE. But when I run the code and while the loop iterates the nrf_drv_saadc_sample() is being called only once...

Any advice of how could I solve this issue?

p.s SAMPLES_IN_BUFFER is 1

Thanks in advance

Nick