Intel® Quark™ Microcontroller Developer Kit D2000 Accelerometer and PWM: Lab Guide

Contents

Overview

The purpose of this lab is to show how to program the Intel® Quark™ Microcontroller D2000 PWM module and Bosch* BMC150 accelerometer integrated in the Intel® Quark™ Microcontroller Developer Kit D2000 board, using Quark Microcontroller Software Interface (QMSI) and Intel® System Studio 2016 for Microcontrollers. The sample project used in this lab reads the acceleration, prints it to the serial port, and also changes on-board user LED brightness using PWM depending on the X axis acceleration (for example, tilt).

Prerequisites

  • Host machine:
    • PC running Microsoft Windows* 7 or later, with two available USB ports
  • Software:
    • Intel® System Studio for Microcontrollers 2016
    • PuTTY terminal emulation software
  • Hardware:
    • Intel® Quark™ Microcontroller Developer Kit D2000 board
    • USB Type A to Micro USB Type B cable. This cable is supplied with the kit.
    • FTDI TTL-232R-3V3 USB to Serial cable
    • 3 male to male jumper wires

Lab Workflow

Lab Instructions

Step 1: Connect the Intel® Quark™ Microcontroller Developer Kit D2000 board

Using jumper wires, connect the FTDI TTL-232R-3V3 cable to the microcontroller, as shown in the picture below.

Make sure that pin 1 of the cable (the black wire, also identified by a small arrow on the connector) is connected to the GND pin of the board. Pin 4 of the cable (orange wire) is connected to the RX pin (0) of the board. And pin 5 of the cable (yellow wire) is connected to the TX pin (1) of the board.

Connect the USB end of the FTDI cable to your PC.

Connect the board to your PC using the USB Type A to Micro USB Type B cable provided in the kit. The green P3V3 LED on the board should light up.

Step 2: Check the USB drivers for the COM port and JTAG adapter

Open Windows Device Manager. Make sure that you have a USB Serial Port device listed under Ports (COM & LPT) and an OpenOCD JTAG device under Universal Serial Bus devices, as shown in the screenshot below. Make a note of the COM port number (COM6 on the screenshot—this might be different on your computer).

If the USB Serial Port device does not appear, or the Ports (COM & LPT) category is missing, the FTDI driver needs to be installed. It can be downloaded from the FTDI web site.

If the OpenOCD JTAG device does not appear, or the Universal Serial Bus devices category is missing, the USB driver needs to be installed. To install the driver, navigate to the C:\IntelSWTools\ISSM_2016.0.027\tools\debugger\driver directory using File Explorer, double-click install.bat, and enter Y in the OpenOCD JTAG Driver window that appears.

Step 3: Run PuTTY

Click the Windows start button, type putty, and press Enter to run the application.

The PuTTY Configuration dialog box appears. Select the appropriate options to configure your connection, as follows:

  • Select the Serial option.
  • Type 115200 in the Speed field. 115200 bits per second (bps) is the default speed of the UART.
  • Type the COM port number you noted earlier (such as COM6) in the Serial Line field.

Click Open to open the serial terminal.

Step 4: Run Intel® System Studio™ for Microcontrollers

Using File Explorer, navigate to the C:\IntelSWTools\ISSM_2016.0.027 directory, and double-click the file iss_mcu_ide_eclipse-launcher.bat.

The Intel® System Studio™ for Microcontrollers prompts you to choose your workspace location, as shown below.

We recommend that you click Browse[AW1] and change the workspace location to your user directory (for example C:\Users\username\Documents\workspace). Click OK to confirm your changes. The Intel® System Studio for Microcontrollers windows will appear as shown in the screenshot below.

Step 5: Update target ROM

Note: This step needs to be performed only once per board.

From the Intel ISSM menu, select Update target ROM… as shown on the screenshot below.

The Update target ROM dialog box appears. Make sure that the selected Intel Quark target is D2000, and the selected Connection is USB Onboard. Click Update to program the ROM to the microcontroller.

Step 6: Create a new project

From the Intel ISSM menu, select New Intel QMSI/BSP Project. The Create new Intel QMSI/BSP Project dialog box appears. Type accel_pwm in the Project Name field. Make sure that the other settings match the settings in the screenshot below.

Click Finish to create the new project.

In the Project Explorer window on the left side of Intel® System Studio for Microcontrollers, click the accel_pwm project. Find the main.c file and double-click it to open it in the editor. Replace the contents of main.c with the code in the Source Code section below. Save the file by pressing Ctrl-S.

Step 7: Build the project

Click the Build icon  on the toolbar to build the project. Alternatively, you can click the arrow next to the icon and select the build configuration from the menu. Intel® Systems Studio for Microcontrollers provides two configurations: debug and release. The debug configuration includes symbols in the generated binary files to facilitate debugging. It is the default configuration. The release configuration optimizes code for deployment.

Step 8: Flash and run the project

Click the arrow next to the Run icon (the green ‘play’ icon). Select accel_pwm (flashing) from the menu. The Intel® Systems Studio for Microcontrollers will recompile the code and flash it to the microcontroller.

Note: Intel® System Studio for Microcontrollers offers two ways to run the code. The first option, accel_pwm, assumes that the code had been already programmed to the microcontroller. The second option, accel_pwm (flashing), will recompile and re-flash the code. Use this option if the source code has been changed since the last time microcontroller was programmed. This is the option used in this lab step.

Note: The flashing process takes some time. You can see where you are in the process by looking at the progress bar at the bottom right corner of the Intel® Systems Studio for Microcontrollers window, as shown below.

Step 9: Test the project

Position the board horizontally. Observe that the user LED DS1—marked as (1) in the picture—is dim (or off). Rotate the board so that the USB connector points up or down. Observe that the user LED is bright.

Switch to the PuTTY window. You should be seeing accelerometer readings being printed out in the terminal. Try to rotate the board. Notice how the accelerometer readings change.

Lab Source Code

How it works

The Accelerometer and PWM sample uses the on-board Bosch BMC150 accelerometer connected to the microcontroller using the I2C interface, the PWM module integrated in Intel® Quark™ Microcontroller D2000, and the on-board user LED DS2. The LED is connected to the I/O pin number 24. The code defines and uses PIN_LED constant to refer to that pin.

The sample begins with initializing and setting up the accelerometer:

/* Initialize Accelerometer */

bmc150_init(BMC150_J14_POS_0);

bmc150_set_accel_mode(BMC150_MODE_2G);

bmc150_set_bandwidth(BMC150_BANDWIDTH_64MS);

The bmc150_init function initializes the I2C and the accelerometer. The BMC150_J14_POS_0 parameter specifies the address of the accelerometer. (The J14 switch was available on CRB boards.)

The bmc150_set_accel_mode and bmc150_set_bandwidth functions configure the accelerometer range (how sensitive it is) and the data rate (how frequently it collects the data), respectively.

Next, the sample initializes a periodic RTC interrupt for a period of 0.1 seconds, and sets up the callback for that interrupt: read_accel_callback.

#define ALARM_PERIOD (QM_RTC_ALARM_SECOND / 10)

/* Set up RTC alarm interrupt */

rtc_cfg.init_val = 0;

rtc_cfg.alarm_en = true;

rtc_cfg.alarm_val = ALARM_PERIOD;

rtc_cfg.callback = read_accel_callback;

qm_irq_request(QM_IRQ_RTC_0, qm_rtc_isr_0);

clk_periph_enable(CLK_PERIPH_RTC_REGISTER | CLK_PERIPH_CLK);

qm_rtc_set_config(QM_RTC_0, &rtc_cfg);

The read_accel_callback reads the accelerometer data using the bmc150_read_accel function, prints the data on the serial terminal using the QM_PRINTF function, calculates the LED brightness depending on the acceleration on the X axis, and calls the set_pwm function to set up PWM accordingly.

The set_pwm function configures a PWM output on the Intel® Quark™ Microcontroller D2000.

Note: PWM (pulse-width modulation) is a technique used by microcontrollers to get an analog signal using a digital output. It uses the ratio between on and off cycles to control the signal amplitude (this ratio is known as the duty cycle).

The set_pwm function performs one of two actions depending on the duty cycle setting:

  1. If the duty_cycle parameter is between 1 and 254, it configures the PWM module, and multiplexes the output of that module to the I/O pin. The PWM module uses two timers. The first timer, hi_count determines the number of system clock cycles in which the output stays in logic ‘1’ state. The second timer, lo_count, determines the number of system clock cycles in which the output stays in logic ‘0’ state. The set_pwm function calculates these parameters using the specified period and the duty_cycle parameters:
/* Configure PWM */

/* Calculate low time and high counts */

pwm_cfg.hi_count = period * duty_cycle / 256;

pwm_cfg.lo_count = period - pwm_cfg.hi_count;

Alternatively, if the duty_cycle parameter is 0 (always off) or 255 (always on), it multiplexes the GPIO module to that I/O pin, configures it in the output mode, and sets the pin value to logic ‘0’ or logic ‘1’, respectively.
if (0 == duty_cycle) {

       qm_gpio_clear_pin(QM_GPIO_0, pin);

} else {

       qm_gpio_set_pin(QM_GPIO_0, pin);

}

Source Code

/* Accelerometer and PWM sample */



#include "qm_pwm.h"

#include "qm_interrupt.h"

#include "qm_scss.h"

#include "qm_gpio.h"

#include "qm_pinmux.h"

#include "qm_rtc.h"

#include "qm_power.h"

#include "bmc150/bmc150.h"



#define PIN_LED 24 /* User LED (DS1) */



#define ALARM_PERIOD (QM_RTC_ALARM_SECOND / 10)



static void read_accel_callback(void);

qm_rc_t set_pwm(const uint8_t pin, uint8_t duty_cycle, uint32_t period);



int main(void)

{

       qm_rtc_config_t rtc_cfg;



       QM_PRINTF("Welcome to Accelerometer and PWM example.\r\n");



       /* Initialize Accelerometer */

       bmc150_init(BMC150_J14_POS_0);

       bmc150_set_accel_mode(BMC150_MODE_2G);

       bmc150_set_bandwidth(BMC150_BANDWIDTH_64MS);



       /* Set up RTC alarm interrupt */

       rtc_cfg.init_val = 0;

       rtc_cfg.alarm_en = true;

       rtc_cfg.alarm_val = ALARM_PERIOD;

       rtc_cfg.callback = read_accel_callback;



       qm_irq_request(QM_IRQ_RTC_0, qm_rtc_isr_0);



       clk_periph_enable(CLK_PERIPH_RTC_REGISTER | CLK_PERIPH_CLK);

       qm_rtc_set_config(QM_RTC_0, &rtc_cfg);



       while(1) {

              cpu_halt();

       }



       return 0;

}



static void read_accel_callback(void)

{

       bmc150_accel_t accel = {0};

       int16_t brightness;



       /* Read accelerometer value */

       if (bmc150_read_accel(&accel) == QM_RC_OK) {

              QM_PRINTF("Accelerometer: x=%d, y=%d, z=%d\r\n",

                           accel.x, accel.y, accel.z);



              /*

               * Calculate LED brightness:

               * Absolute value of acceleration along X axis

               * constrained to 1023 and divided by 256

               */

              brightness = accel.x >= 0 ? accel.x : -accel.x;

              if (brightness < 1024) {

                     brightness /= 4;

              } else {

                     brightness = 255;

              }



              set_pwm(PIN_LED, brightness, 0x1000);

       }



       qm_rtc_set_alarm(QM_RTC_0, (QM_RTC[QM_RTC_0].rtc_ccvr + ALARM_PERIOD));

}



qm_rc_t set_pwm(const uint8_t pin, uint8_t duty_cycle, uint32_t period)

{

       qm_pwm_id_t pwm_id;

       qm_pwm_config_t pwm_cfg;

       qm_gpio_port_config_t gpio_cfg;

       qm_pmux_fn_t gpio_fn;



       /* Find PWM ID for given pin */

       if (19 == pin) {

              pwm_id = QM_PWM_ID_0;

              gpio_fn = QM_PMUX_FN_1;

       } else if (24 == pin) {

              pwm_id = QM_PWM_ID_1;

              gpio_fn = QM_PMUX_FN_0;

       } else {

              /* PWM is not supported on the pin */

              return QM_RC_EINVAL;

       }



       /* Use PWM to generate pulses

        * Use GPIO for constant on or off

        */

       if (duty_cycle != 0 && duty_cycle != 255) {

              /* Configure PWM */

              /* Calculate low time and high counts */

              pwm_cfg.hi_count = period * duty_cycle / 256;

              pwm_cfg.lo_count = period - pwm_cfg.hi_count;

              pwm_cfg.mode = QM_PWM_MODE_PWM;

              pwm_cfg.mask_interrupt = true;

              pwm_cfg.callback = NULL; /* no callback */



              /* Enable clock for PWM */

              clk_periph_enable(CLK_PERIPH_PWM_REGISTER | CLK_PERIPH_CLK);



              /* Set PWM configuration */

              qm_pwm_set_config(QM_PWM_0, pwm_id, &pwm_cfg);



              /* Enable PWM mode */

              qm_pmux_select(pin, QM_PMUX_FN_2);



              /* Start PWM */

              qm_pwm_start(QM_PWM_0, pwm_id);

       } else {

              /* program pin as GPIO and set to 0 or 1 */

              qm_gpio_get_config(QM_GPIO_0, &gpio_cfg);



              /* Enable GPIO mode */

              qm_pmux_select(pin, gpio_fn);



              /* set pin direction to output */

              gpio_cfg.direction |= BIT(pin);

              qm_gpio_set_config(QM_GPIO_0, &gpio_cfg);

              if (0 == duty_cycle) {

                     qm_gpio_clear_pin(QM_GPIO_0, pin);

              } else {

                     qm_gpio_set_pin(QM_GPIO_0, pin);

              }

       }

       return QM_RC_OK;

}

 

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