Configurando ambiente de programação MCUXpresso no Vscode para a série MIMXRT105 Cortex de processadores ARM

By on 4 Jul 2024 | 20:00 .

Categories | | |

Tempo de leitura: #

Visualizações: #

Sumário

Introdução

Desenvolver sistemas embarcados sempre é uma dor de cabeça para começar. Configurar ambientes em máquinas com softwares proprietários geralmente leva muito tempo e acabamos com um setup frágil, então quando se precisa mudar de máquina, formatar ou compilar projetos em outro local tendemos a descobrir que não vai funcionar de primeira novamente.

Por isso gosto sempre de ir atrás de soluções mais open source e mais simples, sem IDE’s integradas, apenas um editor de texto e uma linha de comando. Queria mostrar assim então como podemos instalar e configurar de forma simples um SDK de programação, neste caso o MCUXpress da NXP, e como usá-lo com o editor de texto favorito da gurizada, Vscode.

Quero notar também que existe uma extensão oficial para o Vscode que facilita todo esse processo, e é de fato, a forma mais fácil de usar o SDK com o Vscode, mas ele te tira um pouco a liberdade de usar como quiser, e se você usar a extensão a experiência será muito semelhante a usar a IDE própria da NXP, que pode até ser melhor pois tem ferramentas dedicadas para o desenvolvimento.

Também vale notar que também poderíamos usar a extensão Platform.io, que também permite instalação e desenvolvimento com MCUXpress SDK e também de diversa plataformas embarcadas.

SDK

Dependências

Para instalar o SDK precisamos primeiros instalar as seguintes dependências:

Archlinux

No archlinux podemos instalar tudo a partir do pacman:

$ sudo pacman -Ss git arm-none-eabi-binutils arm-none-eabi-gcc arm-none-eabi-gdb arm-none-eabi-newlib

Exceto o west, que podemos instalar via pip:

$ pip3 install --user -U west

OU pelo aur:

$ yay -S python-west

Repositório

Vamos então clonar o repositório usando a ferramenta west, que a NXP escolheu como forma de manejo dos repositórios.

A forma de organização é a seguintes, a NXP disponibiliza o SDK, exemplos e middlewares na forma de diferentes repositórios no Github, então, se você deseja somente os componentes básicos como acesso as registradores, drivers de periféricos, camada CMSIS, ferramentas e scripts de build, basta clonar o repositório principal.

Agora de você deseja a camada de middleware, com mais abstrações e também exemplos, temos que usar a ferramenta west, qual vai coordenar o pull desses vários repositórios com a versão desejada. Aqui vamos puxar tudo pra ser mais completo.

Primeiro vamos definir qual versão desejamos, no github do SDK, e clicando no menu das branches, onde se diz main, vamos clicar em tags e escolher a versão desejada, vamos usar aqui a última versão estável, MCUX_2.16.000.

Então vamos criar uma pasta temporária e usar o west para puxar o SDK na versão escolhida.

$ mkdir mcuxsdk
$ west init -m "https://github.com/NXPmicro/mcux-sdk" --mr "MCUX_2.16.000" mcuxsdk
$ cd mcuxsdk
$ west update
$ cd ..

Aceite as confirmações e aguarde o download, vai demorar, aqui ficou em cerca de 13 Gb a instalação total.

Agora vamos instalar em um lugar mais fixo em nossa máquina para facilitar referencia-lo em nossas ferramentas, eu recomendo mover o repositório para usr/share/mcuxsdk.

$ sudo mv mcuxsdk /usr/share/
$ cd /usr/share/ 
$ sudo chown -R root:root mcuxsdk

Variáveis de ambiente

Para que os arquivos de build se achem depois, vamos definir algumas variáveis de ambiente, para a arm toolchain e para o sdk. Para isso vai depender do seus tipo de shell vamos os valores serão basicamente estes:

  • ARMGCC_DIR=/usr
  • SdkRootDirPath=/usr/share/mcuxsdk

ZSH ou BASH

Para estas basta adicionar as seguintes linhas em .bashrc ou .zshrc:

export ARMGCC_DIR=/usr
export SdkRootDirPath=/usr/share/mcuxsdk/2.16

Configurando Projeto

O SDK provém templates e exemplos prontos já, mas você irá notar que estes só funcionam dentro das pastas do SDK pois algumas referências são feitas de forma relacional e não absoluta, então para copiar e usar os templates precisamos arrumar alguns paths.

Vamos demonstrar usando a demo hello_world da placa EVKBIMXRT105, vamos copiar o exemplo para uma pasta de trabalho.

$ cp -r /usr/share/mcuxsdk/examples/evkbimxrt1050/demo_apps/hello_world .

Dentro da pasta armgcc do projeto temos vários scripts bat e sh, que chamam o sistema de build Cmake para compilar os projetos do SDK. Só que esses tem a referência relacional ao sdk, vamos mudar essa para o path absoluto do SDK via a variável de ambiente SdkRootDirPath e assim vamos conseguir compilar.

Recomendo usar a ferramenta de search and replace do Vscode para substituir o seguinte regex:

DCMAKE_TOOLCHAIN_FILE=".+/core

por:

DCMAKE_TOOLCHAIN_FILE="$SdkRootDirPath/core `` apenas no arquivos *.sh.

Assim, por exemplo, build_debug.sh irá ser:

#!/bin/sh
if [ -d "CMakeFiles" ];then rm -rf CMakeFiles; fi
if [ -f "Makefile" ];then rm -f Makefile; fi
if [ -f "cmake_install.cmake" ];then rm -f cmake_install.cmake; fi
if [ -f "CMakeCache.txt" ];then rm -f CMakeCache.txt; fi
cmake -DCMAKE_TOOLCHAIN_FILE="$SdkRootDirPath/core/tools/cmake_toolchain_files/armgcc.cmake" -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=debug  .
make -j 2>&1 | tee build_log.txt

Agora dentro de armgcc ainda, podemos tentar compilar invocando:

$ ./build_debug.sh

Se algo der errado, verifique se a sua linha de comando está carregando as variáveis de ambiente, se as variáveis estão sendo configuradas corretamente e se o valores delas batem com os paths de instalação.

Flash / Debug

Para gravar programas vai depender muito do fabricante do seu chip, por exemplo, para familia AVR podemos usar um conversor USB/Serial e o programa avrdude para gravar. Já o STM32 precisamos de um STLink e do programa que vem com o SDK.

No caso do IMXRT105 da NXP não é diferente, mas em todos os casos nós podemos usar o programa openocd, que nos permite gravar diretamente no processador um programa de debug e ter capacidades de debug com GDB, o que é bastante interessante pois o openocd funciona bastando apenas que nosso chip/placa possua uma interface SWD/JTAG, sem precisar de uma probe proprietária e específica.

Assim que configurarmos o openocd, vamos poder abrir um servidor GDB qual nosso vscode poderá interagir e utilizar as suas funções de debug e watch, que é uma das regalias que desejamos e o principal motivo de usar o vscode.

Para instalar vai depender do seus sistema mas ele está disponível geralmente no gerenciador de pacotes ou então com executáveis no website.

No archlinux:

$ sudo pacman -S openocd

Depois disso vamos criar dentro da pasta do projeto um arquivo de configuração:

openocd.cfg:

source [find interface/cmsis-dap.cfg] # interface da minha placa é a padrão CMSIS-DAP
source [find imxrt.cfg]               # target customizado para a familia do processador

set _CHIPNAME MXRT105                 # nome
adapter speed 2000                    # velocidade

O arquivo de configuração basicamente define:

  • A interface a ser usada, por exemplo, probes JLink, STLink, ou no meu caso, minha placa já vem com interface debug em hardware padrão CMSIS-DAP.
  • O target, ou arquitetura, por exemplo, atmega32, stm32, ou no meu caso, imxrt. (Normalmente usaríamos algo como “target/atmega” ou algo do tipo, mas nesse caso em específico o arquivo não vem instalado com o openocd nessa versão dentro da pasta target/, portanto eu baixei o arquivo aqui, e coloquei na pasta do projeto para poder importar dentro desse arquivo de configuração)
  • Configurações secundárias como nomes, velocidade de comunicação e protocolo, por exemplo SWD ou JTag.

Assim basta executar:

$ openocd

E o servidor GDB será aberto e sua conexão com o chip será feita

Vscode

Debug

Agora do lado do Vscode vamos fazer o debug funcionar, para isso vamos a pasta (se não existir ainda) .vscode, e dois arquivos dentro dela:

Launch define iniciar o debug, executando uma build task, se conectando ao GDB e então mostrando a interface de debug no editor. (Lembre de trocar PROJETO pelo nome do seu executável e a preLaunchTask também) launch.json:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "PROJETO (debug)",
            "type": "cppdbg",
            "request": "launch",
            "cwd": "${workspaceFolder}",
            "program": "${workspaceFolder}/armgcc/debug/PROJETO.elf",
            "preLaunchTask": "build debug",
            "MIMode": "gdb",
            "miDebuggerPath": "arm-none-eabi-gdb",
            "miDebuggerServerAddress": "localhost:3333",
            "useExtendedRemote": true,
            "postRemoteConnectCommands": [
                {"text": "mon reset"},
                {"text": "mon halt"},
                {"text": "load"}
            ]
        }
    ]
}

Em tasks definimos a task para ser executada antes do debug, ou seja, a build_debug. (Note como definimos as variáveis de ambiente aqui também novamente, pois o vscode não usa as mesma variáveis que a linha de comando) tasks.json:

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build debug",
            "type": "shell",
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "options": {
                "cwd": "armgcc",
                "env": {
                    "ARMGCC_DIR": "/usr",
                    "SdkRootDirPath": "/usr/share/mcuxsdk/2.16"
                }
            },
            "command": "./build_debug.sh"
        }
    ]
}

Agora abra um terminal, execute o openocd, e dentro do vscode você poderá apertar F5, e a aplicação será compilada, gravada e o debug será aberto no vscode.

Autocomplete

Por fim, para facilitar a vida, vamos adicionar algumas extensões e configurações para podermos ter autocomplete enquanto programamos.

Extensões:

E a configuração dentro de .vscode:

settings.json:

{
    "configurations": [
        {
            "name": "Linux",
            "includePath": [
                "${workspaceFolder}/**",
                "/usr/share/mcuxsdk/core/CMSIS/Core/Include/**",
                "/usr/share/mcuxsdk/core/CMSIS/Driver/Include/**",
                "/usr/share/mcuxsdk/core/drivers/**",
                "/usr/share/mcuxsdk/core/components/**",
                "/usr/share/mcuxsdk/core/utilities/**",
                "/usr/share/mcuxsdk/core/cmsis_drivers/**",
                "/usr/share/mcuxsdk/core/boards/evkbimxrt1050/**",
                "/usr/share/mcuxsdk/core/devices/MIMXRT1052",
                "/usr/share/mcuxsdk/core/devices/MIMXRT1052/**"
            ],
            "defines": [
                "CPU_MIMXRT1052DVL6B",
                "MCUXPRESSO_SDK",
                "SERIAL_PORT_TYPE_UART=1"
            ],
            "compilerPath": "/usr/bin/arm-none-eabi-gcc",
            "cStandard": "c17",
            "cppStandard": "c++17",
            "intelliSenseMode": "linux-gcc-arm"
        }
    ],
    "version": 4
}

Onde definimos alguns paths para o vscode achar os arquivos fonte do sdk, e alguns defines, esses refletem as configurações do CMake do SDK oficial. Só lembre de apontar para o seu chip específico.

Conclusão

É isso rapaziada, tudo funcionando, só cuidar pra adicionar mais paths no vscode caso ele não ache algum arquivo, ver no console mesmo se tudo está compilando e debugando certinho. Provavelmente você querer fazer alguma coisa extra e vai dar algum pau, mas você terá a liberdade de mexer no processo de compilação e gravação e não vai ficar refém de ferramentas que fazer tudo por trás dos panos.

Vale lembrar que algumas opções mais fáceis como a IDE da NXP, a extensão MCUXpress e Platform.io são maneiras mais fáceis de usar tudo isso, vai do seu grau de conforto, minha opinião é, é fácil no inicio e depois só atrapalha.

E é isso, qualquer sugestão de melhorias ou comentários comente abaixo. Valeu e até a próxima!

Referências