Développement du «firmware» le plus simple pour les FPGA installés dans Redd. Partie 2. Code de programme

Ainsi, dans le dernier article, nous avons développé le système de processeur le plus simple, à l'aide duquel nous prévoyons de tester la puce RAM connectée au FPGA du complexe Redd. Aujourd'hui, nous allons créer un programme C ++ pour cet environnement matériel, et nous allons également découvrir comment injecter ce programme, et surtout, le déboguer.



Le programme est développé dans l'environnement Eclipse. Pour le démarrer, sélectionnez l'élément de menu Outils-> Outils de création de logiciels Nios II pour Eclipse .



Nous devons créer un projet et un BSP pour cela. Pour ce faire, cliquez avec le bouton droit de la souris dans la zone Explorateur de projets et sélectionnez l'élément de menu Nouveau-> Application Nios II et BSP dans le modèle .



Le modèle de base sur la base duquel le projet sera créé a été créé lors de la génération du système de processeur. Par conséquent, nous trouvons le fichier qui le contient.



Nous donnerons également un nom au projet (je l'ai SDRAMtest ) et sélectionnerons le type de projet. J'ai choisi Hello World Small . Je voudrais choisir Memory Test , nous faisons un test de mémoire, mais maintenant nous envisageons une manière générale de créer des applications. Par conséquent, nous choisissons l'option générale.



Nous avons créé deux projets. Le premier est notre projet, le second est BSP (Board Support Package, en gros, des bibliothèques pour travailler avec des équipements).



La première chose que je fais habituellement est de modifier les paramètres BSP. Pour ce faire, je sélectionne le deuxième des projets créés, appuie sur le bouton droit de la souris et sélectionne l'élément de menu Nios II -> BSP Editor .



Dans l'éditeur, tout est divisé en groupes:



Mais pour ne pas les parcourir, je vais sélectionner la racine de l'arborescence, l'élément Settings , et considérer tout linéairement. Je vais énumérer ce à quoi vous devez faire attention. Écran des paramètres initiaux:



La prise en charge de la sortie et la prise en charge de la suppression lors de la fermeture est désactivée, ce qui élimine les éléments inutiles de taille énorme du code, mais ils sont désactivés au départ. Ces choucas se sont éteintes, car j'ai choisi l'option minimale Hello, World . Lors du choix d'autres types de code, il est préférable de supprimer également ces daws. Je ne peux pas résister et activer le support C ++. Il est également nécessaire de supprimer la vérification SysID , sinon rien ne fonctionnera. Le fait est que lors de la réalisation du système matériel, je n'ai pas ajouté le bloc correspondant. Les paramètres restants sont explicites et n'ont pas été modifiés. En fait, je n'ai pas encore changé d'autres paramètres. Un peu plus tard, nous reviendrons ici, mais pour l'instant nous appuyons sur le bouton Générer. Nous créons une nouvelle version de BSP basée sur les paramètres définis. À la fin, cliquez sur Quitter.

Maintenant, le plaisir commence. Comment assembler un projet. Appuyez sur la touche Ctrl + B habituelle - nous obtenons une erreur. Erreur de décodage no:



Rien de raisonnable non plus dans la console:



Sélectionnez le projet de construction pour le projet SDRAMtest , nous obtenons une explication raisonnable:



En fait, les modèles qui ne fonctionnent pas sont l'identité d'entreprise de Quartus. C'est une autre raison pour laquelle je n'ai pas choisi le test de mémoire . Il y a de plus en plus de course. Ici, c'est clair quel est le problème.

Cette fonction du fichier alt_putstr.c échoue :

/* * Uses the ALT_DRIVER_WRITE() macro to call directly to driver if available. * Otherwise, uses newlib provided fputs() routine. */ int alt_putstr(const char* str) { #ifdef ALT_SEMIHOSTING return write(STDOUT_FILENO,str,strlen(str)); #else #ifdef ALT_USE_DIRECT_DRIVERS ALT_DRIVER_WRITE_EXTERNS(ALT_STDOUT_DEV); return ALT_DRIVER_WRITE(ALT_STDOUT_DEV, str, strlen(str), 0); #else return fputs(str, stdout); #endif #endif } 

Nous le corrigerons plus tard (pour cela, nous devons compliquer le système matériel). Aujourd'hui, nous n'en avons tout simplement pas besoin. Remplacez son corps par le retour 0 . Le projet commence à se monter.

Super. Nous avons déjà un fichier elf prêt (même s'il n'effectue aucune fonction utile) et nous avons un équipement dans lequel vous pouvez télécharger le fichier hex (rappelez-vous comment nous avons dit au compilateur Quartus que les données RAM devraient être chargées à partir de celui-ci en définissant Onchip RAM?). Comment convertir un elfe en hexagone ? Très simple. Nous abordons le projet de travail, appuyez sur le bouton droit de la souris, sélectionnez l'élément de menu Make Targets-> Build :



Dans la fenêtre qui apparaît, essayez d'abord de sélectionner la première option ( mem_init_install ):



Rien ne se passera. Mais à partir du message d'erreur qui nous est donné, nous apprenons à finaliser le projet pour Quartus:

 ../SDRAMtest_bsp//mem_init.mk:230: *** Deprecated Makefile Target: 'mem_init_install'. Use target 'mem_init_generate' and then add mem_init/meminit.qip to your Quartus II Project. Stop. 

Nous allons sélectionner la construction dans le but de mem_init_generate , après quoi (juste après !!!) nous ajouterons le fichier qip spécifié au projet matériel (nous avons déjà appris comment ajouter des fichiers lorsque nous avons ajouté un système de processeur au projet).



Eh bien, le fichier hexagonal lui-même peut également être ressenti avec vos mains. Le voici:



Super. Nous avons tout pour commencer à remplir le programme avec de vraies fonctionnalités. Nous allons dans le fichier hello_world_small.c . Honnêtement, je suis un peu offensé de travailler avec du C. pur Par conséquent, je le renommerai cpp. Et pour que rien ne se passe mal, je vais ajouter un sort magique au texte existant:



Même texte:
 extern "C" { #include "sys/alt_stdio.h" } int main() { alt_putstr("Hello from Nios II!\n"); /* Event loop never exits. */ while (1); return 0; } 


Il est important d'effectuer l'opération Nettoyer le projet après avoir changé le type de fichier, sinon le compilateur affichera des messages d'erreur indiquant que le fichier * .c n'a pas été trouvé sur la base de certaines informations mises en cache.

Nous rendrons le test de mémoire simple. Je n'ai pas pour tâche d'apprendre au lecteur à tester correctement la puce RAM. Nous nous assurons simplement superficiellement que les bus d'adresses et de données ne sont pas collants et n'ont pas de coupures. Autrement dit, nous écrivons dans chaque cellule tous les zéros et l'adresse de la cellule. Notre tâche est de faire du code de travail, et tout le reste (autres constantes de remplissage et de retard pour vérifier que les données sont régénérées) sont des détails d'implémentation qui compliquent le texte mais ne changent pas son essence.

Commençons par une question simple et naturelle: "Où se trouve la SDRAM dans l'espace d'adressage?" Je me souviens que nous avons appelé la fonction d'attribution automatique des adresses, mais nous n'avons même pas regardé quelles adresses étaient réellement attribuées. En fait, même maintenant, nous n'y regarderons pas. Toutes les informations nécessaires sont dans le dossier:
... \ SDRAMtest_bsp \ system.h .

En conséquence, nous obtenons le code suivant:
 extern "C" { #include "sys/alt_stdio.h" #include <stdint.h> #include "../SDRAMtest_bsp/system.h" #include <altera_avalon_pio_regs.h> } int main() { bool bRes = true; volatile static uint32_t* const pSDRAM = (uint32_t*)NEW_SDRAM_CONTROLLER_0_BASE; static const int sizeInDwords = NEW_SDRAM_CONTROLLER_0_SPAN / sizeof (uint32_t); //  for (int i=0;i<sizeInDwords;i++) { pSDRAM [i] = 0; } //   for (int i=0;i<sizeInDwords;i++) { if (pSDRAM [i] != 0) { bRes = false; } } //   for (int i=0;i<sizeInDwords;i++) { pSDRAM [i] = i; } //    for (int i=0;i<sizeInDwords;i++) { if (pSDRAM [i] != i) { bRes = false; } } if (bRes) { IOWR_ALTERA_AVALON_PIO_DATA (PIO_0_BASE,0x01); } else { IOWR_ALTERA_AVALON_PIO_DATA (PIO_0_BASE,0x02); } /* Event loop never exits. */ while (1); return 0; } 


Nous collectons le fichier hex (je me souviens qu'à travers cette boîte de dialogue):



Après cela, nous compilons l'équipement dans Quartus et entrons dans le programmateur pour charger le «firmware» résultant avec le code de programme initialisé résultant dans la puce.



Versez le «firmware» et obtenez un message indiquant que le système ne vivra que lorsqu'il sera connecté à JTAG (fonctionnalités de la licence du noyau SDRAM dans l'environnement de développement gratuit). En fait, pour le cas de Redd, ce n'est pas critique. Ce JTAG est là tout le temps.



Les résultats du test RAM peuvent être vus sur le connecteur, les contacts C21 (réussi) ou B21 (erreur). Nous nous connectons à eux avec un oscilloscope.



Les deux sorties sont à zéro. Quelque chose ne va pas ici. Reste à comprendre quoi exactement. En fait, un programme inopérant est tout simplement génial, car nous allons maintenant commencer à apprendre le débogage JTAG. Nous visons le projet, sélectionnez Debug As-> Nios II Hardware .



La première fois que le système ne trouve pas le matériel. Cela ressemble à ceci (notez la croix rouge dans l'en-tête de l'onglet en surbrillance):



Basculez vers l'onglet Connexion cible et cochez la case Ignorer les ID système incompatibles . Au cours des expériences suivantes, j'ai parfois également dû définir l' horodatage du système Ignore Mismatched . Juste au cas où, je le mettrai en évidence dans l'image non pas avec un rouge, mais avec un cadre jaune pour souligner qu'il n'est pas nécessaire de l'installer maintenant, mais si le bouton Debug n'est pas activé, il est peut-être temps de l'installer.



Appliquer ( Appliquer ), puis cliquez sur Actualiser les connexions (ce bouton est masqué, vous devez le faire défiler):



Un débogueur apparaît dans la liste, vous pouvez cliquer sur Déboguer ...



Nous nous sommes arrêtés à la fonction main () . Si vous le souhaitez, vous pouvez mettre un point d'arrêt à la fin de l'algorithme et vérifier si le programme l'atteint:



Exécutez le programme:



Le point d'arrêt n'a pas fonctionné. Arrêtons le programme et voyons où il s'exécute.



Tout va mal. Le programme s'est clairement écrasé. En organisant successivement les points d'arrêt, puis en arrêtant (avec le bouton rouge «Stop») et en redémarrant le programme (en utilisant le bouton bug), on retrouve la zone à problème.

Tout meurt lorsque cette ligne est exécutée pour le tout premier élément:


Même texte:
  for (int i=0;i<sizeInDwords;i++) { if (pSDRAM [i] != 0) { bRes = false; } } 


Du point de vue du C ++, tout est propre ici. Mais si vous ouvrez le code désassemblé, vous pouvez voir qu'il y a trop de commandes uniformes là-bas. Il semble que le code se soit effacé. Et il pourrait le faire si l'éditeur de liens le mettait en SDRAM (dont le contenu écrase ce code).



Nous arrêtons le débogage, fermons la perspective de débogage.



Nous allons à l'éditeur BSP, dans lequel nous étions au début de cet article, mais à l'onglet Script de l'éditeur de liens . Si je corrigeais cet onglet au tout début, je ne serais pas en mesure de montrer la technique d'entrée du débogage JTAG (et de souligner toute sa puissance par rapport à la sortie de débogage simple, car le fait du code coincé pendant le débogage JTAG a attiré mon attention). Il en est ainsi. Un bon éditeur de liens met tout en mémoire, dont la taille est plus grande.



Nous redirigeons tout vers onchip_memory ... Maintenant nous avons la SDRAM - c'est juste un morceau de mémoire, dont les performances ne sont pas encore garanties. Vous ne pouvez le donner à aucune action de compilation automatique.



Nous reconstruisons bsp , reconstruisons le projet. Dois-je recréer l'image mémoire et surcharger le FPGA? Ensuite, pour un travail semi-autonome, cela sera nécessaire, mais pendant que le débogage est en cours - non. Une nouvelle version du programme sera immédiatement chargée dans la RAM lorsqu'une nouvelle session de débogage commence. Mais pour qu'au prochain démarrage du FPGA, il ne soit pas nécessaire de lancer le débogueur, de faire un nouveau fichier HEX à la fin du débogage et de collecter avec lui le «firmware» du FPGA.

Pour le nouveau code, un point d'arrêt a été atteint, le résultat du test est vrai :



L'oscilloscope s'est amusé: le rayon jaune a volé en bloc.



Test réussi. Allons un peu délicat et vérifions simultanément les performances du système. Faisons la finale comme ceci:

  //    GPIO if (bRes) { while (true) { IOWR_ALTERA_AVALON_PIO_DATA (PIO_0_BASE,0x01); IOWR_ALTERA_AVALON_PIO_DATA (PIO_0_BASE,0x00); } } else { while (true) { IOWR_ALTERA_AVALON_PIO_DATA (PIO_0_BASE,0x02); IOWR_ALTERA_AVALON_PIO_DATA (PIO_0_BASE,0x00); } } 

En conséquence, nous avons un tel méandre sur l'oscilloscope (tout était connecté via une longue boucle, donc un capteur capacitif est apparu sur la deuxième ligne, ne faites pas attention à lui):



Le résultat est une fréquence d'environ 8,3 MHz à une fréquence d'horloge de 50 MHz sans aucun réglage fin du cœur du processeur et optimisation du code de programme. Autrement dit, l'accès aux ports passe à une fréquence légèrement supérieure à 16 MHz, ce qui correspond à un tiers de la fréquence du système. Non pas qu'il soit complètement différent, mais meilleur que 4 MHz à une fréquence d'horloge de 925 MHz pour Cyclone V SoC ... Non, le processeur NIOS II lui-même est plusieurs fois plus lent que le cinquième noyau Cyclone ARM, mais le processeur, comme je l'ai dit , nous avons x64 dans le système, ici nous avons plus besoin du noyau, qui fournit la logique du fer. Et cette logique est fournie précisément par le travail avec les ports. Si le travail avec les ports est lent, alors tout le reste sera régulièrement inactif, en attendant que le bus ait fini de fonctionner. Les caractéristiques révélées sont la limite d’accès du processeur aux ports, mais pas le matériel dans son ensemble. Cependant, comment mettre en œuvre le travail dans son ensemble, nous examinerons dans le prochain article.

Conclusion


L'article montre comment créer et configurer un projet en C ++ pour l'environnement de processeur le plus simple développé pour le complexe Redd. Les méthodes d'accès à l'équipement, ainsi que la technique de débogage JTAG sont présentées. Téléchargez le kit matériel / logiciel obtenu lors de la rédaction de l'article ici .

Source: https://habr.com/ru/post/fr453682/


All Articles