Apresentei no post anterior minhas aventuras com o porte do .NET nanoFramework para Linux e NuttX, nesse artigo irei mostrar como foi possível executar aplicações .NET nanoFramework usando esse porte em um Raspberry Pi Pico 🤯.

Preparando Raspberry Pi Pico

Para armazenar sua aplicação .NET temos duas opções. Carregar os assemblies de um SDCard, ou gerar um arquivo .uf2 com os assemblies compilados em conjunto com o firmware do runtime.

⚠️ Para gerar o firmware do runtime é necessário ter o Docker rodando no seu computador de desenvolvimento.

⚠️ Se você optar por usar o SDCard para carregar os assemblies, conecte o módulo SDCard como segue no modelo a seguir:

Connection:
      SD card slot   Raspberry Pi Pico
       DAT2          (NC)
       DAT3/CS ----- GP17 (SPI0 CSn)        (Pin 22)
       CMD /DI ----- GP19 (SPI0 TX - MOSI)  (Pin 25)
       VDD     ----- 3V3 OUT                (Pin 36)
       CLK/SCK ----- GP18 (SPI0 SCK)        (Pin 24)
       VSS     ----- GND                    (Pin 3 or 38 or ...)
       DAT0/DO ----- GP16 (SPI0 RX - MISO)  (Pin 21)
       DAT1          (NC)

Para o exemplo em C# que irei demonstrar, também estou usando um push button conectado ao GP6, pino 9 da Pi Pico:

GPIOS

⚠️ No NuttX os GPIOs não são alocados por demanda, mas sim pré configurados durante a build (isso é algo que estou trabalhando para modificar). Sendo assim, por enquanto apenas os seguintes GPIOs da Pi Pico estão disponíveis para uso:

GP25 = GpioPinDriveMode_Output;
GP2  = GpioPinDriveMode_Output;
GP3  = GpioPinDriveMode_Output;
GP4  = GpioPinDriveMode_Output;
GP5  = GpioPinDriveMode_Output;

GP6  = GpioPinDriveMode_Input;
GP7  = GpioPinDriveMode_Input;
GP8  = GpioPinDriveMode_Input;
GP9  = GpioPinDriveMode_Input;

.NET nanoFramework C# Solution

Você pode usar qualquer solução criada pela extensão do .NET nanoFramework para Visual Studio.

Caso você seja usuário Linux, infelizmente não há ainda um template para o dotnet CLI (para ficar independente do VS 2019 por exemplo). Para esse caso eu criei um exemplo que você pode clonar o repositório e usar com o VS Code.

.NET nanoFramework C# Solution

Siga os passos com um terminal aberto:

1- Clone o repositório dos exemplos:

git clone https://github.com/dotnuttx/nanoFrameworkPOSIX-samples.git

2- Entre na pasta PiPico:

cd nanoFrameworkPOSIX-samples/PiPico

Para fins de demonstração vamos compilar o seguinte Program.cs:

using System.Diagnostics;
using System.Threading;
using System.Device.Gpio;
using nanoFramework.Runtime.Native;

GpioController gpioController = new GpioController();
// GP25 (onboard LED)
GpioPin onBoardLED = gpioController.OpenPin(25, PinMode.Output);
// GP6 (pin 9)
GpioPin button = gpioController.OpenPin(6, PinMode.Input);

while (true)
{
    // blink
    onBoardLED.Toggle();

    // check if button is pressed
    if (button.Read() == PinValue.High)
    {
        Debug.WriteLine($"Running nanoFramework on {SystemInfo.TargetName}");
        Debug.WriteLine($"Platform: {SystemInfo.Platform}");
        Debug.WriteLine($"Firmware info: {SystemInfo.OEMString}");
    }

    Thread.Sleep(500);
}

⚠️ Se você estiver no Windows usando o VS 2019 e a extensão do nanoFramework, basta realizar o Build Solution para gerar os assemblies.

⚠️ Se você estiver no Linux siga os comandos do CLI. Irei usar comandos que fazem parte do Mono. Tenha certeza de ter instalado o pacote mais recente mono-complete em sua distro Linux.

3- Faça download dos pacotes NuGet listados no packages.config, execute na raiz da pasta PiPico/:

nuget restore

⚠️ A versão 2.6.4.6 do runtime para rp2040 precisa exatamente da versão 1.10.5-preview.18 do pacote nanoFramework.CoreLibrary

4- Compile a solução, execute:

msbuild

Após a build você deverá ter os seguintes arquivos com extensão .pe na pasta bin/Debug/ do projeto:

ls -l bin/Debug/*.pe

-rw-r--r-- 1 castello castello   960 Jun 23 00:34 bin/Debug/PiPico.pe
-rwxr--r-- 1 castello castello  5684 Jun 19 08:09 bin/Debug/System.Device.Gpio.pe
-rwxr--r-- 1 castello castello 31668 Jun 19 07:25 bin/Debug/mscorlib.pe
-rwxr--r-- 1 castello castello  3412 Jun 19 07:44 bin/Debug/nanoFramework.Runtime.Events.pe
-rwxr--r-- 1 castello castello  1496 Jun 19 07:46 bin/Debug/nanoFramework.Runtime.Native.pe

Esses são os Portable executables/assemblies que o interpretador do .NET nanoFramework sabe ler e executar. Se você tem eles listados na pasta bin/Debug/ do projeto PiPico, parabéns 🎉 você compilou a aplicação com sucesso.

.NET nanoFramework Runtime (usando SDCard) 💾

1- Formate um SDCard para FAT32 e copie todos os arquivos .pe da pasta bin/Debug/ para a raiz do SDCard.

⚠️ Não se preocupe com capacidade de armazenamento do SDCard, recomendo usar o de menor capacidade disponível. Os assemblies gerados são bem pequenos.

4- Remova o SDCard do seu computador de desenvolvimento e plugue no módulo SDCard conectado ao Pi Pico.

3- Instale o nanoFramework Runtime (Raspberry Pi Pico RP2040) na placa. Você pode baixar binários pré-compilados do runtime para Raspberry Pi Pico RP2040 aqui: https://github.com/dotnuttx/nf-Community-Targets/releases

Baixe o arquivo dotnet-nf.rp2040-Nuttx.2646.uf2 .

Ligue o Raspberry Pi Pico, com o botão BOOTSEL pressionado, via USB ao seu computador de desenvolvimento:

Copie o arquivo dotnet-nf.rp2040-Nuttx.2646.uf2 para o armazenamento listado. Pronto, runtime instalado 😎.

.NET nanoFramework Runtime (usando Docker) 🐋

1- Faça pull da Docker image:

docker pull dotnuttx/generate-pico-uf2

2- Na pasta da sua solução, no nosso exemplo nanoFrameworkPOSIX-samples/PiPico, execute o seguinte comando:

docker run --rm -it -v "$(pwd)/bin/Debug:/nf" dotnuttx/generate-pico-uf2

Esse comando ira compartilhar com o container a pasta bin/Debug da sua solução e irá gerar um arquivo .uf2, esse irá conter o .NET nanoFramework runtime com os assemblies .pe já embutidos, pronto para ser gravado na sua Raspberry Pi Pico.

Após a execução do comando verifique se um novo arquivo chamado dotnetnf.uf2 foi criado na pasta bin/Debug da sua solução. Caso positivo, parabéns 🎉 você gerou seu firmware customizado.

3- Instale seu nanoFramework Runtime (Raspberry Pi Pico RP2040) na placa. Ligue o Raspberry Pi Pico, com o botão BOOTSEL pressionado, via USB ao seu computador de desenvolvimento:

Copie o arquivo dotnetnf.uf2 para o armazenamento listado. Pronto, seu runtime foi instalado 😎.

Piscando LEDs

Após a instalação do firmware (cópia do arquivo .uf2), a placa irá se auto reiniciar e o runtime irá executar a aplicação automaticamente.

⚠️ O firmware também cria uma porta serial via o USB conectado ao seu computador, assim podemos visualizar o retorno do Debug.WriteLine. Se conecte na serial, no caso do Linux será listada em /dev/ttyACMx e no Windows o padrão COMx, com um baud rate de 115200.

Se após instalar o runtime você tiver o LED on board da Pi Pico piscando, e ao pressionar o botão a seguinte mensagem for escrita na serial:

Parabéns 🎉! Você executou sua primeira aplicação .NET em uma Raspberry Pi Pico 🤯.

Conclusão

.NET nanoFramework 🤘! Mas vale lembrar que:

⚠️ Esse em um porte não oficial! É algo que estou trabalhando nos finais de semana e durante meu tempo livre, algo EXTREMAMENTE EXPERIMENTAL. Não estou sendo financiado por nenhum grupo ou instituição para tal.

Há muito trabalho pela frente, por enquanto das features específicas de hardware, só GPIO (in e out) estão implementadas (suporte há i2c vem em breve). Para mais informações leia o blog post: Portando .NET nanoFramework para Linux e Nuttx

Já sabemos que o time principal do .NET nanoFramework está trabalhando em um porte da Pi Pico para o Azure RTOS. Os meus experimentos são válidos (eu acho 🤔) como prova de conceito do porte POSIX do nanoFramework. Trabalhando nesse porte podemos rodar o nanoCLR em um arsenal de + de 67 placas microcontroladas de diferentes arquiteturas, das quais o NuttX tem suporte (NuttX é um RTOS com compatibilidade incrível à POSIX), e + uma infinita lista de plataformas e arquiteturas microprocessadas que rodam Linux.

Gostou da possibilidade? Se isso for de alguma forma útil, ou fizer sentido para você, deixe me saber. Me mande um alô no Twitter @math_castello ou no Linkedin 👍