Extensão C para MicroPython em Raspberry Pi Pico

Este é um guia sobre como escrever e executar uma extensão C básica para MicroPython no Raspberry Pi Pico. Vou cobrir as razões para a extensão do MicroPython, como escrever o módulo de extensão, como compilá-lo e como instalá-lo no Pico. Se você quiser ler mais sobre este tópico, por favor, consulte https://docs.micropython.org/en/latest/develop/extendingmicropython.html

Introdução

Porquê estender o MicroPython?

Pode haver razões de multpiple por que você pode querer estender o MicroPython. Uma vez que é uma versão aparada do Python, o MicroPython não está funcionando muito bem quando se trata de tarefas computacionalmente pesadas (semelhante ao Python). O C, por outro lado, é realmente bem adequado para tais tarefas. Uma extensão C para Micropython permite que você execute esses cálculos através da linguagem C e use os resultados em MicroPython. Isto pode acelerar alguns processos por uma ordem de grandeza.

Uma segunda razão pode ser, que você queira fazer interface com algum hardware que usa uma API C de dentro do MicroPython. 

Tipos de extensões MicroPython C

Existem diferentes maneiras de estender o MicroPython : módulos C externos e código de máquina nativo em arquivos .mpy.

Para executar um módulo C externo você precisa recompilá-lo no firmware do MicroPython. Este é um processo bastante complicado, e é por isso que este guia irá focar a segunda alternativa. Se você estiver interessado nesta abordagem, você pode ler mais sobre ela nestas páginas web:                https://docs.micropython.org/en/latest/develop/cmodules.html                      https://www.raspberrypi.org/forums/viewtopic.php?t=300352

O .mpy é um arquivo que armazena código de máquina nativo compilado e pode ser ligado dinamicamente. Isso o torna muito mais flexível, já que você não precisa recompilar todo o firmware do MicroPython.

Escreva o módulo de extensão

Escrever o módulo de extensão é a parte mais fácil de estender o MicroPython. Vou mostrar-lhe como fazê-lo, olhando para um exemplo simples. Para começar, vamos criar um novo diretório chamado factfib. Abra uma nova janela de terminal, cd para o novo diretório e crie um novo arquivo chamado factfib.c. Se você criou o diretório em um Raspberry Pi sob Dekstop, o comando é parecido com este.

cd ~/Desktop/factfib

factfib.c

Aberto factfib.c no seu editor de texto preferido e introduza o seguinte código

#include "py/dynruntime.h

STATIC mp_int_t factorial_helper(mp_int_t x) {
   if (x < 1) {
      return 1;
   }
   return x*factorial_helper(x-1);
}

STATIC mp_obj_t factorial(mp_obj_t x_obj) {
   mp_int_t x = mp_obj_get_int(x_obj);
   mp_int_t rslt = factorial_helper(x);
   return rslt;
}

STATIC MP_DEFINE_CONST_FUN_OBJ_1(factorial_obj, factorial);

STATIC mp_int_t fibonacci_helper(mp_int_t x) {
   if (x <= 0) {
      return 0;
   }
   else if (x == 1) {
      return 1;
   }
   else {
      return (fibonacci_helper(x-1) + fibonacci_helper(x-2));
   }
}

STATIC mp_obj_t fibonacci(mp_obj_t x_obj) {
   mp_int_t x = mp_obj_get_int(x_obj);
   mp_int_t rslt = fibonacci_helper(x);
   return mp_obj_new_int(rslt);
}

STATIC MP_DEFINE_CONST_FUN_OBJ_1(fibonacci_obj, fibonacci);

mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
   MP_DYNRUNTIME_INIT_ENTRY

   mp_store_global(MP_QSTR_factorial, MP_OBJ_FROM_PTR(&factorial_obj));
   mp_store_global(MP_QSTR_fibonacci, MP_OBJ_FROM_PTR(&fibonacci_obj));

   MP_DYNRUNTIME_INIT_EXIT
}

Deixe-me explicar o código acima: Em MicroPython e Python, cada variável é um objecto. Portanto, em C nós as representamos como mp_obj_t. Mas um programa em C só pode trabalhar com variáveis do tipo C, e é por isso que precisamos transformar o objeto em um tipo C. Isto é chamado Marshalling e MicroPython fornece funções para extrair qualquer tipo de C de um objeto.

Esta página de Oliver Robson é realmente útil para a Marshalling https://mpy-c-gen.oliverrobson.tech/. Além disso, você pode encontrar exemplos de Marshalling na documentação do MicroPython. https://docs.micropython.org/en/latest/develop/natmod.html. Aconselho-o a ler este artigo se precisar de mais explicações.

Construir a extensão

Nós construímos a extensão em um arquivo .mpy usando um Makefile. Mas precisamos de configurar algumas coisas primeiro. Certifique-se de que o seu terminal ainda está aberto no arquivo factfib directório. Depois clone o repositório MicroPython GitHub.

sudo apt-get install build-essential libreadline-dev libffi-dev git pkg-config gcc-arm-none-eabi libnewlib-arm-none-eabi

clone de git -submódulos de enfermagem https://github.com/micropython/micropython.git

pip3 instalar Ferramentas de fyelftools>=0,25''.

Estas instalações vão demorar algum tempo, se você quiser economizar tempo e sabe o que está fazendo, você só precisa clonar o diretório /py e /tools do repositório micropython e colocá-los dentro de um micropython pasta dentro do factfib (saltar o segundo comando).

Enquanto a instalação está a decorrer podemos usar o tempo para escrever o Makefile. Basta executar o

tocar Makefile

e abrir o arquivo recém-criado em um editor de texto. 

MPY_DIR = micropython

MOD = factfib

SRC = factfib.c

ARCH = armv7m

include $(MPY_DIR)/py/dynruntime.mk

Você deve ter notado que nós definimos o ARCH variável para armv7m embora o pico seja armv6m. Temos de fazer isto porque o armv6m arquitetura não é (no momento em que estou escrevendo este artigo) suportada pelo dynruntime.mk ferramenta.

Mas, felizmente, ainda podemos compilar uma extensão funcional para o Pico. Só precisamos de modificar a dynruntime.mk que deve ser localizado em micropython/py/dynruntime.mkAbra-a e sob a configuração de Arquitectura no armv7m encontre a variável CFLAGS (deve ser a linha 64). Alterar -mcpu=cortex-m3 para -mcpu=cortex-m0 e salvar o arquivo.

chnge -mcpu=cortex-m3 a -mcpu=cortex-m0

Depois que tudo estiver instalado, execute

marca

e o factfib.mpy será criado um arquivo.

Instalar e testar a extensão

O último passo é a instalação e os testes. Para isso utilizamos o sistema de arquivos que Micropython cria no Raspberry Pi Pico. Primeiro precisamos flashear o Pico com o firmware do MicroPython. A maneira mais fácil de fazer isso é usar o Thonny IDE (pré-instalado no Raspbian).

Se você não está usando um Raspberry Pi para programar seu Pico ou se você nunca usou MicroPython no Pico antes disso, por favor consulte o guia de iniciação ao MicroPython do Raspberry Pi https://www.raspberrypi.org/documentation/rp2040/getting-started/#getting-started-with-micropython

Se você está usando Windows você deve conferir este blog Post sobre o Raspberry Pi Pico e MicroPython no Windows https://picockpit.com/raspberry-pi/raspberry-pi-pico-and-micropython-on-windows/

Feche Thonny depois de ter flashado o seu Pico com o firmware MicroPython e instale o rshell. Nós usamos o rshell para acessar o sistema de arquivos a partir da linha de comando.

sudo pip3 instalar rshell

rshell -versão

Isto imprime a versão rhsell se tudo estiver configurado corretamente. Depois desconecte o pico e conecte-o novamente (sem segurar o botão BOOTSEL) para ter certeza de que nada está tentando acessar o sistema de arquivos. Agora precisamos executar o

rshell -p /dev/ttyACM0 -buffer-size 512

cp factfib.mpy /pyboard/factfib.mpy

Para testar a instalação você poderia usar o rshell ou o Thonny IDE para salvar seu .py no Pico, mas vou demonstrar como usar o intérprete MicroPython sobre o minicom.

Então, a primeira imprensa Ctrl+c para deixar o rshell e depois instalar o minicom via

sudo apt instalar minicom

agora podemos aceder à REPL (Read-eval-print loop) dos Picos

minicom -o -D /dev/ttyACM0

Os três ângulos de fechamento >>> indicam que o intérprete MicroPython está a funcionar. Agora podemos importar a nossa extensão e trabalhar com ele como de costume.

>>> factfib de importação como ff

>>> ff.factorial(5)

>>> 120

>>> ff.fibonacci(7)

>>> 13

Parabéns! Você criou a sua primeira extensão MicroPython C para o Pico! O próximo passo é aprender a escrever e compilar módulos mais complexos. Uma boa maneira de começar é testando como funciona o Marshalling of lists and dicts (veja a página do Marshalling em cima). Se você tiver alguma dúvida sobre este post, sinta-se à vontade para escrever um comentário.

Adeus e até à próxima.

Nathan

2 comentários

  1. PeterB em Novembro 26, 2021 às 8:29 am

    Além do erro no programa c, funcionou como um deleite. Obrigado.

    STATIC mp_obj_t factorial(mp_obj_t x_obj) {
    mp_int_t x = mp_obj_get_int(x_obj);
    mp_int_t rslt = factorial_helper(x);
    retornar mp_obj_new_int(rslt);
    }

Deixe um comentário