Отладочная плата Arduino по цене приличного смартфона

Доброго времени суток, Хабровчане, сегодня речь пойдет о весьма не бюджетной мощной отладочной плате — Arduino Portenta H7. Статья будет обзорной и будет включать в себя описание платы и ее фич, возможные области применения, ну, а в конце напишем пару примеров под этого монстра.

Покупка

Началось все с того, что в один прекрасный зимний вечер от начальства мне поступило задание: «Необходимо приобрести вооот такую отладочную плату

b3205d276aeb3fec8c7a18fad48ec768.jpg

Не задавая лишних вопросов (т. к. это очередная новая игрушка для меня), полез на просторы интернета искать место, где можно бы заказать сие чудо. Первым делом, пошел на официальный сайт ардуины, где данная плата стоит около 100$, однако при попытке заказа в РФ, сайт выдает ошибку, мол «нельзя, извини, браток». Расстраиваться было рано, поэтому полез искать магазины-партнеры, однако и каждый партнер отказывался осуществлять доставку в Россию. Наконец, я вышел на три российских компании, у которых огромными буквами было написано, что они могут доставить в Россию, однако, цена была уже не такой приветливой: (вместо 100$ с официального сайта ~ 7000 руб., российские конторы предлагали купить за ~ 12000). Деньги казённые, так что экономить не имело смысла, и я сразу написал всем трем фирмам. При этом две из них сразу предложили оплатить заказ, но что-то меня предостерегло от этой глупости…. Ибо через неделю все три компании ответили, что «данный товар закончился», и они ничем мне не могут помочь. Однако, спустя еще неделю, представитель одной из компаний написал, что у них есть коллеги, у которых есть еще коллеги, у которых данный товар имеется в наличии (т. е. вы понимаете, как это звучит: «у меня есть друг, у которого есть друг, который знает одного человечка…»). При этом напрямую с этими людьми мне не давали связаться вплоть до момента оплаты. В конечном итоге, плату Arduino Portenta H7 я получил за 17000 руб. (цена весьма неплохого смартфона). На этом самая комичная часть статьи закончена, переходим к более серьезным вещам.

Краткое описание платы

Portenta H7 — пионер в семействе Portenta, предназначенная в основном для промышленного использования, однако, открытый исходный код и удобство использования Arduino позволяет применять ее где угодно.

Модель H7 оснащена двухъядерным процессором Arm Cortex ST, на котором «стоит» Mbed ОС. Mbed ОС — встроенная операционная система реального времени (RTOS), разработанная специально для микроконтроллеров, применяемых в IoT проектах.

Процессор

Особенность Arduino Portenta H7 заключается в одновременном выполнении как высокоуровневого кода с использованием Mbed API, так и поддержании работы с задачами в реальном времени. Т. к. оба ядра имеют полный доступ ко всей периферии, данная плата может спокойно выполнять:

Параллельность выполнения процессов обеспечивают двухъядерный процессор STM32H747, состоящий из Cortex-M7, которое работает при 480 МГц и M4, работающее при 240 МГц. Такая особенность реализует реальную параллельность выполнения программ, к примеру, выполнение Arduino-скетча и программы, написанной на MicroPython. При этом оба ядра свободно «общаются друг с другом» для обмена информацией.

Более того, H7 может работать и как простой встраиваемый микроконтроллер, и может быть использована в качестве главного процессора встраиваемого персонального компьютера.

Различные режимы энергосбережения платы позволяют моментально переключаться в наиболее оптимальные режимы работы для данного момента времени, что значительно снизит энергопотребление устройства.

Machine Learning

На H7 могут быть запущены проекты, написанные с использованием TensorFlow Lite, что реализует возможность запуска алгоритмов машинного обучения на микроконтроллере! При этом одно из ядер может взять на себя функции вычислительного ядра для TensorFlow Lite, в то время как второе будет управлять, например мотором, или производить передачу данных.

GPU

Да, все верно, STM32H747 содержит встроенный GPU (Chrom-ART Accelerator), который реализует, пожалуй, самую впечатляющую особенность Portnenta H7 — подключение внешнего монитора для создания встраиваемого персонального компьютера с графическим интерфейсом пользователя. Более того, чип плата содержит встроенный JPEG энкодер и декодер.

Протоколы передачи данных

Беспроводной модуль Murata 1DX позволяет одновременно управлять WiFi и Bluetooth подключениями, при этом WiFi может работать в режиме точки доступа, в режиме станции, а также в сдвоенном режиме, представляющем собой совокупность двух предыдущих. А скорость передачи данных может достигать 65 Мбит/с.

Bluetooth интерфейс поддерживает как BLE, так и Bluetooth Classic, что позволит применить данное чудо техники в IoT проектах. Про такие протоколы как UART, I2C, SPI, Ethernet, я думаю, говорить смысла нет: H7 поддерживает каждый из них.

Память

Внутренняя память состоит из 2 Мб флэш-памяти , и 1 Мб ОЗУ, разделенной следующим образом:

  • 192 кБ строго отведены для критических по длительности процедур

  • 64 кБ для инструкций

  • 128 кБ для хранения данных

  • 864 кБ пользовательской SRAM

  • 4 кБ для резервной копии SRAM

Также к данной модели можно присоединять дополнительную внешнюю SDRAM и QSPI Flash. Объем подключаемой SDRAM может достигать 64 Мб, напрямую отображаемых в адресном пространстве. QSPI Flash позволяет добавлять до 128 Мб, которые могут быть использованы для хранения данных или кода программы.

Шифрование данных

«На борту» H7 расположены два крипто-чипа: ATECC608A производства Microchip, и SE050C2 от компании NXP.

Ethernet Phy

Дополнительный физический интерфейс 10/100 Ethernet напрямую подключается к внутреннему MAC- адресу платы, обеспечивая полнодуплексную связь с автоматической поддержкой MDIX. А внешнее прерывание по Lan значительно снижает энергопотребление устройства в режиме ожидания.

На борту

Итак, по умолчанию Arduino Portenta H7 имеет в наличии:

  • Двухъядерный микроконтроллер STM32H747 (Cortex-M7, работающий при 480 МГц / M4, работающий при 240 МГц)

  • Графический аппаратный ускоритель Chrom-ART

  • Блок вычисления CRC

  • Встроенный JPEG кодек

  • Оперативная память — 8–64 Мб SDRAM

  • 2–128 Мб NOR Flash

  • 4 DMA контроллера, для облегчения «жизни» основного процессора

  • 1 высокоскоростной контроллер прямого доступа к памяти

  • Поддержка сетевых протоколов 10/100 Phy

  • Встроенный беспроводной модуль с поддержкой беспроводных протоколов BT5.0 и WiFi 802.11

  • Встроенный DisplayPort

  • USB type C

  • Антенна 2.4/5 ГГц

  • 22 таймера и watchdog-ов

  • 4 I2C интерфейса

  • 4 USART/UART — интерфейсов

  • 6 SPI

  • 8-ми битный интерфейс камеры

  • 3 16-ти битных АЦП, с поддержкой до 36 каналов, с поддержкой макс. скорости до 3.6 MSPS

  • 96-ти битный уникальный ID

  • и т.д.

Более того, плата может быть кастомизирована строго под ваш бюджет и нужды.

Набор всех фич просто не перечислить… Для более подробной информации можете ознакомиться с официальным сайтом Arduino: https://www.arduino.cc/pro/hardware/product/portenta-h7

Внешнее описание

Плата приходит в небольшой коробочке, задняя часть которой частично дублирует информацию из даташита.

Внешний вид коробки

f472d72c64d810c4c7be8e2db0e41c6e.jpg

Человеку, который за всю жизнь видел пока только китайские копии Arduino nano, и голые камни ATmega, мне было весьма приятно подержать в руках такое устройство.

Внешний вид платы Arduino Portenta H7

ab60a5e5896146922d63217584640520.jpg

Внешний вид платы с официального сайта

ae27883461f54b96585a0ecc8baa3e14.jpgcceac20cb19f3d04bb2647eb1d22cd6b.jpg

Физические размеры составляют: 66×25 мм.

Области применения

Если говорить о моей работе, то данный агрегат покупался для научно-исследовательских целей (если заинтересует наша деятельность — дайте знать, может в дальнейшем напишу статью о том, что именно мы делали).

Помимо научно-исследовательских целей, плата может найти широкое применение в качестве достаточно компактной системы с машинным обучением, например, вы захотели сделать систему распознавания лиц и приделать ее к домофону. В таком случае Portenta H7 — идеальный вариант.

Также, широкое распространение может получить прецизионное оборудование, в основу которого ляжет данная плата.

И в дополнение к вышесказанному, H7 может использоваться в очень ответственных устройствах, в качестве контроллеров для робототехники, а также в качестве вычислительного процессора для встраиваемых компьютеров. Ну, а основной задачей, согласно сайту является применение платы в производственных целях.

В общем — областей применения — тьма, тут уже кто на что горазд.

Написание классического blink

Вот мы и подходим к концу. Если вам не интересна эта часть, можете смело переходить к заключению. Или ко второму примеру, в котором мы будем работать с WiFi.

Здесь же мы подготовим полностью среду разработки Arduino IDE к работе с Arduino Portenta H7, и напишем классический пример мигания светодиодом (куда уж без этого всего), однако для этого задействуем оба ядра отладочной платы.

Итак, приступим.

Настройка IDE

Первым делом, нам необходимо подгрузить все библиотеки для работы с Portenta, для этого в IDE мы нажимаем Инструменты → Плата → Менеджер плат (Tools→Board→Board Manager)

Менеджер плат

image-loader.svg

В поисковике менеджера плат вбиваем »portenta», и затем выбираем »Arduino mbed-enabled Boards», выбираем необходимую версию (на момент моей работы это была версия 1.30), и скачиваем.

Скачивание ядра

image-loader.svg

Далее, после окончания загрузки можно переходить к программированию устройства.

Программирование Portenta H7

Писать мы будем классический blink, однако попробуем реализовать его на каждом из ядер по отдельности: т.е., к примеру раз в полсекунды светодиод будет моргать красным цветом, а раз в 200 мс — зеленым, при этом за другой цвет будет отвечать второе ядро.

Особенность Portenta H7 заключается в том, что код для каждого ядра можно написать в отдельном файле, а затем загрузить для каждого из ядер по отдельности (однако, если хочется, вместо «двухфайловой» прошивки можно сделать однофайловую). примеры обоих вариантов будут представлены ниже.

M7Blink


void setup() {
    // initialize digital pin LEDR as an output.
    bootM4(); //Waking up the M4 core
    pinMode(LEDR, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
   digitalWrite(LEDR, LOW); // turn the red LED on (LOW is the voltage level)
   delay(500); // wait for 500 milliseconds
   digitalWrite(LEDR, HIGH); // turn the LED off by making the voltage HIGH
   delay(500); // wait for 500 milliseconds
}

Код для моргания красным светодиодом на ядре M7

Вас может смутить, 4 строчка кода (bootM4()) (хотя по названию, в принципе, можно догадаться). Смысл этой строчки становится ясным после того, как мы узнаем каким образом происходит запуск микроконтроллера.

После подачи напряжения, стартует лишь ядро M7, в то время как M4 — спит. Следовательно, для того, чтобы код, написанный для M4 выполнялся, ядро M4 следует принудительно пнуть. Это собственно и достигается командой bootM4().

Далее нам следует написать код для второго ядра «M4Blink»:

M4Blink


void setup() {
    // initialize digital pin LEDG as an output.
    pinMode(LEDG, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
   digitalWrite(LEDG, LOW); // turn the LED on (LOW is the voltage level)
   delay(200); // wait for 200ms
   digitalWrite(LEDG, HIGH); // turn the LED off by making the voltage HIGH
   delay(200); // wait for 200ms
}

Код для моргания зеленым светодиодом на ядре M4

Далее, для загрузки обоих файлов в память МК нам необходимо подключить плату к компьютеру, далее пройтись по цепочке: Инструменты → Плата → Arduino Mbed OS Boards, и выбирать вначале M7 core.

Выбор ядра для загрузки прошивки

6a3f75683302d3ee9955a56f1d5070b4.PNG

Далее, выбираем COM порт, к которому подключена наша плата, и нажимаем «загрузить».

Выбор порта для загрузки проишвки

image-loader.svg

После успешной загрузки, необходимо повторить операцию для ядра M4, однако в цепочке Инструменты → Плата → Arduino Mbed OS Boards необходимо выбрать уже M4 core. При этом цепочка для выбора порта остается такой же, как и в предыдущем случае.

Выбор второго ядра для загрузки прошивки

82e05a9fb467e67cbfefffd1e561fd46.PNG

Если все сделано правильно, то встроенный светодиод на плате начнет моргать зеленым раз в 200 мс, а красным — раз в 500 мс. При наложении цветов, мы получим желтый цвет.

«Однофайловая» прошивка

Далее, приведу пример «однофайловой прошивки», которая не потребует раздельных файлов для разных ядер. Для такой прошивки используются директивы #ifdef, однако ими не стоит злоупотреблять, и большой код все-таки лучше разбить на два файла.

«Однофайловая прошивка»

int myLED;

void setup() {

 randomSeed(analogRead(0));

 #ifdef CORE_CM7
  bootM4();
  myLED = LEDR; // built-in blue LED10 #endif11
 #endif

  #ifdef CORE_CM4
   myLED = LEDG; // built-in greeen LED
  #endif

 pinMode(myLED, OUTPUT);
}

void loop() {
 digitalWrite(myLED, LOW); // turn the LED on
 delay(200);
 digitalWrite(myLED, HIGH); // turn the LED off
 delay( rand() % 2000 + 1000); // wait for a random amount of time between 1 and 3 seconds.
}

Данный код стоит загрузить по отдельности в каждое из ядер платы. Встроенный светодиод будет мигать разными цветами в промежутке времени от 1 до 3 секунд, где время срабатывания определяется функцией рандомных чисел.

Использовать такую плату для моргания светодиодами, ну как то неправильно что ли… Если тема будет интересна, то в дальнейшем, напишем уже нормальные примеры для параллельных процессов.

Далее, будет приведен еще один пример, взятый с оф. сайта Arduino: мы превратим нашу Portenta H7 в WiFi точку доступа.

WiFi Hotspot

В данном примере мы напишем программу, которая сделает из нашей платы WiFi точку доступа, которая будет работать в качестве сервера, выдающего HTML страничку, содержащую три кнопки, по нажатию на которые, будет изменяться свет встроенного в плату светодиода. Итак, приступим.

Код

WiFiServer

#include 
#include "arduino_secrets.h"

///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID;    // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;             // your network key Index number (needed only for WEP)

int status = WL_IDLE_STATUS;

WiFiServer server(80);				//Server port = 80	

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  
  Serial.println("Access Point Web Server");

  pinMode(LEDR,OUTPUT);
  pinMode(LEDG,OUTPUT);
  pinMode(LEDB,OUTPUT); 

  // by default the local IP address of will be 192.168.3.1
  // you can override it with the following:
  // WiFi.config(IPAddress(10, 0, 0, 1));

  if(strlen(pass) < 8){    
    Serial.println("Creating access point failed");
    Serial.println("The Wi-Fi password must be at least 8 characters long");
    // don't continue
    while(true);
  }
    
  // print the network name (SSID);
  Serial.print("Creating access point named: ");
  Serial.println(ssid);

  //Create the Access point
  status = WiFi.beginAP(ssid,pass);
  if(status != WL_AP_LISTENING){
    Serial.println("Creating access point failed");
    // don't continue
    while (true);
  }

  // wait 10 seconds for connection:
  delay(10000);

  // start the web server on port 80
  server.begin();

  // you're connected now, so print out the status
  printWiFiStatus();
  
}

void loop() {

 // compare the previous status to the current status
  if (status != WiFi.status()) {
    // it has changed update the variable
    status = WiFi.status();

    if (status == WL_AP_CONNECTED) {
      // a device has connected to the AP
      Serial.println("Device connected to AP");
    } else {
      // a device has disconnected from the AP, and we are back in listening mode
      Serial.println("Device disconnected from AP");
    }
  }

  WiFiClient client = server.available();   // listen for incoming clients

  if (client) {                             // if you get a client,
    Serial.println("new client");           // print a message out the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
  
    while (client.connected()) {            // loop while the client's connected
     
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        if (c == '\n') {                    // if the byte is a newline character

          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println();

            // the content of the HTTP response follows the header:
            client.print("");
            client.print("");
            client.print("

LED CONTROLS

"); client.print("

RED LED

"); client.print("ON OFF"); client.print("

GREEN LED

"); client.print("ON OFF"); client.print("

BLUE LED

"); client.print("ON OFF"); client.print(" "); // The HTTP response ends with another blank line: client.println(); // break out of the while loop: break; } else { // if you got a newline, then clear currentLine: currentLine = ""; } } else if (c != '\r') { // if you got anything else but a carriage return character, currentLine += c; // add it to the end of the currentLine } // Check to see if the client request was "GET /H" or "GET /L": if (currentLine.endsWith("GET /Hr")) { digitalWrite(LEDR, LOW); // GET /Hr turns the Red LED on } if (currentLine.endsWith("GET /Lr")) { digitalWrite(LEDR, HIGH); // GET /Lr turns the Red LED off } if (currentLine.endsWith("GET /Hg")){ digitalWrite(LEDG, LOW); // GET /Hg turns the Green LED on } if (currentLine.endsWith("GET /Lg")){ digitalWrite(LEDG, HIGH); // GET /Hg turns the Green LED on } if (currentLine.endsWith("GET /Hb")){ digitalWrite(LEDB, LOW); // GET /Hg turns the Green LED on } if (currentLine.endsWith("GET /Lb")){ digitalWrite(LEDB, HIGH); // GET /Hg turns the Green LED on } } } // close the connection: client.stop(); Serial.println("client disconnected"); } } void printWiFiStatus() { // print the SSID of the network you're attached to: Serial.print("SSID: "); Serial.println(WiFi.SSID()); // print your Wi-Fi shield's IP address: IPAddress ip = WiFi.localIP(); Serial.print("IP Address: "); Serial.println(ip); // print where to go in a browser: Serial.print("To see this page in action, open a browser to http://"); Serial.println(ip); }

Код достаточно простой и легко читается, однако все оригинальные комментарии сохранены.

А работает он по следующему принципу: после нажатия на определенную кнопку, телефон посылает Get запрос на сервер, в сообщение указываются параметры H/L (High/Low), R/G/B (Red/Green/Blue), после получения всей последовательности, сервер (Portenta H7) включает/выключает необходимый светодиод и переходит в режим ожидания следующего сообщения.

Создатели кода рекомендуют хранить SSID и пароль точки доступа в отдельном файле. Для этого необходимо нажать на стрелочку под порт монитором в Arduino IDE. Ввести имя файла »arduino_secrets.h».

Создание нового файла

2464021caae24fcd4da37ac701f4a10a.PNG

А в сам файл стоит добавить следующие две строчки, которые будут содержать SSID и пароль точки доступа.

# define SECRET_SSID "PortentaAccessPoint" //You could put your own SSID
# define SECRET_PASS "123Qwerty"					//And password

Ну, а далее остается лишь зашить прошивку в плату. Заливать прошивку стоит также как и в предыдущем примере, а в качестве ядра выбрать M7.

Ошибки

Ошибка создания точки доступа

5fb018a7e3a4cbc2548e99f5c72f1bb1.PNG

Для устранения такой ошибки надо зайти в Файл → Примеры → отлистать до Arduno Portenta → WiFi → PortentaWiFiFirmwareUpdater, и загрузить выбранный файл в микроконтроллер.

После успешного обновления, необходимо опять загрузить нашу прошивку для сервера на Portenta H7.

Подключение к точке доступа

После успешной прошивки, следует открыть порт монитор, и дождаться сообщения о готовности токи доступа.

Сообщение о готовности точки доступа

89dbabad73330c92f2e1e3407ca356b6.PNG

Далее, после подключения устройства (в моем случае — это смартфон) необходимо в строке браузера выполнить подключение (отправку Get запроса) к нашему серверу по его ip адресу.

HTML страница нашего сервера

27d17baf0bc9dcf22aaa1fb4bccc6657.jpg

А для управления светодиодами, стоит нажимать на кнопки on/of у соответствующих цветов. При этом на Portenta H7 будут приходить сообщения, которые будут также отображаться в порт мониторе.

Отправка запросов на сервер

5b80df14902a3db0cbf741a33f6e6033.PNG

Собственно на этом, данный пример завершен.

Заключение

В общем то и все. В данной статье я провел обзор новой платы производства Arduino, рассмотрел некоторые из ее особенностей, привел области применения такого устройства, и познакомил читателя с настройкой IDE для работы с данной платой.

Если данная тема понравится, то в дальнейшем могу разобрать более детально некоторые из фич платы, а плюсом и написать более интересные программы. Да и к тому же, сам хотел бы более подробно разобраться с этим девайсом (раз уж дали такую игрушку). В общем, жду ваших комментариев.

Всем спасибо, до новых встреч!

© Habrahabr.ru