Tutorial microcontrôleur STM32

Résumé

Le but de ce tutorial est de vous faire découvrir et utiliser desmicrocontrôleurs. Nous allons utiliser des STM32 à base de coeurs cortex M3et cortex M4F.

Les microcontrôleurs

Un microcontrôleur contient :

Le microcontrôleur est le composant de base de tout circuit électronique. Vous en trouverez un ou plusieurs dans de nombreux objets du quotidient:

Téléphone portable (plusieurs), montre( composant basse consommation), passe Navigo et cartes bleu (microcontrôleurs sécurisés), ordinateur portable (alimentation)...

Suivant la taille de leurs donnée de base, plusieurs catégories de microcontrôleurs existent:

Les carte de découverte

Pour ce tutorial, deux cartes de développement STM32L-DISCOVERY et STM32F4DISCOVERY seront utilisées. Ces cartes peuvent être commandées pour environ 15€ chacune sur FARNELL.

La première partie de ce tutorial utilisera la STM32L-DISCOVERY pour réaliser les fonctions suivantes :

  1. Hello World!
  2. Clignotement de LEDS
  3. Commande de servomoteurs par PWM
  4. Commande de servomoteurs numériques AX12 par UART

La seconde partie de ce tutorial utilisera la carte STM32F4DISCOVERY, et réalisera les fonctions:

  1. Installation de FreeRTOS et clignotement de diode
  2. Communication par bus USB, Hello World!
  3. Commande de moteur par PWM
  4. Acquisition de position moteur par encodeur en quadrature
  5. Asservissement moteur par PID
  6. Acquisition de tensions analogiques, génération de tension analogiques, commandes de GPIO par USB

Hello World!

Installation de l'environnement

Pour commencer, nous allons installer l'environnement de développement de la carte STM32L-DISCOVERY.

Nous allons utiliser l'environnement de développement de IAR Systems: Embedded Workbench for ARM 6.21

La version kickstart est gratuite pour notre utilisation, elle est limitée à 32ko, ce qui est suffisant. 

Téléchargez cette version sur le site de IAR. Il est nécessaire de s'enregistrer pour obtenir la licence d'activation.

Exécutez le fichier installant les drivers du ST-LINK. Ce fichier se trouve dans le répertoire    [IAR_INSTALL_DIRECTORY]\Embedded Workbench 6.0_2\arm\drivers\ST-Link\ST-Link_V2_USBdriver.exe

Récupérez le code du projet dans le serveur mercurial (TODO)

Ce projet contient deux branches, une branche default qui continet le code de base, une branche correction qui contient les solutions aux problèmes.

Ouverture du projet

Le projet se trouve dans ' /Project/EWARM/Training.eww '. Ouvrez le dans IAR.

Compilation

Exécutez Project/Rebuildall. Cela doit recompiler tout le projet.

Branchez la carte. Tapez ctrl+d pour télécharger le programme vers la carte et passer en mode debug. F5 lance l'exécution du programme.

Vous pouvez placer des wait points en cliquant dans l'éditeur juste à gauche de la ligne de code voulue. Cela arrètera l'exécution à cette ligne,  ce qui est utile pour débugger.

Hello World!

Vous pouvez maintenant modifer le code pour afficher "Hello World!"

Bravo, vous venez de réaliser votre premier programme sur STM32.

Clignotement de diode

Clignotement de la diode embarquée

Vous pouvez utiliser les fonctions déjà existantes pour faire clignoter les deux diodes embarquées.

GPIO_LOW(LD_PORT,LD_BLUE)  => on peut également l'utiliser avec LD_GREEN

GPIO_HIGH(LD_PORT,LD_BLUE)=>idem

GPIO_TOGGLE(LD_PORT,LD_BLUE)=>idem

TEMPO

Ces macros sont définies dans discover_board.h et discover_function.h (Vous pouvez voir où une fonction est définie avec clique droit +"goto definition of" ou F12).

Vous pouvez changer le rythme de clignotement en appelant Delay(duree),  duree définit le temps d'attente en multiple de 5 ms

Sous le capot

GPIO

En technologie ARM, l'ensemble des périphériques est accessible dans l'espace mémoire. Pour changer la valeur d'une sortie, il suffit de changer le bit correspondant à la bonne addresse mémoire. C'est ce que font les macros GPIO_LOW,GPIO_HIGH et GPIO_TOGGLE.

Elles prennent en entrée une adresse mémoire (GPIOA) et un masque (GPIO_Pin_1). GPIO_TOGGLE fait un 'OU EXCLUSIF' bit à bit du contenu de la case mémoire avec le masque, ce qui va changer le bit correspondant à la broche PA1 dans le registre ODR. CEla nécessite plusieurs opérations(lecture du masque, lecture de ODR, XOR des deux, écriture de ODR). 

Afin d'optimiser les opérations simples sur les bits, chaque banc de GPIO possède un registre spécial nommé GPIOx_BSRR qui permet en écrivant directement dedans de forcer à '0' ou à '1' certaines des sorties tout en laissant les autres inchangées.

Les adresses mémoire des registres sont définies dans le fichier stm32l1xx_gpio.h. Ce fichier est fourni par ST ou IAR et contient la liste de l'ensemble des registres liés aux GPIOs.

L'ensemble des registres et de leur contenu est décrit dans le Reference manual STM32L151xx and STM32L152xx, un petit document de moins de 600 pages.

Delay

Cette fonction écrit la valeur du temps à attendre dans la variable globale volatile TimingDelay, et attend que cette varible passe à zéro.

TimingDelay est modifiée par une fonction exécutée dans une routine d'interruption : TimingDelay_Decrement. Cette fonction est appelée toute les 5 ms. Cette interruption est programmée à l'initialisation du programme, en utilisant un timer qui va se déclencher toutes les 10 ms, et lever une interruption qui exécutera cette fonction. Une interruption arrête le déroulement normal du programme pendant son exécution. Celui-ci reprendra à la fin de l'interruption. Les interruptions sont utilisées pour exécuter des fonctions devant respecter un cadencement précis, ou pour réagir à des évènements. Comme le déroulement normal du programme est arrété pendant le traitement d'une exécution, on veille généralement à réduire la durée de celle-ci.

La déclaration de la variable globale TimingDelay en volatile est CAPITALE. Cela indique au compilateur que cette variable peut être modifié par des évènements hors de l'exécution normale du programme. En voyent cela, le compilateur ne va pas optimiser le code pour cette variable, et toujours faire les accès nécessaires. D'ailleurs les registres GPIOs sont également définis en volatile pour la même raison.

Clignotement de deux diodes en même temps

Vous pouvez maintenant créer les macros:

GPIO_DOUBLE_LOW(a , b,c)  qui met à zéros deux diodes b et c sur le port a

GPIO_DOUBLE_HIGH(a,b,c)  qui met à un deux diodes b et c sur le port a

GPIO_DOUBLE_TOGGLE(a,b,c) qui change la valeur de deux diodes b et c sur le port a

Clignotement d'une diode externe

Nous allons faire clignoter une diode externe. Nous allons la connecter sur la broche PA1.

Cette broche est actuellement utiliser pour le LCD. Pour la déconnecter du LCD, il faut enlever celui-ci de son support, et tordre ses trois premières broches (les trois premières en comptant à partir de l'encoche, dans le sens inverse des aiguilles d'une montre).

Le STM32 est alimenté en 3V. On veut faire passer un courant de 6 mA dans une diode dont la tension interne est de 2V. Calculez la résistance nécessaire, et réalisez le circuit.

Il faut maintenant modifier le code de notre programme pour que les broches PA1, PA2 et PA3 soient utilisées en fonction GPIO plutôt que LCD.

Pour cela il faut changer leur configuration. Cette modification est faite dans main.c, dans la fonction 'void  Init_GPIOs (void)'.

La broche externe PA1 est connectée à la broche 1 du port A. Recopiez le code utilisé pour initialiser les leds bleus et vertes, remplacez LD_PORT par GPIOA et remplacez LD_GREEN|LD_BLUE par GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3.

Cela configurera PA1,PA2 et PA3 en sorties en mode push/pull. Placez ce bloc de code après le bloc déclarant les broches du LCD, sinon votre configuration sera écrasée par la configuration du LCD. 

Vous pouvez maintenant faire clignoter la diode.

Clignotement de diode (avancée)

Problème

Le  code de clignotement précédent utilise une attente active Delay qui bloque l'exécution du programme et empèche toute autre action. On voudrait pouvoir réaliser d'autres opérations pendant que notre diode clignote. 

Plusieurs solutions sont possibles pour résoudre ce problème:

Clignotement dans la routine d'interruption

Modifiez la routine d'interruption SysTick_Handler pour appeler une fonction faisant clignoter une diode.

Utilisation du Timer

Le STM32l possède plusieurs timers permettant de réaliser des opérations complexes nécessitant des temporisations précises, ou des compteurs avancés. Un de ces timers est déjà utilisé pour réaliser l'interruption à 10ms utilisée par la fonction Delay.

La broche PA1 que nous utilisons est marquée TIM2_CH2, elle est connectée au canal 2 du timer 2.

Ce timer possède la fonction PWM. Il peut être programmé pour avoir un compteur qui met la sortie à '1' tant qu'il est inférieur à une certaine valeur, et à '0' dans le cas contraire.

  1. Il faut dans un premier temps configurer le compteur, pour qu'il utilise en entrée le bon compteur.
  2. Configurez la broche PA1 pour qu'elle soit commandée par le canal 2 du timer.
  3. Configurez le compteur du timer 2 pour qu'il compte à la bonne vitesse, et définir également la valeur à laquelle il boucle à zéro.
  4. Il faut programmer le canal 2 du timer2 en mode PWM.
  5.  Activez le compteur

  1. Activez TIM clock en utilisant la fonction RCC_APBxPeriphClockCmd(RCC_APBxPeriph_TIMx, ENABLE)
  2. Configurez la broche PA1 en Alternate Function. Vous pouvez réutiliser et adapter le code utilisé pour initialiser le LCD). en remplaçant GPIO_AF_LCD par GPIO_AF_TIM2.
  3. Configurez le timer, sinon il fonctionnera avec la configuration par defaut:
           - Autoreload value = 0xFFFF
            - Prescaler value = 0x0000
            - Counter mode = Up counting
            - Clock Division = TIM_CKD_DIV1
  4. Configurez la structure TIM_OCInitStruct avec les paramètres voulus, y compris:
           - TIM Output Compare mode: TIM_OCMode
           - TIM Output State: TIM_OutputState
           - TIM Pulse value: TIM_Pulse
           - TIM Output Compare Polarity : TIM_OCPolarity
    Appelez TIM_OCxInit(TIMx, &TIM_OCInitStruct) pour configurer le bon canal avec la configuration définie.
  5. Appelez la fonction TIM_Cmd(ENABLE) pour activer le compteur

Commande de servomoteurs

Les  servomoteurs se commandent par des impulsions de 1 à 2ms environ répétées toutes les 20 ms (pour plus d'informations se référer au cours électronique pour la robotique).

Modifiez votre programme de clignotement de diode avec timer pour générer des implusions de commande de servo. Modifiez la carte pour y connecter un servomoteur.Connectez le au port PA2.Modifiiez le code en conséquence.

Commande se servomoteurs numériques AX-12

Les servomoteurs AX-12 peuvent se commander comme des servomoteurs classiques, mais ils peuvent également être pilotés en numérique.

Ils communiquent en utilisant le protocole UART. Ce protocole est décrit dans le pdf en annexe .

todo:mettre pdf