Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Intel® Quark™ SE Microcontroller C1000 Developer Kit - Accelerometer Tutorial

16 Jan 2017 1  
Using Intel® Quark™ Microcontroller Software Interface (Intel® QMSI), this sample application reads and outputs accelerometer data to the serial port.

This article is in the Product Showcase section for our sponsors at CodeProject. These articles are intended to provide you with information on products and services that we consider useful and of value to developers.

Get access to the Grove* IoT Commercial Developer Kit, a complete hardware and software solution that allows professional developers to create exciting new scalable IoT solutions with the latest Intel® boards. Visit the Intel® Developer Zone for IoT.

Intel® System Studio for Microcontrollers includes multiple sample applications to help you get up to speed with its basic functionality and become familiar with the Intel® Quark™ Microcontroller Software Interface (Intel® QMSI). This sample application reads and outputs accelerometer data to the serial port.

Requirements

Instructions

  1. Connect the USB cable to the developer board and the host PC:

    Note: This is the USB port that is connected to the FTDI chip

  2. Launch the Intel ® System Studio for Microcontrollers IDE.
  3. Create a project with the "Accelerometer" sample project file:

    • From the File menu, select New, and then select Intel Project for Microcontrollers.
    • Follow the "Create a new Project" screens

      • Developer board: Intel® Quark™ SE C1000 Developer Board
      • Project type: Intel® QMSI (1.1)
      • Core: Sensor Subsystem
      • Project name: Accelerometer found in the Developer Board Sensors folder
  4. Click Finish.

    Note: The Accelerometer sample application runs on the Sensor Subsystem core, which doesn’t support the IPP library. Therefore it is not possible to build this sample application using the IPP library.

  5. Configure the Serial Terminal window to see the sensor output. This window will display your accelerometer sensor’s data via the UART interface over the serial cable.

    • On the bottom right-hand of the screen select the Serial Terminal pane and click on the plus sign + icon to open a new serial terminal connection:

    • Ensure the correct serial port is selected; the Custom configuration menu can also be clicked to modify the default serial connection settings:

      Tip: The port will vary depending on the serial hardware used, and there may be more than one listed. There are a few ways to check your port:

      • Linux*: Use the ‘dmesg’ command to view your port status.
      • Windows*: Open Device Manager to view the Ports (COM & LPT) status.

        With either of these options, you can unplug the USB cable from your PC and reconnect it to see which COM port appears for the board.

    • Click OK and the connection to the Serial Terminal will be made. You should see status "Connected" in the serial console.

      Note: If you close the Serial Terminal window, you can open it again from:
      Window › Show View › Other › Intel ISSM › Serial Terminal

  6. Build and deploy your project.

    1. Select the "Accelerometer" project in the Project Explorer.
    2. Click the Build button to compile the project.
    3. From the Run drop-down list, select "Accelerometer (flashing)".
      Note: you can also deploy and debug. From the Debug drop-down list, select "Accelerometer (flashing)".

    4. You can now view X, Y, and Z values from the accelerometer in the Serial Terminal window.

How it Works

The accelerometer sample uses the on-board Bosch BMC160 accelerometer connected to the microcontroller using the I2C interface, and the RTC (real time clock) integrated in the Intel® Quark™ microcontroller. It also uses integrated UART module for the data output over serial port.

The sample begins in the main function with setting up RTC parameters in an rtc configuration structure:

/* Configure the RTC and request the IRQ. */
rtc.init_val = 0;
rtc.alarm_en = true;
rtc.alarm_val = INTERVAL;
rtc.callback = accel_callback;
rtc.callback_data = NULL;

This configuration enables the RTC alarm, and sets accel_callback as the callback function for the RTC alarm. It is used to periodically print accelerometer data.

Next the code requests an interrupt for the RTC by using a QMSI API call, and also enables the RTC clock:

qm_irq_request(QM_IRQ_RTC_0, qm_rtc_isr_0);

/* Enable the RTC. */
clk_periph_enable(CLK_PERIPH_RTC_REGISTER | CLK_PERIPH_CLK);

After that it configures the accelerometer parameters depending on the accelerometer type (BMC150 or BMI160):

	/* Initialise the sensor config and set the mode. */
	bmx1xx_init(cfg);
	bmx1xx_accel_set_mode(BMX1XX_MODE_2G);

#if (BMC150_SENSOR)
	bmx1xx_set_bandwidth(BMC150_BANDWIDTH_64MS); /* Set the bandwidth. */
#elif(BMI160_SENSOR)
	bmx1xx_set_bandwidth(BMI160_BANDWIDTH_10MS); /* Set the bandwidth. */
#endif /* BMC150_SENSOR */

Next the RTC configuration is set up, thus enabling the RTC alarm:

/* Start the RTC. */
qm_rtc_set_config(QM_RTC_0, &rtc);

A while loop is used to wait for the defined number of samples from the accelerometer to be read and printed to the serial console output:

/* Wait for the correct number of samples to be read. */
while (!complete)

Each time the 125 millisecond interval is reached and the RTC alarm is triggered, the following accel_callback function is invoked. The accel data structure defined at the start of the function is passed into the bmx1xx_read_accel function which populates it with the current accelerometer data read. If this read is successful the accelerometer data is printed to the serial console output, otherwise an error message is printed.

/* Accel callback will run every time the RTC alarm triggers. */
static void accel_callback(void *data)
{
       bmx1xx_accel_t accel = {0};

       if (0 == bmx1xx_read_accel(&accel)) {
              QM_PRINTF("x %d y %d z %d\n", accel.x, accel.y, accel.z);
       } else {
              QM_PUTS("Error: unable to read from sensor");
       }

The callback function checks if the defined number of samples have been read, if not the RTC alarm is reset and the count is incremented, otherwise the complete variable is set to true.

/* Reset the RTC alarm to fire again if necessary. */
if (cb_count < NUM_SAMPLES) {
       qm_rtc_set_alarm(QM_RTC_0,
                     (QM_RTC[QM_RTC_0].rtc_ccvr + INTERVAL));
       cb_count++;
} else {
       complete = true;
}

Note that the application by default reads 500 samples (NUM_SAMPLES) before exiting.

Finally when the complete variable is set to true, the while loop exits and the applications prints a final statement to the serial console output and exits.

       QM_PUTS("Finished: Accelerometer example app");

       return 0;
}

Accelerometer Sample Application Code

/*
* {% copyright %}
*/

/*
* QMSI Accelerometer app example.
*
* This app will read the accelerometer data from the onboard BMC150/160 sensor
* and print it to the console every 125 milliseconds. The app will complete
* once it has read 500 samples.
*
* If the app is compiled with the Intel(R) Integrated Performance Primitives
* (IPP) library enabled, it will also print the Root Mean Square (RMS),
* variance and mean of the last 15 samples each time.
*/

#include <unistd.h>
#if (__IPP_ENABLED__)
#include <dsp.h>
#endif
#include "clk.h"
#include "qm_interrupt.h"
#include "qm_isr.h"
#include "qm_rtc.h"
#include "qm_uart.h"
#include "bmx1xx/bmx1xx.h"

#define INTERVAL (QM_RTC_ALARM_SECOND >> 3) /* 125 milliseconds. */
#define NUM_SAMPLES (500)
#if (__IPP_ENABLED__)
/* Number of samples to use to generate the statistics from. */
#define SAMPLES_SIZE (15)
#endif /* __IPP_ENABLED__ */

static volatile uint32_t cb_count = 0;
static volatile bool complete = false;

#if (__IPP_ENABLED__)
static float32_t samples[SAMPLES_SIZE];

static void print_axis_stats(int16_t value)
{
      static uint32_t index = 0;
      static uint32_t count = 0;
      float32_t mean, var, rms;

      /* Overwrite the oldest sample in the array. */
      samples[index] = value;
      /* Move the index on the next position, wrap around if necessary. */
      index = (index + 1) % SAMPLES_SIZE;

      /* Store number of samples until it reaches SAMPLES_SIZE. */
      count = count == SAMPLES_SIZE ? SAMPLES_SIZE : count + 1;

      /* Get the root mean square (RMS), variance and mean. */
      ippsq_rms_f32(samples, count, &rms);
      ippsq_var_f32(samples, count, &var);
      ippsq_mean_f32(samples, count, &mean);

      QM_PRINTF("rms %d var %d mean %d\n", (int)rms, (int)var, (int)mean);
}
#endif /* __IPP_ENABLE__ */

/* Accel callback will run every time the RTC alarm triggers. */
static void accel_callback(void *data)
{
      bmx1xx_accel_t accel = {0};

      if (0 == bmx1xx_read_accel(&accel)) {
            QM_PRINTF("x %d y %d z %d\n", accel.x, accel.y, accel.z);
      } else {
            QM_PUTS("Error: unable to read from sensor");
      }

#if (__IPP_ENABLED__)
      print_axis_stats(accel.z);
#endif /* __IPP_ENABLE__ */

      /* Reset the RTC alarm to fire again if necessary. */
      if (cb_count < NUM_SAMPLES) {
            qm_rtc_set_alarm(QM_RTC_0,
                        (QM_RTC[QM_RTC_0].rtc_ccvr + INTERVAL));
            cb_count++;
      } else {
            complete = true;
      }
}

int main(void)
{
      qm_rtc_config_t rtc;
      bmx1xx_setup_config_t cfg;

      QM_PUTS("Starting: Accelerometer example app");

      /* Configure the RTC and request the IRQ. */
      rtc.init_val = 0;
      rtc.alarm_en = true;
      rtc.alarm_val = INTERVAL;
      rtc.callback = accel_callback;
      rtc.callback_data = NULL;

      qm_irq_request(QM_IRQ_RTC_0, qm_rtc_isr_0);

      /* Enable the RTC. */
      clk_periph_enable(CLK_PERIPH_RTC_REGISTER | CLK_PERIPH_CLK);

#if (QUARK_D2000)
      cfg.pos = BMC150_J14_POS_0;
#endif /* QUARK_D2000 */

      /* Initialise the sensor config and set the mode. */
      bmx1xx_init(cfg);
      bmx1xx_accel_set_mode(BMX1XX_MODE_2G);

#if (BMC150_SENSOR)
      bmx1xx_set_bandwidth(BMC150_BANDWIDTH_64MS); /* Set the bandwidth. */
#elif(BMI160_SENSOR)
      bmx1xx_set_bandwidth(BMI160_BANDWIDTH_10MS); /* Set the bandwidth. */
#endif /* BMC150_SENSOR */

      /* Start the RTC. */
      qm_rtc_set_config(QM_RTC_0, &rtc);

      /* Wait for the correct number of samples to be read. */
      while (!complete)
            ;

      QM_PUTS("Finished: Accelerometer example app");

      return 0;
}

For more complete information about compiler optimizations, see our Optimization Notice.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here