Get access to the new Intel® IoT Developer Kit, a complete hardware and software solution that allows developers to create exciting new solutions with the Intel® Galileo and Intel® Edison boards. Visit the Intel® Developer Zone for IoT.
Intel® System Studio for Microcontrollers includes multiple samples 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, and also uses the Intel® Integrated Performance Primitives for Microcontrollers (DSP functions) library to compute root mean square, variance, and mean for the last 15 Z axis readings.
Requirements
Instructions
- Connect the FTDI cable for serial output by connecting the cables in the following configuration:
- Connect GND (black) from the serial cable to the board's GND pin.
- Connect TXD (orange) from the serial cable to the board's RX pin.
- Connect RXD (yellow) from the serial cable to the board's TX pin.
<img height="575px" src="1126293/board.png" width="640px" />
- Launch the Intel ® System Studio for Microcontrollers IDE.
- Create a project with the "Accelerometer" sample project file, as follows:
- From the File menu, select New, and then select Intel Project for Microcontrollers. The Create a new Project wizard appears.
- Specify the following values in the Create a new Project wizard:
- Developer board: Intel® Quark™ D2000 Developer Board
- Project type: Intel® QMSI (1.1)
- Connection type: USB-Onboard
- Project name: Accelerometer
- Click Finish.
<img height="521px" src="1126293/Save_as_new_Project_dialog_box.png" width="614px" />
- Set up the Serial Terminal view to see the sensor output. This window will display the accelerometer's sensor data via the UART interface over the serial cable.
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:
Note: If you close the Serial Terminal window, you can open it again by choosing Window > Show View > Other > Intel ISSM > Serial Terminal
- At the bottom right of the window, select the Serial Terminal tab, and click the <img alt="ISSM Window Serial Terminal Add icon" height="16" src="https://software.intel.com/sites/default/files/managed/88/78/ISSM_Window_Serial_Terminal_Plus_icon.png" title="ISSM Window Serial Terminal Add icon" width="16" /> icon to open a new serial terminal connection.
<img height="241px" src="1126293/ISSM_Window_Serial_Terminal_tab_cropped.png" width="640px" />
- Ensure that the correct serial port is selected. You can also click the Custom configuration menu to modify the default serial connection settings.
<img height="220px" src="1126293/Open_Serial_Terminal_dialog.png" width="535px" />
- Unplug the FTDI cable from your PC and refresh the "Open Serial Terminal" window to determine which COM port is active.
- Linux*: Use the ‘dmesg’ command to view your port status.
- Windows*: Open Device Manager to view the Ports (COM & LPT) status.
- Click OK and the connection to the Serial Terminal will be made. You should see status "Connected" in the serial console.
- Build and deploy your project.
Note: you can also deploy and debug. From the Debug <img alt="ISSM Window Debug drop-down list" height="22" src="https://software.intel.com/sites/default/files/managed/bc/84/clip_image005_debugddl.png" title="ISSM Window Debug drop-down list" width="39" /> drop-down list, select "Accelerometer (flashing)".
- Select the "Accelerometer" project in the Project Explorer.
- Click the Build <img alt="ISSM Window Build button" height="21" src="https://software.intel.com/sites/default/files/managed/f8/03/clip_image001_buildbutton.png" title="ISSM Window Build button" width="26" /> button to compile your project.
- From the Run <img alt="ISSM Window Run drop-down list" height="14" src="https://software.intel.com/sites/default/files/managed/6c/f6/clip_image003_runddl.png" title="ISSM Window Run drop-down list" width="28" /> drop-down list, select "Accelerometer (flashing)".
- View X, Y, and Z values from the accelerometer in the terminal.
How It Works
The accelerometer sample uses the onboard Bosch BMC150 accelerometer connected to the microcontroller using the I2C interface, and the RTC (real time clock) integrated in Intel® Quark™ microcontroller. It also uses the 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:
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);
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):
#if (QUARK_D2000)
cfg.pos = BMC150_J14_POS_0;
#endif /* QUARK_D2000 */
bmx1xx_init(cfg);
bmx1xx_accel_set_mode(BMX1XX_MODE_2G);
#if (BMC150_SENSOR)
bmx1xx_set_bandwidth(BMC150_BANDWIDTH_64MS);
#elif(BMI160_SENSOR)
bmx1xx_set_bandwidth(BMI160_BANDWIDTH_10MS);
#endif /* BMC150_SENSOR */
The cfs.pos parameter is used to configure the accelerometer address for the BMC150 accelerometer. The Intel® Quark™ Microcontroller D2000 Developer Kit board has a jumper that allows changing the address. The BMC150_J14_POS_0 is the default (no jumper, I2C address 0x10) configuration.
Next, the RTC configuration is set up, thus enabling the RTC alarm:
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:
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.
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 is enabled (it is enabled by default in the sample application), it prints the statistics for the Z axis by calling the print_axis_stats function. (See the print_axis_stats function description, below.)
#if (__IPP_ENABLED__)
print_axis_stats(accel.z);
#endif /* __IPP_ENABLE__ */
The callback function checks whether 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.
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 by default, the application 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;
}
Intel® Integrated Performance Primitives for Microcontrollers Library
The Intel® Integrated Performance Primitives for Microcontrollers library is a set of building blocks for signal and data processing applications for x86-based microcontrollers. Intel® IPP is available with an Intel® IPP classic-style API and a generic DSP-style API; this application is developed with the DSP-style API to demonstrate the usage of Intel® IPP for Microcontrollers in a DSP use case. Additional information on Intel® IPP can be found in the Intel® System Studio for Microcontrollers User and Reference Guide.
The print_axis_stats function uses the Intel IPP (Intel® Integrated Performance Primitives) library to print the statistics of the last 15 (set by NUM_SAMPLES) Z axis readings.
First, it updates the samples array with the new Z axis sample, and if needed, updates the samples count:
static void print_axis_stats(int16_t value)
{
static uint32_t index = 0;
static uint32_t count = 0;
float32_t mean, var, rms;
samples[index] = value;
index = (index + 1) % SAMPLES_SIZE;
count = count == SAMPLES_SIZE ? SAMPLES_SIZE : count + 1;
Next, it calculates and prints root mean square, variance, and mean values for the collected samples, using the ippsq statistics functions:
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);
}
Accelerometer Sample Application Code
#include
#if (__IPP_ENABLED__)
#include
#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)
#define NUM_SAMPLES (500)
#if (__IPP_ENABLED__)
#define SAMPLES_SIZE (15)
#endif
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;
samples[index] = value;
index = (index + 1) % SAMPLES_SIZE;
count = count == SAMPLES_SIZE ? SAMPLES_SIZE : count + 1;
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
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
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");
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);
clk_periph_enable(CLK_PERIPH_RTC_REGISTER | CLK_PERIPH_CLK);
#if (QUARK_D2000)
cfg.pos = BMC150_J14_POS_0;
#endif
bmx1xx_init(cfg);
bmx1xx_accel_set_mode(BMX1XX_MODE_2G);
#if (BMC150_SENSOR)
bmx1xx_set_bandwidth(BMC150_BANDWIDTH_64MS);
#elif(BMI160_SENSOR)
bmx1xx_set_bandwidth(BMI160_BANDWIDTH_10MS);
#endif
qm_rtc_set_config(QM_RTC_0, &rtc);
while (!complete)
;
QM_PUTS("Finished: Accelerometer example app");
return 0;
}