mercredi 2 avril 2014

LPC810, partie 4, programmation

Les 3 premiers articles présentaient l'environnement et le LPC810. Dans cette partie je vais discuter de la programmation en analysant l'exemple de la partie 3.

Après avoir créer le projet rgb_blinky dans la partie 3 on avait 4 fichiers dans le dossier src

  • cr_startup_lpc8xx.c, ce fichier contient le code d'initialisation du MCU et est généré automatiquement. Normalement il n'est pas nécessaire de modifier son contenu.
  • crp.c, Si on a sélectionné l'option "Enable Code Read Protect" dans les options du projets ce fichier contient le code de protection. Normalement on ne touche pas à ce fichier.
  • mtb.c, correspond à la fenêtre d'options Micro Trace Buffer lors de la création du projet. On n'a pas à toucher à ce fichier.
  • main.c, c'est le fichier principal de notre application, celui sur lequel on travaille.

Le squelette de l'application

Si on ouvre main.c dans l'éditeur on voit qu'il y a 2 fichiers d'entête inclus dans le squelette de l'application.

LPC8xx.h contient toutes les définitions nécessaire pour accéder les modules internes du MCU. On va y revenir.

cr_section_macros.h ne contient que des macros qui définissent les sections de mémoire. Ces informations sont utilisées par le compilateur et le linker mais normalement on n'a pas besoin de s'en préoccuper.

On pourrait écrire notre application sans inclure d'autres entête mais ça augmenterais notre charge de travail. C'est pourquoi on a inclus dans notre projet les librairies CMSIS_CORE_LPC8xx et lpc8xx_driver_lib.

CMSIS_CORE_LPC8xx contient le code d'initialisation du MCU ainsi que les fonctions de base qu'on retrouve dans toute application 'C' tel que stdio.h, stdlib.h, string.h, math.h, etc. On inclus donc dans notre projet les entêtes dont on a besoins pour référencer les fonctions de ces modules.

lpc8xx_driver_lib contient les pilotes de périphériques disponibles dans le microcontrôleur. Il faut inclure le(s) fichier(s) d'entête pour les périphériques qu'on utilise dans notre application.

Dans le projet rgb_blinky j'ai inclus les 2 fichiers d'entête suivant:

#include "lpc8xx_gpio.h"  // utilisation des entrées/sorties sans périphérique
#include "lpc8xx_mrt.h"   // utilisation du multi-rate timer

Si on se réfère à la partie 2 de cette série, où j'explique les modules interne du LPC810 et qu'on regarde le contenu du fichier d'entête LPC8xx.h on constate que pour chaque bloc du schéma on a une structure définie comme typedef. par exemple:
typedef struct
{
  union {
    __IO uint32_t PINASSIGN[9];
    struct {
      __IO uint32_t PINASSIGN0;
      __IO uint32_t PINASSIGN1;
      __IO uint32_t PINASSIGN2;
      __IO uint32_t PINASSIGN3;
      __IO uint32_t PINASSIGN4;
      __IO uint32_t PINASSIGN5;
      __IO uint32_t PINASSIGN6;
      __IO uint32_t PINASSIGN7;
      __IO uint32_t PINASSIGN8;
    };
  };
  __I  uint32_t  RESERVED0[103];
  __IO uint32_t  PINENABLE0;
} LPC_SWM_TypeDef;

et plus bas on retrouve une variable de type pointer dont le nom est LPC_SWM. Chaque périphérique utilise un certains nombre de registres SFR et les éléments de la structure correspondent à ces registres. Donc dans le programme on retrouve:

 LPC_SWM->PINENABLE0 = PINENABLE0_RESRVD|DIS_ACMP_I1|DIS_ACMP_I2|
                       DIS_SWCLK|DIS_SWDIO|DIS_XTALIN|DIS_XTALOUT|
                       DIS_CLKIN|DIS_VDDCMP;
Le registre PINENABLE0 permet d'activer/désactiver certaines fonctions pour libérer les GPIO. Par défaut SWCLK et SWDIO accaparent les broches 3 et 4, donc si on veut utiliser ces broches pour alimenter la LED RGB on doit désactiver ces 2 fonctions.

La fonction delayMs() qui est définie dans lpc8xx_mrt.c utilise le périphérique Multi-rate Timer on doit donc l'activer et le réinitialiser:

   LPC_SYSCON->SYSAHBCLKCTRL |= ENABLE_MRT;
   LPC_SYSCON->PRESETCTRL |=  MRT_RESET;
Les fonctions GPIOinit(), GPIOSetDir() et GPIOSetBitValue() sont définies dans lpc8xx_gpio.c
  • GPIOinit(), initialise les GPIO.
  • GPIOSetDir(), configure une broche entrée ou sortie. Le premier argument est le no de port. Le deuxième est le no de bit et le troisième est 0 pour entrée et 1 pour sortie.
  • GPIOSetBitValue(), fixe la valeur d'un broche en sortie. Le premier argument est le no de port. Le deuxième est le no de bit et le troisième est la valeur de sortie.

Dans la boucle while(1) on contrôle la valeur des sorties en affectant les bits directement dans le registre NOT0 ce registre inverse les bits de sortie dont la valeur est mis à 1 dans le registre. C'est une registre toggle. Il y a aussi un registre SET0 pour mettre les sorties à 1 et un registre CLR0 pour mettre les sorties à 0. Ces registres permettent de modifier simultanément plusieurs sorties.

Conclusion

Dans ce programme exemple on voit donc 2 façons d'utiliser les périphériques. Soit on utilise des fonctions de la librairie lpc800_driver_lib soit on accède directement les SFR à partir des structures définies dans LPC8xx.h Il faut noter que la librairie lpc800_driver_lib est fournie à titre d'exemple et qu'en conséquence est n'est pas très bien documentée et incomplète. Cependant la licence en début de fichier mentionne qu'on a le droit de modifier le code source de cette librairie à condition d'y laisser l'information de licence et de ne l'utiliser que pour des MCU NXP. Il faut considérer cette librairie comme un point de départ qui reste à développer.

Aucun commentaire:

Enregistrer un commentaire