Les codeurs en STM32
Bon, assez d'amuse-gueules, on arrive vers le plat. Le codeur est un truc important. Si on loupe le codeur, on loupe le tout, on ne sais pas ou on est. Ya deux types de codeur - les codeurs relatif, qui génère deux signaux en quadrature donnant les pas et leurs directions, et les codeurs absolus qui donne la position exacte du codeur. On parlera des codeurs relatif ici.
Comment gérer un codeur, donc?
- Lire ses signaux directement, en "user code". Cela ne laisse pas trop de temps pour faire autre choses, car on peut louper des pas.
- Avec un timer qui génère un interrupt assez rapide, on peut scruter les deux entrées et réagir aux changements. Comme option 1, mais avec moins de chance de louper des changements (au moins si ils ne sont pas plus rapides que les interrupts, mais on peut scheduler celles-ci pour éviter). Par contre, on est sujet aux artefacts du "Nyquist sampling frequency".
- On peut mettre des interrupts sur les changements des deux entrées, et avec un peu de logique, on suit les impulsions du codeur. Ceci est la méthode la plus utilisé sur les µCs en générale.
- Sur les STM32 (et, de mémoire, sur les STM8) y a un mode "codeur" sur quelques uns des timers. Ceci est vraiment intéressant, car la totalité du logique se passe en dehors de, et indépendant de, la code qui se passe sur le processeur. Y a presque rien a faire, et c'est ça qu'on va faire. Moins de code, fainéantise comme philosophie.
En se repérant a section 15.3.12 de RM0008, on se découvrira comment ça marche. On definira un niveau de filtrage pour eviter les fausses lectures (debouncing), et le timer va compter, sous la controle de codeur, de 0 a n, par repetition (ou n est le nombre de pulsations/tour generé par le codeur, et que on va donner au timer comme "auto reload value").
On peut utiliser le mode DMA du timer pour copier ses valeurs internes vers nos variables chaque fois que ca change, et / ou utiliser des interrupts capture/compare pour faire des choses au passage de zero. On peut utiliser notre compteur comme "gachette" pour demarrer un autre timer, et encore d'autres choses. Le tout avec un minimum absolu de code executant sur le processeur meme.
Toujours ignorant le "retomber dans les pas", on s'en fout bien assez du positionnement exacte de la broche. Ce qu'on veut, c'est sa vitesse, combien de µS entre chaque changement de position, et ca, on n'as pas directement. Pour l'avoir, en mode "naïf", on pourrait utiliser le mode codeur, avec un interrupt sur chaque changement. Dans l'interrupt, on prends le temps exacte, et on calcul notre vitesse. Admettons un vitesse maximale de broche en filetage de 240 t/m, ca fait 4 t/s, ce qui fait (avec le codeur de vibram) 2000 interrupts/sec si on interrupt sur chaque pulsation, ou 1000 interrupts/sec si on interrupt sur une seule signal. En effet, on a utilisé le mode codeur pour eviter de faire un interrupt sur chaque changement des signaux, mais on va faire un interrupt a chaque changement des signaux quand meme.
Dans RM0008, meme, il est dit
The timer, when configured in Encoder Interface mode provides information on the sensor’s current position. You can obtain dynamic information (speed, acceleration, deceleration) by measuring the period between two encoder events using a second timer configured in capture mode. The output of the encoder which indicates the mechanical zero can be used for this purpose. Depending on the time between two events, the counter can also be read at regular times. You can do this by latching the counter value into a third input capture register if available (then the capture signal must be periodic and can be generated by another timer). when available, it is also possible to read its value through a DMA request generated by a Real-Time clock.
Admettons qu'on va utiliser TIM2 (timer 2) en mode codeur. Pour avoir le valeur de codeur en temps reel pour notre application, on va le configurer pour faire un transfert DMA de sa compteur vers nos variables (voila le pourquoi du
volatile
dans le pseudocode dessus). A ce point la, on a le valeur de codeur, sans aucun code mise apart sa configuration.
On va aussi configurer sa compteur comme signal de reset pour un autre compteur, par exemple TIM3, qui fera un DMA de son compteur sur le trigger, encore, vers nos variables. On peut jouer sur le prescaler de ce compteur pour compter le temps pour un ou plusiers "ticks" de codeur. Encore, on fini avec les valeurs qu'on veut, sans faire executer du code sur le processeur.
Il exist une autre probleme. Qu'est-ce-que va passer quand le codeur s'arrete subitement? On n'aura plus de updates, donc notre PaP va continuer a avancer a sa vitesse actuel, broche a l'arret, jusqu'au butee, ruinant notre piece. Mince alors. Il faut un watchdog, quelque chose qui arret le PaP en cas d'arret de broche. Et encore, on as des outils pour ca. Sur notre timer "esclave", on configurera un interrupt sur un canal capture/compare; si le compteur arrive vers un valeur predefini, on aura un interrupt qui peut arreter le tout.
Donc, on aura les valeurs qui nous interesse, automatiquement et sans avoir besoin d'executer du code, et un petit bout de code qui sera execute en cas d'arret, ce qui doit arriver assez peu souvent.
Prochaine etape, du code pour faire en sort que ca se passe comme ca.