O .NET Core 3 foi lançado no dia 23/09/2019, com novidades para o mundo dos sistemas Embarcados e IoT. Como vimos no artigo anterior agora temos suporte a ARMv8 64 bits, onde demonstramos o deploy de um “Hello World” utilizando .NET Core e C# em uma placa com processador i.MX8QXP.
Nesse artigo vamos demonstrar a segunda novidade deste lançamento, as interfaces para acesso a GPIO do .NET Core 3, que eu tive o prazer de contribuir para o projeto open source do GitHub da .NET Foundation (fico devendo um artigo sobre os aspectos técnicos destas contribuições aqui no Embarcados).
Bibliotecas .NET Core IoT
O .NET Core pode ser usado para criar aplicativos para dispositivos IoT Linux Embarcado. É normal que aplicativos de IoT interajam com sensores, monitores e dispositivos de entrada que exigem o uso de GPIO (General Purpose Input Output), portas seriais ou hardware semelhante.
Para facilitar acesso e padronizar uma API a essas interfaces, utilizando .NET Core, que foi criado o projeto dotnet/iot, dentro do grupo da .NET Foundation que dá suporte ao projeto open source do .NET Core. Esse projeto implementa a System.Device.Gpio library que tem as interfaces para acesso a GPIO, PWM, I2C e SPI.
A comunidade do projeto dotnet/iot ainda foi além e desenvolveu também a biblioteca IoT.Device.Bindings, que utiliza a API do System.Device.Gpio para fornecer abstrações, drivers, e classes prontas para controle de sensores e dispositivos populares.
Hardware para Demonstrações – Apalis iMX8QM
No artigo anterior eu utilizei um Toradex Colibri iMX8QXP ARMv8 64 bits quad core 4x Cortex-A35. Neste artigo eu estou com um monstro mais poderoso ainda: o Apalis iMX8QM, que foi lançado oficialmente pela Toradex nesta última terça feira 08/10/2019. Um ARMv8 64 bits HEXA core com 2x Cortex-A75, 4x Cortex-A53, 4 GB de RAM (SIM eu falei 4 GB RAM) e 16 GB eMMC.
A Toradex foi uma das seletas parceiras da NXP com acesso antecipado ao i.MX8QM para desenvolvimento do System on Module Apalis iMX8QM e do ecossistema de software, junto a seus parceiros e clientes. Estou com um monstro desses em mãos, para testes, e foi ele que utilizei nas demonstrações deste artigo.
System.Device.Gpio – Demonstração
Qual a melhor forma de exemplificar a utilização de uma API de GPIO? Ahh, o bom e velho LED blink, o Hello World dos sistemas embarcados.
Vamos primeiramente criar, em um computador de desenvolvimento, nosso projeto com o comando:
dotnet new console
Lembrando que estamos utilizando o novo .NET Core 3. No comando acima o .NET SDK vai criar nosso projeto com o nome da pasta de onde executamos o comando. No meu caso minha pasta tem o nome demo2, logo meu projeto vai ser configurado com o nome demo2.
Para utilizar a biblioteca System.Device.Gpio temos que adicionar seu pacote NuGet ao projeto. Execute o seguinte comando para adicionar o pacote NuGet do dotnet/iot:
dotnet add package System.Device.Gpio --version 1.0.0 dotnet restore
Agora podemos, enfim, escrever o código C# do Blink:
using System;
using System.Threading;
using System.Device.Gpio;
namespace demo2
{
class Program
{
static void Main(string[] args)
{
// GpioController set bank 0 as default
GpioController controller = new GpioController();
// GPIO bank 0 line 12
int GPIO0_IO12 = 12;
// say hello
Console.WriteLine("Blinking on Apalis iMX8QM with .NET Core 3");
// set pin mode to output
controller.OpenPin(GPIO0_IO12, PinMode.Output);
// blink forever
while(true)
{
Console.WriteLine("Blink");
controller.Write(GPIO0_IO12, PinValue.High);
Thread.Sleep(500);
controller.Write(GPIO0_IO12, PinValue.Low);
Thread.Sleep(500);
}
}
}
}
Note a linha 14, onde estamos construindo um objeto GpioController que terá os comandos de interface para controlar nossos pinos de entrada e saída. Na linha 20 usamos o método OpenPin para configurar nosso pino, onde teremos conectado um LED, para output, esse método é muito importante pois todos os outros métodos do controller só serão executados em um pino anteriormente configurado. E por fim nas linhas 25 e 27, dentro da nossa estrutura de repetição, utilizamos o método Write que vai setar o nível lógico do pino que foi configurado como output.
Deploy – LED Blink
Para realizar o deploy para a arquitetura do nosso sistema embarcado vou utilizar o mesmo comando do artigo passado, mas com um adendo:
dotnet publish -r linux-arm64 --self-contained true /p:PublishSingleFile=true
Outra novidade do .NET Core 3 é que agora temos a opção de publicar um projeto como sendo um único arquivo executável, que é a função desse último argumento /p:PublishSingleFile=true. Agora ao invés de ser gerada uma pasta /publish com todas as dependências, vários .dll e .so, teremos apenas dois arquivos:
Assim, copiando apenas esse executável gerado, já teremos todo nosso projeto pronto para ser executado no nosso sistema embarcado:
scp bin/Debug/netcoreapp3.0/linux-arm64/publish/demo2 torizon@10.42.0.22:/home/torizon
Acessando o bash da placa, via ssh, podemos então executar o programa .NET Core 3 IoT:
Lembrando que no caso de acesso ao hardware, GPIO nesse caso, precisamos executar com privilégios de super usuário. Nesse momento, se tudo deu certo, teremos um LED piscando conectado à porta GPIO0_IO12 do nosso Apalis iMX8QM.
IoT.Device.Bindings – Demonstração
Para demonstração das bibliotecas do IoT.Devices.Bindings vou utilizar um sensor de temperatura muito popular: o onipresente DHT11.
Para utilizar o IoT.Devices.Bindings em nosso projeto temos que primeiramente adicionar o pacote NuGet:
dotnet add package Iot.Device.Bindings --version 1.0.0
O DHT11 já tem uma implementação pronta para uso, então podemos utilizar o sensor facilmente:
using System;
using System.Threading;
using Iot.Device.DHTxx;
using Iot.Units;
namespace demo3
{
class Program
{
static void Main(string[] args)
{
// GPIO bank 0 line 12
int GPIO0_IO12 = 12;
// say hello
Console.WriteLine("DHT11 on Apalis iMX8QM with .NET Core 3");
// use the Dht11 class
using (Dht11 sensor = new Dht11(GPIO0_IO12))
{
while (true)
{
// easy device controll
Temperature temp = sensor.Temperature;
double humidity = sensor.Humidity;
if (sensor.IsLastReadSuccessful)
{
Console.WriteLine($"Temperature :: {temp.Celsius}");
Console.WriteLine($"Humidity :: {humidity}");
Console.WriteLine("----------------------------------");
}
// wait 1 second to the next read
Thread.Sleep(1000);
}
}
}
}
}
Note como simplesmente instanciamos um objeto do tipo Dht11, linha 19, referenciando o pino de dados conectado à placa e ao sensor e pronto. Podemos então requisitar a temperatura, linha 24, e a umidade do sensor, linha 25. O objeto vai realizar as chamadas e controles necessários, por debaixo dos panos utilizando as APIs do System.Device.Gpio, para entregar esses dados de forma fácil.
Deploy – DHT11
Executando os mesmos comandos do deploy da demonstração do LED Blink dentro da pasta do projeto:
dotnet publish -r linux-arm64 --self-contained true /p:PublishSingleFile=true
Copiando o executável único gerado via ssh:
scp bin/Debug/netcoreapp3.0/linux-arm64/publish/demo3 torizon@10.42.0.22:/home/torizon
E pronto, teremos as leituras do DHT11 sendo apresentadas no bash da placa:
Confira o vídeo onde demonstro a utilização e programação descritas nesse artigo na prática:
Conclusões
Legal como o System.Device.Gpio tem uma API bem simples, algo bem parecido com as chamadas do Arduino por exemplo, para você programar dispositivos com linguagem C# e o .NET Core 3.0.
As implementações do IoT.Device.Bindings facilitam e agilizam muito o desenvolvimento de aplicações IoT, com uma extensa lista de dispositivos e sensores disponíveis. Você pode acompanhar todos dispositivos no Github do projeto: https://github.com/dotnet/iot/tree/master/src/devices
Lembrando que o .NET Core e o .NET IoT são projetos da Microsoft totalmente open source. Ou seja, como eu contribuí, você também pode contribuir! A comunidade é um grande adjuvante na inclusão e suporte de vários dispositivos para o projeto.






