filetage avec microcontrolleur

  • Auteur de la discussion vibram
  • Date de début
R

richard21

Nouveau
Pour le STM32F103C8 il y’en a seulement quatre timers TIM1,…TIM4 et biensûr le « SysTick » qui est propre à l’architecture ARM donc présent dans tout les processeurs et microcontrôleurs ARM.

Tout les quatre timers sont utilisables en mode « encoder » à condition que les pins, qui correspondent aux canaux CH1 et CH2 de chaque timer, ne soient pas occupés par d’autres périphériques

Exemple : si l’ USART1 est active, on ne pourra pas utiliser le timer1 et le timer4 en mode « encoder » au même temps, donc l’un ou l’autre.

Dans ton cas le timer TIM4 réponds très bien aux besoins de ton application.
 
V

vibram

Compagnon
Bonjour à tous,
Je reprends un peu le sujet car je tente un double projet: filetage / avance auto et diviseur de broche, oui mooooonsieur ! :wink:

Je reviens car j'ai besoin d'un peu d'aide sur le code. Il n'a presque pas changé pour le moment.
Je sais qu'il n'est pas hyper lisible en l'état mais c'est à cause de la phase d'apprentissage on va dire (je cherche des excuses comme je peux).

Voici mon code:
https://paste.ee/p/0HmAu

et la config cubemx (cf images)

Mon probleme:
J'aimerais afficher la vitesse de rotation (car je reflechis à un petit ecran avec les infos "utiles").
La variable RPM est calculée dans l'instance de TIM2 qui me sert aussi à detecter les états sur les boutons
APB Timer est à 72MHz


et mon TIM2 init:

Probleme: ma variable RPM reste à 0 meme lorsque j'applique une vitesse constante

Est-ce que vous voyez une erreur evidente ?


Merci :wink:

schaublin2.JPG


schaublin1.JPG
 
V

vibram

Compagnon
Bonjour à tous

Je me permets de re poster mon message ici pour un peu plus de visibilité

Voici mon code:
https://paste.ee/p/0HmAu

et la config cubemx (cf images)

Mon probleme:
J'aimerais afficher la vitesse de rotation (car je reflechis à un petit ecran avec les infos "utiles").
La variable RPM est calculée dans l'instance de TIM2 qui me sert aussi à detecter les états sur les boutons
APB Timer est à 72MHz
Le multiplicateur 47619.0476 est le résultat de la formule frequence/(PSC + 1) * (Period + 1)
Mon but était de multiplier le nombre de pulses entre 2 intervalles
Pendant l'écriture de ce message, je me rends compte que pour avoir les tours/minutes, je dois encore multiplier par 60 car j'ai une frequence en hertz.

Voyez-vous un autre probleme?



et mon TIM2 init:

Probleme: ma variable RPM reste à 0 meme lorsque j'applique une vitesse constante

Est-ce que vous voyez une erreur evidente ?


Merci :wink:

Voir la pièce jointe 428138

Voir la pièce jointe 428139
 
O

Otatiaro

Compagnon
Salut,

Désolé mais je n'utilise pas (ou très rarement) la HAL.
C'est quelle cible (F1 visiblement, mais quelle ref, que je vois si j'ai une nucleo) ?
Auquel cas, si tu peux m'envoyer le projet complet, je peux jeter un coup d'oeil (thomaslegrand@eznov.com).

Thomas.
 
V

vibram

Compagnon
Salut,

Désolé mais je n'utilise pas (ou très rarement) la HAL.
C'est quelle cible (F1 visiblement, mais quelle ref, que je vois si j'ai une nucleo) ?
Auquel cas, si tu peux m'envoyer le projet complet, je peux jeter un coup d'oeil (thomaslegrand@eznov.com).

Thomas.

Salut Thomas, merci pour la proposition
C'est un STM32F103C8T6. J'utilise HAL depuis peu car j'ai des bases assez faibles donc ca me permet d'utiliser des outils tout faits.
Je t'envoie le projet en PJ.


Je ne sais pas si elle est évidente et même si c'est une erreur car je ne connais pas cette carte, seulement je trouve étrange ceci :
:shock:

Oui c'est bien normal, j'utilise 2 timers
Le TIM4 me sert à lire mon codeur
Le TIM2 me sert d'interruption pour lire l'état des boutons poussoirs ainsi que faire ce fameux calcul de vitesse :wink:
 
V

vibram

Compagnon
Je pense que j'ai un probleme au niveau de la frequence: je calcule la vitesse sur des intervalles trop courts ce qui me donne une valeur de 0 non représentative.

Je pense ajouter quelque chose de la sorte:


Il faut "juste" que j'adapte mon facteur de 47619.0476, je vais essayer de déterminer la nouvelle valeur
 
V

vibram

Compagnon
Bon le code fait bugger l affichage de l écran, je Continue de chercher
 
S

simon74

Compagnon
Ca me semble que ton code opere par "polling", donc "tous les x µs, je lise le statut de mon codeur". Mais les timers TIM2-TIM5, TIM1 et TIM8 ont des capacités pour lire et gerer les codeurs quadrature directement, sans que tu as besoin de toucher quoi que ce soit. Si tu veut savoir combien de temps par revolution, utilise un slave timer qui se demarre automatiquement quand ton codeur touche a zero.
 
C

coredump

Compagnon
Evite d'utiliser des nombres flottants, surtout pour les reconvertir en entier derriere. travaille plutot avec des fractions entières (d'abord la multiplication et ensuite la division).
L’intérêt c'est que c'est plus rapide et utilise beaucoup moins de code (pas de librairie flottante).
 
V

vibram

Compagnon
Evite d'utiliser des nombres flottants, surtout pour les reconvertir en entier derriere. travaille plutot avec des fractions entières (d'abord la multiplication et ensuite la division).
L’intérêt c'est que c'est plus rapide et utilise beaucoup moins de code (pas de librairie flottante).

Merci c'est entre autre pour cela que je voulais utiliser le TIM1 toutes les secondes, cela me simplifie le code.
je dois juste trouver pourquoi il n'est pas activé comme le TIM2...


edit: trouvé:HAL_TIM_Base_Start_IT(&htim1); cette ligne était commentée .. :wink:
 
V

vres

Compagnon
Bonjour,
Comme la fréquence du TIM2 est très élevée il me semble, il est fort probable que enc_value - old_enc_value soit égal à 1 ou 0.
Si tu veux une mesure plus précise il faut travailler avec un buffer circulaire.
Avec un timer tu peux générer 2 interruptions avec une fréquence différente.

Par exemple si ta fréquence d' interruption est de 1kHz et ton buffer est de 2000 valeurs, ta mesure sera prise sur 2 secondes mais sera actualisée toute les 0.001 seconde. elle sera stable et précise.
En plus comme ça comme le souligne coredump tu n'aura pas du tout besoin de flottant, le F1 n'a pas de FPU.
 
V

vibram

Compagnon
Merci à vous,
j'ai trouvé mon probleme et mixé vos solutions:

J'utilise TIM1 qui est configuré pour avoir un interrupt toutes les secondes, ca ca fonctionnait bien.

En revanche dans TIM1, il venait lire la valeur du codeur (et mettait en mémoire la valeur précedente du codeur) pourtant mes RPM restaient à 0.
En fait c'est que dans TIM2, je viens aussi lire la valeur du codeur et j'avais utilisé la meme variable. Du coup j'avais quand meme un raffraichissement de ma variable très rapide.
J'ai mis d'autres variables et ca fonctionne bien.
Je devrait faire une moyenne pour lisser la valeur et ce sera top.

La je bosse sur un STM32F103 mais à terme ce sera soit un 411RE à 100MHz et FPU, ou alors un STM32 encore un poil plus récent, je n'ai pas encore regardé mais un STM32F446RE me semble tout indiqué pour ce que je veux faire.
 
T

tronix

Compagnon
La je bosse sur un STM32F103 mais à terme ce sera soit un 411RE à 100MHz et FPU, ou alors un STM32 encore un poil plus récent, je n'ai pas encore regardé mais un STM32F446RE me semble tout indiqué pour ce que je veux faire.

Quelle est l'application prévue ? Car un STM32F103 devrait être largement suffisant pour un projet amateur. Et dans la plupart des cas, on se passe sans problème de la virgule flottante, qu'il faut d'ailleurs tout faire pour éviter sur un processeur ne disposant pas de FPU. Il suffit de travailler en virgule fixe.
 
V

vibram

Compagnon
le 411RE est à 100MHz et le 446RE à 180
J'ai un 411RE sous la main mais tant qu'à faire je prendrai le 446RE pour le projet final.

J'en profite pour poser une question rapide:
J'utilise un TIMER pour piloter le driver du PAP. J'aimerais laisser la possibilité de choisir la vitesse à l'utilisateur. Tu penses que c'est une bonne idée de faire varier l'interrupt du timer via des variables prescaler et period ? et ensuite je reinitialise le TIMER en fonction des variables pour la vitesse voulue.


C'est un projet pour tour sans VM type schaublin 102 avec un codeur sur la broche.
Avec ce codeur, je vais m'en servir pour faire un diviseur de broche et/ou asservir le chariot longitudinal avec un moteur PAP pour du filetage ou simplement une avance auto.
J'ai tendance à prendre un MCU avec une autre frequence car je pense prendre un codeur 2500ppr donc 10'000 en quadrature, si la broche commence à tourner vite, j'ai besoin d'une frequence élevée. Je n'ai pas besoin d'une telle prcésion pour l'asservissement mais pour le diviseur c'est plus que pas mal
 
T

tronix

Compagnon
Pour commencer, je ne connais pas les micro STM, mais je pense que l'on retrouve un peu les mêmes choses sur les 32bits modernes des différentes marques. Pourquoi pas 180MHz plutôt que 100MHz, pas la peine de se contraindre inutilement, mais il n'y a pas un rapport 2, et il est peu probable que cela ne se jouera pas là à mon avis. Ou c'est bien codé et cela tournera à l'aise sur le 100MHz, ou cela ne marchera sur aucun des 2. Il faut vraiment essayer d'utiliser au mieux les périphériques pour alléger au maximum le travail du processeur, et surtout les actions à faire en temps réel. Les interruptions à fréquence élevée sont souvent pénalisantes, à cause de la sauvegarde du contexte. Donc les éviter et étudier les PWM, timers et autres périphériques, ainsi et surtout que les façons d'utiliser les canaux DMA. De cette façon, il est possible de réaliser des choses qui ne semblent accessibles qu'aux FPGA. Par exemple gérer des signaux à mieux que 100ns près (voire beaucoup plus court, c'est alors du pur hardware). Impossible en soft direct, même sous interruption. Mais si c'est directement le périphérique qui le gère (avec DMA), cela devient facile. Une interruption à fréquence plus basse, pour lire ou écrire la table utilisée en DMA par le périphérique, et le tour est joué. L'utilisation ou la préparation des données se fait alors tranquillement, quand le processeur n'a rien de plus urgent à faire. C'est la clé pour réaliser des fonctions rapides et fiables en micro-contrôleur.
Et changer la période du timer en cours d'exécution est une bonne solution, il faut juste vérifier ce qui se passe au moment du changement. Pour piloter des moteurs ou équivalent, j'utiliserais plutôt (sur mes composants) un timer fixe avec des sorties PWM connectées à ce timer, en changeant les valeurs de set et reset. Encore une fois pour que cela tourne au maximum tout seul sans intervention du processeur quand c'est possible.
Et c'est là que les HAL ne sont pas toujours une aide, en masquant les périphériques réels, et complexifiant finalement leur utilisation, contrairement au but recherché.
 
T

tronix

Compagnon
J'ajoute aussi que pour ce projet, la virgule flottante ne me semble pas forcément nécessaire. La virgule fixe suffit (c'est en fait de l'entier, mais le lsb représente par exemple 1/32 d'unité, on choisit comme on veut). Et s'il faut faire des calculs successifs, on supprime l'accumulation des erreurs d'arrondi en sauvegardant le reste pour le calcul suivant.
Mais il y a une gymnastique à faire pour ne pas se planter.
 
Dernière édition:
S

simon74

Compagnon
Pour moi, tu t'en fait enormement trop de code pour ce que tu veut faire. Moins de code = moins de bugs surtout en embedded ou on peut compter au moins un bug pour tous les 10 lignes de C.. Utilise la fonctionnalité deja present dans la µC.

Pour moi, donc :

Tim2 en mode encoder ...
ARR = however many counts you have per rotation
IC1PS = %00 (disable prescaler)
SMS = %011 (count on each signal, hi res quoi)
CC1S = %01 (IC1 = TI1)
CC2S = %01 (IC2 = TI2)
CC1P = %0 (rising edge sur input 1)
CC2P = %0 (rising edge sur input 2)
IC1F = %011 (input filter, input doit tenir 8 clocks pour que ca soit consideré stable, tu peut jouer avec cela)
CEN = %1 (enable)

A ce moment la, CNT donne la position actuel, et CR1.DIR donne la direction.

Maintenant, tu peut utiliser DMA, encore automatiquement et sans que ton code a besoin de faire quoi que ca soit apart le configurer, pour mettre ces values la dans des variables que tu controles.

Ca ne donne toujours pas la velocité. Donc, on prends un deuxieme counter, trigger mode avec TIM2, sort les resultats par DMA, et encore, tu as les resultats sans besoin de faire quoi que ce soit.

Pas de code. Pas de bugs.
 
V

vibram

Compagnon
Merci pour vos réponses.
@simon74 malheureusement je n'ai pas tes compétences, c'est pourquoi j'utilise HAL, je debarque des tutos arduinos puis STM32 donc pour moi hors de question de manipuler les registres, c'est bien trop au dessus de mes compétences.

Je fonctionne toujours en deux étapes: d'abord je fais un code optionnel et ensuite j'essaie de l'optimiser.

Pour le moment mon niveau de code semble suffire à l'utilisation. L'utilisation des virgules flotantes etc est quelque chose que j'ai bien à l'esprit surtout pour la partie division. Ce sera une des prochaines étapes.
je ne prétends surtout pas qu'il est bon, mais c'est suffisant et comme tout le monde, je manque un peu de temps pour m'en occuper.

Donc pour le moment voila ou j'en suis:
mon STM32 gère le codeur et le driver du PAP.
Il me reste à étudier le système de variation de vitesse pour les avances auto (cf mon message en 1ere page sur la variation du timer) et la communication en serial avec un arduino + ecran 5 pouces et l'intégration de l'algo de bresenham pour le diviseur
 
S

simon74

Compagnon
c'est bien trop au dessus de mes compétences.
Franchement, c'est plus facile, meme si on a besoin de comprendre ce qui se passe, que de essayer de faire toi meme. Les competences, ca s'ameliore, mais les problemes restents les memes. Un des problemes le plus difficile et mal compris, meme par des informaticiens etoilées, c'est de gerer plusiers taches dependents au meme temps - ce que tu est en train d'essayer de faire. En plus, tu essaye de le faire avec C, et cela sans les bequilles classique comme posix threads ect, c'est presque perdu d'avance; tu tire un balle direct dans la pied.

[nota] Je ne code presque plus en C ou C++

Si t'avait un tour et un tete a aleser, tu ne fera quand meme pas tes alesages a la lime? Pourtant, la tour, c'est plus difficile a comprendre qu'une lime.

Passe moi un MP.
 
V

vibram

Compagnon
Je comprends mais lea quelques tuto que j'ai trouvé pour programmer un stm32 en touchant directement les registres, même censé être pour débutant, était déjà trop poussé pour moi.
Je pense qu'il me faudrait une vraie formation mais je n'ai pas encore trouvé cela
 
T

tronix

Compagnon
Le C est très bien pour faire de l'embarqué. Toutes mes applications tournent en C, y compris avec du traitement de signal et pilotage très contraignant de modulateur I/Q, sans problème, et plein de tâches tournant simultanément. Et sans OS. Mais en respectant quelques règles simples.
 
O

Otatiaro

Compagnon
Salut,

Le C est très bien pour faire de l'embarqué. Toutes mes applications tournent en C, y compris avec du traitement de signal et pilotage très contraignant de modulateur I/Q, sans problème, et plein de tâches tournant simultanément. Et sans OS. Mais en respectant quelques règles simples.

Le C c'est bien, le C++ c'est mieux ... avant je faisait mes projets STM32 en C et bare metal (sans OS), maintenant on fait tout en C++ et avec un OS maison:
- on code plus rapidement
- on fait du code plus propre et compréhensible
- comme il est plus facile à comprendre, il est plus facile à maintenir, et il y a moins de bugs
- le code est réutilisable à 100% d'un projet à un autre
- on maîtrise beaucoup mieux ce qui se passe dans l'ordonnancement des tâches et des IRQ (merci SystemView)
- on ne passe plus des heures et des heures à se demander quelle interruption doit préhempter laquelle, à gérer les priorités (voir les inversions de priorité), les ISR sont réduites au plus simple et le traitement se fait dans les tâches, c'est le scheduler qui s'occupe d'ordonnancer tout ça correctement
- au final le code est plus rapide qu'en C, si on ne fait pas n'importe quoi (si si, je maintiens, le C++ est PLUS RAPIDE que le C)

Après avoir donné une formation pour passer de l'arduino au STM32 à Station F cet été avec ST, on va monter une formation (toujours estampillée ST) ici sur le C++ pour l'embarqué, c'est un sujet qui me tient beaucoup à cœur, parce que j'en ai marre de m'entendre dire que les devs embarqué ne devraient faire que du C et que le C++ c'est lourd, c'est lent et ça ne sert à rien (c'est tout l'inverse ...).

Thomas.
 
O

Otatiaro

Compagnon
En complément et histoire de donner des arguments simples mais percutants, voilà un petit test que je viens de faire sur la carte sur laquelle je bosse (STM32F746VGT6) :

int testC(uint8_t value)
{
uint32_t start = DWT->CYCCNT;

uint32_t buffer[333];
uint32_t i;
for (i = 0; i < 333; i++)
buffer = value;

return DWT->CYCCNT - start;
}


int testCpp(uint8_t value)
{
auto start = DWT->CYCCNT;


std::array<uint8_t, 333> buffer;
buffer.fill(value);


return DWT->CYCCNT - start;
}


bool testCvsCpp(uint8_t value)
{
auto c = testC(value);
auto cpp = testCpp(value);
return c > cpp;
}


Il s'agit tout simplement de déclarer un tableau et de le remplir d'une valeur fixe. Je suis resté en O0, mais le résultat en O3 serait encore pire ...
La première et dernière ligne ne sont là que pour compter le nombre de cycles d'horloge passées dans la fonction, si on les enlève:
- en C on a 4 lignes dont la signification ne saute pas de suite aux yeux (avec de l'habitude on comprend vite), on a une constante répétée (la taille du tableau), et au moins une dizaine de bugs prêts à vous sauter à la gorge.
- en C++ on a 2 lignes de code, la constante n'est pas répétée, la signification est limpide (la fonction "fill" est très claire, rempli le tableau), et il est compliqué de se tromper ou de faire un dépassement (c'est le compilateur qui s'en occupe, plus le codeur)


Et maintenant la grande révélation ... le nombre de cycles d'horloge (sans trucage, si vous avez une nucleo vous pouvez refaire le test chez vous, j'ai utilisé Atollic dernière version, donc compilateur GCC assez récent).
- en C : 6421 cycles d'horloge
- en C++ : 1101 cycles d'horloge, quasiment 6x plus rapide !!!!!!!!


Alors évidemment ça ne tombe pas du ciel, pourquoi le C++ peut être aussi rapide ? Tout simplement parce qu'on laisse plus de latitude au compilateur pour optimiser en ne rajoutant pas de contrainte particulière, je m'explique:
- en C on a demandé spécifiquement au compilateur de remplir le tableau octet par octet
- en C++ on lui a simplement demandé de remplir le tableau, la différence parait infime, mais ici le compilateur a eu la liberté de copier la valeur par paquet de 4 octets (on est sur une plateforme 32 bits), et probablement d'utiliser du store/load multiple, qui est la solution la plus rapide pour copier de la mémoire avec le Cortex-M (et pourtant je n'ai pas pris un taille de tableau en multiple de 4, pour ne pas l'avantager encore plus).


Il faudrait par exemple en C utiliser "memset" qui lui peut optimiser davantage, mais il faut connaitre (en C++ il suffit de faire "buffer." et de laisser l'IDE vous proposer les méthodes accessibles), et la syntaxe (pointeur) laisse encore plus de possibilités de mettre des bugs partout.

Et pour enfoncer le clou, sur un calcul de ce type, il suffirait de mettre la fonction C++ en constexpr (si les entrées sont connues au moment de la compilation, ce qui est le cas ici si la variable "value" est une valeur fixe dans le code, et le résultat prendrait seulement quelques cycles d'horloge, puisque c'est le compilateur lui-même qui ferait le calcul à la compilation, et non plus à l'exécution !

Bref il y a beaucoup de choses à dire sur le sujet.

Thomas.

EDIT : Détail intéressant, je viens de regarder sur godbolt.org les deux version en compilation O3, et le compilateur est suffisamment intelligent pour comprendre que la version C est un remplissage de tableau, et le remplacer par un appel à memset, ce qui donne exactement le même résultat que la version C++. Mais on se base là sur une optimisation du compilateur qui n'aura pas toujours lieu (il faut vraiment que le pattern soit reconnu par le compilateur), alors que la version C++ est toujours optimizable (y compris en O0).
 
Dernière édition:
T

tronix

Compagnon
Bonjour,

ma remarque ne concernait absolument pas le C++, même si je connais des spécialistes qui n'en pensent pas beaucoup de bien, pas à cause de la vitesse. Mais c'était suite au post de Simon74 qui disait ne plus utiliser C ou C++, je n'ai pas compris en quoi il programmait. Là n'est pas la question. C'est comme la vitesse d'exécution, elle dépend surtout de la conception du programme. Et c'est là que les librairies Arduino, si elles sont simples à utiliser, elles sont souvent peu efficaces, car avec plein de fonctions bloquantes et de boucles d'attente.
Pour revenir au sujet initial, il faudrait reposer toutes les contraintes sur les signaux en entrée et de sortie, leur fréquence et le temps de cycle pour voir s'il faut faire des efforts et où. C'est comme l'isolation thermique, on commence par les plus grosses fuites. Et optimiser ou avoir du code plus rapide n'a pas forcément beaucoup d'intérêt si c'est au détriment de la rapidité d'écriture ou de la maintenabilité. Un processeur 8 bits peut être très bien. Mais si un programme ne fonctionne dessus qu'au prix de gros efforts d'optimisation, il est plus judicieux (sauf très grande série, pas le cas ici) de passer sur du 32 bits. C'était le sujet initial. Ce qui m'intéresse dans le sujet, c'est comment il faut s'y prendre pour faire fonctionner le système, pas si l'initialisation d'un tableau avec une constante va prendre 6us ou 1us en C ou en C++ (on peut aussi le faire en DMA, cela ira encore plus vite). Pour ces débats, je pense en effet qu'il y a d'autres forums.
Avec quelques méthodes simples (cela s'adresse à des amateurs, il ne faut pas l'oublier), et en utilisant mieux les périphériques disponibles (ne dépend absolument pas du langage !!!), on peut faire de très belles choses.
 
Dernière édition:
J

jms

Compagnon
Bonjour,

Merci de revenir au thème su sujet, l'aide à VIBRAM.
 
O

Otatiaro

Compagnon
Je vous avais prévenu, c'est un sujet qui me tient à cœur :wink:
Pour info on est aussi passé en MP avec VIBRAM pour avancer sur son sujet.

Thomas.
 

Sujets similaires

Père-Pendiculaire
Réponses
23
Affichages
663
Père-Pendiculaire
Père-Pendiculaire
N
Réponses
27
Affichages
838
Jean 47
J
2
Réponses
27
Affichages
1 348
jean-jacques
J
C
Réponses
0
Affichages
3 516
caramel
C
B
Réponses
19
Affichages
2 056
boumboauto
B
tournele
Réponses
106
Affichages
14 590
tournele
tournele
Haut