Ce que nous allons faire
Le CH32V003 étant assez rudimentaire, il se prêtait mal à des explications détaillées sur les bus et les horloges. Nous avons donc manipulé ces objets sans s'y attarder jusqu'à maintenant. Le CH32V307 étant très complet de ce point de vue, il nous donne l'occasion d'aborder ce sujet important.
Les bus
De la même façon qu'un bus (véhicule) sert à transporter des personnes entre différentes localités, un bus (circuit) sert à transporter des données entre différents composants d'un système digital, ici un micro-contrôleur.
De la même façon qu'un voyageur monte dans le bus à un arrêt et descend à un autre, une donnée est produite par un sous-système et utilisée par un autre.
Le diagramme ci-dessous est extrait du manuel de référence du CH32V307, il s'agit de la Figure 1-6 CH32V30x (Connection / interconnection / high capacity general-purpose) system architecture, page 11 du PDF :
On y voit que le processeur (marqué "RISC-V (V4F)") est relié par un "System bus" à un multiplexeur (marqué "MUX"), qui est un système d'aiguillage des communications. Ce multiplexeur permet au processeur d'accéder directement à la RAM et à quelques périphériques rapides (ex. Ethernet, USB).
Ce multiplexeur est aussi relié à un autre bus marqué "HB", forme abrégée de AHB, ou Advanced High-performance Bus. Celui-ci dessert quelques périphériques et est aussi relié par des ponts (bridge en anglais) à 2 autres bus marqués "PB1" et "PB2", PB étant la forme abrégée de APB, ou Advanced Peripheral Bus. Tous les autres périphériques sont reliés à ces 2 bus, PB1 et PB2.
On retrouve donc ici les fameux AHB, APB1 et APB2 figurant dans les noms de certaines fonctions et constantes qui nous sont familières. C'est ainsi en consultant ce diagramme que vous pouvez savoir s'il faut utiliser RCC_AHBPeriphClockCmd(), RCC_APB1PeriphClockCmd() ou RCC_APB2PeriphClockCmd() pour activer un périphérique donné.
AHB et APB font partie de ls spécification AMBA, ou Advanced Microcontroller Bus Architecture, développée par ARM et devenue un standard industriel de facto car libre de droits. Je vous donne ce lien uniquement pour satisfaire votre éventuelle curiosité, il n'est absolument pas nécessaire de lire cette documentation pour utiliser ces bus - vous l'avez d'ailleurs fait sans problème jusqu'à maintenant.
Les horloges
Un signal d'horloge est à un système digital ce que le cœur est à notre corps. Si notre cœur ne bat pas, notre corps est inerte. Il en va de même pour les systèmes digitaux, c'est leur horloge qui leur permet de changer d'état. C'est pour cette raison que nous devons utiliser RCC_AHBPeriphClockCmd(), RCC_APB1PeriphClockCmd() ou RCC_APB2PeriphClockCmd() pour activer les périphériques dont nous avons besoin, car à la mise sous tension, leur horloges des périphériques sont toutes désactivées.
Physiquement, un signal d'horloge est une alternance régulière et continue de niveaux logiques haut et bas. Si vous levez le bras et que vous le laissez retomber de façon continue et lente, vous ne risquez pas de vous fatiguer. Par contre, si vous le faites rapidement, vous n'allez pas tarder à vous essouffler aller vite nécessite plus d'énergie. Il en va exactement de même en électronique, c'est pourquoi un micro-contrôleur intègre de nombreux dispositifs pour configurer la fréquence de ses horloges internes. Nous allons voir ça de plus près.
Le diagramme ci-dessous est extrait du manuel de référence du CH32V307, il s'agit de la Figure 3-2 CH32V305/307/317 and CH32F205/207 clock tree structure, page 33 du PDF :
Pour produire un signal d'horloge, on utilise un dispositif appelé oscillateur (oscillator en anglais). Il en existe de nombreux types, mais seuls 2 types concernent les micro-contrôleurs, les oscillateurs à quartz (crystal en anglais et les oscillateurs RC.
Un oscillateur à quartz utilise les déformations d'un cristal de quartz sous l'effet du courant électrique pour produire des changements d'état. C'est ce type d'oscillateur qu'on trouve dans les montres électroniques. Il a l'avantage d'être très précis et stable, mais le cristal de quartz ne peut pas être intégré dans le micro-contrôleur, donc ça requiert un composant externe.
Un oscillateur RC utilise la charge et la décharge d'un condensateur à travers une résistance pour produire les changements d'état. C'est très économique, facile à intégrer dans le micro-contrôleur, mais bien moins précis et stable qu'un quartz. Pour vous donner une idée, la précision est de l'ordre de 1% pour un oscillateur RC et de l'ordre de 0.001% pour un oscillateur à quartz.
On voit sur le diagramme que le CH32V307 intègre 4 oscillateurs :
Le HSE (High-Speed External crystal oscillator), qui peut fonctionner avec des quartz taillés pour des fréquences allant de 3 à 25 MHz. Le HSE est la manière la plus courante de cadencer le micro-contrôleur dans son ensemble.
Le HSI (High-Speed Internal RC oscillator), qui a une fréquence fixe de 8 MHz. Le HSI est l'oscillateur utilisé pour cadencer le micro-contrôleur à la mise sous tension. Si le développeur veut utiliser le HSE, il doit le démarrer puis basculer le micro-contrôleur sur lui dans la phase d'initialisation de l'application. C'est ce qui se passe dans system_ch32v30x.c, selon l'option d'horloge que vous avez choisi.
Le LSE (Low-Speed External crystal oscillator), prévu pour fonctionner avec un quartz de 32768 Hz. Il est destiné à fournir une base de temps de bonne qualité à l'horloge temps réel (RTC). Il doit être démarré explicitement lors de l'initialisation de la RTC.
Le LSI (Low-Speed Internal RC oscillator), qui a une fréquence fixe de 40 kHz. Celui-ci est utilisé par le watchdog indépendant (IWDG) et peut aussi servir pour l'horloge temps réel (RTC) si une dérive importante est acceptable.
Vous remarquez sur le diagramme que HSE et HSI ne sont pas utilisés directement mais passent par des blocs marqués "PLLxMUL". Une PLL (Phase-Locked Loop, boucle à verrouillage de phase) agit comme un multiplicateur de fréquence dont le coefficient est configurable. C'est de cette façon qu'on peut arriver à cadencer le micro-contrôleur à 144 MHz à partir d'un quartz de 8 MHz.
Nous avons vu que notre micro-contrôleur comporte plusieurs bus internes pour communiquer avec des périphériques de performances très différentes. En particulier, les bus APB sont connectés à des périphériques qui sont entre 10 et 100 fois plus lents que le processeur. C'est pourquoi on voit sur le diagramme des horloges des blocs marqués "prescaler". Ceux-ci divisent la fréquence du signal d'horloge qu'ils reçoivent par un coefficient configurable pour produire une nouvelle horloge plus lente et mieux adaptée à son utilisation.
Enfin, les symboles en forme de D sur le diagramme sont des portes logiques ET. Si l'entrée marquée "peripheral clock enable" est au niveau logique bas, la sortie de la porte reste en permanence à l'état bas. Si vous appliquez un niveau logique haut à l'entrée "peripheral clock enable", la sortie de la porte reproduira le signal d'horloge présent sur son autre entrée. Les fonctions RCC_AHBPeriphClockCmd(), RCC_APB1PeriphClockCmd() et RCC_APB2PeriphClockCmd() contrôlent simplement l'état de l'entrée "peripheral clock enable" du périphérique qu'on leur indique.
Ce que nous avons appris
Nous avons vu dans ce cours :
Ce que sont les bus et les horloges et à quoi ils servent
Comment les horloges sont générées et contrôlées
Les différents oscillateurs et leur utilité