Sensor

The sensor API can be used for easier access of the sensores. This tutorials is made for the eval board. Some connections or configuration may differ for your board.

MIS2DH

The MIS2DH is a 3-axis gyroscope. Like always the first step is to initialize the sensor and to release it after its not used anymore. For the initialization, a configuration is needed. The options differs for every sensor type. For this sensor, the poll rate, power consumtion, sensitivity and a fliter can be speified. values_per_block and block_count are needed when we read the data which we got from the sensor.

#include "usoc_user_services.h"
#include "usoc_sensor_API.h"

usoc_sensor_lock_t lock;

int main() {
  usoc_MIS2DH_config_t config;

  config.output_rate = MIS2DH_RATE_10HZ;
  config.power_mode = MIS2DH_MODE_NORMAL;
  config.range = MIS2DH_RANGE_2G;
  config.filter = MIS2DH_FILTER_NONE;
  config.values_per_block = 20;
  config.block_count = 4;

  usoc_printf("init sensor\n");
  usoc_init_sensor(USOC_SENSOR_L2_MIS2DH, &lock, &config, MIS2DH_callback);

  usoc_printf("release sensor\n");
  usoc_release_sensor(USOC_SENSOR_L2_MIS2DH, &lock);

  return 0;
}

As you can see a callback is needed for the initialization of the sensor, which is getting called, when data is available. We will develop this funktion now. The call back has one parameter from type usoc_sensor_intent_t in which contains the data from the sensor. Because memory is allocated for the data we have to free it, so it doesnt get leaked. Which is done with usoc_sensor_free_buff_blk.

#include "usoc_user_services.h"
#include "usoc_sensor_API.h"

usoc_sensor_lock_t lock;

void MIS2DH_callback(usoc_sensor_intent_t intent) {
  usoc_printf("Got data from sensor MIS2DH: \n");

  usoc_sensor_free_buff_blk(USOC_SENSOR_L2_MIS2DH, &lock, intent.intent_data_ptr);
}

int main() {
  usoc_MIS2DH_config_t config;

  config.output_rate = MIS2DH_RATE_10HZ;
  config.power_mode = MIS2DH_MODE_NORMAL;
  config.range = MIS2DH_RANGE_2G;
  config.filter = MIS2DH_FILTER_NONE;
  config.values_per_block = 20;
  config.block_count = 4;

  usoc_printf("init sensor\n");
  usoc_init_sensor(USOC_SENSOR_L2_MIS2DH, &lock, &config, MIS2DH_callback);

  usoc_printf("release sensor\n");
  usoc_release_sensor(USOC_SENSOR_L2_MIS2DH, &lock);

  return 0;
}

If you run this code now, you will notice that the callback is never called. This is because of two reasons. First the sensor needs to be enabled and second usoc_idle() needs to be called, to give the callback time to execute. So now we start the sensor and stop it after usage.

#include "usoc_user_services.h"
#include "usoc_sensor_API.h"

usoc_sensor_lock_t lock;

void MIS2DH_callback(usoc_sensor_intent_t intent) {
  usoc_printf("Got data from sensor MIS2DH: \n");

  usoc_sensor_free_buff_blk(USOC_SENSOR_L2_MIS2DH, &lock, intent.intent_data_ptr);
}

int main() {
  usoc_MIS2DH_config_t config;

  config.output_rate = MIS2DH_RATE_10HZ;
  config.power_mode = MIS2DH_MODE_NORMAL;
  config.range = MIS2DH_RANGE_2G;
  config.filter = MIS2DH_FILTER_NONE;
  config.values_per_block = 20;
  config.block_count = 4;

  usoc_printf("init sensor\n");
  usoc_init_sensor(USOC_SENSOR_L2_MIS2DH, &lock, &config, MIS2DH_callback);

  usoc_printf("start sensor\n");
  usoc_sensor_start(USOC_SENSOR_L2_MIS2DH, &lock);

  usoc_printf("stop sensor\n");
  usoc_sensor_stop(USOC_SENSOR_L2_MIS2DH, &lock);

  usoc_printf("release sensor\n");
  usoc_release_sensor(USOC_SENSOR_L2_MIS2DH, &lock);

  return 0;
}

Now we add usoc_idle() and a global counter, which shows, how many times the callback got executed. If a certain number is reached we stop with the idle loop and end the program.

#include "usoc_user_services.h"
#include "usoc_sensor_API.h"

usoc_sensor_lock_t lock;
uint8_t counter = 0;

void MIS2DH_callback(usoc_sensor_intent_t intent) {
  counter++;
  usoc_printf("Got data from sensor MIS2DH: \n");

  usoc_sensor_free_buff_blk(USOC_SENSOR_L2_MIS2DH, &lock, intent.intent_data_ptr);
}

int main() {
  usoc_MIS2DH_config_t config;

  config.output_rate = MIS2DH_RATE_10HZ;
  config.power_mode = MIS2DH_MODE_NORMAL;
  config.range = MIS2DH_RANGE_2G;
  config.filter = MIS2DH_FILTER_NONE;
  config.values_per_block = 20;
  config.block_count = 4;

  usoc_printf("init sensor\n");
  usoc_init_sensor(USOC_SENSOR_L2_MIS2DH, &lock, &config, MIS2DH_callback);

  usoc_printf("start sensor\n");
  usoc_sensor_start(USOC_SENSOR_L2_MIS2DH, &lock);

  while(counter < 5) {
    usoc_idle();
  }

  usoc_printf("stop sensor\n");
  usoc_sensor_stop(USOC_SENSOR_L2_MIS2DH, &lock);

  usoc_printf("release sensor\n");
  usoc_release_sensor(USOC_SENSOR_L2_MIS2DH, &lock);

  return 0;
}

It is time to finally read the data and to print it out. The variable intent has an property which contains the data pointer. The data itself is of the type usoc_MIS2DH_data_t. The type itself has x, y and z properties which cointain the data of the gyroscope.

#include "usoc_user_services.h"
#include "usoc_sensor_API.h"

usoc_sensor_lock_t lock;
uint8_t counter = 0;

void MIS2DH_callback(usoc_sensor_intent_t intent) {
  counter++;
  usoc_printf("Got data from sensor MIS2DH: \n");

  usoc_MIS2DH_data_t *data = (usoc_MIS2DH_data_t *)intent.intent_data_ptr;

  for(size_t i = 0; i < intent.size; i++) {
      usoc_printf("x: %i, y: %i, z: %i \n", data->x, data->y, data->z);
      data++;
  }

  usoc_sensor_free_buff_blk(USOC_SENSOR_L2_MIS2DH, &lock, intent.intent_data_ptr);
}

int main() {
  usoc_MIS2DH_config_t config;

  config.output_rate = MIS2DH_RATE_10HZ;
  config.power_mode = MIS2DH_MODE_NORMAL;
  config.range = MIS2DH_RANGE_2G;
  config.filter = MIS2DH_FILTER_NONE;
  config.values_per_block = 20;
  config.block_count = 4;

  usoc_printf("init sensor\n");
  usoc_init_sensor(USOC_SENSOR_L2_MIS2DH, &lock, &config, MIS2DH_callback);

  usoc_printf("start sensor\n");
  usoc_sensor_start(USOC_SENSOR_L2_MIS2DH, &lock);

  while(counter < 5) {
    usoc_idle();
  }

  usoc_printf("stop sensor\n");
  usoc_sensor_stop(USOC_SENSOR_L2_MIS2DH, &lock);

  usoc_printf("release sensor\n");
  usoc_release_sensor(USOC_SENSOR_L2_MIS2DH, &lock);

  return 0;
}

BME680

The BME680 is a gas sensor for measuring relative humidity, barometric pressure, ambient temperature and gas. This tutorial contains only a way to read out the raw values. For the corrected values you need the Bosch library, Which is not available for risc-v at the moment the tutorial was written.

We start as always with the initialization of the sensor. For that we need to provide a config and a callback function. The config is of the type usoc_BME680_config_t. It allows settings for oversampling temperature (t), pressure (p) and humidity (h). It also contains a setting for a filter. The callback method only free the memory that got allocated for the callback.

#include "usoc_user_services.h"
#include "usoc_sensor_API.h"
#include "usoc_sensor_BME680_public.h"

usoc_sensor_lock_t lock;

void BME680_callback(usoc_sensor_intent_t intent) {
    usoc_printf("Got data from sensor BME680: \n");

    usoc_sensor_free_buff_blk(USOC_SENSOR_L2_BME680, &lock, intent.intent_data_ptr);
}

int main() {
    usoc_BME680_config_t config;

    config.oversampling_t = BME680_OVERSAMPLING_OFF;
    config.oversampling_p = BME680_OVERSAMPLING_OFF;
    config.oversampling_h = BME680_OVERSAMPLING_OFF;
    config.filter_tp = BME680_FILTER_0;
    config.values_per_block = 20;
    config.block_count = 4;

    usoc_printf("init sensor\n");
    usoc_init_sensor(USOC_SENSOR_L2_BME680, &lock, &config, BME680_callback);

    usoc_printf("release sensor\n");
    usoc_release_sensor(USOC_SENSOR_L2_BME680, &lock);

    return 0;
}

Before data will be read, the sensor has to be started. After work it can be stopped again.

#include "usoc_user_services.h"
#include "usoc_sensor_API.h"
#include "usoc_sensor_BME680_public.h"

usoc_sensor_lock_t lock;

void BME680_callback(usoc_sensor_intent_t intent) {
    usoc_printf("Got data from sensor BME680: \n");

    usoc_sensor_free_buff_blk(USOC_SENSOR_L2_BME680, &lock, intent.intent_data_ptr);
}

int main() {
    usoc_BME680_config_t config;

    config.oversampling_t = BME680_OVERSAMPLING_OFF;
    config.oversampling_p = BME680_OVERSAMPLING_OFF;
    config.oversampling_h = BME680_OVERSAMPLING_OFF;
    config.filter_tp = BME680_FILTER_0;
    config.values_per_block = 20;
    config.block_count = 4;

    usoc_printf("init sensor\n");
    usoc_init_sensor(USOC_SENSOR_L2_BME680, &lock, &config, BME680_callback);

    usoc_printf("start sensor\n");
    usoc_sensor_start(USOC_SENSOR_L2_BME680, &lock);

    usoc_printf("stop sensor\n");
    usoc_sensor_stop(USOC_SENSOR_L2_BME680, &lock);

    usoc_printf("release sensor\n");
    usoc_release_sensor(USOC_SENSOR_L2_BME680, &lock);

    return 0;
}

To enable the call back to be run usoc_idle needs to be executed to free time for the callback. For multiple callback a counter is added to the function and we idle until the callback has been called 5 times.

#include "usoc_user_services.h"
#include "usoc_sensor_API.h"
#include "usoc_sensor_BME680_public.h"

usoc_sensor_lock_t lock;
uint8_t counter = 0;

void BME680_callback(usoc_sensor_intent_t intent) {
    counter++;
    usoc_printf("Got data from sensor BME680: \n");

    usoc_sensor_free_buff_blk(USOC_SENSOR_L2_BME680, &lock, intent.intent_data_ptr);
}

int main() {
    usoc_BME680_config_t config;

    config.oversampling_t = BME680_OVERSAMPLING_OFF;
    config.oversampling_p = BME680_OVERSAMPLING_OFF;
    config.oversampling_h = BME680_OVERSAMPLING_OFF;
    config.filter_tp = BME680_FILTER_0;
    config.values_per_block = 20;
    config.block_count = 4;

    usoc_printf("init sensor\n");
    usoc_init_sensor(USOC_SENSOR_L2_BME680, &lock, &config, BME680_callback);

    usoc_printf("start sensor\n");
    usoc_sensor_start(USOC_SENSOR_L2_BME680, &lock);

    while(counter < 5) {
        usoc_idle();
    }

    usoc_printf("stop sensor\n");
    usoc_sensor_stop(USOC_SENSOR_L2_BME680, &lock);

    usoc_printf("release sensor\n");
    usoc_release_sensor(USOC_SENSOR_L2_BME680, &lock);

    return 0;
}

Now the data can be finally be read. For that the intent_data_ptr will be converted to the matching struct which is usoc_BME680_data_t. This struct contains 4 properties which contain the raw values for tempreature, pressure, humidity and gas.

#include "usoc_user_services.h"
#include "usoc_sensor_API.h"
#include "usoc_sensor_BME680_public.h"

usoc_sensor_lock_t lock;
uint8_t counter = 0;

void BME680_callback(usoc_sensor_intent_t intent) {
    counter++;
    usoc_printf("Got data from sensor BME680: \n");
    usoc_BME680_data_t *data = (usoc_BME680_data_t *)intent.intent_data_ptr;

    for(size_t i = 0; i < intent.size; i++) {
      usoc_printf("t: %i, p: %i, h: %i, g: %i \n", data->t, data->p, data->h, data->g);
      data++;
    }

    usoc_sensor_free_buff_blk(USOC_SENSOR_L2_BME680, &lock, intent.intent_data_ptr);
}

int main() {
    usoc_BME680_config_t config;

    config.oversampling_t = BME680_OVERSAMPLING_OFF;
    config.oversampling_p = BME680_OVERSAMPLING_OFF;
    config.oversampling_h = BME680_OVERSAMPLING_OFF;
    config.filter_tp = BME680_FILTER_0;
    config.values_per_block = 20;
    config.block_count = 4;

    usoc_printf("init sensor\n");
    usoc_init_sensor(USOC_SENSOR_L2_BME680, &lock, &config, BME680_callback);

    usoc_printf("start sensor\n");
    usoc_sensor_start(USOC_SENSOR_L2_BME680, &lock);

    while(counter < 5) {
        usoc_idle();
    }

    usoc_printf("stop sensor\n");
    usoc_sensor_stop(USOC_SENSOR_L2_BME680, &lock);

    usoc_printf("release sensor\n");
    usoc_release_sensor(USOC_SENSOR_L2_BME680, &lock);

    return 0;
}
init sensor
start sensor
Got data from sensor BME680:
t: 1, p: 2040, h: 511245, g: 204
Got data from sensor BME680:
t: 1, p: 2040, h: 511245, g: 204
Got data from sensor BME680:
t: 1, p: 2040, h: 511245, g: 204
Got data from sensor BME680:
t: 1, p: 2040, h: 511245, g: 204
Got data from sensor BME680:
t: 1, p: 2040, h: 511245, g: 204
stop sensor
release sensor

CMP8270

The CMP8270 is a pressure sensor, which is connected over the can bus.

The senor api provides an easy way to access this senor. The first step is to initialize the sensor with usoc_init_sensor. To do that, a lock handler, the configuration for the Sensor and a callback function is needed. After usage the sensor has to be released again with usoc_release_sensor. This function needs the acquired lock to release it. Both functions also need the sensor type as parameter, which is USOC_SENSOR_L3_CMP8270 for the CMP8270.

#include "usoc_user_services.h"
#include "usoc_sensor_API.h"
#include "usoc_sensor_CMP8270_public.h"

usoc_sensor_lock_t lock;

void CMP8270_callback(usoc_sensor_intent_t intent) {

}

int main() {
    usoc_CMP8270_config_t config;

    config.values_per_block = 20;
    config.block_count = 4;

    usoc_printf("init sensor\n");
    usoc_init_sensor(USOC_SENSOR_L3_CMP8270, &lock, &config, CMP8270_callback);

    usoc_printf("release sensor\n");
    usoc_release_sensor(USOC_SENSOR_L3_CMP8270, &lock);

    return 0;
}

Memory is allocated for each callback the result is written to. To avoid memory leaks, this memory block has to be released with usoc_sensor_free_buff_blk. The pointer needed for this function is the argument of the callback.

#include "usoc_user_services.h"
#include "usoc_sensor_API.h"
#include "usoc_sensor_CMP8270_public.h"

usoc_sensor_lock_t lock;

void CMP8270_callback(usoc_sensor_intent_t intent) {
    usoc_sensor_free_buff_blk(USOC_SENSOR_L3_CMP8270, &lock, intent.intent_data_ptr);
}

int main() {
    usoc_CMP8270_config_t config;

    config.values_per_block = 20;
    config.block_count = 4;

    usoc_printf("init sensor\n");
    usoc_init_sensor(USOC_SENSOR_L3_CMP8270, &lock, &config, CMP8270_callback);

    usoc_printf("release sensor\n");
    usoc_release_sensor(USOC_SENSOR_L3_CMP8270, &lock);

    return 0;
}

After intialising the sensor, we are ready to start it so that it can send us some data. To do so, we call the function usoc_sensor_start.

Now that the sensor is started, it will record data which will be internally buffered. The first thing we want to achieve is that our callback is called when sensor data is available. The function usoc_idle is responsible for this. It will check if there is new sensor data and will call the given callback if so. We will need to constantly call this function while recording sensor data which is usually done in an infinite while loop.

Since we want our tutorial program to end at some point, we will contrain the while loop to five iterations. We do that by using a counter variable which we will increase inside the callback.

After we have finished recording sensor data we make a call to usoc_sensor_stop to stop it.

#include "usoc_user_services.h"
#include "usoc_sensor_API.h"
#include "usoc_sensor_CMP8270_public.h"

usoc_sensor_lock_t lock;
uint8_t counter = 0;

void CMP8270_callback(usoc_sensor_intent_t intent) {
    counter++;

    usoc_sensor_free_buff_blk(USOC_SENSOR_L3_CMP8270, &lock, intent.intent_data_ptr);
}

int main() {
    usoc_CMP8270_config_t config;

    config.values_per_block = 20;
    config.block_count = 4;

    usoc_printf("init sensor\n");
    usoc_init_sensor(USOC_SENSOR_L3_CMP8270, &lock, &config, CMP8270_callback);

    usoc_printf("start sensor\n");
    usoc_sensor_start(USOC_SENSOR_L3_CMP8270, &lock);

    while(counter < 5) {
        usoc_idle();
    }

    usoc_printf("stop sensor\n");
    usoc_sensor_stop(USOC_SENSOR_L3_CMP8270, &lock);

    usoc_printf("release sensor\n");
    usoc_release_sensor(USOC_SENSOR_L3_CMP8270, &lock);

    return 0;
}

Now we can read and print out the sensor data. Its data format is defined in the struct usoc_CMP8270_data_t.

#include "usoc_user_services.h"
#include "usoc_sensor_API.h"
#include "usoc_sensor_CMP8270_public.h"

usoc_sensor_lock_t lock;
uint8_t counter = 0;

void CMP8270_callback(usoc_sensor_intent_t intent) {
    counter++;
    usoc_printf("Got data from sensor CMP8270: \n");
    usoc_CMP8270_data_t *data = (usoc_CMP8270_data_t *)intent.intent_data_ptr;

    for(size_t i = 0; i < intent.size; i++) {
        usoc_printf("pressure: %i\n", data->pressure);
        data++;
    }

    usoc_sensor_free_buff_blk(USOC_SENSOR_L3_CMP8270, &lock, intent.intent_data_ptr);
}

int main() {
    usoc_CMP8270_config_t config;

    config.values_per_block = 20;
    config.block_count = 4;

    usoc_printf("init sensor\n");
    usoc_init_sensor(USOC_SENSOR_L3_CMP8270, &lock, &config, CMP8270_callback);

    usoc_printf("start sensor\n");
    usoc_sensor_start(USOC_SENSOR_L3_CMP8270, &lock);

    while(counter < 5) {
        usoc_idle();
    }

    usoc_printf("stop sensor\n");
    usoc_sensor_stop(USOC_SENSOR_L3_CMP8270, &lock);

    usoc_printf("release sensor\n");
    usoc_release_sensor(USOC_SENSOR_L3_CMP8270, &lock);

    return 0;
}