Un premier projet pour Visual Studio Code

Ce premier projet simple a cinq objectifs :


 - Comprendre comment configurer Visual Studio Code,
 - Comprendre comment compiler un projet sous Visual Studio Code.
 - Comprendre comment lancer l'exécution d'un projet sous Visual Studio Code,

 - Comprendre comment déboguer d'un projet sous Visual Studio Code,

 - Comprendre comment intégrer une librairie d'accès aux ressources matériel du Pico.


Ce projet est un exemple de lecture de la température du Pico. Il fonctionnera aussi bien sur un Pico que sur un Pico W. Pour les débutants, il est conseillé de lire la rubrique Un premier projet avant celle-ci car elle détaille les composants de base d'un projet (le fichier CMakeLists.txt principalement).


Avant de créer ce projet, vérifiez ou mettez en place la liaison entre la plateforme de développement et le Pico telle que décrite à la rubrique Un premier projet / Relier le Pico à la plateforme de développement.

Création du projet

Nous pourrions créer notre premier projet à l'aide de l'utilitaire "Pico Project Generator", mais afin de bien comprendre comment tout cela fonctionne, nous allons créer ce projet manuellement. Si vous avez suivi les procédures d'installation données aux rubriques Installation du kit de développement sur un Raspberry Pi ou Installation du kit de développement sur un PC Linux, vous pouvez créer ce projet dans un répertoire enfant du répertoire "pico/pico-projects". Nous allons également créer les 2 fichiers de base de tout projet. Dans un terminal, exécutez les commandes suivantes :


cd ~
cd pico/pico-projects
mkdir picotemp
cd picotemp
touch CMakeLists.txt
touch picotemp.cpp


Avec n'importe quel éditeur de texte, par exemple : Geany, modifiez les deux fichiers que nous venons de créer comme suit.


Fichier CMakeLists.txt


Copier/Coller le code suivant :


cmake_minimum_required(VERSION 3.13)

set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

# Pull in Raspberry Pi Pico SDK (must be before project)
include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)

if (PICO_SDK_VERSION_STRING VERSION_LESS "1.3.0")
   message(FATAL_ERROR "Raspberry Pi Pico SDK version 1.3.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}")
endif()

project(picotemp C CXX ASM)

# Initialise the Raspberry Pi Pico SDK
pico_sdk_init()

# Add executable. Default name is the project name, version 0.1
add_executable(picotemp picotemp.cpp )

pico_set_program_name(picotemp "picotemp")
pico_set_program_version(picotemp "0.1")

pico_enable_stdio_uart(picotemp 1)
pico_enable_stdio_usb(picotemp 0)

pico_add_extra_outputs(picotemp)

# Add the standard include files to the build
target_include_directories(picotemp PRIVATE
   ${CMAKE_CURRENT_LIST_DIR}
   ${CMAKE_CURRENT_LIST_DIR}/..
)

# Add the standard library to the build
# Add any user requested libraries
target_link_libraries(picotemp
      pico_stdlib
)

Pour des explications sur le contenu de ce fichier, se reporter à la rubrique Un premier projet.


Fichier picotemp.cpp


Copier/Coller le code suivant :


‹stdio.h›
#include "pico/stdlib.h"

int main()
{
   stdio_init_all();

   printf("Hello World!\n");

   return 0;
}

Le contenu de ce fichier sera modifié par la suite.

Configurer Visual Studio Code

Visual Studio Code est un super logiciel qui peut faire tellement de trucs que ça en fait une véritable usine à gaz. Il doit être configuré pour chaque projet. Pour un certain nombre de fonctionnalités (pas toutes...), il peut être configuré manuellement, mais c'est fastidieux... Il y en a partout. La méthode de configuration la plus simple, et parfois même l'unique méthode de configuration est de lui fournir des fichiers de configuration.


Ces fichiers de configuration sont au format JSON et portent l'extension ".json. Pour configurer Visual Studio Code, nous allons lui fournir 4 fichiers de ce type positionnés dans un répertoire spécifique de notre projet. Ouvrez un terminal et exécutez les commandes suivantes :


cd ~
cd pico/pico-projects/picotemp
mkdir .vscode
cd .vscode
touch c_cpp_properties.json
touch settings.json
touch extensions.json
touch launch.json


Avec n'importe quel éditeur de texte, par exemple : Geany, modifiez les fichiers que nous venons de créer comme suit.


Fichier c_cpp_properties.json


Copier/Coller le code suivant :


{
  "configurations": [
    {
      "name": "Linux",
      "includePath": [
        "${workspaceFolder}/**",
        "${env:PICO_SDK_PATH}/**"
      ],
      "defines": [],
      "compilerPath": "/usr/bin/arm-none-eabi-gcc",
      "cStandard": "gnu17",
      "cppStandard": "gnu++14",
      "intelliSenseMode": "linux-gcc-arm",
      "configurationProvider" : "ms-vscode.cmake-tools"
    }
  ],
  "version": 4
}

En deux mots : Ce fichier définie la plateforme de fonctionnement : Linux, indique la localisation des fichiers d'inclusion, précise le compilateur à utiliser ainsi que les versions de langages C et C++, indique que le mode intellisense de Visual Studio Code est celui du compilateur C/C++ et définie que cmake est notre utilitaire de configuration du projet.


Fichier settings.json


Copier/Coller le code suivant :


{
  "cmake.configureOnOpen": false,
  "cmake.statusbar.advanced": {
    "debug" : {
    "visibility": "hidden"
      },
    "launch" : {
    "visibility": "hidden"
      },
    "buildTarget" : {
    "visibility": "hidden"
      }
  },
}

Ce fichier configure le plugin cmake pour s'assurer que le bon debogueur est utilisé et que Visual Studio Code ne tentera pas de lancer l'exécution du programme sur l'hôte de développement plutôt que sur le Pico.


Fichier extensions.json


Copier/Coller le code suivant :


{
  "recommendations": [
    "marus25.cortex-debug",
    "ms-vscode.cmake-tools",
    "ms-vscode.cpptools"
  ]
}

Ce fichier définie les plugin d'extensions requis par le projet.


Fichier launch.json


Ce fichier définie comment Visual Studio Code doit lancer une exécution ou un débogage du projet.


ATTENTION : Ce fichier devra être adapté en fonction de votre configuration de liaison entre la plateforme de développement (Rapsberry Pi ou PC Linux) et le Pico. Nous donnons ci-dessous les versions adaptées aux configurations de liaisons décrites au paragraphe Un premier projet / Relier le Pico à la plateforme de développement.


   Liaison directe entre un Rapsberry Pi et le Pico :


Copier/Coller le code suivant :


{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Cortex Debug",
      "cwd": "${workspaceRoot}",
      "executable": "${command:cmake.launchTargetPath}",
      "request": "launch",
      "type": "cortex-debug",
      "servertype": "openocd",
      "gdbPath": "gdb-multiarch",
      "device": "RP2040",
      // Config Pi <--> Pico
      "configFiles": [
        "interface/raspberrypi-swd.cfg",
        "target/rp2040.cfg"
        ],
      "svdFile": "${env:PICO_SDK_PATH}/src/rp2040/hardware_regs/rp2040.svd",
      "runToEntryPoint": "main",
      "postRestartCommands": [
        "break main",
        "continue"
      ]
    }
  ]
}

   Liaison via Debug Probe entre un PC Linux ou un Rapsberry Pi et le Pico :


Copier/Coller le code suivant :


{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Cortex Debug",
      "cwd": "${workspaceRoot}",
      "executable": "${command:cmake.launchTargetPath}",
      "request": "launch",
      "type": "cortex-debug",
      "servertype": "openocd",
      "gdbPath": "gdb-multiarch",
      "device": "RP2040",
      // Config Pi/PC <--> Debug Probe <--> Pico
      "configFiles": [
        "interface/cmsis-dap.cfg",
        "target/rp2040.cfg"
        ],
      "svdFile": "${env:PICO_SDK_PATH}/src/rp2040/hardware_regs/rp2040.svd",
      "runToEntryPoint": "main",
      "serverArgs": [
        "-c" "adapter speed 5000"
        ],
      "postRestartCommands": [
        "break main",
        "continue"
      ]
    }
  ]
}

Comme il est détaillé à la rubrique Configuration openocd de la page d'installation du SDK sur un PC Linux, il est absolument nécessaire de pouvoir lancer openocd depuis visual studio code sans avoir besoin d'être un super utilisateur. Avant d'aller plus loin, vérifiez que vous avez effectué les opérations de la rubrique Configuration openocd.

Charger le projet dans Visual Studio Code

Dans ce paragraphe, nous chargeons le projet dans Visual Studio Code, nous le compilons, le chargeons et vérifions son exécution en mode release.


Avant de lancer Visual Studio Code il est nécessaire de créer un répertoire "build" pour notre projet :


cd ~
cd pico/pico-projects/picotemp
mkdir build


Démarrez Visual Studio Code. Dans Visual Studio Code, ouvrez un répertoire (commande Ctrl+K suivi de Ctrl+O) et sélectionnez le répertoire "/pico/pico-projects/picotemp". L'interface opérateur de Visual Studio Code devrait ressembler à ça /



Nous allons d'abord vérifier que nous compilons et exécutons correctement une version en mode "Release". Sur la barre d'état en bas de la fenêtre de Visual Studio, cliquez sur "Cmake [Debug] Ready" :



Un menu s'ouvre en haut de l'éditeur. sélectionnez l'option "Release Optimize for speed - exclude debug information". Sur la barre d'état vérifiez que le texte écrit à côté de l'icône outil est bien "[GCC 10.3.1 arm-none-eabi] :



Si ce n'est pas le cas, cliquez sur ce texte et choisissez cette option dans le menu déroulant qui s'ouvre en de l'éditeur.


Compilez le projet par un appui sur le bouton "Build" :



Dans la barre de menu principal de Visual Studio, sélectionnez le menu "Terminal", puis l'option "New Terminal". La fenêtre de Visual Studio doit alors afficher un terminal :



Dans ce terminal exécutez la commande :


cd build


Lancez un terminal (indépendamment de Visual Studio), et dans ce terminal, exécutez la commande suivante :


sudo minicom -D /dev/ttyACM0 -b 115200


De retour dans le terminal de Visual Studio, exécutez la commande suivante :


openocd -f interface/cmsis-dap.cfg -target/rp2040.cfg -c "adapter speed 5000" -c "program picotemp.elf verify reset exit"


L'autre terminal doit afficher "Hello World".

Débogage du projet dans Visual Studio Code

Pour compiler le programme en mode "Debug", Dans la barre d'état de Visual Studio, sélectionnez la variante "CMake {Debug]" comme cela a été fait pour la variante "CMake {Release]" au paragraphe précédent, puis, compilez le projet par un appui sur le bouton "Build".


Sélectionnez le mode "Run and Debug" : Raccourci : Ctrl+Maj+D. La fenêtre de Visual Studio est alors la suivante :



Pour lancer l'exécution, cliquez sur la fleche verte comme le montre l'image ci-dessous :



La barre d'outils de débogage est alors affichée :



Pour démarrer l'exécution, clicquez sur la flêche de couleur bleue :



L'autre terminal doit afficher "Hello World".


Les fonctions des boutons de la barre d'outils de débogage sont :


Réinitialise le Pico sans redémarrer le programme
Démarre le programme
Exécute l'instruction en pas à pas
Entre dans la fonction en pas à pas
Sort de la fonction en pas à pas
Réinitialise et redémarre le programme
Arrête le programme et le débogage

Lecture de la température du Pico

Le Pico dispose d'une sonde de température interne qu'il est possible de lire via son convertisseur analogique numérique (ADC). La sonde de température est reliée à l'entrée 4 de l'ADC. Pour pouvoir accéder aux fonctions du SDK de lecture de l'ADC, il faut d'abord modifier la section "target_link_libraries" du fichier "CMakeLists.txt" pour utiliser la librairie "hardware_adc". La modification à apporter est la suivante :


# Add the standard library to the build
# Add any user requested libraries
target_link_libraries(picotemp
      pico_stdlib
      hardware_adc
)

Il faut bien sur ajouter l'inclusion du fichier d'entête correspondant dans le fichier "picotemp.cpp" comme suit :


#include ‹stdio.h›
#include "pico/stdlib.h"
#include "hardware/adc.h"

Notre programme va mesurer cette température toutes les secondes. Nous devons, initialiser le convertisseur, activer la sonde de température et sélectionner l'entrée 4 du convertisseur. Nous devons inclure une boucle infinie avec cette temporisation de 1 seconde dans la fonction "main" et y utiliser la fonction "adc_read" du SDK sur l'entrée 4 du convertisseur. Le code est donc modifié comme suit :


int main()
{
  uint rawADC;

  stdio_init_all();

  adc_init();
  adc_set_temp_sensor_enabled(true);
  adc_select_input(4);

  while(true)
  {
    rawADC = adc_read();

    sleep_ms(1000);
  }
}

La référence de tension du convertisseur interne au Pico est de 3,3V. La conversion se fait sur 12 bit, soit une résolution en tension de 3,3 / 4096. Pour obtenir une valeur en tension, nous devons donc multiplier la lecture du convertisseur (variable rawADC) par cette résolution. Nous modifions donc le code comme suit :


int main()
{
  uint rawADC;
  float voltage;
  stdio_init_all();

  adc_init();
  adc_set_temp_sensor_enabled(true);
  adc_select_input(4);

  while(true)
  {
    rawADC = adc_read();
    voltage = rawADC * (3.3 / 4096);

    sleep_ms(1000);
  }
}

La documentation du Pico nous dit que la formule de linéarisation de tension en température pour la sonde de température interne est : "Température = 27.0f - (Tension - 0.706f) / 0.001721f". On finalise notre code comme suit :


int main()
{
  uint rawADC;
  float voltage;
  float temperature;

  stdio_init_all();

  adc_init();
  adc_set_temp_sensor_enabled(true);
  adc_select_input(4);

  while(true)
  {
    rawADC = adc_read();
    voltage = rawADC * (3.3 / 4096);
    temperature = 27.0f - (voltage - 0.706f) / 0.001721f;

    printf("Température Pico : %.2f °C", temperature);

    sleep_ms(1000);
  }
}

Lancez une compilation en debug ou release, lancez le programme. Dans un terminal dans lequel vous lancez "minicom", la température du Pico sera affichée.