Используем встроенный микроконтроллер в Intel Edison

867a4f7cd0d74902b2068fa5ca9f7730.jpgДумаю, что многие из вас уже знакомы с Intel Edison по предыдущим заметкам, и у некоторых после прочтения спецификации, вероятно, возникал вопрос —, а что это за второй загадочный процессор MCU, работающий на частоте 100 МГц? Зачем он нужен? Как его использовать?
Между тем роль MCU в некоторых случаях исключительно важна. Те, кто пробовал применять Edison для работы с различными сенсорами, возможно, уже заметили — Intel Edison не обеспечивает real-time отклика на их показания при работе из Linux. И тут на помощь приходит MCU. Пришло время немного рассказать про этот встроенный микроконтроллер, его архитектуру, области применения и рассмотреть практический пример.
В программное обеспечение для Intel Edison начиная с версии 2.1 добавлена возможность использования встроенного микроконтроллера.

Рассмотрим систему на чипе, используемую в Intel Edison Compute Module:
c909f9fc900349fbbcdeab4c2ccbab34.png

Система на чипе, используемая в Intel Edison Compute Module включает в себя два процессора:

  1. Двухъядерный процессор Intel Atom, работающий на частоте 500 МГц. Обозначен как Host CPU.
  2. Микроконтроллер с архитектурой Minute IA, работающий на частоте 100 МГц. Обозначен как MCU.


Рассмотрим микроконтроллер детальнее. Вычислительное ядро Minute IA представляет собой энергоэффективную архитектуру, основанную на 486 с добавлением команд для совместимости с Pentium. Помимо вычислительного ядра, микроконтроллер содержит подсистему ввода-вывода (GPIO, I2C, High Speed UART, DMA) и SRAM. Микроконтроллер имеет доступ ко всем портам GPIO в Edison Compute Module. Суммарный объем SRAM для кода и данных 192 кб. На микроконтроллере запущена операционная система реального времени Viper OS от компании WindRiver.

Приложение для микроконтроллера работает поверх ядра Viper и управляет периферией, подключенной к MCU, независимо от процессора Intel Atom. Например, оно может управлять GPIO портами, взаимодействовать с сенсорами по протоколу I2C или UART, и обмениваться данными с процессором Intel Atom.

Зачем нужен микроконтроллер в Intel Edison?


Я бы выделил две области, где можно применить встроенный микроконтроллер:

  1. Работа с портами ввода/вывода и интерфейсами с real-time откликом.
  2. Энергоэффективность.


Процессор Intel Atom и стандартный дистрибутив Yocto Linux не позволяют «из коробки» реализовать приложения с real-time откликом. Приложение может быть вытеснено планировщиком задач, что приведет к недопустимой и непрогнозируемой задержке. На микроконтроллере запущено единственное приложение и real-time операционная система, поэтому обеспечить real-time отклик возможно. Это требуется для работы со многими датчиками, где протокол взаимодействия зависит от строгого соблюдения коротких временных интервалов. Для их подключения без встроенного микроконтроллера пришлось бы использовать отдельный микроконтроллер, на котором реализовать всю функциональность по работе с такими датчиками. В качестве примера решения для Intel Edison с внешним микроконтроллером можно привести плату расширения SparkFun Block for Intel Edison — Arduino.

Повысить энергоэффективность с помощью микроконтроллера можно в тех приложениях, где основной процессор может находиться в состоянии сна, а микроконтроллер ожидать определенного события (например, превышения пороговых значений с сенсора).
При необходимости микроконтроллер пробуждает основной процессор. Пример реализации приведен в статье Using the MCU SDK and API: Code examples.

В качестве примера работы с микроконтроллером Intel Edison рассмотрим подключение ультразвукового датчика расстояния HC-SR04. Измеренное расстояние будем выводить на символьный экран Grove LCD RGB Backlight.

Ультразвуковой датчик расстояния HC-SR04


f4c05c68170140cab2b81385b35b0f20.jpg
Датчик имеет 4 вывода:

  • Vcc — 5V.
  • Trig — сигнал Trigger к датчику. Микроконтроллер подает 10 микросекундный импульс датчику. Датчик инициирует процесс замера.
  • Echo — сигнал Echo от датчика к микроконтроллеру. Длительность импульса пропорциональна измеренной дистанции.
  • Gnd — Земля.


Вот как выглядит процесс работы с датчиком на экране осциллографа:
3083c808d8f44f3a957ab84b46fef7a6.png

  • 1 канал — Trig
  • 2 канал — Echo


Микроконтроллер подает импульс на Trig. После этого датчик отвечает импульсом на Echo.
Длительность импульса пропорциональна измеренному расстоянию.
Измеренное расстояние вычисляется по формуле (взята из спецификации на датчик):

дистанция(см) = длительность импульса Echo (микросекунды) / 58


По спецификации датчик может замерять расстояния от 2 до 400 см.
Измерить длительность импульса с прогнозируемой погрешностью без real-time будет проблематично.
Процесс замера может быть, например, вытеснен планировщиком и результат измерения будет неверным.

Подключаем HC-SR04 к микроконтроллеру Intel Edison


a3a75f5cf2f14895a183d8fbb7670e1f.jpg

Используемые компоненты:

  • Edison Compute Module
  • Edison Arduino Board
  • Grove Basic Shield
  • Символьный экран Grove LCD RGB Backlight
  • Ультразвуковой датчик расстояния HC-SR04
  • Макетная плата


Первым делом подключаем Edison Compute Module к Edison Arduino board. Затем подключаем плату расширения Grove Basic Shield к Edison Arduino Board. Grove LCD RGB Backlight подключается к I2C разъему на Grove Basic Shield.

Ультразвуковой датчик расстояния HC-SR04 подключается к Grove Basic Shield следующим образом:

  • Vcc к +5V.
  • Trig к пину #3.
  • Echo к пину #4.
  • Gnd к Gnd.


Пины 3, 4 выбраны случайным образом, вместо них можно использовать другие.

Обновление прошивки Intel Edison


Поддержка микроконтроллера доступна в Intel Edison® Board Firmware Software Release начиная с версии 2.1. Если у вас прошивка старее, то её нужно обновить.

Узнать текущую версию прошивки можно командой:

# configure_edison --version


Данный пример создавался на прошивке версии 146.

Процесс обновления прошивки подробно описан в статье Flashing Intel Edison. Лично я обычно пользуюсь способом, описанным в разделе Alternate Flashing Method.
Внимательно прочитайте инструкцию перед прошивкой.

Подключаем Intel Edison через Ethernet-over-USB


Для работы с Edison из среды MCU SDK нужно создать сетевое подключение.
Для этого нужно, например, подключить USB кабель к среднему micro-USB порту (переключатель должен быть установлен в сторону micro-USB портов).
В Linux сеть настраивается командой:

# ifconfig usb0 192.168.2.2


IP-адрес Intel Edison: 192.168.2.15
Более подробно процесс подключения описывается в статье Connecting to your Intel® Edison board using Ethernet over USB.

MCU SDK


Для создания приложений, которые будут выполняться на встроенном микроконтроллере, выпущена кроссплатформенная среда разработки MCU SDK, основанная на Eclipse. Процесс установки подробно рассмотрен в статье Installing the MCU SDK.
MCU SDK позволяет создавать, компилировать, загружать на плату и отлаживать приложения для микроконтроллера.

Взаимодействие с MCU


Чтобы взаимодействовать с микроконтроллером из Linux доступны несколько интерфейсов:
/dev/ttymcu0 — Канал для обмена данными. Из Linux можно работать с помощью стандартных файловых операций. Из программы на микроконтроллере обмен производится с помощью функций host_send и host_receive.
/dev/ttymcu1 — Канал, по которому микроконтроллер отправляет отладочные сообщения функцией debug_print.
/sys/devices/platform/intel_mcu/log_level — Позволяет установить уровень отладочных сообщений (fatal, error, warning, info, debug).

Работа с портами Edison Arduino Board


Микроконтроллер встроен в Edison Compute Module и управляет портами ввода-вывода, размещенными на 70-выводном разъеме модуля.
Если необходимо использовать микроконтроллер c Edison Arduino Board, то нужно найти соответствие GPIO порта в Edison Compute Module номеру порта в Edison Arduino Board.
Затем нужно сконфигурировать мультиплексирование и установить направление в преобразователе логических уровней.
При работе с портами на Linux-уровне все эти действия выполняет библиотека MRAA. В случае с микроконтроллером об этом необходимо позаботиться самостоятельно с помощью скриптов (init_DIG.sh, init_i2c8.sh, init_mcu_PWM.sh, set_DIG.sh, read_DIG.sh, init_UART1.sh). Более подробная информация приведена в Intel® Edison Kit for Arduino* Hardware Guide (таблица 4).

Программа для Linux


Небольшой скрипт на Python, который будет получать данные от встроенного микроконтроллера и выводить их на символьный дисплей. Для работы с символьным дисплеем воспользуемся модулем Jhd1313m1 из библиотеки UPM.

Скрипт show_distance.py:
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)


Программа для микроконтроллера


Программа на микроконтроллере должна при получении от хоста команды get_distance произвести измерение дистанции и отправить результат на хост (дистанция в сантиметрах, либо -1 в случае ошибки).
Настраиваем порты на Edison Arduino Board:

./init_DIG.sh -o 3 -d output
./init_DIG.sh -o 4 -d input


Напомню, что микроконтроллер работает с GPIO портами на Edison Compute Module, которые отличаются от нумерации на Edison Arduino Board. Таблица соответствия приведена, например, в конце статьи Blinking an LED using the MCU.

Программа для микроконтроллера в MCU SDK:
#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);
                }
        }
}



Добавляем скрипт в автозапуск


Создаем файл, который будет запускать наш скрипт:

Файл /home/root/startup.sh
#!/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



Помечаем скрипты как исполняемые:

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


Так как Yocto Linux использует systemd, то для добавления скрипта в автозапуск нужно создать файл так называемого «сервиса».

Создаем файл /lib/systemd/system/startup-script.service
[Unit]
Description=Startup User Script
After=syslog.target

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

[Install]
WantedBy=multi-user.target


Добавляем скрипт в автозапуск:

# systemctl enable startup-script


После перезагрузки на символьном дисплее должна отобразиться измеренная дистанция:
b0d05c3991f84944b69faa6033ac0744.JPG

Использованные ресурсы


© Habrahabr.ru