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

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;

  case BLE_CUS_EVT_NOTIFICATION_DISABLED:

    err_code = app_timer_stop(m_notification_timer_id);
    APP_ERROR_CHECK(err_code);
    break;
    }

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.

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

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 :

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......
  
  }

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

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++;
    }
    selectMuxPin(callback_counter); // na - change MUX channel to read the next sensor
  }
}

// Function to switch multiplexer's channel
void selectMuxPin(int channel) {
  for (int i = 0; i < MUX_CTRL_CHA; i++) {

    if (channel & (1 << i)) {
      nrf_gpio_pin_set(ctrlPins[i]);
    } else {
      nrf_gpio_pin_clear(ctrlPins[i]);
    }
  }
}

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

Parents Reply Children
Related