До недавнего времени разрабатывать IoT приложения на C# можно было только для компьютеров построенных на архитектуре ARM или x86. Поддержка RISC-V процессоров для платформы .NET уже давно в стадии разработки. В начале этого года был представлен не официальный .NET 8.0 SDK, который уже сейчас вы сможете запустить на RISC-V процессоре под ОС Debian/Ubuntu. В качестве платформы запуска возьмем одноплатный компьютер Sipeed Lichee RV на RISC-V процессоре Allwinner D1 (ядро Alibaba/T-Head Xuantie C906 RISC-V). В первой части поста рассмотрим установку .NET 8.0 SDK на Sipeed Lichee RV. Во второй, запустим приложение для работы с контактами GPIO и датчиком BME280 для замера температуры, влажности и давления.
❯ Предыстория
Первоначальная работа по портированию платформы .NET для RISC-V архитектуры началась в 2023 году инженером Dong-Heon Jung из Samsung. Тогда платформа .NET максимум, что могла выполнить, это вывести «helloworld». Сейчас CoreCLR позволяет выполнять многие вещи, но пока все работает достаточно медленно. В текущие планы портирования не входит JIT оптимизация, функций SIMD, главное это выполнение любого кода. Основная ветка обсуждения процесса портирования RISC-V support #36748.
❯ Подготовка образа
Для Sipeed Lichee RV необходимо загрузить образ от Олега, одного из ведущих мейнтейнеров проекта Armbian. В ветке обсуждения можно отслеживать последние изменения. На данный момент порт работает на платах Nezha D1 и Lichee RV (Dock).
- Для платы Nezha D1 поддерживается: HDMI, LAN, USB, аналоговый вывод через 3.5 jack;
- Для платы Lichee RV Dock поддерживается: HDMI, WiFi, USB, USB-LAN.
Образы можно скачать по ссылке. Все дальнейшие работы выполнялись на образе Armbian_23.09_Nezha_lunar_current_6.1.0.img.xz от 2023.09.30. Образ построен на Ubuntu 23.04 (lunar), ядро Linux 6.1.0-rc3-d1.
Для запуска потребуется micro-SD карта и программа balenaEtcher, с помощью которой образ записывается на карту-памяти.
Armbian — это самый популярный дистрибутив Linux, предназначенный для одноплатных компьютеров построенных на ARM процессоре, список поддерживаемых плат огромен: Orange Pi, Banana Pi, Odroid, Olimex, Cubietruck, Roseapple Pi, Pine64, NanoPi и др.
Первый запуск Armbian сопровождается инициализацией системных настроек, в рамках которых необходимо ответить на несколько вопросов связанных с конфигурацией системы.
❯ Установка .NET 8.0 SDK на Sipeed Lichee RV
Готовая сборка опубликована на GitHub dkurt/dotnet_riscv. Вы можете установить SDK, так и отдельно Runtime среду исполнения AspNetCore и NETCore. Для RISC-V архитектуры определен RID: linux-riscv64.
Установку выполним в каталог /usr/share/dotnet. Скрипт для установки:
$ export INSTALLPATH=/usr/share/dotnet
$ sudo apt-get update
$ sudo apt-get install -y wget tar
$ wget -O dotnet-sdk-riscv64.tar.gz "https://github.com/dkurt/dotnet_riscv/releases/download/v8.0.100/dotnet-sdk-8.0.100-linux-riscv64.tar.gz"
$ sudo mkdir -p $INSTALLPATH
$ sudo tar -xf dotnet-sdk-riscv64.tar.gz -C "$INSTALLPATH" --checkpoint=.100
$ rm dotnet-sdk-riscv64.tar.gz
$ sudo ln -s $INSTALLPATH/dotnet /usr/bin/dotnet
По итогу установки отобразим информацию об SDK:
root@nezha:~# dotnet --info
.NET SDK:
Version: 8.0.100
Commit: 57efcf1350
Workload version: 8.0.100-manifests.6c33ef20
Runtime Environment:
OS Name: ubuntu
OS Version: 23.04
OS Platform: Linux
RID: linux-riscv64
Base Path: /usr/share/dotnet/sdk/8.0.100/
.NET workloads installed:
Workload version: 8.0.100-manifests.6c33ef20
There are no installed workloads to display.
Host:
Version: 8.0.0
Architecture: riscv64
Commit: 5535e31a71
.NET SDKs installed:
8.0.100 [/usr/share/dotnet/sdk]
.NET runtimes installed:
Microsoft.AspNetCore.App 8.0.0 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.NETCore.App 8.0.0 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
...
Теперь можно запускать .NET приложения c помощью команды dotnet myapp.dll.
❯ Создание первого приложения
Создадим первое приложение DotnetConsoleAppCoreCLRInfo.
$ dotnet new console -n DotnetConsoleAppCoreCLRInfo
Перейдем в каталог DotnetConsoleAppCoreCLRInfo и заменим код в Program.cs на следующий:
using System;
using System.Runtime.InteropServices;
namespace DotnetConsoleAppCoreCLRInfo
{
class Program
{
static void Main(string[] args)
{
//Runtime Info
Console.WriteLine(".NET console application!");
bool isMono = typeof(object).Assembly.GetType("Mono.RuntimeStructs") != null;
//output
Console.WriteLine($"Hello World {(isMono ? "from Mono!" : "from CoreCLR!")}");
Console.WriteLine(typeof(object).Assembly.FullName);
Console.WriteLine(System.Reflection.Assembly.GetEntryAssembly ());
Console.WriteLine($".NET version: {RuntimeInformation.FrameworkDescription}");
Console.WriteLine($"OS architecture: {RuntimeInformation.OSArchitecture}");
Console.WriteLine($"OS Id: {RuntimeInformation.RuntimeIdentifier}");
Console.WriteLine("Successfully!");
}
}
}
Запустим приложение командой:
$ dotnet run
Запуск приложения DotnetConsoleAppCoreCLRInfo
В программном коде выполняется проверка окружения «Mono.RuntimeStructs», Mono или CoreCLR. Еще до портирования .NET на RISC-V можно было запускать программы под Mono в режиме работы ОС поверх гипервизора RISC-V Open Source Supervisor Binary Interface (OpenSBI). Процесс восстановления зависимостей и компиляции занял ~8 минут. Если код компилировать локально на x86, то процесс существенно ускоряется.
Приложение dotnet-iot-coreclr-info-riscv64 на GitHub — .NET IoT Samples.
❯ Работа с контактами GPIO
На несущей Dock плате для Lichee RV выведен разъем GPIO на 40-pins с шагом 2,54 мм частично совместимый с аналогичным разъемом Raspberry Pi, так же присутствуют линии питания на 3.3V и 5V, но некоторые выводы GND не соответствуют выводам на Raspberry Pi.
- Подключим светодиод к контакту с номером линии 144, метка PE16.
Для управления контактами GPIO используется библиотека Libgpiod. Библиотека Libgpiod позволяет работать с контактами GPIO одноплатного компьютера из .NET среды исполнения, она может быть установлена на Linux (Armbian). Библиотека не является аппаратно-зависимой, что позволяет ее использовать на различных одноплатных компьютерах архитектуры ARM32, ARM64, RISC-V и x86. Как работать с GPIO рекомендуется ознакомиться с публикацией Программирование на Python и установка Docker для Sipeed Lichee RV RISC-V.
Теперь необходимо установить библиотеку Libgpiod версии 1.6.4, несмотря на наличие последней версии 2.1.1. Начиная с версии 2.0 для библиотеки libgpiod требуется интерфейс uAPI v2 GPIO символьных устройств, который впервые был добавлен в ядро Linux 5.10. Соответственно изменились вызовы интерфейсов. Поддержка второй версии Commit Add libgpiodv2 support (#2184) уже внесена в библиотеку System.Device.Gpio, но еще не вышел новый релиз с дополнениями.
Скрипт установки библиотеки libgpiod и утилит для x86/ARM32/ARM64/RISC-V:
$ sudo apt-get update
$ sudo apt-get install -y curl
$ curl -SL --output setup-libgpiod.sh https://raw.githubusercontent.com/devdotnetorg/docker-libgpiod/dev/setup-libgpiod.sh
$ chmod +x setup-libgpiod.sh
$ sudo ./setup-libgpiod.sh
Рекомендуется вариант установки из бинарников (4) Installation from binaries.
Создадим новое приложение DotnetBlinkLEDApp по аналогии как в предыдущем варианте и заменим код в Program.cs на следующий:
using System;
using System.Device.Gpio;
using System.Device.Gpio.Drivers;
using System.Threading;
namespace DotnetBlinkLEDApp
{
class Program
{
static void Main(string[] args)
{
/*Blink an LED
*
https://docs.microsoft.com/en-us/dotnet/iot/tutorials/blink-led
*
*/
Console.WriteLine("Blinking LED.");
//for Linux
//Board: Lichee RV.
//https://habr.com/ru/companies/timeweb/articles/649327/
//Pin: PE16.
//GPIOCHIP = 0, LED_PIN = 144
const int GPIOCHIP = 0;
const int LED_PIN = 144;
GpioController controller;
var drvGpio = new LibGpiodDriver(GPIOCHIP);
controller = new GpioController(PinNumberingScheme.Logical, drvGpio);
controller.OpenPin(LED_PIN, PinMode.Output);
controller.Write(LED_PIN,PinValue.Low);
bool ledOn = false;
const int count=5;
for(int i=1;i<count;i++)
{
Console.WriteLine($"Step: {i} of {count}");
controller.Write(LED_PIN, ((ledOn) ? PinValue.High : PinValue.Low));
Console.WriteLine($"LED: {((ledOn) ? "High" : "Low")}");
Thread.Sleep(100);
ledOn = !ledOn;
}
}
}
}
После запуска приложения светодиод должен мигать, но с большей задержкой, чем указано в программном коде из-за медленной работы CoreCLR.
Приложение dotnet-iot-blink-riscv64 на GitHub — .NET IoT Samples.
❯ Подключение датчика Bosh BME280
Датчик BME280 компании Bosch Sensortec используется для замера физических величин, таких как температура, влажность, атмосферное давление, подключается по шине I2C. В образе уже включена шина I2C. Контакты для подключения шины I2C:
- Контакт PB1 — линия SDA (Serial Data) — эта линия отвечает непосредственно за передаваемые данных;
- Контакт PB0 — линия SCL (Serial Clock) — эта линия отвечает за синхронизацию соединения.
Для проверки включения шины I2C необходимо выполнить команду:
$ ls -l /sys/bus/i2c/devices/i2c-*
Проверка включения шины I2C:
root@nezha:~# ls -l /sys/bus/i2c/devices/i2c-*
lrwxrwxrwx 1 root root 0 Jan 2 1970 /sys/bus/i2c/devices/i2c-0 -> ../../../devices/platform/soc/5500000.hdmi/i2c-0
lrwxrwxrwx 1 root root 0 Jan 2 1970 /sys/bus/i2c/devices/i2c-1 -> ../../../devices/platform/soc/2502800.i2c/i2c-1
В списке присутствует второе устройство /sys/bus/i2c/devices/i2c-1, то шина I2C включена и не требует дополнительных действий для работы. Первое устройство это шина I2C входящая в состав вывода HDMI.
Более подробно о подключение датчика BME280 пост .NET IoT. Часть 4. Шина I2C, подключение датчика Bosh BME280.
По аналогии с примером GPIO создаем новое приложение DotnetBME280App и содержимое Program.cs заменяем на вариант из проекта dotnet-iot-bme280 на GitHub — .NET IoT Samples. Номер шины I2C остается тот же:
const int busId = 1;
Запускаем приложение:
Запуск приложения DotnetBME280App
Шина I2C успешно работает, как и датчик BME280.
Приложение dotnet-iot-bme280-riscv64 на GitHub — .NET IoT Samples.
Шаблоны проектов для RISC-V и удобная удаленная отладка есть в расширение .NET FastIoT, пост Простая разработка IoT приложений на C# для Raspberry Pi и других одноплатников, на Linux.
❯ Вывод
Уже сейчас предварительные версии IoT приложений для RISC-V процессоров можно успешно тестировать. Базовая периферия в виде управления контактами GPIO и шина I2C работает, пакеты NuGet в проект подтягиваются. Работает медленно, но все же работает. Работа над портированием RISC-V ведется активно, в дальнейшем будет предоставлен скрипт сборки SDK с последними Commits.
❯ Ресурсы
- RISC-V support Issue #36748 — GitHub dotnet/runtime
- Build .NET SDK for RISC-V — GitHub dkurt/dotnet_riscv
- .NET is a cross-platform runtime — GitHub Xinlong-Wu/runtime
- .NET IoT Samples — GitHub devdotnetorg/dotnet-iot-samples
Возможно, захочется почитать и это:
- ➤ Паттерн внедрение зависимостей в .NET nanoFramework для микроконтроллеров
- ➤ Пилим «Даллас» или «Шапка» и «Опёнок» на ожившем SUN-4c IPC station
- ➤ Фантастически быстрый деплой веб-приложения
- ➤ Автомашинист. Оживляем «автопилот» для электрички
- ➤ То, что мертво, умереть не может. Battletech
Новости, обзоры продуктов и конкурсы от команды Timeweb.Cloud — в нашем Telegram-канале ↩
Комментарии (14)
Johan_Palych
27.05.2024 14:24Canonical штампует имиджи
Preinstalled server image
https://cdimage.ubuntu.com/releases/24.04/release/
RISC-V for Allwinner Nezha preinstalled server image
For RISC-V computers, with support for Allwinner Nezha
https://cdimage.ubuntu.com/releases/24.04/release/ubuntu-24.04-preinstalled-server-riscv64+nezha.img.xz
RISC-V for Sipeed LicheeRV Dock preinstalled server image
For RISC-V computers, with support for Sipeed LicheeRV Dock
https://cdimage.ubuntu.com/releases/24.04/release/ubuntu-24.04-preinstalled-server-riscv64+licheerv.img.xz
LicheeRV Dock
https://wiki.ubuntu.com/RISC-V/LicheeRV
buldo
27.05.2024 14:24Интересно, ядро от вендора? Со времён 6.1 в каждом релизе mainline появлялись изменения для D1 и licheeRV
NutsUnderline
27.05.2024 14:24Так или иначе но тут dotnet запускается под linux со всеми вытекающими потребностями к ресурсам.
Раньше помню была плата уровня Arduino, че то уровня STM32 специально заточенная под dotnet типа ebmbedded я так понимаю baremetal, ну может rtos. И похоже не взлетело.
GennPen
27.05.2024 14:24Раньше помню была плата уровня Arduino, че то уровня STM32 специально заточенная под dotnet типа ebmbedded я так понимаю baremetal, ну может rtos. И похоже не взлетело.
Есть под RP Pi. Раньше вроде продвигали это, но что то приутихло.
devzona Автор
27.05.2024 14:24+1Под RP Pi это редакция Window 10 IoT Core с запуском .NET приложений. MS эту редакцию давно не развивает из-за отсутствия спроса. К сожалению, в MS работают "аналитеги" и не понимают рынок IoT вещей в принципе. Window 10 IoT Core бесплатная, но нельзя сделать нормальный вывод любой графики на LCD по HDMI или другому интерфейсу. В других редакциях для ARM есть вывод графики, но они стоят денежку. Таким образом, для хобби проектов лучший вариант это Linux на уровне поддержки полноценной ОС. Можно хоть торговый терминал сделать, любого робота, запустить docker, а с Window 10 IoT Core такого не сделаешь. Уточнение, графика на Window 10 IoT Core может быть написана только на Universal Windows Platform (UWP) и поддерживается максимум 2 ГБ RAM.
devzona Автор
27.05.2024 14:24+1Вы говорите про .NET Micro Framework, да MS закрыла проект, как и многие другие. Но проект ушел в сводное плаванье. Закрытую версию продолжила развивать компания GHI Electronics, открытая версия превратилась в проект .NET nanoFramework, который сейчас поддерживается сообществом. nF работает на многих МК, в основном на ESP32 и STM32. Почитать:
.NET nanoFramework — платформа для разработки приложений на C# для микроконтроллеров
Программируем микроконтроллеры ESP32 и STM32 на C# (nanoFramework)
NutsUnderline
27.05.2024 14:24да, там похоже байт код, но работает без линукса. значит все таки как то живое
GennPen
Запустятся только собранные dll? Самозапускающиеся под target-runtime linux (зависимые от установленного net core и независимые) не запустятся?
ColdPhoenix
судя по всему проект собирается прямо там.
target-runtime linux не существует, потому естественно работать не будет(там скорее всего будет linux-x64).
В теории на такой машине можно собрать будет бинарник с RID - linux-riscv64 и перенести на другую такую же
GennPen
Да, вы правы, перепроверил, только x64 и arm.
devzona Автор
Либо собрать в контейнере используя buildx, Сборка Docker контейнеров для ARM и RISC-V архитектуры используя Buildx
devzona Автор
Запустится, только компилировать необходимо на самом устройстве т.е. представлена версия SDK для RISC-V.
Команда: dotnet build -r linux-riscv64
devzona Автор