STM32F407(STM32F4-DISCOVERY) - Approche non standard - Bibliothèque standard partie 1. Configuration du STM32F10x SPL à l'aide de définitions de macro

Jusqu'à présent, nous avons utilisé la bibliothèque standard du noyau - CMSIS. Pour configurer un port au mode de fonctionnement souhaité, nous avons dû nous tourner vers pour trouver le registre responsable d'une certaine fonction, et également rechercher dans un gros document d'autres informations liées à ce processus. Les choses deviendront encore plus douloureuses et routinières lorsque nous commencerons à travailler avec une minuterie ou un ADC. Le nombre de registres y est bien supérieur à celui des ports d'E/S. Réglage manuel prend beaucoup de temps et augmente le risque de commettre une erreur. Par conséquent, de nombreuses personnes préfèrent travailler avec la bibliothèque de périphériques standard - StdPeriph. Ça donne quoi ? C'est simple - le niveau d'abstraction augmente, vous n'avez pas besoin d'entrer dans la documentation et de penser principalement aux registres. Dans cette bibliothèque, tous les modes de fonctionnement et paramètres de la périphérie MK sont décrits sous forme de structures. Désormais, pour configurer un périphérique, il suffit d'appeler la fonction d'initialisation du périphérique avec une structure remplie.

Vous trouverez ci-dessous une image avec une représentation schématique des niveaux d'abstraction.

Nous avons travaillé avec le CMSIS (qui est le plus « proche » du cœur) pour montrer le fonctionnement du microcontrôleur. La prochaine étape est la bibliothèque standard, que nous allons apprendre à utiliser maintenant. Viennent ensuite les pilotes de périphériques. Ils sont compris comme des fichiers *.c \ *.h qui fournissent une interface logicielle pratique pour contrôler n'importe quel appareil. Par exemple, dans ce cours, nous vous fournirons les pilotes pour la puce max7219 et le module WiFi esp8266.

Un projet standard comprendra les fichiers suivants :


Tout d'abord, bien sûr, ce sont les fichiers CMSIS qui permettent à la bibliothèque standard de fonctionner avec le noyau, nous en avons déjà parlé. Deuxièmement, les fichiers de bibliothèque standard. Et troisièmement, les fichiers utilisateur.

Les fichiers de la bibliothèque se trouvent sur la page dédiée au MK cible (pour nous c'est stm32f10x4), dans la section Ressources de conception(dans l'IDE CooCox, ces fichiers sont téléchargés depuis le référentiel de l'environnement de développement). Chaque périphérique correspond à deux fichiers - en-tête (*.h) et code source(*.c). Description détaillée peut être trouvé dans le fichier de support, qui se trouve dans les archives de la bibliothèque sur le site Web.

  • stm32f10x_conf.h - fichier de configuration de la bibliothèque. L'utilisateur peut connecter ou déconnecter des modules.
  • stm32f10x_ppp.h - fichier d'en-tête de périphérique. Au lieu de ppp, il peut y avoir gpio ou adc.
  • stm32f10x_ppp.c - pilote de périphérique écrit en langage C.
  • stm32f10x_it.h - fichier d'en-tête qui inclut tous les gestionnaires d'interruptions possibles (leurs prototypes).
  • stm32f10x_it.c est un fichier de code source modèle contenant une routine de service d'interruption (ISR) pour les situations d'exception dans Cortex M3. L'utilisateur peut ajouter ses propres ISR pour les périphériques utilisés.

La bibliothèque standard et les périphériques ont une convention en matière de dénomination des fonctions et de notation.

  • PPP est un acronyme pour périphériques, tels que ADC.
  • Fichiers système, d'en-tête et de code source - commencez par stm32f10x_.
  • Les constantes utilisées dans un fichier sont définies dans ce fichier. Les constantes utilisées dans plusieurs fichiers sont définies dans les fichiers d'en-tête. Toutes les constantes de la bibliothèque périphérique sont le plus souvent écrites en majuscules.
  • Les registres sont traités comme des constantes et sont également appelés lettres MAJUSCULES.
  • Les noms de fonctions spécifiques aux périphériques incluent un acronyme, tel que USART_SendData() .
  • Pour configurer chaque périphérique, la structure PPP_InitTypeDef est utilisée, qui est transmise à la fonction PPP_Init().
  • Pour désinitialiser (définir la valeur par défaut), vous pouvez utiliser la fonction PPP_DeInit().
  • La fonction qui permet d'activer ou de désactiver des périphériques s'appelle PPP_Cmd().
  • La fonction d'activation/désactivation d'interruption est appelée PPP_ITConfig.

AVEC liste complète vous pouvez à nouveau consulter le fichier de support de la bibliothèque. Réécrivons maintenant la LED clignotante en utilisant la bibliothèque de périphériques standard !

Avant de commencer le travail, regardons le fichier stm32f10x.h et trouvons la ligne :

#définir USE_STDPERIPH_DRIVER

Si vous configurez le projet à partir de zéro à l'aide des fichiers de bibliothèque de l'archive téléchargée, vous devrez alors décommenter cette ligne. Il vous permettra d'utiliser la bibliothèque standard. Cette définition (macro) ordonnera au préprocesseur d'inclure le fichier stm32f10x_conf.h :

#ifdef USE_STDPERIPH_DRIVER #include "stm32f10x_conf.h" #endif

Ce fichier contient des modules. Si vous n'en avez besoin que de spécifiques, désactivez le reste, cela vous fera gagner du temps lors de la compilation. Comme vous l'avez peut-être deviné, nous avons besoin de modules RTC et GPIO (cependant, à l'avenir, nous aurons également besoin de _bkp.h, _flash, _pwr.h, _rtc.h, _spi.h, _tim.h, _usart.h) :

#include "stm32f10x_flash.h" // pour init_pll() #include "stm32f10x_gpio.h" #include "stm32f10x_rcc.h"

Comme la dernière fois, vous devez d'abord activer la synchronisation du port B. Cela se fait par la fonction déclarée dans stm32f10x_rcc.h :

Void RCC_APB2PeriphClockCmd (uint32_t RCC_APB2Periph, FunctionalState NewState);

L'énumération FunctionalState est définie dans stm32f10x.h :

Énumération Typedef (DISABLE = 0, ENABLE = !DISABLE) FunctionalState ;

Déclarons une structure pour configurer notre jambe (vous pouvez la trouver dans le fichier stm32f10x_gpio.h) :

LED GPIO_InitTypeDef ;

Il nous reste maintenant à le remplir. Regardons le contenu de cette structure :

Structure Typedef ( uint16_t GPIO_Pin; GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode; ) GPIO_InitTypeDef;

Toutes les énumérations et constantes nécessaires peuvent être trouvées dans le même fichier. Ensuite, la fonction init_leds() réécrite prendra la forme suivante :

Void led_init() ( // Activer la synchronisation RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // Déclarer la structure et la remplir GPIO_InitTypeDef LED; LED.GPIO_Pin = GPIO_Pin_0; LED.GPIO_Speed ​​​​= GPIO_Speed_2MHz; LED.GPIO_Mode = GPIO_Mode_ Out_PP; // Initialisez le port GPIO_Init( GPIOB, &LED); )

Réécrivons la fonction main() :

Int main(void) ( led_init(); while (1) ( GPIO_SetBits(GPIOB, GPIO_Pin_0); delay(10000000); GPIO_ResetBits(GPIOB, GPIO_Pin_0); delay(10000000); ) )

L'essentiel est de se faire une idée de l'ordre d'initialisation : allumer l'horloge périphérique, déclarer la structure, remplir la structure, appeler la méthode d'initialisation. D'autres périphériques sont généralement configurés de la même manière.

Dans cette publication, je vais essayer de me concentrer sur les points principaux pour démarrer rapidement avec les microcontrôleurs STM32F10x basés sur la bibliothèque de périphériques standards du fabricant STMicroelectronics.

L'article utilisera Eclipse CDT comme environnement de développement. Puisque l’accent sera mis sur le code du programme, vous pouvez effectuer en toute sécurité toutes les manipulations dans Code::Blocks.

La structure générale du projet pour les microcontrôleurs ARM est décrite dans mon article.

Ici, je vous rappelle brièvement que pour construire un projet pour les microcontrôleurs ARM (STM32F10x en particulier), vous aurez besoin d'un script linker et d'un fichier C-Startup.

Un script de liaison est un fichier contenant des instructions permettant de placer le code du programme et les données dans la mémoire du microcontrôleur. Il peut commander le chargement de votre code de programme dans la mémoire de programme Flash ou dans la mémoire de données SRAM.

Les microcontrôleurs avec différentes quantités de mémoire de programme et de données nécessitent des scripts de présentation différents. Ils peuvent être obtenus auprès du fabricant du microcontrôleur - STMicroelectronics.
Décompressez la bibliothèque de périphériques standard STM32F10x de l'archive ARM_Toolchain/Lib/stm32f10x_stdperiph_lib.zip.
Il contient des exemples de projets pour divers environnements de développement (IAR EWB, Keil uVision, Atollic True Studio, etc.). Le plus proche pour nous est Atollic True Studio, puisqu'il s'agit d'une modification d'Eclipse.
Allez dans le répertoire Project/StdPeriph_Template/TrueSTUDIO, on y trouve plusieurs sous-répertoires dont les noms correspondent aux noms des cartes de développement STM3210x-EVAL.

Découvrez laquelle de ces cartes utilise la même ligne de microcontrôleur que la vôtre. Copiez le fichier stm32_flash.ld du répertoire approprié vers votre projet.

Il est également possible de créer un script universel dans lequel seule la quantité de mémoire de programme et de données sera modifiée en fonction du microcontrôleur utilisé.

Le code de démarrage (C-Startup) pour les microcontrôleurs STM32 peut être écrit en C ou en Assembleur.
Bien que la bibliothèque de périphériques standard STM32F10x (en abrégé STM32F10x SPL) soit souvent critiquée pour ses bugs, elle constitue le moyen le plus simple de démarrer rapidement lors du démarrage de la programmation STM32.
Mais vous voulez toujours qu’il y ait une sorte d’alternative. En fait, il y en a beaucoup, par exemple la programmation en langage assembleur :)

C'est le chemin le plus difficile et le plus inutile. La deuxième façon consiste à utiliser la bibliothèque CMSIS, qui fournit une syntaxe pour accéder aux structures du langage C afin d'accéder à divers périphériques du microcontrôleur. Le moyen le plus simple et le plus logique (à mon avis) est d’utiliser des bibliothèques.

Si vous êtes catégoriquement opposé au STM32F10x SPL, il existe une autre alternative spécialement pour vous : la bibliothèque libopencm3. Dans ce document, la majeure partie des exemples sont concentrés autour de la série principale de microcontrôleurs STM32F10x, mais ce n'est qu'une question de temps avant que des exemples pour d'autres séries (STM32F2xx/4xx) n'apparaissent. Vous pouvez toujours rejoindre le projet libopencm3 et accélérer ce processus.

La norme CMSIS est également facultative pour une utilisation dans vos programmes.
Vous pouvez vous en passer en consacrant des efforts et du temps à implémenter le niveau HAL (Hardware Abstraction Layer) dans le langage de programmation C.

Dans certains cas, cette méthode peut être la seule d'une manière accessible. Par exemple, votre organisation utilise des puces personnalisées basées sur des cœurs de calcul développés par ARM et des périphériques spécifiques au secteur.

Ou vous devez implémenter un logiciel en C pour les microcontrôleurs dotés d'un cœur ARM9, pour lesquels les fabricants se concentrent sur l'utilisation de logiciels prêts à l'emploi. systèmes d'exploitation(Linux, QNX, Windows CE), par conséquent, les fabricants ne peuvent pas fournir de bibliothèques pour la programmation en langage C sous forme pure ou en combinaison avec un RTOS plus léger.

Heureusement, les fabricants de microcontrôleurs basés sur le cœur Cortex-M3 proposent aux développeurs un grand nombre de bibliothèques de codes. Cela s'applique également aux microcontrôleurs STM32.
Continuons notre examen de la bibliothèque STM32F10x SPL. Nous le considérerons à l'aide d'un exemple.
Vous pouvez ouvrir cet exemple ou créer votre propre projet à partir de zéro pour mieux comprendre l'ensemble du processus de ce qui se passe.

Pour le deuxième cas, je listerai les étapes nécessaires :

  • Créer un nouveau projet vide dans Eclipse
  • Copiez le script de mise en page et démarrez le fichier dans le projet
  • Créer un nouveau Makefile ou copier un modèle
  • Lorsque vous utilisez le Makefile de mon exemple comme modèle, vous devez créer les répertoires src, inc, bin, obj dans le projet et créer les sous-répertoires Debug et Release dans les répertoires bin et obj.
  • Copiez les fichiers source et d'en-tête nécessaires à partir des bibliothèques CMSIS et STM32F10x SPL.
  • Apportez les modifications nécessaires à la section des paramètres utilisateur du modèle Makefile, le cas échéant.
  • Créez de nouvelles cibles « Debug », « cleanDebug », « Release », « cleanRelease », « Program » dans la fenêtre « make target » d'Eclipse.
  • Lancez la cible « Debug » et surveillez son exécution dans la fenêtre « Console ».

Pour une meilleure compréhension du matériel, j'ai divisé l'article en plusieurs paragraphes indépendants, chacun décrivant un seul aspect du travail avec la bibliothèque STM32F10x SPL.

Configuration du STM32F10x SPL à l'aide de définitions de macro

Pour configurer la bibliothèque, des valeurs de macro prédéfinies sont utilisées, que nous allons maintenant considérer.
Ils peuvent être définis dans les fichiers d'en-tête à l'aide d'une directive de préprocesseur #définir ou passez les valeurs des définitions de macro via la clé -D Compilateur GCC.
Dans mon exemple, j'utilise la deuxième méthode.
Dans la variable Makefile DÉFINIR contient les macros nécessaires pour compiler la bibliothèque STM32F10x SPL.
Définition des macros STM32F10X_MD précise si le microcontrôleur utilisé appartient à la ligne Densité moyenne.
Cela inclut les microcontrôleurs avec une mémoire Flash de 64 à 128 Ko.
Le tableau suivant répertorie les noms des macros pour différentes séries de microcontrôleurs :

Nom de la série Macro Description
Ligne de valeur basse densité STM32F10X_LD_VL avec capacité de mémoire Flash 16 - 32 Ko
Faible densité STM32F10X_LD
avec capacité de mémoire Flash 16 - 32 Ko
Ligne Value de densité moyenne STM32F10X_MD_VL Mémoire flash
64 - 128 Ko
Densité moyenne STM32F10X_MD microcontrôleurs des séries STM32F101xx, STM32F102xx, STM32F103xx avec mémoire Flash 64 - 128 Ko
Ligne Value haute densité STM32F10X_HD_VL microcontrôleurs de la série STM32F100xx avec volume
Flash - mémoire 256 - 512 Ko
Haute densité STM32F10X_HD avec du volume
Mémoire flash 256 - 512 Ko
Densité XL STM32F10X_XL
Mémoire Flash 512 - 1024 Ko
Ligne de connectivité STM32F10X_CL

Pour définir la fréquence d'horloge du microcontrôleur, vous devez supprimer le commentaire de la macro avec la valeur de fréquence d'horloge requise dans le fichier system_stm32f10x.c.

#si défini (STM32F10X_LD_VL) || (défini STM32F10X_MD_VL) || (défini STM32F10X_HD_VL) #define SYSCLK_FREQ_24MHz 24000000 #else /* #define SYSCLK_FREQ_HSE HSE_VALUE */ /* #define SYSCLK_FREQ_24MHz 24000000 */ /* #define SYSCLK_FREQ_36MHz 3600 0000 */ / * #définir SYSCLK_FREQ_48MHz 48000000 */ /* #définir SYSCLK_FREQ_56MHz 56000000 * / #définir SYSCLK_FREQ_72MHz 72000000 #endif

#si défini (STM32F10X_LD_VL) || (défini STM32F10X_MD_VL) || (défini STM32F10X_HD_VL)

/* #define SYSCLK_FREQ_HSE HSE_VALUE */

#définir SYSCLK_FREQ_24MHz 24000000

#autre

/* #define SYSCLK_FREQ_HSE HSE_VALUE */

/* #définir SYSCLK_FREQ_24MHz 24000000 */

/* #définir SYSCLK_FREQ_36MHz 36 000 000 */

/* #définir SYSCLK_FREQ_48MHz 48000000 */

/* #définir SYSCLK_FREQ_56MHz 56000000 */

#définir SYSCLK_FREQ_72MHz 72000000

#fin si

Utilisation prévue résonateur à quartz avec une fréquence de 8 MHz pour tous les principaux
série de microcontrôleurs, à l'exception de la ligne Connectivity, pour laquelle il est nécessaire d'installer un résonateur à quartz de 25 MHz.
Si vous utilisez des résonateurs à quartz avec d'autres valeurs de fréquence, vous devez alors modifier la valeur de la macro HSE_VALUE dans le fichier d'en-tête stm32f10x.h et adapter toutes les fonctions dépendantes en conséquence.
Le but de la macro USE_STDPERIPH_DRIVER n'est pas difficile à deviner : utiliser la bibliothèque de périphériques standard STM32F10x.
USE_FULL_ASSERT – utilisez la macro ASSERT pour déboguer le programme.

Utilisation de la macro assert_param dans la bibliothèque

Toutes les fonctions de la bibliothèque STM32F10x SPL utilisent la macro assert_param pour vérifier leurs arguments.
Cette macro vérifie une expression impliquant l'argument de fonction testé pour l'égalité à zéro. Si la valeur de l'expression est zéro, alors la fonction de gestion des erreurs d'argument assert_failed est appelée, sinon (l'expression n'est pas nulle), la vérification de l'argument réussit.
Vous devez implémenter la fonction assert_failed dans votre programme.
Il affiche le message d'erreur, le nom du fichier et le numéro de la ligne de code qui a provoqué l'erreur.
La macro debug_printf peut être sortie via USART en utilisant la bibliothèque standard new_lib ou, par exemple, la bibliothèque de M. Chen.

#define debug_printf xprintf /* printf */ #ifdef USE_FULL_ASSERT void assert_failed(uint8_t* fichier, ligne uint32_t) ( debug_printf("Valeur de paramètres incorrecte : fichier %s sur la ligne %d\r\n", fichier, (int)ligne) ; while (1) ( ) )/* assert_failed */ #endif/*USE_FULL_ASSERT*/

#define debug_printf xprintf /* printf */

#ifdef USE_FULL_ASSERT

void assert_failed (uint8_t * fichier, ligne uint32_t)

debug_printf( "Valeur de paramètres incorrecte : fichier %s sur la ligne %d\r\n", fichier , (int ) ligne ) ;

pendant que(1)

) /* assert_failed */

#endif/*USE_FULL_ASSERT*/

La fonction assert_failed implémentée dans votre code est utilisée uniquement lorsque la macro USE_FULL_ASSERT est déclarée. Sinon, tout le code de débogage est exclu de la source. Cette fonctionnalité est implémentée dans le fichier d'en-tête des paramètres de la bibliothèque de pilotes stm32f10x_conf.h.

#ifdef USE_FULL_ASSERT #define assert_param(expr) ((expr) ? (void)0: assert_failed((uint8_t *)__FILE__, __LINE__)) void assert_failed(uint8_t* file, uint32_t line); #else #define assert_param(expr) ((void)0) #endif /* USE_FULL_ASSERT */

#ifdef USE_FULL_ASSERT

#define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))

void assert_failed (uint8_t * fichier, ligne uint32_t) ;

#autre

#define assert_param(expr) ((void)0)

#endif /* USE_FULL_ASSERT */

Il n'y a pas grand chose à expliquer ici. Regardons un exemple d'utilisation de assert_param.

void set_param(uint8_t * param, uint8_t valeur) ( ​​assert_param(param != NULL); *param = valeur; )/*set_param*/

void set_param (uint8_t * param, valeur uint8_t)

assert_param (param != NULL ) ;

* paramètre = valeur ;

) /*set_param*/

La fonction définit la valeur du paramètre via un pointeur passé en argument. Si la macro USE_FULL_ASSERT n'est pas déclarée, alors on peut supposer que les lignes
assert_param(param != NULL) n'est tout simplement pas dans le code, sinon le paramètre est vérifié dans cette définition.
Si le pointeur n'est pas défini, alors la valeur param != NULL sera fausse et la fonction assert_failed sera exécutée, qui affichera le nom de fichier et le numéro de ligne avec l'erreur via USART, puis bouclera, empêchant ainsi la valeur d'être attribué à une adresse non définie en mémoire.
Vous n'êtes pas du tout obligé d'utiliser la macro assert_param dans votre code, mais dans le code de la bibliothèque
STM32F10x SPL il est utilisé partout.
La fonction set_param peut être implémentée avec une vérification des erreurs d'argument sans utiliser assert_param.

#define ERREUR (-1) #define OK (0) int set_param(uint8_t * param, uint8_t value) ( ​​​​int r = ERREUR; if (param == NULL) return r; *param = valeur; r = OK; return r ; )/*set_param*/

#define ERREUR (-1)

#définir OK (0)

int set_param (uint8_t * param, valeur uint8_t)

int r = ERREUR ;

si (param == NULL )

retourner r ;

* paramètre = valeur ;

r = OK ;

retourner r ;

) /*set_param*/

Fichier C-Startup dans la bibliothèque STM32F10x SPL

Dans le code de démarrage, le microcontrôleur est initialement initialisé, la pile est configurée, la section BSS est réinitialisée et la fonction principale main() est appelée.
Le code de démarrage n'a aucun rapport direct avec la bibliothèque STM32F10x SPL. Cependant, dans ce code de démarrage, avant d'appeler la fonction main() du programme, la fonction d'initialisation du microcontrôleur SystemInit() est appelée, qui fait partie du CMSIS.
Il peut être facilement trouvé dans la bibliothèque CMSIS.
Accédez au répertoire Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/startup/TrueSTUDIO et copiez le fichier requis. Il ne reste plus qu'à savoir à quelle ligne appartient le microcontrôleur utilisé dans votre projet.
Pour ce faire, regardez le tableau suivant :

Nom de la série Nom de fichier Description
Ligne de valeur basse densité startup_stm32f10x_ld_vl.s microcontrôleurs de la série STM32F100xx avec volume
Mémoire flash 16 - 32 Ko
Faible densité startup_stm32f10x_ld.s séries de microcontrôleurs STM32F101xx, STM32F102xx, STM32F103xx
avec capacité de mémoire Flash 16 - 32 Ko
Ligne Value de densité moyenne startup_stm32f10x_md_vl.s série de microcontrôleurs STM32F100xx
Densité moyenne startup_stm32f10x_md.s séries de microcontrôleurs STM32F101xx, STM32F102xx, STM32F103xx
avec capacité de mémoire Flash 64 - 128 Ko
Ligne Value haute densité startup_stm32f10x_hd_vl.s série de microcontrôleurs STM32F100xx
Haute densité startup_stm32f10x_hd.s séries de microcontrôleurs STM32F101xx, STM32F103xx
avec capacité de mémoire Flash 256 - 512 Ko
Densité XL startup_stm32f10x_xl.s séries de microcontrôleurs STM32F101xx, STM32F103xx
avec capacité de mémoire Flash 512 - 1024 Ko
Ligne de connectivité startup_stm32f10x_cl.s microcontrôleurs des séries STM32F105xx et STM32F107xx

Le fichier de démarrage contient les noms des gestionnaires de vecteurs d'interruption et d'exception, mais seul le gestionnaire de vecteurs de réinitialisation est implémenté, dans lequel toute l'initialisation initiale est effectuée avant d'appeler la fonction main().
L'implémentation de tous les autres gestionnaires d'exceptions relève de la responsabilité du programmeur d'application. Si votre programme n'utilise aucun gestionnaire, il n'est pas nécessaire de les enregistrer. Si une exception se produit, le gestionnaire par défaut sera utilisé - en boucle le code du programme.

Composition de la bibliothèque CMSIS

Comme indiqué précédemment dans cette publication, la bibliothèque CMSIS permet d'accéder aux modules périphériques du microcontrôleur en utilisant des éléments des structures du langage C.
L'implémentation de cette bibliothèque est divisée en deux parties. La première partie donne accès à la périphérie du cœur Cortex-M3 et la deuxième partie donne accès à la périphérie. modèle spécifique microcontrôleur.
Étant donné que la norme CMSIS est la même pour tous les microcontrôleurs dotés d'un cœur Cortex-M3, la mise en œuvre de la première partie sera la même pour tous les fabricants, mais la deuxième partie sera différente pour chaque fabricant.
CMSIS comprend plusieurs fichiers d'en-tête et sources. La première partie comprend les fichiers :

  • core_cm3.h
  • core_cm3.c

La deuxième partie de CMSIS comprend le fichier C-Startup, ainsi que les fichiers suivants :

  • stm32f10x.h
  • system_stm32f10x.h
  • system_stm32f10x.c

Le fichier d'en-tête stm32f10x.h contient des définitions de macros pour accéder aux modules périphériques des microcontrôleurs stm32f10x.
Les fichiers system_stm32f10x.h et system_stm32f10x.c implémentent l'initialisation initiale du microcontrôleur.

Composition et configuration de la bibliothèque STM32F10x SPL

La bibliothèque se compose de fichiers sources et d'en-tête du même nom que les modules périphériques avec le préfixe stm32f10x_.
Par exemple, l'implémentation de l'interaction avec le module USART est contenue dans les fichiers stm32f10x_usart.h et stm32f10x_usart.c.
Il existe des conventions pour nommer les éléments de la bibliothèque et certaines règles de codage, qui sont décrites dans la documentation.
La bibliothèque contient l'implémentation de pilotes pour les modules de microcontrôleurs périphériques.
Les noms des éléments de la bibliothèque utilisent les acronymes suivants pour les modules périphériques :

Acronyme Module périphérique
CDA Convertisseur analogique-numérique
BKP registres de sauvegarde
PEUT Interface CAN
CEC contrôleur de consommation
CRC module de calcul de somme de contrôle
CAD Convertisseur numérique analogique
DBGMCU débogage du microcontrôleur
DMLA contrôleur d'accès direct à la mémoire
EXTI contrôleur d'interruption externe
FSMC contrôleur de mémoire externe
ÉCLAIR Mémoire de programme Flash
GPIO ports E/S à usage général
I2C Interface I2C
I2S Interface I2S (son)
IWDG minuterie de surveillance indépendante
NVIC contrôleur d'interruption imbriqué
REP contrôleur de puissance
RCC réinitialisation et contrôleur d'horloge
RTC contrôleur en temps réel (horloge)
SDIO Interface SDIO
IPS Interface SPI
SysTique minuterie système
TIM minuterie de base ou avancée
USART série universelle synchrone-asynchrone
émetteur-récepteur
WWDG chien de garde de fenêtre

Sur la base de ces acronymes, les noms des modules logiciels de la bibliothèque sont formés. Vous n'êtes pas obligé d'utiliser tous les modules de la bibliothèque.
Afin d'utiliser uniquement les modules nécessaires dans le projet, la bibliothèque doit être configurée.
À ces fins, chaque projet qui utilise la bibliothèque STM32F10x SPL doit avoir un fichier d'en-tête stm32f10x_conf.h.

#include "stm32f10x_gpio.h" //#include "stm32f10x_i2c.h" //#include "stm32f10x_iwdg.h" //#include "stm32f10x_pwr.h" #include "stm32f10x_rcc.h"

#include "stm32f10x_gpio.h"

//#include "stm32f10x_i2c.h"

//#include "stm32f10x_iwdg.h"

//#include "stm32f10x_pwr.h"

#include "stm32f10x_rcc.h"

Pour activer le module requis, vous devez décommenter la directive #inclure avec les fichiers d'en-tête correspondants.
Le fichier d'en-tête stm32f10x_conf.h est inclus dans stm32f10x.h, donc pour utiliser les fonctions de la bibliothèque STM32F10x SPL, il vous suffit d'inclure un seul fichier d'en-tête stm32f10x.h dans votre code source

// dans le fichier stm32f10x.h #ifdef USE_STDPERIPH_DRIVER #include "stm32f10x_conf.h" #endif

Je répète que le projet doit également définir les macros USE_STDPERIPH_DRIVER, USE_FULL_ASSERT et une macro qui précise la série du microcontrôleur utilisé (par exemple, STM32F10X_MD pour la ligne Medium densité).
Si vous utilisez la valeur de fréquence de quartz standard et que le contrôleur fonctionne à une fréquence d'horloge maximale de 72 MHz, vous n'aurez rien d'autre à changer.
Vous devez ajouter une liste de fichiers de bibliothèque à compiler dans le Makefile.
Par exemple:

SRC += stm32f10x_rcc.c SRC += stm32f10x_gpio.c

SRC += stm32f10x_rcc . c

SRC += stm32f10x_gpio . c

Utilisation de la bibliothèque STM32F10x SPL. Mécanismes de travail

Pour débuter la programmation à l'aide de la librairie périphérique, le plus simple est de regarder les exemples fournis avec la librairie. Mais néanmoins, pour comprendre le code de ces exemples, vous devez avoir des connaissances de base sur la syntaxe et l’utilisation de la bibliothèque.
Tous les modules de microcontrôleurs périphériques répertoriés précédemment sont initialement désactivés, aucun signal d'horloge ne leur est fourni et ils ne consomment pas d'électricité.
Pour utiliser un module périphérique, vous devez d'abord lui fournir un signal d'horloge. Le signal d'horloge est fourni par le module d'horloge et de réinitialisation RCC.
A ces fins, la bibliothèque a les fonctions suivantes :

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_PPPx, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_PPPx, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_PPPx, ENABLE);

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_PPPx, ENABLE);

RCC_APB2PeriphClockCmd (RCC_APB2Periph_PPPx, ENABLE) ;

RCC_APB1PeriphClockCmd (RCC_APB1Periph_PPPx, ENABLE) ;

Ici, PPP désigne le nom de l'actonyme du module (par exemple ADC ou USART), et x est le numéro du module périphérique.
Tout d'abord, vous devez savoir à quel bus le module que vous utilisez est connecté.
Au total, les microcontrôleurs dotés d'une architecture de base Cortex-M3 disposent de trois bus :
bus d'instructions, bus de données et bus système. Le bus d'instructions connecte le cœur à la mémoire programme Flash. Les bus de données et système sont combinés dans une matrice de bus AHB (ARM Hi-Speed ​​​​Bus), qui fonctionne à la fréquence centrale. Cependant, la fréquence du bus AHB peut être réduite en installant des diviseurs. Le bus AHB connecte des appareils à haut débit tels que le noyau et le module DMA.
Les périphériques d'E/S sont connectés au bus AHB via les bus intermédiaires APB1 et APB2 (ARM Peripheral Bus).
La fréquence maximale de fonctionnement du bus APB2 est de 72 MHz, la fréquence du bus APB1
limité à 36 MHz.
Vous pouvez savoir à quel bus le module périphérique que vous utilisez est connecté dans la documentation ou consulter le fichier d'en-tête stm32f10x_rcc.h.
Ouvrez ce fichier et recherchez les valeurs RCC_AHBPeriph, RCC_APB1Periph et RCC_APB2Periph dans l'ordre.

#define RCC_AHBPeriph_DMA1 ((uint32_t)0x00000001) #define RCC_AHBPeriph_DMA2 ((uint32_t)0x00000002) #define RCC_AHBPeriph_SRAM ((uint32_t)0x00000004) #define RCC_AHBPeriph_FLITF ((uint3 2_t) 0x00000010) #define RCC_AHBPeriph_CRC ((uint32_t)0x00000040)

#define RCC_AHBPeriph_DMA1 ((uint32_t)0x00000001)

#define RCC_AHBPeriph_DMA2 ((uint32_t)0x00000002)

#define RCC_AHBPeriph_SRAM ((uint32_t)0x00000004)

#define RCC_AHBPeriph_FLITF ((uint32_t)0x00000010)

#define RCC_AHBPeriph_CRC ((uint32_t)0x00000040)

Par les noms des macros, nous déterminons quels modules sont connectés à quels bus. Vous pouvez également faire preuve de bon sens pour déterminer quel pneu appartient à l’un des trois. Par exemple, le module USART est un périphérique d'entrée/sortie, ce qui signifie qu'il est connecté à l'un des bus APB. USART est une interface à débit assez bas, elle est donc probablement connectée au bus APB1.

#define RCC_APB1Periph_USART2 ((uint32_t)0x00020000) #define RCC_APB1Periph_USART3 ((uint32_t)0x00040000) #define RCC_APB1Periph_UART4 ((uint32_t)0x00080000) #define RCC_APB1Periph_UART5 ((uint32_t)0x00100000)

Après avoir envoyé un signal d'horloge au module périphérique, vous pouvez configurer ses paramètres en appelant la fonction d'initialisation :

PPP_Init(PPP, &PPP_InitStructure);

PPP_Init (PPP , & amp ; PPP_InitStructure ) ;

Comme de nombreux paramètres doivent être passés à la fonction d'initialisation pour initialiser un module périphérique, un pointeur vers une structure est utilisé comme argument. La structure elle-même avec les paramètres d'initialisation doit être créée en mémoire avant d'appeler la fonction d'initialisation ; les éléments de la structure doivent se voir attribuer les valeurs nécessaires :

PPP_InitTypeDef PPP_InitStructure = (val1, val2, ..., valN);/* initialisation de la structure lors de sa déclaration */

Vous pouvez d'abord créer une structure puis attribuer les valeurs nécessaires à ses éléments :

PPP_InitTypeDef PPP_InitStructure ; PPP_InitStructure.member1 = val1; PPP_InitStructure.member2 = val2; PPP_InitStructure.memberN = valN;

PPP_InitTypeDef PPP_InitStructure ;

PPP_InitStructure . membre1 = val1 ;

PPP_InitStructure . membre2 = val2 ;

PPP_InitStructure . membreN = valN ;

Regardons un exemple du projet stm32f10xQuickstart :

GPIO_InitTypeDef GPIO_InitStructure ; #ifdef USE_STM32H_103 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 ; GPIO_InitStructure.GPIO_Speed ​​​​= GPIO_Speed_50MHz ; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; GPIO_Init(GPIOC, &GPIO_InitStructure);

GPIO_InitTypeDef GPIO_InitStructure ;

#ifdef USE_STM32H_103

RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOC, ENABLE) ;

GPIO_InitStructure . GPIO_Pin = GPIO_Pin_12 ;

GPIO_InitStructure . GPIO_Speed ​​​​= GPIO_Speed_50MHz ;

GPIO_InitStructure . GPIO_Mode = GPIO_Mode_Out_PP ;

GPIO_Init(GPIOC, & GPIO_InitStructure);

Les éléments de la structure GPIO_InitStructure se voient attribuer la valeur du numéro de broche, du mode et de la vitesse du port.
En appelant la fonction GPIO_Init, la ligne 12 du port GPIOC est initialisée.
Le premier argument de la fonction GPIO_Init est un pointeur vers la zone mémoire du périphérique GPIOC, converti en pointeur vers une structure GPIO_TypeDef.

// stm32f10x.h #define GPIOC ((GPIO_TypeDef *) GPIOC_BASE) #define GPIOC_BASE (APB2PERIPH_BASE + 0x1000) #define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) #define PERIPH_BASE ((uint32_t)0x40000000) typedef struct ( __IO uint32_t CRL ; __IO uint32_t CRH ; __IO uint32_t IDR; __IO uint32_t ODR; __IO uint32_t BSRR; __IO uint32_t BRR; __IO uint32_t LCKR; ) GPIO_TypeDef;

//stm32f10x.h

#définir GPIOC ((GPIO_TypeDef *) GPIOC_BASE)

#définir GPIOC_BASE (APB2PERIPH_BASE + 0x1000)

#définir APB2PERIPH_BASE (PERIPH_BASE + 0x10000)

#définir PERIPH_BASE ((uint32_t)0x40000000)

structure typedef

IO uint32_t CRL ;

IO uint32_t CRH ;

IO uint32_t IDR ;

IO uint32_t ODR ;

IO uint32_t BSRR ;

IO uint32_t BRR ;

IO uint32_t LCKR ;

) GPIO_TypeDef ;

La structure GPIO_InitStructure est de type GPIO_InitTypeDef, décrit dans le fichier d'en-tête
stm32f10x_gpio.h :

//stm32f10x_gpio.h structure typedef ( uint16_t GPIO_Pin; GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode; )GPIO_InitTypeDef; typedef énumération ( GPIO_Speed_10MHz = 1, GPIO_Speed_2MHz, GPIO_Speed_50MHz )GPIOSpeed_TypeDef ; typedef enum (GPIO_Mode_AIN = 0x0, GPIO_Mode_IN_FLOATING = 0x04, GPIO_Mode_IPD = 0x28, GPIO_Mode_IPU = 0x48, GPIO_Mode_Out_OD = 0x14, GPIO_Mode_Out_PP = 0x10, GPIO_Mode_AF_OD = 0x1C, GPIO_Mode_AF_PP = 0x18) GPIOMode_TypeDef ;

//stm32f10x_gpio.h

structure typedef

uint16_t GPIO_Pin ;

GPIOSpeed_TypeDef GPIO_Speed ​​​​;

GPIOMode_TypeDef GPIO_Mode ;

) GPIO_InitTypeDef ;

énumération typedef

GPIO_Speed_10MHz = 1,

GPIO_Speed_2MHz,

GPIO_Speed_50MHz

) GPIOSpeed_TypeDef ;

énumération typedef

(GPIO_Mode_AIN = 0x0,

GPIO_Mode_IN_FLOATING = 0x04 ,

GPIO_Mode_IPD = 0x28,

GPIO_Mode_IPU = 0x48,

GPIO_Mode_Out_OD = 0x14,

GPIO_Mode_Out_PP = 0x10,

GPIO_Mode_AF_OD = 0x1C ,

GPIO_Mode_AF_PP = 0x18

) GPIOMode_TypeDef ;

Comme vous pouvez le constater, les types de données de la structure initialisée peuvent être utilisés comme types personnalisés, comme GPIOSpeed_TypeDef, et des types de données avec des valeurs spécifiques pour faciliter l'initialisation des registres périphériques, comme GPIOMode_TypeDef.
4 bits sont alloués pour configurer chaque broche GPIO.
L'image suivante montre le format du bit zéro du GPIO :

Mode – mode de fonctionnement de sortie (entrée/sortie). Plus précisément, ces valeurs sont légèrement plus grandes : les ports configurés comme ports de sortie ont une limitation sur la fréquence maximale du signal de sortie.

Mode Description
00 entrée
01 fréquence de sortie jusqu'à 10 MHz
10 fréquence de sortie jusqu'à 2 MHz
11 fréquence de sortie jusqu'à 50 MHz

CNF – bits de configuration de sortie. Dépend du mode de fonctionnement :

Convenez qu'avec cette structure du registre de configuration des broches, définir vous-même tous les bits pour la configuration sera extrêmement gênant. Il sera beaucoup plus facile de le faire en utilisant la fonction de bibliothèque GPIO_Init.
Après avoir initialisé le module périphérique, il doit être activé à l'aide de la fonction PPP_Cmd :

PPP_Cmd(PPP, ACTIVER);

PPP_Cmd(PPP, ACTIVER);

Cette fonction n'existe pas pour les modules GPIO ; après initialisation, vous pouvez immédiatement utiliser les broches GPIO. Il ne faut pas oublier que la bibliothèque fournit uniquement une interface avec le matériel du microcontrôleur. Si le module matériel n'a pas d'indicateur d'activation/désactivation, alors l'appel de fonction PPP_Cmd(PPP, ACTIVER) impossible.
Pour contrôler l'état de la broche GPIOx en mode sortie et lire la valeur en mode entrée ou sortie, la bibliothèque propose les fonctions suivantes :

void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx); uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);

void GPIO_SetBits (GPIO_TypeDef * GPIOx , uint16_t GPIO_Pin ) ;

void GPIO_ResetBits (GPIO_TypeDef * GPIOx , uint16_t GPIO_Pin ) ;

uint8_tGPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_tGPIO_Pin) ;

uint16_tGPIO_ReadOutputData(GPIO_TypeDef* GPIOx) ;

uint8_tGPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_tGPIO_Pin) ;

uint16_tGPIO_ReadInputData(GPIO_TypeDef* GPIOx) ;

Le reste des modules périphériques est configuré et fonctionne de la même manière. Cependant, il existe certaines différences dues aux spécificités du module matériel spécifique, je vous recommande donc fortement de voir d'abord des exemples d'utilisation du module sélectionné pour la bibliothèque STM32F10x SPL.

Gestion des interruptions et des exceptions

Le cœur Cortex-M3 comprend un contrôleur d'interruption vectorisé imbriqué. Le contrôleur prend en charge jusqu'à 240 sources pouvant provoquer des interruptions du cœur du processeur. Le nombre de vecteurs sur 240 possibles implémentés dans un modèle de microcontrôleur spécifique dépend du fabricant. Les microcontrôleurs Stm32f10x peuvent avoir jusqu'à 43 de ces vecteurs. Ces lignes d'interruption sont appelées masquables. De plus, il existe 15 vecteurs d'interruption de base Cortex-M3 et une interruption EXTI externe non masquable.
Le contrôleur prend en charge les interruptions imbriquées, où une autre interruption peut se produire dans un gestionnaire. À cet égard, chaque source d'interruption a sa propre priorité. 16 niveaux de priorité d'interruption sont pris en charge.
Les vecteurs d'interruption du cœur Cortex-M3 ont les valeurs de priorité les plus élevées.
Les trois niveaux d'interruption les plus élevés sont affectés aux vecteurs et ne peuvent pas être modifiés :

Nombre Gestionnaire Une priorité Description
1 Réinitialiser_Handler -3 (le plus élevé) Réinitialiser le vecteur
2 NMI_Handler -2 Interruption non masquable
3 HardFault_Handler -1 Conditions d'urgence

Tous les autres vecteurs d'interruption peuvent se voir attribuer des niveaux de priorité de 0 à 15.
Le niveau de priorité le plus élevé correspond à une valeur inférieure. Le niveau de priorité peut être attribué non seulement à un vecteur individuel, mais également à un groupe entier de vecteurs. Cette fonctionnalité facilite le travail avec un grand nombre de vecteurs d'interruption.
Pour définir le groupe prioritaire, une fonction de la bibliothèque STM32F10x SPL est utilisée.

Depuis longtemps, voire très longtemps, il n'y a pas eu de nouveaux articles sur notre article, il est donc temps de se rattraper 😉 Aujourd'hui nous allons commencer à étudier le STM32F4. Et, probablement, nous commencerons par créer un nouveau projet pour ces contrôleurs, même si, pour être honnête, je ne voulais pas écrire d'article à ce sujet, car nouveau projet ici, il est créé, en principe, de la même manière que pour STM32F103(). Mais il arrive quand même que certaines difficultés surviennent avec le STM32F4, alors examinons néanmoins ce processus en détail)

Alors, lançons Keil, créons un nouveau projet - Projet -> Nouveau projet uVision. Nous enregistrons le nouveau projet dans un dossier, puis il nous sera demandé de sélectionner le microcontrôleur à utiliser. Eh bien, choisissons, que ce soit STM32F407VG :

Terminé, dans la boîte de dialogue qui apparaît, cliquez sur « Oui » et le premier fichier sera ajouté à notre projet - startup_stm32f4xx.s. Comme avant, nous utiliserons des bibliothèques CMSIS Et Bibliothèque de périphériques standard, mais bien sûr déjà pour les contrôleurs STM32F4xx. Nous devons donc absolument les télécharger et ajouter les fichiers nécessaires à notre projet encore vide. À propos, j'ai entendu plus d'une fois de la part de différentes personnes dire qu'elles rencontraient des bibliothèques « pas si » pour F4, et que même le projet le plus simple n'était pas mis en place. Je n'ai moi-même pas rencontré cela, cependant, voici les bibliothèques testées que j'utilise moi-même :

Donc, nous l'avons téléchargé, tout est prêt, maintenant nous ajoutons les fichiers au projet. L'image montre ce dont vous aurez besoin :

Eh bien, la préparation est terminée, créons maintenant un nouveau fichier .c, qui contiendra notre code. Allons à Fichier->Nouveau, un fichier vide s'ouvre dans Keil, cliquez sur Fichier->Enregistrer sous et enregistrez-le sous le nom test.c, par exemple. Lors de l’enregistrement, n’oubliez pas de préciser l’extension du fichier (.c). Le fichier a été créé, super, mais nous devons également l'ajouter à notre projet. Eh bien, en fait, il n'y a rien de compliqué là-dedans 😉 Écrivons un programme de test vide dans ce fichier :

#inclut "stm32f4xx.h" #inclut "stm32f4xx_rcc.h" #inclut "stm32f4xx_gpio.h" /*******************************************************************/ int main() ( while (1 ) ( __NOP() ; ) ) /*******************************************************************/

Presque tout est prêt, il ne reste plus qu'à regarder les paramètres du projet - Projet->Options pour la cible… Une fenêtre s'ouvre avec de nombreux onglets, nous ne nous intéressons ici qu'à quelques-uns. Ouvrir l'onglet C/C++ et dans le champ Définir nous écrivons :

Eh bien, sur le terrain vous devez ajouter des chemins à absolument tous les fichiers inclus dans le projet. Après avoir terminé cette étape, vous pouvez appuyer sur F7 (Build) et le projet sera construit sans erreurs ni avertissements. Comme vous pouvez le constater, rien de compliqué)

Mais en général, personnellement, je fais les choses un peu différemment. Regardez l'inconvénient de cette approche. Nous avons donc téléchargé les bibliothèques CMSIS et SPL quelque part, ajouté des fichiers à partir de ces dossiers, noté les chemins d'accès aux fichiers, tout est cool. MAIS! Le projet ne sera pas construit sur un autre ordinateur, puisque les chemins sont tous absolus, c'est-à-dire qu'ils pointent vers des dossiers spécifiques sur votre ordinateur. Et sur une autre machine vous devrez effectivement refaire les étapes pour créer un nouveau projet. C'est un énorme inconvénient. Par conséquent, je crée généralement un dossier séparé pour un nouveau projet, dans lequel je crée des sous-dossiers pour CMSIS, SPL et autres bibliothèques utilisées, et dans ces dossiers je place tous les fichiers dont j'ai besoin dans chaque projet spécifique. Par exemple, créons le dossier STM32F4_Test pour notre nouveau projet et les dossiers suivants :

J'ai mis tous les fichiers nécessaires que nous avons ajoutés lors de la création du projet au début de l'article dans les dossiers CMSIS et SPL. Maintenant, nous lançons Keil, créons un nouveau projet et l'enregistrons dans notre sous-dossier Projet afin que tous les fichiers du projet soient au même endroit et ne provoquent pas de chaos.)

Le projet a été créé, maintenant, comme auparavant, nous y ajoutons simplement tous les fichiers des dossiers STM32F4_CMSIS et STM32F4_SPL. Nous plaçons notre fichier de test .c avec la fonction main() dans le dossier Source et l'ajoutons également au projet. Il ne reste plus qu'à configurer les paramètres =) Tout est pareil - dans le champ de définition on écrit :

USE_STDPERIPH_DRIVER, STM32F4XX



Nous assemblons le projet - il n'y a pas d'erreurs, le vol est normal ! En principe, nous avons finalement obtenu la même chose, mais maintenant le projet sera immédiatement assemblé sur n'importe quel autre ordinateur sans aucun problème, ce qui est très pratique et utile) Absolument tous les fichiers du projet sont désormais situés à proximité, dans le même dossier, et les chemins sont devenus relatifs et n'ont pas besoin d'être modifiés.
C'est tout, en fait, dans un futur proche nous ferons quelque chose pour programmer le STM32F4, c'est sûr, alors à bientôt ! ​​;)

Projet complet à partir d'un exemple d'article -

J'ai indiqué que la bibliothèque standard est connectée au système. En fait, CMSIS est connecté - le système de représentation structurelle généralisée de MK, ainsi que SPL - la bibliothèque périphérique standard. Regardons chacun d'eux :

CMSIS
Il s'agit d'un ensemble de fichiers d'en-tête et d'un petit ensemble de codes permettant d'unifier et de structurer le travail avec le noyau et la périphérie du MK. En fait, sans ces fichiers, il est impossible de travailler normalement avec MK. Vous pouvez obtenir la bibliothèque sur la page de documentation d'accompagnement du MK.
Cette bibliothèque, selon la description, a été créée pour unifier les interfaces lorsque l'on travaille avec n'importe quel MK de la famille Cortex. Cependant, en réalité, il s’avère que cela n’est vrai que pour un seul fabricant, à savoir En passant à un microcontrôleur d'une autre entreprise, vous êtes obligé d'étudier ses périphériques presque à partir de zéro.
Bien que les fichiers relatifs au cœur du processeur du MK soient identiques chez tous les fabricants (ne serait-ce que parce qu'ils ont le même modèle de cœur de processeur - fourni sous forme de blocs IP par ARM).
Par conséquent, travailler avec des parties du noyau telles que les registres, les instructions, les interruptions et les unités de coprocesseur est standard pour tout le monde.
Quant à la périphérie, les STM32 et STM8 (du coup) sont presque similaires, et cela est aussi en partie vrai pour les autres MK sortis par ST. Dans la partie pratique, je montrerai à quel point il est simple d'utiliser CMSIS. Cependant, les difficultés d'utilisation sont associées à la réticence des gens à lire la documentation et à comprendre la conception MK.

SPL
Bibliothèque de périphériques standard - bibliothèque de périphériques standard. Comme son nom l'indique, le but de cette bibliothèque est de créer une abstraction pour la périphérie du MK. La bibliothèque se compose de fichiers d'en-tête dans lesquels sont déclarées des constantes lisibles par l'homme pour la configuration et l'utilisation des périphériques MK, ainsi que des fichiers de code source collectés dans la bibliothèque elle-même pour les opérations avec les périphériques.
SPL est une abstraction sur CMSIS, présentant à l'utilisateur une interface commune pour tous les MCU, non seulement d'un fabricant, mais généralement pour tous les MCU dotés d'un cœur de processeur Cortex-Mxx.
On pense que c'est plus pratique pour les débutants, car... permet de ne pas réfléchir au fonctionnement des périphériques, mais la qualité du code, l'universalité de l'approche et la contrainte des interfaces imposent certaines restrictions au développeur.
De plus, les fonctionnalités de la bibliothèque ne permettent pas toujours d'implémenter avec précision la configuration de certains composants tels que l'USART (port série universel synchrone-asynchrone) sous certaines conditions. Dans la partie pratique, je décrirai également le travail avec cette partie de la bibliothèque.

Salut tout le monde. Comme vous vous en souvenez dans le dernier article que nous avions mis en place progiciel travailler avec les microcontrôleurs STM32 et a compilé le premier programme. Dans cet article, nous nous familiariserons avec l'architecture de cette carte, ce microcontrôleur et les bibliothèques disponibles pour le travail.

Ci-dessous une photo du tableau Découverte STM32F3 , où : 1 — Capteur MEMS. Gyroscope numérique 3 axes L3GD20. 2 - Système MEMS dans un boîtier contenant un accéléromètre linéaire numérique à 3 axes et un capteur géomagnétique numérique à 3 axes LSM303DLHC. 4 – LD1 (PWR) – Alimentation 3,3 V. 5 – LD2 – LED rouge/verte. La valeur par défaut est rouge. Le vert signifie la communication entre ST-LINK/v2 (ou V2-B) et le PC. J'ai ST-LINK/v2-B, ainsi qu'un affichage personnalisé port USB. 6. -LD3/10 (rouge), LD4/9 (bleu), LD5/8 (orange) et LD6/7 (vert). Dans le dernier article, nous avons flashé la LED LD4. 7. – Deux boutons : USER personnalisé et réinitialiser RÉINITIALISER. 8. - UTILISATEUR USB avec connecteur Mini-B.

9 - Débogueur/programmateur USB ST-LINK/V2. 1 0. - Microcontrôleur STM32F303VCT6. 11. — Générateur externe haute fréquence 8 MHz. 12. – Il devrait y avoir ici un générateur basse fréquence, malheureusement il n'est pas soudé. 13. – SWD-interface. 14. – Les cavaliers de sélection de la programmation des contrôleurs externes ou internes, dans le premier cas, doivent être retirés. 15 – Jumper JP3 – un cavalier conçu pour connecter un ampèremètre pour mesurer la consommation du contrôleur. Il est clair que s'il est supprimé, notre pierre ne démarrera pas. 16. – STM32F103C8T6 il y a une carte de débogage dessus. 17. — LD3985M33R Régulateur à faible chute de tension et niveau de bruit, 150 mA, 3,3 V.

Examinons maintenant de plus près l'architecture du microcontrôleur STM32F303VCT6. Son spécifications techniques: boîtier LQFP-100, cœur ARM Cortex-M4, fréquence de cœur maximale 72 MHz, capacité de mémoire programme 256 Ko, type de mémoire Programmes FLASH, volume mémoire vive SRAM 40 Ko, RAM 8 Ko, nombre d'entrées/sorties 87, interfaces (CAN, I²C, IrDA, LIN, SPI, UART/USART, USB), périphériques (DMA, I2S, POR, PWM, WDT), ADC/DAC 4 *12 bits/2*12 bits, tension d'alimentation 2...3,6 V, température de fonctionnement –40...+85 C. Dans la figure ci-dessous, il y a un brochage, où nous voyons 87 ports d'entrée/sortie, dont 45 E/S normales (TC, TTa), 42 E/S tolérantes 5 volts (FT, FTf) – compatibles avec 5 V. (sur la carte il y a des broches 5 V à droite, 3,3 V à gauche). Chaque ligne d'E/S numérique peut servir de ligne d'E/S générale.
destination ou fonction alternative. Au fur et à mesure de l'avancée des projets, nous ferons progressivement connaissance avec la périphérie.

Considérez le schéma fonctionnel ci-dessous. Le cœur est un cœur ARM Cortex-M4 32 bits fonctionnant jusqu'à 72 MHz. Il dispose d'une unité à virgule flottante FPU intégrée et d'une unité de protection de mémoire MPU, de cellules de traçage de macro intégrées - Embedded Trace Macrocell (ETM), qui peuvent être utilisées pour surveiller le processus d'exécution du programme principal à l'intérieur du microcontrôleur. Ils sont capables de produire en continu ces observations via les contacts ETM tant que l'appareil fonctionne. NVIC (Contrôleur d'interruption vectorielle imbriqué) – module de contrôle d'interruption. TPIU (unité d'interface de port de trace). Contient de la mémoire FLASH – 256 Ko, SRAM 40 Ko, RAM 8 Ko. Entre le cœur et la mémoire se trouve une matrice de bus, qui permet de connecter directement les appareils. Ici également, nous voyons deux types de matrice de bus AHB et APB, la première étant plus productive et utilisée pour la communication à haut débit. composants internes, et ce dernier est destiné aux périphériques (périphériques d'entrée/sortie). Le contrôleur dispose de 4 ADC (ADC) 12 bits (5 Mbit/s) et d'un capteur de température, 7 comparateurs (GP Comparator1...7), 4 amplificateurs opérationnels programmables (OpAmp1...4) (PGA (Programmable Gain Array )), 2 canaux DAC (DAC) 12 bits, RTC (horloge en temps réel), deux minuteries de surveillance - indépendantes et fenêtrées (WinWatchdog et Ind. WDG32K), 17 minuteries à usage général et multifonctionnel.

De manière générale, nous avons examiné l'architecture du contrôleur. Regardez maintenant les bibliothèques de logiciels disponibles. Après avoir fait un aperçu, nous pouvons souligner les éléments suivants : CMSIS, SPL et HAL. Examinons chacun d'eux en utilisant un exemple simple de clignotement d'une LED.

1). CMSIS(Cortex Microcontroller Software Interface Standard) - bibliothèque standard pour Cortex®-M. Fournit une prise en charge des appareils et simplifie interfaces logicielles. CMSIS fournit des informations cohérentes et interfaces simples pour le noyau, ses périphériques et les systèmes d'exploitation temps réel. Son utilisation est une manière professionnelle d'écrire des programmes, car... implique l'écriture directe dans les registres et, par conséquent, une lecture et une étude constantes des fiches techniques sont nécessaires. Indépendant du fabricant du matériel.
CMSIS comprend les composants suivants :
- CMSIS-CORE : démarrage cohérent du système et accès aux périphériques ;
- CMSIS-RTOS : Exécution logicielle déterministe en temps réel logiciel temps réel);
- CMSIS-DSP : Implémentation rapide du traitement du signal numérique traitement numérique signaux);
- CMSIS-Driver : Interfaces périphériques génériques pour le middleware et le code d'application (Interfaces périphériques générales pour le middleware et le code d'application) ;
- CMSIS-Pack : Accès facile aux composants logiciels réutilisables composants logiciels);
- CMSIS-SVD : vue cohérente de l'appareil et des périphériques périphériques);
- CMSIS-DAP : Connectivité au matériel d'évaluation à faible coût. Logiciel de débogage.

Par exemple, écrivons un programme - faites clignoter une LED. Pour cela, nous avons besoin d'une documentation décrivant les registres. Dans mon cas RM0316 Manuel de référence STM32F303xB/C/D/E, STM32F303x6/8, STM32F328x8, STM32F358xC, STM32F398xE MCU avancés basés sur ARM ®, ainsi qu'une description de la jambe spécifique dont il est responsable DS9118: MCU+FPU Cortex®-M4 32b basé sur ARM®, jusqu'à 256 Ko de Flash + 48 Ko de SRAM, 4 CAN, 2 canaux DAC, 7 composants, 4 PGA, minuteries, 2,0-3,6 V. Pour commencer, nous allons chronométrer le port dans le programme, car Par défaut, tout est désactivé, ce qui permet de réduire la consommation d'énergie. Ouvrez le manuel de référence et regardez la section Réinitialisation et contrôle de l'horloge, puis la carte des registres RCC et voyez quel registre est responsable de l'activation d'IOPEEN.

Passons à la description du pointage des périphériques de ce registre Registre d'activation de l'horloge périphérique AHB (RCC_AHBENR), où l'on voit que ce port est sous le 21ème bit. Allumez-le RCC->AHBENR|=(1<<21) . Далее сконфигурируем регистры GPIO. Нас интересует три: GPIOE_MODER и GPIOx_ODR . C помощью них повторим программу с предыдущей статьи, затактируем PE8. Первый отвечает за конфигурацию входа выхода, выбираем 01: General purpose output mode. GPIOE->MODER|=0×10000 . La seconde sert à activer le niveau bas/haut sur la jambe. Ci-dessous le programme :

#inclure "stm32f3xx.h " //Fichier d'en-tête du microcontrôleur
entier non signé i ;
délai nul() (
pour (i=0;i<500000;i++);
}
int principal (vide) (
RCC->AHBENR|=(1<<21);
GPIOE->MODER|=0×10000 ;
tandis que (1)(
retard();
GPIOE->ODR|=0×100 ;
retard();
GPIOE->ODR&=~(0×100);
} }

2). SPL(Bibliothèque de périphériques standard)- cette bibliothèque est destinée à regrouper tous les processeurs de ST Electronics. Conçu pour améliorer la portabilité du code et s'adresse principalement aux développeurs débutants. ST travaille sur un remplacement du SPL appelé « couche basse » compatible avec HAL. Les pilotes Low Layer (LL) sont conçus pour fournir une couche presque légère et orientée expert, plus proche du matériel que HAL. En plus de HAL, des API LL sont également disponibles. Un exemple du même programme en SPL.

#inclure
#inclure
#inclure
#définir la LED GPIO_Pin_8
int main() (
longtemps je;
GPIO_InitTypeDef gpio ;
// La LED bleue est connectée au port E, broche 8 (bus AHB)
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOE, ENABLE);
// Configurer le port E (LED)
GPIO_StructInit(&gpio); //déclare et initialise une variable de structure de données
gpio.GPIO_Mode = GPIO_Mode_OUT ;
gpio.GPIO_Pin = LED ;
GPIO_Init(GPIOE, &gpio);
// LED clignotantes
tandis que (1) (
// Sur
GPIO_SetBits(GPIOE, LED);
pour (je = 0; je< 500000; i++);
// Tout est éteint
GPIO_ResetBits(GPIOE, LED);
pour (je = 0; je< 500000; i++);
} }

Chaque fonction est décrite dans la documentation technique Manuel d'utilisation UM1581 Description de la bibliothèque de périphériques standard STM32F30xx/31xx. Ici, nous connectons trois fichiers d'en-tête qui contiennent les données, structures, fonctions de contrôle de réinitialisation et de synchronisation nécessaires, ainsi que pour la configuration des ports d'entrée/sortie.

3). HAL- (Niveau d'accès matériel, couche d'abstraction matérielle)- Une autre bibliothèque commune pour le développement. Avec lequel le programme CubeMX pour la configuration que nous avons utilisée dans le dernier article a également été publié. Là, nous avons également écrit un programme pour faire clignoter une LED en utilisant cette bibliothèque. Comme nous le voyons dans la figure ci-dessous, le cube génère les pilotes HAL et CMSIS. Eh bien, décrivons les principaux fichiers utilisés :
- system_stm32f3x.c et system_stm32f3x.h- fournir un ensemble minimal de fonctions pour configurer le système de chronométrage ;
— core_cm4.h – donne accès aux registres du cœur et de ses périphériques ;
- stm32f3x.h - fichier d'en-tête du microcontrôleur ;
— startup_system32f3x.s — code de démarrage, contient une table de vecteurs d'interruption, etc.

#include "main.h"
#include "stm32f3xx_hal.h"
void SystemClock_Config(void); /*Déclarer les fonctions de configuration de l'horloge*/
vide statique MX_GPIO_Init(void); /*Initialiser les E/S*/
int principal (vide) (
/*Réinitialisation de tous les périphériques, Initialise l'interface Flash et le Systick.*/
HAL_Init();
/* Configurer l'horloge système */
SystemClock_Config();
/* Initialise tous les périphériques configurés */
MX_GPIO_Init();
tandis que (1) (
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_8); //Changer l'état de la jambe
HAL_Delay(100); )
}
annuler SystemClock_Config (vide){
RCC_OscInitTypeDef RCC_OscInitStruct ;
RCC_ClkInitTypeDef RCC_ClkInitStruct ;

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI ;
RCC_OscInitStruct.HSIState = RCC_HSI_ON ;
RCC_OscInitStruct.HSICalibrationValue = 16 ;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE ;
si (HAL_RCC_OscConfig (&RCC_OscInitStruct) != HAL_OK){

}
/**Initialise les horloges des bus CPU, AHB et APB */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI ;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1 ;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1 ;
si (HAL_RCC_ClockConfig (&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK){
_Error_Handler(__FILE__, __LINE__);
}
/**Configurer l'heure d'interruption du Systick*/
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
/**Configurer le Systick */
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* Configuration de l'interruption SysTick_IRQn */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/** Configurer les broches comme entrée-sortie analogique EVENT_OUT EXTI */
vide statique MX_GPIO_Init (vide){
GPIO_InitTypeDef GPIO_InitStruct ;
/* Activation de l'horloge des ports GPIO */
__HAL_RCC_GPIOE_CLK_ENABLE();
/*Configurer le niveau de sortie de la broche GPIO */
HAL_GPIO_WritePin (GPIOE, GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11
|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET);
/*Configurer les broches GPIO : PE8 PE9 PE10 PE11 PE12 PE13 PE14 PE15 */
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP ;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed ​​​​= GPIO_SPEED_FREQ_LOW ;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
}
void _Error_Handler (fichier char *, ligne int){
tandis que (1) (
} }
#ifdef USE_FULL_ASSERT

Void assert_failed (fichier uint8_t*, ligne uint32_t){
}
#fin si
Ici, tout comme dans l'exemple précédent, on peut visualiser la description de chaque fonction dans la documentation, par exemple Manuel d'utilisation de l'UM1786 Description des pilotes STM32F3 HAL et de couche basse.

On peut résumer que la première option, utilisant CMSIS, est moins lourde. Il existe une documentation pour chaque bibliothèque. Dans les projets ultérieurs, nous utiliserons HAL et CMSIS à l'aide du programme de configuration STCube et, si possible, utiliserons les registres directement, sans wrappers logiciels. Arrêtons-nous là aujourd'hui. Dans le prochain article, nous examinerons les principes de base de la construction Maison intelligente. Au revoir tout le monde.




Haut