Invisto
Invisto · your interface partner
Mailinfo@invisto.beTelefoon+32 477 42 11 14KantoorHangar K, Kortrijknlen
Alle inzichten
inzichten/Embedded Linux

.NET op embedded Linux: waarom C# een sterke keuze kan zijn

.NET op embedded Linux: waarom C# een sterke keuze kan zijn

Wie aan embedded software denkt, denkt al snel aan C of C++. Zodra een product op een application processor met Linux draait, ziet de softwarecontext er wel helemaal anders uit. Met procesisolatie, virtueel geheugen, networking, systemd en een volwaardig besturingssysteem kun je ook een managed runtime zoals .NET op een robuuste manier inzetten. Wij doen dat graag, en in dit artikel leggen we uit waarom, en waar je op moet letten.

Embedded Linux hoeft niet in C of C++

Op microcontrollers zijn C en C++ nog altijd de logische keuze. Een embedded Linux-platform met bijvoorbeeld een Cortex-A53/A55, een x86-processor of een vergelijkbare application processor zit in een andere klasse. Daar is meestal genoeg geheugen en rekenkracht om een managed runtime te gebruiken.

Native code blijft heel waardevol voor drivers, bestaande stacks, code waar performance kritisch is en specifieke hardware-integratie. Ze hoeft alleen niet automatisch de taal van de volledige applicatie te bepalen. Zo hoeft ook niet elke applicatieontwikkelaar een specialist in low-level C/C++ te zijn.

Modern .NET is echt cross-platform

Het oude beeld van .NET als Windows-technologie klopt al lang niet meer. Modern .NET draait native op Linux en ondersteunt de architecturen die ertoe doen, zoals x64 en Arm64. Een applicatie kan als Linux-service draaien, integreert met systemd en publiceer je specifiek voor het target.

Embedded Linux      |   systemd      | .NET runtime      |C# application

Het ecosysteem is een groot voordeel

Het sterkste argument voor .NET is niet alleen C# zelf, maar het hele ecosysteem eromheen. Veel van wat in industriële toepassingen telkens terugkomt, is er goed ondersteund, en een grote groep ontwikkelaars kent het al:

  • Networking: HTTP, REST, WebSockets, TLS en volwassen MQTT-libraries.
  • Data: JSON, XML, SQLite, databases en serialisatie.
  • Concurrency: Tasks, async/await en channels.
  • Logging: ILogger en structured logging.
  • Softwarearchitectuur: dependency injection, configuratie en hosted services.
  • Testen: volwassen tooling voor unit- en integratietests.
  • Cloudintegratie: een natuurlijke aansluiting op ASP.NET Core en cloudservices.

Productiviteit telt

In veel embedded Linux-producten zit de complexiteit niet in registers. Ze zit in de business logic, de communicatie, de dataopslag, de synchronisatie, de foutafhandeling en de gebruikersinterface. Garbage collection, async/await, LINQ, NuGet en de sterke tooling rond C# kunnen de ontwikkeling dan flink versnellen.

Bij embedded applicaties met veel business logic laat C# ontwikkelaars meer tijd besteden aan het product en minder aan infrastructuur.

Daarnaast vind je makkelijker ontwikkelaars. Een edge-applicatie hoeft niet geschreven te worden door iemand die tegelijk expert is in C++, memory ownership, CMake en cross-compilatie.

Waar .NET het best past: industriële edge-applicaties

We vinden .NET vooral interessant wanneer Linux de grens vormt tussen de low-level hardware en de productapplicatie. Denk aan dataloggers, gateways, connected machines, edge computers, lokale API’s, machine-HMI’s en systemen die data verzamelen en naar de cloud synchroniseren.

Sensors / CAN / PLC / peripherals               |        Embedded Linux               |       .NET application          /         \     Local UI      Cloud

Je kunt nog altijd aan de hardware

Een C#-applicatie hoeft de hardware niet rechtstreeks via registers aan te sturen. Linux abstraheert veel interfaces via gestandaardiseerde subsystemen en device interfaces. Seriële communicatie, GPIO, I2C, SPI en CAN spreek je vanuit userspace aan, afhankelijk van het platform en de beschikbare libraries.

CAN controller      |Linux SocketCAN      |.NET application

Native code waar het nodig is

Niet alles hoeft managed code te zijn. Via native interoperability, onder meer P/Invoke, roept C# bestaande C- of C++-libraries aan. Zo behoud je bewezen protocolstacks, hardwarebibliotheken of componenten waar performance kritisch is.

C# application      |native interop / P/Invoke      |C / C++ library      |hardware / protocol / accelerator

Gebruik native code waar het zinvol is, en niet overal omdat het zo hoort.

Avalonia maakt .NET ook interessant voor HMI’s

Embedded .NET hoeft niet headless te zijn. Met Avalonia bouw je moderne grafische interfaces in C# die ook op Linux draaien. Voor bepaalde industriële HMI’s is dat een interessant alternatief naast Qt/QML.

Avalonia UI-------------------------C# application logic-------------------------.NET-------------------------Embedded Linux-------------------------ARM / x86 hardware

Qt blijft bijzonder sterk voor diepe embedded integratie, producten op basis van C++ en volwassen toepassingen van embedded graphics. Hoe de licenties daar werken, lees je in Qt-licenties voor embedded devices. Avalonia met .NET wordt interessant als je team al veel C#-kennis heeft, de applicatie veel business logic bevat, of je dezelfde technologie ook voor backend en tooling gebruikt.

Avalonia op embedded hardware: vlot eens het draait, trager bij het opstarten

Onze ervaring met Avalonia op voldoende krachtige embedded Linux-hardware is positief. Zodra de applicatie draait, voelt de interface heel soepel aan. Animaties en interactie doen niet onder voor wat gebruikers van een moderne HMI verwachten.

Het verschil met een lean native applicatie merk je vooral bij het opstarten. De .NET-runtime en de UI-stack moeten geïnitialiseerd zijn voor de eerste volledige UI verschijnt, en op een embedded ARM-platform voel je die startup time duidelijker.

Eens Avalonia draait, kan het heel vlot zijn op embedded hardware. Aan de opstarttijd moet je wel aandacht besteden.

Daar kun je in het productontwerp rekening mee houden. Start de UI vroeg via systemd, stel niet-kritieke initialisatie uit tot na het eerste frame, start backendservices parallel op en toon eventueel een bootsplash. Native AOT kan voor sommige configuraties interessant zijn, maar dat moet je samen met Avalonia en alle gebruikte dependencies concreet valideren.

Eén ecosysteem van device tot cloud

Een organisatorisch voordeel krijg je wanneer je C# niet alleen op het toestel maar ook in de backend gebruikt. Je team deelt dan kennis, modellen en tooling over de verschillende lagen van het product.

DEVICE: C# / .NET / Avalonia      |MQTT / HTTPS      |CLOUD: ASP.NET Core      |API / database / services

Hoe krijg je .NET in een Yocto-product?

Er zijn verschillende manieren om te deployen. Welke het best past, hangt af van hoeveel .NET-applicaties er op het toestel draaien, hoe je OS- en applicatie-updates beheert en hoeveel controle je over de runtimeversie wilt.

Optie 1: de .NET-runtime in het Yocto-image

De .NET-runtime en de nodige native dependencies bouw en beheer je als deel van het root filesystem. De applicatie gebruikt dan de runtime die het platform levert.

Yocto image├─ Linux / systemd├─ .NET runtime├─ native dependencies└─ application

Dat is aantrekkelijk als meerdere services dezelfde runtime delen, of als je runtime en applicaties bewust als één platformstack beheert. De Yocto-layers en -recipes en de gewenste .NET-versie worden dan wel deel van je BSP- en imagebeheer.

Optie 2: self-contained deployment

Je kunt de applicatie ook voor het target publiceren met de nodige .NET-runtimecomponenten erbij. Het basis-image van Yocto hoeft dan geen .NET-runtime als platformpackage te leveren.

Yocto image├─ Linux / systemd└─ application/   ├─ executable   ├─ .NET runtime components   └─ managed / native dependencies
dotnet publish -c Release -r linux-arm64 --self-contained true

Voor embedded Linux is dat vaak een aantrekkelijke taakverdeling. Yocto is verantwoordelijk voor het besturingssysteem en de BSP, en de applicatie brengt de .NET-runtimeversie mee waarmee ze gebouwd en getest is. Zo beheer en test je de applicatiestack onafhankelijker van het root filesystem.

Self-contained betekent overigens niet per se één statisch bestand, en ook niet dat elke native systeemdependency verdwijnt. De targetarchitectuur, de libc en eventuele native libraries horen nog altijd bij de compatibiliteitsanalyse.

Optie 3: Native AOT

Native AOT compileert .NET-code vooraf naar native code. Dat kan voordelen geven voor de opstarttijd en in bepaalde scenario’s voor de footprint. Het is wel geen oplossing voor alles. Reflection, dynamische codegeneratie en libraries die op runtimefeatures steunen, kunnen extra werk of beperkingen opleveren. Voor een concrete embedded stack moet je AOT dus valideren in plaats van ervan uit te gaan dat het werkt.

Yocto en .NET: controle en productiviteit

Een custom Yocto Linux-image en een high-level applicatiestack gaan prima samen. Yocto geeft je controle over de BSP, de kernel, de drivers, de packages en de reproduceerbaarheid. Daarboven verhoogt .NET de productiviteit van de applicatieontwikkeling. Waarom we voor zo’n product vaak bij Yocto uitkomen, lees je in Yocto vs Ubuntu vs Debian.

Application / Avalonia.NET runtime or self-contained app-------------------------systemd / Linux services-------------------------Custom Yocto BSP-------------------------ARM SoC

Ook op een sterk op maat gemaakt embedded Linux-platform mag de applicatiestack high-level zijn.

En de performance?

C en C++ blijven de juiste keuze wanneer maximale controle over het geheugen, zeer lage latency of specifieke native libraries centraal staan. Voor een Linux-toestel met voldoende RAM is de vraag vaak eerder of het verschil met C++ voor jouw toepassing echt iets uitmaakt.

Een applicatie die CAN-data verwerkt, JSON encodeert, MQTT-berichten verstuurt, een database beheert en een HMI toont, wordt meestal begrensd door I/O en applicatielogica en veel minder door pure CPU-performance.

Garbage collection: de belangrijke nuance

Managed memory heeft een prijs. Garbage collection kan latency veroorzaken, en daardoor is .NET niet vanzelf geschikt voor hard real-time control loops. Voor gewone edge-, HMI- en dataverwerkingstoepassingen speelt dat veel minder.

Real-time MCU      |CAN / UART / Ethernet      |Embedded Linux      |.NET application      |UI / Cloud / Storage

In onze eigen X Series maken we die scheiding ook. De eenvoudige, deterministische power- en ignitionlogica draait op een microcontroller, en de application processor draait de veel rijkere Linux-applicatielaag.

Updates en lifecycle

Ook .NET-applicaties moet je na de uitrol onderhouden. Afhankelijk van de architectuur update je een applicatie apart, als container of samen met het volledige Linux-image. Authenticiteit, rollback, versiebeheer en gecontroleerde roll-outs blijven belangrijk.

Met Otaryx bouwen we rond die bredere embedded lifecycle: software- en image-updates, remote diagnostics, gefaseerde uitrol en monitoring. Welke taal je voor de applicatie kiest, verandert niets aan de noodzaak om het product zijn hele levensduur beheersbaar te houden.

Wanneer is .NET een sterke kandidaat?

Toepassing .NET als kandidaat
Industriële edge computer Sterk
Datalogger of gateway Sterk
Cloud-connected toestel Sterk
Machine-HMI Sterk
Complexe business logic Sterk
Kleine Cortex-M MCU Meestal niet
Hard real-time control loop Meestal niet
Linux kernel driver Nee
Zware low-level DSP Native C/C++ is vaak logischer

Tot slot

Embedded Linux geeft je de keuze. C en C++ blijven uitstekende tools wanneer low-level controle, determinisme en maximale performance belangrijk zijn, maar veel industriële applicaties hoeven niet volledig in native code geschreven te worden.

Met modern .NET combineren we de controle en robuustheid van een embedded Linux-platform met de productiviteit, de tooling en het ecosysteem van C#. Yocto beheert daarbij het platform, en de .NET-applicatie leveren we als geïntegreerde runtime, als self-contained deployment of, waar het zinvol is, met Native AOT.

Onze ervaring met Avalonia past in hetzelfde verhaal. Op geschikte embedded hardware kan de applicatie uitstekend en heel vloeiend draaien, zolang je de langere opstarttijd bewust meeneemt in de systeemarchitectuur. Embedded Linux met .NET? Wij vinden het een prima combinatie.

Twijfel je welke taal en stack bij je Linux-toestel passen? Laten we eens sparren.

Plan een gesprek