.NET nanoFramework — это бесплатная платформа с открытым исходным кодом, основанная на .NET и предназначена для малых встраиваемых устройств, микроконтроллеров. С её помощью можно разрабатывать различные устройства для Интернета вещей, носимые устройства, научные приборы, робототехнические устройства, можно создавать прототипы и даже использовать на промышленном оборудовании. В первой части мы познакомились с платформой .NET nanoFramework, её архитектурой, основными возможностями, посмотрели примеры программного кода. Теперь перейдем к практике, установим nanoFramework на микроконтроллеры серии ESP32 и STM32, напишем первый «Hello World!», поработаем с аппаратными интерфейсами, и оценим переносимость кода с «большого» .NET на платформу nanoFramework.
Оглавление
- Для кого предназначена платформа nanoFramework?
- Поддержка устройств
- Библиотеки классов
- Драйвера датчиков
- Установка расширения
- Загрузка среды nanoFramework в микроконтроллер ESP-WROOM-32
- Создание первого приложения
- Мигаем встроенным светодиодом
- Использование событий, устройство — кнопка
- Загрузка среды nanoFramework в микроконтроллер ST Nucleo64 F411RE
- Запуск тестового примера со светодиодом и кнопкой на ST Nucleo64 F411RE
- Подключение датчика BME280 к шине I2C
- Сравнение переносимости кода между проектами .NET IoT для Linux и nanoFramework
- Итог
- Что дальше?
- Дополнение. Отладочная плата TTGO T-Energy с модулем ESP32-WROVER-B
- Ресурсы
Для кого предназначена платформа nanoFramework?
Сейчас на рынке представлено большое количество самых разнообразных микроконтроллеров. Одна из самых известных на сегодняшний день это платформа Arduino, которая использует язык программирования C/C++. По степени удобства, легкости, простоте, nanoFramework ничуть не уступает платформе Arduino. Несмотря на небольшой возраст, nanoFramework уже работает на многих микроконтроллерах, с поддержкой отладки кода и точками останова в удобной IDE MS Visual Studio. nanoFramework просто идеальное решение для существующих .NET разработчиков, которые не хотят останавливаться на достигнутом и им тоже интересна разработка для Интернета вещей (IoT). Ведь все что необходимо знать и уметь для программирования на nanoFramework, они уже знают и умеют. Программный код и библиотеки в большой степени переносимы один-к-одному, только необходимо учитывать малый объем RAM и низкую производительность процессора.
Отладка кода приложения на nanoFramework в Visual Studio 2019
Платформа nanoFramework отлично подходит и для сферы обучения. Нет ничего лучше, чем научиться разрабатывать приложения на C# для микроконтроллеров, где у тебя нет гигабайтов оперативной памяти и n-количества ядер процессора, вот тут начинаешь серьезно задумываться над оптимизацией алгоритмов.
И конечно nanoFramework подойдет всем тем, кто стремится к творчеству и хочет сделать свою жизнь более интересной и разнообразной, добавить в неё автоматизацию, роботов, и ИИ. Финансовые затраты для начала работы с nanoFramework составят не более стоимости чашки «кофа» в Starbucks (при условии покупки микроконтроллера ESP32). Для разработки используется бесплатная версия Visual Studio 2019 Community Edition. Все что от вас требуется, это терпение и упорство.
С момента публикации первой части прошло более полугода, с того времени произошли серьезные изменения. Первое, команда разработчиков обновила логотип. Шутка, на самом деле его действительно обновили, но ещё добавили новые функции и существенно расширили поддержку различных микроконтроллеров.
Рассмотрим некоторые микроконтроллеры для платформы nanoFramework.
Поддержка устройств
Поддерживаемые устройства делятся на две категории: основные платы и поддерживаемые сообществом (дополнительная ссылка — GitHub nanoframework/nf-Community-Targets). В зависимости от устройства будут доступны все или только некоторые сборки (.NET Assemblies). При выборе обращайте внимание на поддерживаемые функции, такие как: Gpio, Spi, I2c, Pwm, Adc, Dac, Serial, OneWire, CAN, Events, SWO, Networking, Large Heap и UI. Например, работа с графическими дисплеями в серии модулей ESP32 будет доступна только на тех, в состав которых входит память PSRAM(Pseudo static RAM).
Модуль ESP-WROOM-32 — самое простое и доступное решение для начала осваивания nanoFramework. На основе данного модуля построена отладочная плата ESP32 DevKit v1, стоимостью до $3.65. В основе модуля чип SoC ESP32-D0WDQ6 от компании Espressif, в него входит 2-ядерный 32-битный процессор Tensilica Xtensa LX6 с блоками памяти ROM на 448 КБ и SRAM на 520 КБ. На кристалле расположены беспроводные модули Wi-Fi/Bluetooth, датчик Холла и сенсор температуры, доступны интерфейсы: ШИМ, АЦП, ЦАП, I2C, SPI, UART/Serial, I2S. Дополнительно модуль содержит Flash-память на 4 МБ.
Отладочная плата ESP32 DevKit v1
При выборе модуля, возможно, вы встретите обозначение не ESP-WROOM-32, а
ESP32-WROOM-32U или ESP32-WROOM-32D. Разница заключается в следующем:
- ESP32-WROOM-32U — модуль ESP-WROOM-32 с подключением внешней антенны;
- ESP32-WROOM-32D — модуль ESP-WROOM-32 c встроенной антенной в виде змейки на самой плате.
Важно! Обычно на отладочной плате с модулем ESP-WROOM-32 размещают две кнопки EN и Boot. Кнопка EN — перезагрузка, Boot — ручной перевод микроконтроллера в режим загрузки прошивки. При нажатие кнопки Boot, контакт GPIO0 на микроконтроллере замыкается на Землю(GND), и в терминале можно увидеть следующий текст:
ets Jun 8 2016 00:22:57 rst:0x1 (POWERON_RESET),boot:0x7 (DOWNLOAD_BOOT(UART0/UART1/SDIO_REI_REO_V2)) waiting for download
Кнопки EN и Boot на плате с модулем ESP-WROOM-32
У некоторых пользователей модулей ESP-WROOM-32 без кнопки Boot, исходя из сообщений на форумах, возникают проблемы с переключением микроконтроллера в режим прошивки, поэтому лучше приобретайте модули с наличием кнопки Boot на плате. Но это касается модулей первой версии/ревизии, в третьей ревизии для прошивки нажимать кнопку Boot не обязательно. Далее этот момент будет подробно рассмотрен в пункте выбора прошивки.
Недавно команда разработчиков nanoFramework сообщила, что следующие прошивки для устройств ESP32 будут основаны на системе сборки ESP-IDF 4.3.1. Это означает поддержку микроконтроллеров всей серии ESP32, включая: ESP32_S2, ESP32_S3, ESP32_C3 (RISC-V). Новая система сборки позволяет легко добавлять новые библиотеки и функции в nanoFramework, которые доступны или предоставляются ESP-IDF. Теперь у двухъядерных чипов ESP32 задействованы оба ядра для работы кода. Был успешно перенесен компонент mbedTLS из ESP-IDF без потери оптимизации и использования аппаратных блоков (криптографические вычисления, генерации случайных чисел и т. д.). Конфигурация сети, профили Wi-Fi, CA корневые сертификаты и сертификаты устройств X509 теперь доступны для использования также на всей серии ESP32 устройств.
Если вам не хватает количества контактов GPIO, то можно выбрать один из микроконтроллеров поддерживаемых сообществом — STM32. Например, отладочная плата ST Nucleo64 F411RE на базе SoC Cortex-M4@100 MHz с блоками памяти ROM на 512 КБ и SRAM на 128 КБ. Дополнительно на плате размещены контакты для подключения Arduino-совместимых модулей. По стоимости плата уже существенно дороже ESP32, на торговых площадках продается от $29 и выше.
Библиотеки классов
В связи с малыми аппаратными возможностями микроконтроллеров, в отличие от .NET IoT, у каждого класса библиотек есть соответствующий Nuget пакет. Все пакеты добавляются с помощью системы Nuget , как это принято в .NET Core. Рассмотрим подробно библиотеки классов для представления возможностей платформы. Все библиотеки делятся на общие для всех устройств и на специальные, предназначенные для конкретных микроконтроллеров или серии устройств. Классы, имеющие название, например System.Device.Gpio совместимы с .NET IoT для Linux, а с названием Windows.Device.Gpio совместимы с Windows IoT Core. Полный список библиотек в документации
Class Libraries. Documentation — nanoFramework.
Библиотеки .NET nanoFramework (xlsx, pdf)
Библиотека класса /название Nuget пакета | Описание |
Базовые (Bases) | |
Base Class Library (nanoFramework.CoreLibrary) | известный как mscorlib, базовый класс для платформы |
nanoFramework.Runtime.Events (nanoFramework.Runtime.Events) | поддержка событий |
nanoFramework.Runtime.Native (nanoFramework.Runtime.Native) | поддержка низкоуровневых функций, таких как управление сборщиком мусора (GC — garbage collection), электропитание, часы реального времени и получение системной информации об устройстве |
System.Threading (nanoFramework.System.Threading) | поддержка многопоточности |
System.Math (nanoFramework.System.Math) | поддержка математических функций |
System.Text (nanoFramework.System.Text) | поддержка кодирования/декодирования текста и класса StringBuilder |
System.Text.RegularExpressions (nanoFramework.System.Text.RegularExpressions) | поддержка регулярных выражений |
System.Collections (nanoFramework.System.Collections) | поддержка коллекций: ArrayList, Dictionary, Queue (очередь), Stack (стек). Так же поддерживается работа через интерфейсы: Ienumerable, Ienumerator и т. д. |
nanoFramework.Json (nanoFramework.Json) | сериализация/десериализация в JSON |
nanoFramework.ResourceManager (nanoFramework.ResourceManager) | управление ресурсами приложения |
Microsoft.Extensions.Logging (nanoFramework.Logging) | логирование (совместим с Microsoft.Extensions.Logging) |
Аппаратные интерфейсы (Hardware interfaces) | |
System.Device.Gpio (nanoFramework.System.Device.Gpio) | поддержка управления контактами GPIO (general-purpose input/output) |
Windows.Device.Gpio (nanoFramework.Windows.Devices.Gpio) | поддержка управления контактами GPIO (general-purpose input/output) |
System.Device.Dac (nanoFramework.System.Device.Dac) | поддержка ЦАП (цифро-аналогового преобразователя), digital-to-analog converter,DAC |
Windows.Devices.Adc (nanoFramework.Windows.Devices.Adc) | поддержка АЦП (аналого-цифрового преобразователя), analog-to-digital converter, ADC |
System.Device.I2c (nanoFramework.System.Device.I2c) | поддержка протокола I2C (Inter-Integrated Circuit) — последовательная шина данных для связи интегральных схем, использующая две двунаправленные линии связи (SDA и SCL). |
Windows.Devices.I2c (nanoFramework.Windows.Devices.I2c) | поддержка протокола I2C (Inter-Integrated Circuit) — последовательная шина данных для связи интегральных схем, использующая две двунаправленные линии связи (SDA и SCL). |
System.Device.Spi (nanoFramework.System.Device.Spi) | поддержка шины SPI (Serial Peripheral Interface). Подключаются высокоскоростные устройства такие как LCD дисплеи, сетевые карты, и т. д. |
Windows.Devices.Spi (nanoFramework.Windows.Devices.Spi) | поддержка шины SPI (Serial Peripheral Interface). Подключаются высокоскоростные устройства такие как LCD дисплеи, сетевые карты, и т. д. |
nanoFramework.Devices.OneWire (nanoFramework.Devices.OneWire) | поддержка протокола OneWire, можно подключить например датчик температуры DS18B20 |
System.IO.Ports (nanoFramework.System.IO.Ports) | поддержка последовательных портов COM |
Windows.Devices.SerialCommunication (nanoFramework.Windows.Devices.SerialCommunication) | поддержка последовательных портов COM |
System.Device.Pwm (nanoFramework.System.Device.Pwm) | поддержка ШИМ (широтно-импульсной модуляции), pulse-width modulation PWM. Используется для управления яркости LCD дисплеев, и регулирования скорости работы двигателей |
Windows.Devices.Pwm (nanoFramework.Windows.Devices.Pwm) | поддержка ШИМ (широтно-импульсной модуляции), pulse-width modulation PWM. Используется для управления яркости LCD дисплеев, и регулирования скорости работы двигателей |
nanoFramework.Devices.Can (nanoFramework.Devices.Can) | поддержка протокола CAN (Controller Area Network) — это промышленный стандарт, позволяющий осуществить объединение в единую сеть различных узлов, механизмов, датчиков и т. п. |
Сеть (Networking) | |
Windows.Devices.WiFi (nanoFramework.Windows.Devices.WiFi) | поддержка протокола Wi-Fi. Доступно сканирование точек доступа (AP) и подключение к ним |
System.Net (nanoFramework.System.Net) | поддержка сети. Доступна работа с DNS, веб-прокси, поддерживаются сокеты и SSL-шифрование |
System.Net.Http (nanoFramework.System.Net.Http) | поддержка http-протокола |
System.Net.Http.Client (nanoFramework.System.Net.Http.Client) | поддержка http клиента |
System.Net.WebSockets (nanoframework.System.Net.WebSockets) | поддержка WebSocket |
System.Net.Http.Server (nanoFramework.System.Net.Http.Server) | поддержка http сервера. Можно создать свой Web-сервер для обеспечения удаленного управления устройством |
nanoFramework.WebServer (nanoFramework.WebServer) | «упрощенная версия» ASP.NET, REST API |
nanoFramework.Networking (nanoFramework.Networking.Sntp) | поддержка клиента протокола SNTP (Simple Network Time Protocol), позволяет удаленно управлять устройством по данному протоколу, поддержка является де-факто стандартом для коммутаторов, маршрутизаторов, концентраторов и т. д. |
nanoFramework.Azure.Devices (nanoFramework.Azure.Devices.Client) | клиент Azure IoT Devices |
Хранение данных (Storage) | |
System.IO.FileSystem (nanoFramework.System.IO.FileSystem) | поддержка файловых систем, работа с microSD и MMC памятью |
Windows.Storage (nanoFramework.Windows.Storage) | поддержка хранения файлов на носителях |
Windows.Storage.Streams (nanoFramework.Windows.Storage.Streams) | классы потоковой записи/чтения данных на носитель |
Графический интерфейс (GUI) | |
nanoFramework.Graphics (nanoFramework.Graphics) | поддержка вывода графики на дисплей и UI |
System.Drawing (nanoFramework.System.Drawing) | работа с графикой |
Аппаратно-зависимые (Hardware dependent) | |
nanoFramework.Hardware.Esp32 (nanoFramework.Hardware.Esp32) | аппаратные функции Esp32 такие, как управление режимами засыпания устройства |
nanoFramework.Hardware.Esp32.Rmt (nanoFramework.Hardware.Esp32.Rmt) | поддержка удаленного управления RMT (Remote Control) |
nanoFramework.M5Stack (nanoFramework.M5Stack) | аппаратные функции M5Stack, такие как управление встроенным LCD |
nanoFramework.Hardware.Stm32 (nanoFramework.Hardware.Stm32) | аппаратные функции Stm32 |
nanoFramework.Hardware.TI (nanoFramework.Hardware.TI) | аппаратные функции TI(Texas Instruments) такие как управление электропитанием |
nanoFramework.TI.EasyLink (nanoFramework.TI.EasyLink) | аппаратные функции TI EasyLink |
Сторонние (Third party) | |
Amqp.* (AMQPNetLite.nanoFramework) | поддержка протокола AMQP (Advanced Message Queuing Protocol) для брокеров-сообщений, например для RabbitMQ |
Amqp.* (AMQPNetMicro.nanoFramework) | поддержка протокола AMQP (Advanced Message Queuing Protocol) для брокеров-сообщений, например для RabbitMQ |
nanoFramework.M2Mqtt (nanoFramework.m2mqtt) | поддержка протокола MQTT. Протокол обмена сообщениями по шаблону издатель-подписчик (pub/sub) |
Драйвера датчиков
Многие датчики, используемые для подключения к Arduino, также поддерживаются платформой, среди них: акселерометры, газоанализаторы, замер уровня освещения, барометры, термометры, инфракрасные датчики, гироскопы, компасы, драйверы двигателей, NFC-модули и т. д.
Полный список поддерживаемых датчиков представлен в документации List and category of devices. Devices — nanoFramework. С примерами GitHub nanoFramework.IoT.Device/devices.
Установка расширения
Для разработки приложений для nanoFramework потребуется Microsoft Visual Studio Community 2019 Version 16.11, установленная платформа .NET, ОС Windows 10 (в Windows 7 не открывается панель Device Explorer). Расширение устанавливается стандартно, через меню: Extensions -> Manage Extensions. Название расширения: .NET nanoFramework VS2019 Extension.
Расширение nanoFramework для Microsoft Visual Studio
После установки расширения появится окно Device Explorer (меню View -> Other Windows -> Device Explorer). В этом окне наиболее важные всего три кнопки: Ping Device, Device Capabilities, Erase App.
Панель Device Explorer расширения nanoFramework
Команды:
- Ping Device — проверяет доступность подключенного устройства/микроконтроллера;
- Device Capabilities — выводит в консоль список возможностей устройства;
- Erase App — удаляет загруженное приложение (nanoFramework остается на месте).
Загрузка среды nanoFramework в микроконтроллер ESP-WROOM-32
Для возможности исполнения .NET кода на микроконтроллере, необходимо его прошить соответствующей прошивкой nanoFramework. Прошивка осуществляется с помощью утилиты nanoFirmwareFlasher. Установим драйвера для микроконтроллера, утилиту и прошьем устройство.
Шаг 1 — Установка драйвера для моста CP2102 USB to UART
Если при подключении отладочной платы ESP32 DevKit v1 по USB вы видите, что в Диспетчере устройств микроконтроллер находится в узле Другие устройства, значит необходимо установить драйвер.
Загружаем драйвер с официального сайта CP210x USB to UART Bridge VCP Drivers и устанавливаем. После установки драйвера, микроконтроллер доступен на порту COM3.
Шаг 2 — Установка утилиты nanoFirmwareFlasher
Теперь устанавливаем утилиту nanoFirmwareFlasher, для этого запускаем командную строку от имени Администратора и выполняем команду:
dotnet tool install -g nanoff
Для вызова справки выполнить команду:
nanoff --help
Обновление утилиты выполняется следующей командой:
dotnet tool update -g nanoff
Шаг 3 — Вывод идентификационной информации для отладочной платы
Иногда бывает сложно понять, какой перед тобой микроконтроллер из серии ESP32, особенно если он пришел с китайской площадки. Поэтому до прошивки можно вывести идентификационную информацию на экран командой:
nanoff --platform esp32 --serialport COM3 --devicedetails
где параметр —platform указывает на Target платформы, —serialport — номер COM порта, в данном случае COM3.
Результат выполнения команды:
Идентификационная информация отладочной платы
Когда будет появляться фиолетовая строка «*** Hold down the BOOT/FLASH button in ESP32 board ***«, то в этот момент необходимо нажать на плате кнопку Boot, иначе команда не выполнится.
Из вывода видим, что на плате установлен чип ESP32-D0WDQ6 с 4 Мб Flash памяти, на борту есть Wi-Fi и BT.
Шаг 4 — Выбор прошивки
Теперь переходим к самому сложному шагу. Для серии ESP32 существует несколько различных прошивок (ESP32 Firmware versions). Espressif выпускает чипы SoC, затем на их основе формирует модули. Обратимся к описанию ESP32-S Series на официальном сайте. Модули серии ESP32 выпускаются на базе чипов:
- ESP32-D0WD-V3 (третья версия/ревизия);
- ESP32-D0WD (первая версия/ревизия — старый вариант);
- ESP32-D0WDQ6 (первая версия/ревизия — старый вариант);
- и другие.
Чипы ESP32-D0WD и ESP32-D0WDQ6 по функциональности ничем не отличаются, различие заключается только в форм-факторе самого чипа.
Рассмотрим различия между модулями. Существуют модули версии ESP32-WROOM и ESP32-WROVER, эти модули выпускаются как на базе ESP32-D0WD-V3, так и на ESP32-D0WD. Модуль ESP32-WROVER отличается от ESP32-WROOM только наличием памяти PSRAM. PSRAM — это дополнительный напаянный чип RAM помимо встроенной памяти. Обычно указывается в описании к плате и бывает размером 2 или 8 Мб. Дополнительная оперативная память необходима, если подключаете дисплей для вывода UI используя WPF (поддерживается в модулях ESP-WROVER-KIT с LCD ILI9341 на SPI интерфейсе).
Доступные прошивки (target) nanoFramework:
- ESP32_REV0 — (DEV) подходит для всех плат ESP32 без поддержки PSRAM;
- ESP32_REV3 — (DEV) подходит для всех плат ESP32 с чипом ESP32 версии/ревизии 3 без поддержки PSRAM;
- ESP32_PSRAM_REV0 — (DEV) подходит для всех плат ESP32 с поддержкой PSRAM;
- ESP32_PSRAM_REV3 — (DEV) подходит для всех плат ESP32 с чипом ESP32 версии/ревизии 3 и поддержкой PSRAM;
- ESP32_WROOM_32 — подходит для всех плат ESP32 c поддержкой PSRAM, но не поддерживает Bluetooth BLE из-за ограничений памяти в разделе IRAM, вызванных исправлениями PSRAM;
- ESP32_WROOM_32_BLE — подходит для всех плат ESP32, поддерживает Bluetooth BLE, но PSRAM отключен;
- ESP32_WROOM_32_V3_BLE — подходит для всех плат ESP32 с чипом ESP32 версии/ревизии 3, одновременно поддерживается PSRAM и Bluetooth BLE;
- ESP32_PSRAM_REV3_ILI9341 — (упоминается в документации, но прошивка не найдена) подходит для всех плат ESP32 с чипом ESP32 версии/ревизии 3 и поддержкой PSRAM, включает драйвер для LCD ILI9341;
- ESP32_PSRAM_REV3_ILI9342 — (упоминается в документации, но прошивка не найдена) подходит для всех плат ESP32 с чипом ESP32 версии/ревизии 3 и поддержкой PSRAM, включает драйвер для LCD ILI9342;
- ESP_WROVER_KIT — специальный вариант для отладочной платы ESP WROVER KIT. Включает в себя функции UI, поддержку PSRAM и драйвер для SPI LCD ILI9341;
- ESP32_PICO — подходит для всех плат ESP32 с ESP32 PICO без поддержки PSRAM, например ESP32-PICO-KIT и M5Stack ATOM;
- ESP32_PICO_ST7735S — (упоминается в документации, но прошивка не найдена) подходит для платы ESP32 PICO, включает драйвер для LCD ST7735S;
- ESP32_PICO_ST7789V — (упоминается в документации, но прошивка не найдена) подходит платы для M5Stick C Plus, включает драйвер для LCD ST7789V;
- ESP32_REV0_ILI9342 — (упоминается в документации, но прошивка не найдена) подходит платы для M5Stack, включает драйвер для ILI9342;
- ESP32_LILYGO — специальный вариант для отладочной платы LilyGO ESP32, включает поддержку Ethernet PHY.
Перенесем из документации сводную таблицу основных прошивок с описанием опций:
Название прошивки | Wi-Fi | Ethernet | Bluetooth | PSRAM(Large heap) | ESP32 version |
---|---|---|---|---|---|
WROOM_32 | ✔️ | ✔️ | 0 -> 3 | ||
WROOM_32_BLE | ✔️ | ✔️ | 0 -> 3 | ||
WROOM_32_V3_BLE | ✔️ | ✔️ | ✔️ | version 3 only | |
ESP_WROVER_KIT | ✔️ | ✔️ 2Mb heap + Graphics | 0 -> 3 | ||
EP32_PICO | ✔️ | ✔️ | 0 -> 3 | ||
ESP32_LILYGO | ✔️ | ✔️ | ✔️ | 0 -> 3 |
- Отладочная плата построена на чипе ESP32-D0WDQ6, первой ревизии;
- Включена поддержка Wi-Fi, BT;
- Модуль PSRAM недоступен.
Исходя из полученной информации, подойдут прошивки: ESP32_REV0 и ESP32_WROOM_32_BLE. Из двух прошивок выбираем ESP32_WROOM_32_BLE, т. к. поддержка Bluetooth BLE будет не лишней.
Если вы не знаете какую прошивку выбрать, то подойдет универсальная прошивка ESP32_REV0 и ESP32_PSRAM_REV0.
Полный каталог прошивок представлен в Repository: nanoframework-images. Список прошивок только для серии Espressif ESP32 Series. Общий список прошивок GitHub nanoframework/nf-interpreter.
Шаг 5 — Прошивка ESP-WROOM-32
Для прошивки необходимо подключить отладочную плату и выполнить команду:
nanoff --update --target ESP32_WROOM_32_BLE --serialport COM3
где параметр —target указывает на идентификатор прошивки, —serialport — номер COM порта, в данном случае COM3.
Результат выполнения команды:
Если прошивка не загрузится с репозитория, то можно повторить операцию или её загрузить со страницы ESP32_WROOM_32_BLE, и распаковать, например по пути: «c:\nanofw». В архиве будет несколько файлов:
Распакованная прошивка для ESP-WROOM-32
Для прошивки устройства, используя локальную прошивку, выполнить команду:
nanoff --update --clrfile "C:\nanofw\nanoCLR.bin" --serialport COM3
где параметр —clrfile — путь к файлу nanoCLR.bin, —serialport — номер COM порта, в данном случае COM3.
Не забываем во время прошивки нажимать на кнопку «Boot». Устройство готово для загрузки .NET программ!
Создание первого приложения
Запустим Visual Studio 2019 Community Edition и откроем окно Device Explorer. Выполним команду Device Capabilities. В результате выполнения команды в консоль будет выведена информация о возможностях микроконтроллера.
Информация о возможностях ESP-WROOM-32
Из полученных данных наиболее важен список Native Assemblies. Данный список содержит сборки, которые мы можем использовать в своем проекте, все остальные библиотеки необходимо включать в проект в виде исходного кода. Дополнительно можно сформировать прошивку со своими нативными сборками на C++, но как это сделать будет в продолжении.
Создадим новое приложение, выберем тип проекта: Blank Application (nanoFramework).
Шаблон проекта Blank Application (nanoFramework)
Шаблонный проект выведет отладочное сообщение в консоль.
Шаблонный проект nanoFramework
Запустим проект на отладку
В окне отладки будет выведено сообщение: «Hello from nanoFramework!».
Отлично, первое приложение запущено! Далее, запустим стандартную программу мигания светодиодом.
Мигаем встроенным светодиодом
На плате ESP32 DevKit v1 размещён встроенный светодиод, подключенный к контакту GPIO2. Запустим программу Blink, аналогичную как на Arduino. Для этого создадим новый проект nanoframework-esp32-blink, и добавим Nuget-пакет: nanoFramework.System.Device.Gpio. Исходный код возьмем из проекта GitHub nanoframework/Samples — Blinky.
Файл Program.cs.
public class Program { private static GpioController s_GpioController; public static void Main() { s_GpioController = new GpioController(); // ESP32 DevKit: 4 is a valid GPIO pin in, some boards // like Xiuxin ESP32 may require GPIO Pin 2 instead. GpioPin led = s_GpioController.OpenPin(2,PinMode.Output); led.Write(PinValue.Low); while (true) { led.Write(PinValue.High); Thread.Sleep(1000); led.Write(PinValue.Low); Thread.Sleep(1000); } } }
Разберем пример:
- s_GpioController = new GpioController() — инициализирует объект контроллера доступа к GPIO;
- GpioPin led = s_GpioController.OpenPin(2,PinMode.Output) — метод OpenPin переводит контакт GPIO2 в режим вывода;
- led.Write(PinValue.Low) — подает логический «0» на контакт;
- led.Write(PinValue.High) — логическая «1», подано напряжение в 3.3V.
Демонстрация работы программного кода:
Любой устройство взаимодействует с внешним миром и нуждается в управление, теперь добавим кнопку и реализуем новую логику.
Использование событий, устройство — кнопка
К микроконтроллеру подключим кнопку и реализуем следующую логику: встроенный светодиод загорается и остается в положение включено при удержании нажатой кнопки. При отпускание кнопки светодиод гаснет. Светодиод будем использовать тот же, контакт GPIO2. Кнопку подключим к контакту GPIO25, на плате обозначен как «D25«. Создадим новый проект nanoframework-esp32-button, и добавим Nuget-пакет: nanoFramework.System.Device.Gpio.
Отладочная плата ESP32 DevKit v1 с подключенной кнопкой
Схема подключения кнопки к контакту D25 отладочной платы ESP32 DevKit v1 (fzz)
Файл Program.cs.
using System; using System.Diagnostics; using System.Threading; using System.Device.Gpio; namespace nanoframework_esp32_button { public class Program { //Board: ESP32 DevKit static GpioController s_GpioController; static int s_BluePinNumber=2; static int s_UserButtonPinNumber=25; public static void Main() { s_GpioController = new GpioController(); //setup blue LED s_GpioController.OpenPin(s_BluePinNumber, PinMode.Output); s_GpioController.Write(s_BluePinNumber, PinValue.Low); //setup user button s_GpioController.OpenPin(s_UserButtonPinNumber, PinMode.Input); //s_GpioController.OpenPin(s_UserButtonPinNumber, PinMode.InputPullUp); //Event registration s_GpioController.RegisterCallbackForPinValueChangedEvent( s_UserButtonPinNumber, PinEventTypes.Falling | PinEventTypes.Rising, UserButton_ValueChanged); //Infinite Thread.Sleep(Timeout.Infinite); } private static void UserButton_ValueChanged(object sender, PinValueChangedEventArgs e) { // read Gpio pin value from event Debug.WriteLine("USER BUTTON (event) : " + e.ChangeType.ToString()); Debug.WriteLine("USER BUTTON (event) : " + ((((int)e.ChangeType) == 1) ? "Rising" : "Falling")); //if (e.ChangeType != PinEventTypes.Rising) //for DFRobot if (e.ChangeType == PinEventTypes.Rising) { s_GpioController.Write(s_BluePinNumber, PinValue.High); } else { s_GpioController.Write(s_BluePinNumber, PinValue.Low); } } } }
Разберем пример:
- s_GpioController.OpenPin(s_UserButtonPinNumber, PinMode.Input) — открывает контакт кнопки и выставляет режим работы на ввод (сигнал поступает от кнопки). Если необходимо исключить считывание внешних наводок, то можно использовать подтяжку к питанию PinMode.InputPullUp (не все контакты ввода поддерживают);
- s_GpioController.RegisterCallbackForPinValueChangedEvent — обработка прерывания реализуется путем добавление Callback на изменение состояние контакта. Callback регистрируется в контроллере GPIO. Указываем номер контакта — s_UserButtonPinNumber, событие срабатывание — Falling (изменение с «1» на «0») или Rising (изменение с «0» на «1»), название функции обработки — UserButton_ValueChanged.
Демонстрация работы программного кода:
Основной принцип работы с nanoFramework понятен, теперь вернемся к микроконтроллеру ST Nucleo64 F411RE и, прошьем его средой nanoFramework, и запустим простую программу использующую светодиод и кнопку.
Загрузка среды nanoFramework в микроконтроллер ST Nucleo64 F411RE
Шаг 1 — Подключение ST Nucleo64 F411RE
До подключение микроконтроллеров STM32 необходимо установить драйвер для отладчика/программатора ST-Link, для этого устанавливаем драйвер ST-LINK USB driver signed for Windows 7-10 и подключаем устройство. После подключения в Диспетчере устройств должно появиться устройство ST-Link Debug.
Выполним команду обнаружения устройств ST-Link:
nanoff --listjtag
Результат выполнения команды:
Обнаруженные устройства ST-Link
Если плата появилась в списке, то можно переходить к следующему шагу.
Шаг 2 — Обновление прошивки ST-Link
Если мы попытаемся загрузить nanoFramework в микроконтроллер, то возможно появится подобная ошибка, которая говорит о необходимости обновления прошивки ST-Link Debug.
Сообщение о необходимости обновления прошивки ST-Link Debug
Загружаем и запускаем STM32 ST-LINK utility. Выбираем в меню ST-LINK -> Firmware update.
Нажимаем на кнопку Device Connect, затем Yes >>>>
Если прошивка успешно загрузиться будет сообщение Update succesfull.
Если на этом этапе возникнут трудности, то можете посмотреть видео-инструкцию ST Link Update — Web learning.
Шаг 3 — Прошивка ST Nucleo64 F411RE
Для прошивки необходимо выполнить команду:
nanoff --update --target ST_NUCLEO64_F411RE_NF --jtag
где параметр —target указывает на идентификатор прошивки ST_NUCLEO64_F411RE_NF.
Теперь запустим Visual Studio Community и выполним команду Device Capabilities.
Информация о возможностях ST Nucleo64 F411RE
Из полученных данных видно, что nanoCLR работает на ChibiOS v21.6.
Запуск тестового примера со светодиодом и кнопкой на ST Nucleo64 F411RE
В отличие от ESP32, на плате дополнительно ещё размещена кнопка, которую можно программировать под свои задачи. Светодиод на плате обозначен меткой LD2 (Green LED), кнопка — B1 (USER). Добавим немного другую логику работы отличную от примера для ESP32, встроенный светодиод загорается и выключается по нажатию на кнопку.
Светодиод LD2 (Green LED) и кнопка B1 USER на плате ST Nucleo64 F411RE
Создадим новый проект nanoframework-stm32-button, и добавим Nuget-пакет: nanoFramework.Windows.Devices.Gpio. Обратите внимание, пакет отличается от предыдущего примера, название — nanoFramework.Windows.*. Как было сказано выше, API библиотек в которых присутствует Windows.*, совпадают с .NET на Windows IoT Core, которая работает на Raspberry Pi. Поэтому возьмем готовый код Push button — Raspberry Pi, с сайта MS. Из изменений в коде будут только другие номера контактов (c Raspberry Pi не совпадают).
Светодиод LD2 (Green LED) подключен к контакту Arduino D13, что соответствует STM32 I/O PA5 (pin 21). Контакт кнопки B1 USER соответствует STM32 I/O PC13 (pin 2). В STM32 принято обращение к контактам по названию. Контакт PA5, где P— port, A-литера порта, 5 — номер контакта. Поэтому в программный код дополнительно будет добавлена функция конвертации буквенного обозначения контактов в номерной — int PinNumber(char port, byte pin). Описание контактов GitHub nanoframework/nf-Community-Targets/ChibiOS/ST_NUCLEO64_F411RE_NF/.
Файл Program.cs.
using System; using System.Diagnostics; using System.Threading; using Windows.Devices.Gpio; namespace nanoframework_stm32_button { public class Program { private static int LED_PIN; private static int BUTTON_PIN; private static GpioPin ledPin; private static GpioPin buttonPin; private static GpioPinValue ledPinValue = GpioPinValue.High; public static void Main() { // ST Nucleo64 F411RE: PA5 is LED_GREEN LED_PIN = PinNumber('A', 5); // ST Nucleo64 F411RE: PC13 is B1_USER BUTTON_PIN = PinNumber('C', 13); //Next as .NET for Raspberry Pi, Windows IoT Core //Controller var gpio = new GpioController(); //Init ledPin = gpio.OpenPin(LED_PIN); ledPin.SetDriveMode(GpioPinDriveMode.Output); buttonPin = gpio.OpenPin(BUTTON_PIN); buttonPin.SetDriveMode(GpioPinDriveMode.Input); // Initialize LED to the OFF state by first writing a HIGH value // We write HIGH because the LED is wired in a active LOW configuration ledPin.Write(ledPinValue); // Check if input pull-up resistors are supported if (buttonPin.IsDriveModeSupported(GpioPinDriveMode.InputPullUp)) buttonPin.SetDriveMode(GpioPinDriveMode.InputPullUp); else buttonPin.SetDriveMode(GpioPinDriveMode.Input); // Set a debounce timeout to filter out switch bounce noise from a button press buttonPin.DebounceTimeout = TimeSpan.FromMilliseconds(50); // Register for the ValueChanged event so our buttonPin_ValueChanged // function is called when the button is pressed buttonPin.ValueChanged += buttonPin_ValueChanged; //Infinite Thread.Sleep(Timeout.Infinite); } static void buttonPin_ValueChanged(object sender, GpioPinValueChangedEventArgs e) { Debug.WriteLine("USER BUTTON (event) : " + ((e.Edge ==GpioPinEdge.RisingEdge)? "RisingEdge" : "FallingEdge")); // toggle the state of the LED every time the button is pressed if (e.Edge == GpioPinEdge.FallingEdge) { ledPinValue = (ledPinValue == GpioPinValue.Low) ? GpioPinValue.High : GpioPinValue.Low; ledPin.Write(ledPinValue); } } static int PinNumber(char port, byte pin) { if (port < 'A' || port > 'J') throw new ArgumentException(); return ((port - 'A') * 16) + pin; } } }
Разберем пример:
- int PinNumber(char port, byte pin) — функция конвертации буквенного обозначения контактов в номерной;
- gpio.OpenPin(LED_PIN) — открывает контакт для его использования;
- ledPin.SetDriveMode(GpioPinDriveMode.Output) — установка направления работы контакта — вход/выход (GpioPinDriveMode.Input/GpioPinDriveMode.Output);
- ledPin.Write(ledPinValue) — подает логический «0»GpioPinValue.Low или «1»(GpioPinValue.High) на контакт;
- buttonPin.IsDriveModeSupported(GpioPinDriveMode.InputPullUp) — проверка наличия подтягивающего резистора (pull-up);
- buttonPin.SetDriveMode(GpioPinDriveMode.InputPullUp) — включение режима работы контакта на ввод с поддержкой pull-up;
- buttonPin.DebounceTimeout — интервал в течение которого не будут регистрироваться события (необходимо для исключения дребезга контактов);
- buttonPin.ValueChanged — подпись на событие изменения состояния;
- void buttonPin_ValueChanged — функция, которая вызывается при изменение состояния кнопки. Свойство e.Edge принимает значение GpioPinEdge.RisingEdge(изменение с «0» на «1»), или GpioPinEdge.FallingEdge (изменение с «1» на «0»).
Демонстрация работы программного кода:
Подключение датчика BME280 к шине I2C
Модуль BME280 фирмы Bosch Sensortec предназначен для измерения атмосферного давления, температуры и влажности. По сравнению с первыми датчиками серии (BMP085 и BMP180), он имеет лучшие характеристики и меньшие размеры. Отличие от датчика BMP280 – наличие гигрометра, что позволяет измерять относительную влажность воздуха и создать на его основе маленькую метеостанцию.
Назначение контактов:
- VCC — питание модуля 3.3 В или 5 В;
- GND — Ground;
- SCL — линия тактирования (Serial CLock);
- SDA — линия данных (Serial Data).
Модуль работает по двухпроводному интерфейсу I2C, адрес по умолчанию 0x76. Данный датчик уже был использован в проекте Метеостанция на Banana Pi M64 (Linux, C#, Docker, RabbitMQ, AvaloniaUI), поэтому детальнее ознакомится с характеристиками и шиной I2C можно по вышеуказанной ссылке. Подключим датчик BME280 к отладочной плате ESP32 DevKit v1.
Отладочная плата ESP32 DevKit v1 с датчиком BME280
Схема подключения BME280 к шине I2C отладочной платы ESP32 DevKit v1 (fzz)
Создадим новый проект nanoframework-esp32-bme280, и добавим для работы с шиной I2C Nuget-пакет: nanoFramework.System.Device.I2c. Драйвер для работы с BME280 возьмем с каталога драйверов nanoFramework.IoT.Device — BMxx80 Device Family. Перенесем драйвер в папку /libs/. Дополнительно команда разработчиков nanoFramework для работы с физическими величинами используют библиотеку UnitsNet.
Файл Program.cs. Инициализация датчика BME280.
// when connecting to an ESP32 device, need to configure the I2C GPIOs // used for the bus Configuration.SetPinFunction(21, DeviceFunction.I2C1_DATA); Configuration.SetPinFunction(22, DeviceFunction.I2C1_CLOCK); // bus id on the MCU const int busId = 1; I2cConnectionSettings i2cSettings = new(busId, Bme280.SecondaryI2cAddress); using I2cDevice i2cDevice = I2cDevice.Create(i2cSettings); using Bme280 bme80 = new Bme280(i2cDevice) { // set higher sampling TemperatureSampling = Sampling.LowPower, PressureSampling = Sampling.UltraHighResolution, HumiditySampling = Sampling.Standard, }; // set this to the current sea level pressure in the area for correct altitude readings Pressure defaultSeaLevelPressure = WeatherHelper.MeanSeaLevel;
Разберем пример:
- Configuration.SetPinFunction(21, DeviceFunction.I2C1_DATA) — функция из пространства имен nanoFramework.Hardware.Esp32. В связи с работой nanoFramework на различных микроконтроллерах, например для работы с I2C, требуется дополнительное конфигурирования контактов. В данном случае для шины I2C с идентификатором «1», передача данных DATA определяется на GPIO21;
- busId = 1 — идентификатор шины I2C — 1;
- new I2cConnectionSettings(busId, Bme280.SecondaryI2cAddress) — создание конфигурации устройства I2C, указывается идентификатор шины I2C и адрес устройства(0x76);
- I2cDevice.Create(i2cSettings) — создание I2C устройства;
- new Bme280(i2cDevice) — инициализация датчика BME280;
- TemperatureSampling, PressureSampling, HumiditySampling — указание точности измерений физических величин;
- WeatherHelper.MeanSeaLevel — для определения уровня высоты указывается точка отсчета от уровня моря.
Файл Program.cs. Чтение данных с датчика BME280.
// Perform a synchronous measurement var readResult = bme80.Read(); // Note that if you already have the pressure value and the temperature, you could also calculate altitude by using // var altValue = WeatherHelper.CalculateAltitude(preValue, defaultSeaLevelPressure, tempValue) which would be more performant. bme80.TryReadAltitude(defaultSeaLevelPressure, out var altValue); Debug.WriteLine($"Temperature: {readResult.Temperature.DegreesCelsius}\u00B0C"); Debug.WriteLine($"Pressure: {readResult.Pressure.Hectopascals}hPa"); Debug.WriteLine($"Altitude: {altValue.Meters}m"); Debug.WriteLine($"Relative humidity: {readResult.Humidity.Percent}%");
Разберем пример:
- bme80.Read() — чтение показаний датчика;
- bme80.TryReadAltitude — получение значения высоты над уровнем моря;
- readResult.Temperature, readResult.Pressure, readResult.Humidity — получение данных температуры, давления, влажности.
Запустим проект:
Чтение данных с датчика BME280 на nanoFramework
Для вывода данных планировалось подключить OLED-дисплей SSD1306 с разрешением 128х64 точек. Но как оказалось не все так просто. Существует два варианта данного дисплея, только с шиной I2C и шиной I2C/SPI. Именно второй вариант был приобретен. Особенностью управления по шине I2C варианта I2C/SPI являлось наличие дополнительного контакта для инициализации. Была перенесена логика инициализации с примера для Arduino, но видимо что-то пошло не так и инициализация не удалась. Поэтому при использовании в проектах nanoFramework подключайте SSD1306 только с шиной I2C (драйвер — SSD13xx & SSH1106 OLED display family). Вместо датчика BME280 можно использовать альтернативный более простой BMP180 — barometer, altitude and temperature sensor.
Сравнение переносимости кода между проектами .NET IoT для Linux и nanoFramework
Основой для nanoFramework послужил проект .NET Micro Framework, который впоследствии Microsoft прекратила развивать. Компания GHI Electronics единственная продолжательница исходного .NET Micro Framework сохранившая преемственность старого кода. Разработчики nanoFramework поступила иначе, они взяли главную идею и структуру внутренней реализации, но откинув прошлое, реализовали платформу совместимую по интерфейсам API с «большим» фреймворком .NET IoT. Это сразу решило множество задач:
- Разработчики решений .NET IoT могут писать код для nanoFramework без необходимости переучивания;
- Драйвера к датчикам из .NET IoT практически без изменений можно перенести в nanoFramework;
- Объединенная кодовая база дает двойное преимущество. В одном устройстве можно реализовать сопряжение одноплатного компьютера и микроконтроллера используя платформу .NET с общими классами.
В связи с малыми ресурсами микроконтроллеров, 100% переносимости кода не будет, но вычислительные способности микроконтроллеров растут, и с расчетом на будущее, совместимость потенциально может только возрасти.
В качестве примера проверки совместимости, для проекта на .NET IoT был взял драйвер/класс кнопки Button (nanoFramework.IoT.Device), позволяющий подписываться на события одиночного и двойного клика, с фильтрацией дребезга кнопки. Классы драйвера Button в проект dotnet-iot-button-from-nanoframework были перенесены без какого либо изменения, располагаются по пути /libs/Button/.
Кнопка для проекта dotnet-iot-button-from-nanoframework
Кнопка подключена на контакт GPIO38 одноплатного компьютера Banana Pi BPI-M64, как и в проекте Управляем контактами GPIO из C# .NET 5 в Linux на одноплатном компьютере Banana Pi M64 (ARM64) и Cubietruck (ARM32). В Program.cs добавим следующий код:
Файл Program.cs.
//for Linux const int GPIOCHIP = 1; const int BUTTON_PIN = 38; GpioController controller; var drvGpio = new LibGpiodDriver(GPIOCHIP); controller = new GpioController(PinNumberingScheme.Logical, drvGpio); // Initialize a new button with the corresponding button pin GpioButton button = new(buttonPin: BUTTON_PIN,controller); Debug.WriteLine("Button is initialized, starting to read state"); ....
Единственное отличие от nanoFramework, исключая другие номера контактов, заключается в выборе драйвера для доступа к GPIO. В ОС в качестве драйвера можно выбирать: LibGpiodDriver, RaspberryPi3Driver и SysFsDriver. Далее со строки GpioButton button = new(buttonPin: BUTTON_PIN,controller), все вызовы функций в исходном коде не отличаются от реализации для nanoFramework. Все работает без исключений!
Запуск проекта в Visual Studio Code с драйвером Button из nanoFramework в проекте .NET IoT для Linux
Возможно один небольшой проект не будет репрезентативной выборкой, но команда разработчиков nanoFramework уже достигла впечатляющих результатов. Сам факт возможности переноса кода существенно расширяет сферы использования платформы nanoFramework.
Итог
В свое время проект Arduino взорвал рынок программирования для микроконтроллеров, в одно мгновение выяснилось, что для управления контактами GPIO, работы с шиной I2C и сетью, не требуется мозга размером с вселенную. Разрабатывать небольшие устройства могут и школьники, то что раньше было просто невозможно, оказалось вполне себе реализуемым. Большой популярностью Arduino обязан двум вещам, это скрытие сложной внутренней реализации без ущерба функциональности управления устройством и легкости программирования, используя Arduino IDE. Проект nanoFramework достиг той же высоты. Теперь до прошивки устройства, вы можете выяснить спецификацию и выбрать подходящую прошивку. Процесс прошивки не требует особых познаний, главное установить драйвера для моста UART и вовремя нажимать на кнопку Boot, а в некоторых случаях и этого не требуется. Для написания кода необходимо установить бесплатную Visual Studio 2019 Community и расширение .NET nanoFramework VS2019 Extension. В Visual Studio доступна интерактивная отладка с просмотром содержимого переменных, что более чем достаточно для комфортного кодинга. Управление устройствами в nanoFramework так же удобно, как и в решение GHI Electronics, за исключение работы не ниже ОС Windows 10.
Сама платформа nanoFramework дает возможность работы с различными микроконтроллерами, скрывая всю сложную реализацию. Причем если используете микроконтроллеры на ChibiOS, то на уровне ОС можете реализовать модули требующие более быстрого отклика, и вызывать необходимые функции ОС из nanoFramework, сочетая быструю скорость вместе с удобным программирование на C#.
Проект nanoFramework быстро развивается, поэтому документирование новых функций пока не поспевает за темпами разработки. Из отрицательных моментов, не понравилась структура проектов-драйверы для датчиков — GitHub nanoFramework.IoT.Device/devices. Драйверы ссылаются на классы из папки /src/, которые можно было разместить в общих сборках для nanoFramework. Это несколько ломает красивую структуру. Некоторые драйверы (для BME280), содержат лишние зависимости пакетов, например на — Nerdbank.GitVersioning. Это удобно, если вы занимаетесь тестирование и сборкой проектов для CI и публикации, но если вам необходимо просто скачать и добавить драйвер для своего проекта под ESP32, то это лишние проблемы и сложности, в особенности для новичков.
Очень порадовало существенное расширение перечня микроконтроллеров серии ESP32. Теперь вы можете выбрать себе отладочную плату на свой вкус и цвет.
Что дальше?
Одной из сильных сторон nanoFramework заключается в отличной поддержки сетевых протоколов из коробки. Даже есть «упрощенная версия» ASP.NET — библиотека nanoFramework.WebServer. Создание Wi-Fi сканера, Web API, отправка данных в облако, работа с брокерами сообщений RabbitMQ, будет в продолжении. И конечно же подключим LCD экран для интерактивного взаимодействия с устройством.
Дополнение. Отладочная плата TTGO T-Energy с модулем ESP32-WROVER-B
Когда пост уже был закончен пришла отладочная плата на базе модуля ESP32-WROVER-B. Полное наименование платы — LILYGO TTGO T-Energy ESP32 8MByte PSRAM WiFi & Bluetooth Module 18650 Battery ESP32-WROVER-B Development Board.
Идентификационная информация отладочной платы
На скриншоте можно увидеть наименование чипа ESP32-D0WD-V3 последней версии/ревизии чипа ESP32. Утилита почему-то не распознала наличие PSRAM в модуле объемом 8 Мбайт.
Обсуждение на Habr.com
Ресурсы
- .NET NANOFRAMEWORK — Making it easy to write C# code for embedded systems
- GitHub nanoFramework
- Документация nanoFramework
- API Docs .NET nanoFramework
- .NET nanoFramework — платформа для разработки приложений на C# для микроконтроллеров
- Samples — nanoFramework
- Драйверы к датчикам, дисплеям, модулям — nanoFramework.IoT.Device
- nanoFirmwareFlasher — allows flashing a .NET nanoFramework target with nanoBooter, nanoCLR, managed application or backup files
- Отладочные платы поддерживаемые сообществом — nf-Community-Targets
- Репозиторий сообщества. Драйверы, расширения, утилиты, демонстрации функций