.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<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;

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

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-канале

Комментарии (14)


  1. GennPen
    27.05.2024 14:24

    Запустятся только собранные dll? Самозапускающиеся под target-runtime linux (зависимые от установленного net core и независимые) не запустятся?


    1. ColdPhoenix
      27.05.2024 14:24
      +1

      судя по всему проект собирается прямо там.

      target-runtime linux не существует, потому естественно работать не будет(там скорее всего будет linux-x64).

      В теории на такой машине можно собрать будет бинарник с RID - linux-riscv64 и перенести на другую такую же


      1. GennPen
        27.05.2024 14:24

        (там скорее всего будет linux-x64)

        Да, вы правы, перепроверил, только x64 и arm.


      1. devzona Автор
        27.05.2024 14:24

        Либо собрать в контейнере используя buildx, Сборка Docker контейнеров для ARM и RISC-V архитектуры используя Buildx


    1. devzona Автор
      27.05.2024 14:24

      Запустится, только компилировать необходимо на самом устройстве т.е. представлена версия SDK для RISC-V.

      Команда: dotnet build -r linux-riscv64


    1. devzona Автор
      27.05.2024 14:24
      +1


  1. Johan_Palych
    27.05.2024 14:24

    Canonical штампует имиджи
    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


    1. buldo
      27.05.2024 14:24

      Правда у меня они иногда не запускались


  1. buldo
    27.05.2024 14:24

    Интересно, ядро от вендора? Со времён 6.1 в каждом релизе mainline появлялись изменения для D1 и licheeRV


  1. NutsUnderline
    27.05.2024 14:24

    Так или иначе но тут dotnet запускается под linux со всеми вытекающими потребностями к ресурсам.

    Раньше помню была плата уровня Arduino, че то уровня STM32 специально заточенная под dotnet типа ebmbedded я так понимаю baremetal, ну может rtos. И похоже не взлетело.


    1. GennPen
      27.05.2024 14:24

      Раньше помню была плата уровня Arduino, че то уровня STM32 специально заточенная под dotnet типа ebmbedded я так понимаю baremetal, ну может rtos. И похоже не взлетело.

      Есть под RP Pi. Раньше вроде продвигали это, но что то приутихло.


      1. 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.


    1. 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)


      1. NutsUnderline
        27.05.2024 14:24

        да, там похоже байт код, но работает без линукса. значит все таки как то живое