BSP et pilotes standalone
Comprendre la bibliothèque C embarquée, la structure d'un BSP et les deux niveaux de pilotes utilisés par une application Vitis.
Le rôle du BSP
Une application embarquée ne doit pas deviner la configuration du matériel. Le Board Support Package, ou BSP, décrit les services disponibles pour un processeur et un domaine logiciel précis.
Le terme standalone désigne ici un environnement bare-metal minimal. Le programme s'exécute sans Linux et utilise directement le BSP, les pilotes et les exceptions du processeur.
Dans Vitis, une plateforme associe le fichier XSA à un ou plusieurs domaines. Chaque domaine choisit un processeur, un système d'exploitation et un BSP. Une modification du matériel impose donc de mettre à jour la plateforme avant de reconstruire l'application.
Le BSP contient quatre familles d'éléments.
| Élément | Rôle |
|---|---|
| En-têtes générés | Adresses, identifiants et paramètres du matériel |
| Pilotes | Accès aux périphériques du PS et de la PL |
| Bibliothèques | C standard, fichiers, réseau et services système |
| Code de démarrage | Table des vecteurs, initialisation et gestion des exceptions |
La bibliothèque C utilisée en standalone s'appuie sur Newlib, une implémentation adaptée aux systèmes embarqués. Elle fournit des fonctions courantes comme memcpy, printf et l'allocation dynamique. Les services qui supposent la présence d'un système d'exploitation doivent être adaptés à la plateforme.
Lire xparameters.h
xparameters.h est généré depuis le matériel exporté. Il contient les adresses de base, les identifiants de périphériques, les identifiants d'interruption et certaines fréquences.
#include "xparameters.h"
#define LED_BASEADDR XPAR_FPT_LED_BANK_BASEADDR
#define TIMER_ID XPAR_XTTCPS_0_DEVICE_IDCes symboles sont plus sûrs qu'une adresse écrite directement dans le code. Ils restent cependant liés au nom des instances du Block Design. Après une modification de l'IP ou de l'Address Editor, il faut régénérer le XSA et le BSP.
Pilotes de niveau 0
Le niveau 0 fournit des macros proches des registres. Il est compact et explicite. Le programme doit connaître l'adresse de base et les offsets.
#include "xgpio_l.h"
void leds_write(UINTPTR base, u32 value)
{
XGpio_WriteReg(base, XGPIO_TRI_OFFSET, 0x0U);
XGpio_WriteReg(base, XGPIO_DATA_OFFSET, value & 0xFFU);
}Cette approche convient à un chargeur, à un test court ou à une séquence d'initialisation. Elle offre peu de protection contre une mauvaise instance ou un mauvais ordre d'appel.
Pilotes de niveau 1
Le niveau 1 utilise une structure d'instance. Une fonction de recherche récupère la configuration, puis une fonction d'initialisation relie cette configuration à l'objet logiciel.
XGpio gpio;
int gpio_init(void)
{
int status = XGpio_Initialize(&gpio, XPAR_FPT_LED_BANK_DEVICE_ID);
if (status != XST_SUCCESS) {
return XST_FAILURE;
}
XGpio_SetDataDirection(&gpio, 1, 0x0U);
return XST_SUCCESS;
}La structure conserve l'adresse et l'état du pilote. Ce modèle facilite plusieurs instances, les callbacks et la vérification des erreurs.
Choisir les bibliothèques
Le BSP peut intégrer des composants supplémentaires. XilFFS fournit un système de fichiers FAT pour une carte SD ou une mémoire eMMC. lwIP fournit une pile réseau légère. D'autres bibliothèques gèrent la mémoire Flash ou des interfaces de stockage.
Chaque bibliothèque augmente la taille du programme et peut demander des buffers. Le choix doit être fait à partir du besoin réel, de la mémoire disponible et du modèle d'exécution.
Une initialisation robuste
Une application fiable vérifie chaque retour. Elle ne continue pas si le pilote ne trouve pas sa configuration.
Le programme ci-dessous est un exemple complet proposé dans ce cours. init_platform() appelle le code de préparation défini dans platform.c. Son contenu dépend de la cible et peut notamment gérer les caches ou une UART 16550. Il ne configure pas automatiquement l'AXI GPIO, qui reste initialisé séparément par gpio_init().
cleanup_platform() exécute le nettoyage prévu dans platform.c, généralement la désactivation des caches dans un projet standalone. Le programme l'appelle sur le chemin d'erreur et avant son retour normal. Cette fonction ne libère pas automatiquement les périphériques initialisés par l'application.
int main(void)
{
int status;
init_platform();
status = gpio_init();
if (status != XST_SUCCESS) {
xil_printf("GPIO initialization failed\r\n");
cleanup_platform();
return XST_FAILURE;
}
XGpio_DiscreteWrite(&gpio, 1, 0x55U);
cleanup_platform();
return XST_SUCCESS;
}Dans ce programme, le code de plateforme prépare uniquement les services prévus par platform.c. Le pilote configure le GPIO. La fonction main() applique ensuite la logique de l'application et traite chaque erreur avant de quitter.
Références officielles
La structure actuelle d'une plateforme, des domaines et du BSP est décrite dans le guide Vitis Embedded Software Development UG1400. Les sources et les exemples officiels des pilotes sont disponibles dans le dépôt AMD embeddedsw.
À retenir
Le XSA décrit le matériel. Dans le projet de plateforme Vitis, l'ingénieur crée les domaines logiciels et choisit leur processeur cible. La génération du BSP fournit ensuite les pilotes et les bibliothèques adaptés à chaque domaine. Le niveau 0 accède directement aux registres. Le niveau 1 apporte une structure d'instance et une interface plus sûre.
Tester mes connaissances - Quiz du chapitre