Запускаем .NET на RISC-V и разрабатываем IoT приложение для Sipeed Lichee RV

.NET nanoFramework Weatherstation

До недавнего времени разрабатывать 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


dotnet risc-v lichee-rv
Запуск приложения 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


После запуска приложения светодиод должен мигать, но с большей задержкой, чем указано в программном коде из-за медленной работы 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;


Запускаем приложение:

dotnet risc-v lichee-rv
Запуск приложения 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.

Ресурсы



Возможно, захочется почитать и это:

Новости, обзоры продуктов и конкурсы от команды Timeweb.Cloud — в нашем Telegram-канале


b5pjofdoxth14ro-rjsrn7sbmiy.png

© Habrahabr.ru