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

Using an MCU on the Intel® Edison Board with the Ultrasonic Range Sensor

13 Nov 2015 1  
The Intel® Edison board contains an internal microcontroller unit (MCU) in addition to the CPU. In this article, I explain the benefits of using an internal MCU for both

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

The Intel® Edison board contains an internal microcontroller unit (MCU) in addition to the CPU. In this article, I explain the benefits of using an internal MCU for both

  • Real-time
  • Power efficiency

MCU is important in several applications. For example, Linux* on the Intel® Edison board does not provide a real-time response when working with sensors. MCU support has been available on the Intel® Edison® Board Firmware Software Release since version 2.1.

Let’s look at the system-on-chip (SoC) used in the Intel® Edison compute module:

The SoC used in the Intel® Edison compute module includes two CPUs:

  • Dual-core Intel® Atom™ processor running at 500 MHz. Labeled as Host CPU.
  • MCU with Minute Intel® architecture running at 100 MHz. Labeled as MCU.

The Minute Intel architecture core is energy-efficient architecture, based on the Intel® 486 with added instructions for compatibility with the Intel® Pentium® processor. The MCU contains a rich I/O subsystem (GPIO, I2C, high-speed UART, DMA) and SRAM, and has access to all GPIO pins in the Intel® Edison compute module. The total SRAM size for code and data is 192 kb. The MCU is running with the real-time Viper* OS from WindRiver.

The MCU program works on the Viper core and controls the peripherals connected to the MCU, independently of the Intel Atom processor. For example, it can control the GPIO pins, communicate with sensors with I2C and UART protocols, and communicate with the Intel Atom processor.

Reasons to use the MCU on the Intel® Edison

Using the MCU is beneficial for two reasons: providing real-time microsecond delays and power efficiency.

The Intel Atom processor and Yocto Project* standard Linux* distribution do not support real-time applications “out of the box.”

The Linux application could be preempted by the scheduler, which leads to unacceptable and unpredictable delays, so it’s not possible to provide a real-time response.

The MCU runs a single application and a real-time OS, which makes it possible to provide a real-time response.

A real-time response is required for many sensors where the communication protocol depends on the strict compliance of short timings.

To connect these sensors to the Intel® Edison board without an internal MCU, you will need to use an external MCU. All the sensor communication is implemented in an external MCU in this case. For example, SparkFun Block* for Intel® Edison board – Arduino extension board provides external MCU functionality. However, the use of an external MCU increases BOM costs and the complexity of the solution.

An MCU could improve the power efficiency in applications where the CPU is set to sleep state, and the MCU is waiting for an external event (for example, when the sensor value is rises above the threshold).

When the external event occurs, the MCU wakes up the CPU. Implementation examples are provided in the article Using the MCU SDK and API: Code examples.

To illustrate how to use the internal MCU, we will connect Ultrasonic Ranging Sensor HC-SR04 to the Intel® Edison board. We will output the measured distance to the Grove* LCD RGB Backlight symbolic display.

Ultrasonic Ranging Sensor HC-SR04

The sensor has four pins:

  • Vcc: 5V
  • Trig: Trigger signal to sensor. The MCU sends a 10 us pulse to the sensor. Sensors initiate a single measurement.
  • Echo: Echo signal from sensor to MCU. Pulse width is proportional to the measured distance.
  • Gnd: Ground

The picture demonstrates the protocol on the oscilloscope screen:

  • 1 channel: Trig
  • 2 channel: Echo

The MCU sends a pulse to the Trig pin. After that, the sensor responds with a pulse on the Echo pin.

The pulse duration is proportional to the measured distance.

The distance is calculated using the formula (from the sensor datasheet):

Distance (cm) = Echo pulse duration (us) / 58

The sensor could measure the distance from 2 cm to 400 cm as mentioned in datasheet.

It’s not possible to measure the duration of such a short pulse with estimated accuracy without microsecond real-time delays. For example, the scheduler could preempt the measurement process and the measurement result will become invalid.

Connecting the HC-SR04 sensor to the MCU on the Intel® Edison board

Components:

  • Intel® Edison compute module
  • Intel® Edison board for Arduino
  • Grove Basic Shield
  • Grove LCD RGB Backlight
  • Ultrasonic Range Sensor HC-SR04
  • Breadboard

First, assemble the Intel® Edison compute module and the Intel® Edison board for Arduino. Next, connect the Grove Base Shield extension board to Intel® Edison board for Arduino. Connect the Grove LCD RGB Backlight to any I2C port on the Grove Basic Shield.

Connect the Ultrasonic Range Sensor HC-SR04 to the Grove Basic Shield as follows:

  • Vcc to +5V
  • Trig to Pin 3
  • Echo to Pin 4
  • Gnd to Gnd

Pins 3 and 4 are selected randomly. You can use any GPIO pin for this purpose.

Updating the Intel® Edison board firmware

MCU support was added to the Intel® Edison Board Firmware Software Release in version 2.1. If you have older firmware, you will need to update it.

To get the current firmware version, use the following command:

# configure_edison –version

This example is based on firmware version 146.

Firmware update instructions are provided in the article Flashing Intel® Edison. I prefer to use the alternate flashing method described in the article.

Please, read the instructions carefully before flashing.

Connecting the Intel® Edison board using Ethernet over USB

You must configure the network connection to connect with the Intel® Edison board from the MCU SDK.

To do that, connect the USB cable to the top micro-USB port and set the micro-switch to the bottom position (toward the micro-USB port).

To configure the network on Linux:

# ifconfig usb0 192.168.2.2

Intel® Edison board IP address: 192.168.2.15

For more information, please refer to the article Connecting to your Intel® Edison board using Ethernet over USB.

MCU SDK

The developer needs the MCU SDK to create applications for the internal MCU. The MCU SDK is a cross-platform IDE based on Eclipse*. The installation process is explained in the article Installing the MCU SDK.

The MCU SDK provides functionality to create, compile, upload to the board, and debug applications for MCU.

Communicating with the MCU

Several interfaces are available to communicate with the MCU at the Linux level:

/dev/ttymcu0 — Interface to send/receive data to/from the MCU. It is possible to operate using standard read and write file operations from Linux. The MCU program can use host_send and host_receive functions.

/dev/ttymcu1 — Interface to send debug messages from the MCU using debug_print function.

/sys/devices/platform/intel_mcu/log_level — Interface to set log level for debug messages (fatal, error, warning, info, debug).

Working with the Intel® Edison board for Arduino pins from the MCU

MCU is integrated in the Intel® Edison compute module and can control GPIOs located on the 70-pin Hirose module connector.

To use the MCU with the Intel® Edison board for Arduino, you need to find a map between the Intel® Edison compute module GPIO pin and the Intel® Edison board for Arduino pin. Configure the multiplexors and level shifters to route the GPIO from the Intel® Edison compute module to the Intel® Edison board for Arduino pin.

When working from the Linux level, these routines are handled in the MRAA library. In case of MCU, developer needs to handle these using the scripts (init_DIG.sh, init_i2c8.sh, init_mcu_PWM.sh, set_DIG.sh, read_DIG.sh, init_UART1.sh). More information is provided inTable 4 in Intel® Edison Kit for Arduino* Hardware Guide.

Script for Linux

The Python* script show_distance.py below fetches the data from the internal MCU and shows them on the Grove LCD display. We will use the Jhd1313m1 module from the UPM library to work with the Grove LCD display.

show_distance.py (Note: all the files/scripts are included as a .zip at the end of this article)

import time
import pyupm_i2clcd

RET_ERROR = -1

if __name__ == '__main__':
    lcd = pyupm_i2clcd.Jhd1313m1(6, 0x3E, 0x62)
    with open('/dev/ttymcu0', 'w+t') as f:
        while True:
            f.write('get_distance\n') # Send command to MCU
            f.flush()
            line = f.readline() # Read response from MCU, -1 = ERROR
            value = int(line.strip('\n\r\t '))
            lcd.clear()
            if value == RET_ERROR:
                lcd.setColor(255, 0, 0) # RED
                lcd.write('ERROR')
            else:
                lcd.setColor(0, 255, 0) # GREEN
                lcd.write('%d cm' % (value,))
            time.sleep(1)

MCU program

The MCU program waits for the get_distance command from the host CPU. If the program receives the get_distance command, it measures the distance and sends the result to the host CPU (distance in cm or -1 in case of error).

Set up the pins on the Intel® Edison board for Arduino:

# ./init_DIG.sh -o 3 -d output

# ./init_DIG.sh -o 4 -d input

The MCU works with the GPIO pins on the Intel® Edison compute modules that have different numbers from the labels on the Intel® Edison board for Arduino. For more information, refer to the table in the article Blinking an LED using the MCU.

mcu.c (Note: all the files/scripts are included as a .zip at the end of this article)

#include "mcu_api.h"
#include "mcu_errno.h"

// Arduino Extension PIN = 3
#define TRIG 12
// Arduino Extension PIN = 4
#define ECHO 129

// From HC-SR04 datasheet
#define MIN_DISTANCE 2
#define MAX_DISTANCE 400

#define MAX_WAIT 10000
#define RET_ERROR -1

int get_distance() {
	// Send Trig signal to HC-SR04
	gpio_write(TRIG, 1);
	mcu_delay(10);
	gpio_write(TRIG, 0);

	// Read Echo signal from HC-SR04
	int i;

	i = 0;
	while ((gpio_read(ECHO) == 0) && (i < MAX_WAIT)) {
		mcu_delay(1);
		i++;
	}

	unsigned long t0 = time_us();
	if (gpio_read(ECHO) == 0 || i == MAX_WAIT) {
		return RET_ERROR;
	}

	i = 0;
	while ((gpio_read(ECHO) == 1) && (i < MAX_WAIT)) {
		mcu_delay(1);
		i++;
	}

	unsigned long t1 = time_us();
	if (gpio_read(ECHO) == 1 || i == MAX_WAIT) {
		return RET_ERROR;
	}

	unsigned long distance = (t1 - t0) / 58;
	if (MIN_DISTANCE < distance && distance < MAX_DISTANCE) {
		return distance;
	} else {
		return RET_ERROR;
	}
}

#define MAX_BUF 255
unsigned char buf[MAX_BUF];

void mcu_main() {
	// Setup Trig as OUTPUT
	gpio_setup(TRIG, 1);
	// Initially set Trig to LOW
	gpio_write(TRIG, 0);
	// Setup Echo as INPUT
	gpio_setup(ECHO, 0);

	while (1) {
		unsigned int len;
		len = host_receive(buf, MAX_BUF);

		if ((len >= 12) && (strncmp(buf, "get_distance", 12) == 0)) {
			unsigned int distance;
			distance = get_distance();
			len = mcu_snprintf(buf, MAX_BUF, "%d\n", distance);
			host_send(buf, len);
		}
	}
}

Adding our script to auto start

To launch our script, first create a shell script:

File /home/root/startup.sh:

startup.sh (Note: all the files/scripts are included as a .zip at the end of this article)

#!/bin/bash

cd /home/root

# configure PIN3 as GPIO OUPUT (TRIG signal)
./init_DIG.sh -o 3 -d output

# configure PIN4 as GPIO INPUT (ECHO signal)
./init_DIG.sh -o 4 -d input

python show_distance.py

Mark scripts as executables:

# chmod a+x /home/root/startup.sh

# chmod a+x /home/root/init_DIG.sh

The Yocto Project Linux uses systemd, so we need to create “service” file to add the script to auto start.

Create the file/lib/systemd/system/startup-script.service:

startup-script.service (Note: all the files/scripts are included as a .zip at the end of this article)

[Unit]
Description=Startup User Script
After=syslog.target

[Service]
ExecStart=/home/root/startup.sh

[Install]
WantedBy=multi-user.target

Add the service to auto start:

# systemctl enable startup-script

After rebooting, symbol display shows the measured distance:

Source Code

Used resources

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