• L'Assemblée Générale du Prius Touring Club aura lieu le 7 décembre 2024 du côté de Rennes. Si vous êtes adhérent renseignez-vous ici.

PCM pour MBED

  • Initiateur de la discussion Initiateur de la discussion thierryb
  • Date de début Date de début
Désolé je n'ai pas le temps de me plonger dans le code, mais s'il y a concurrence en C, vous allez devoir regarder les fonctions pthread_mutex_lock et pthread_mutex_unlock afin de regrouper l'écriture d'un buffer et l'incrément du pointeur dans un seul bloc ininterruptible (de même pour la lecture et le décrément). Il faut veiller à isoler uniquement le code critique et ne pas faire d'opération lente (genre du logging) dans un tel bloc car sinon on peut perdre bcp en rapidité.
Have fun!
 
Je ne connais rien à l'env de dev sur MBED, donc j'avoue que j'ai dit ça au pif, mais s'il y a conccurence il faut forcément un système pour gérer des sections critiques (s'il n'y en a pas il faut le faire soi-même à la main et perso je trouve les mutex bcp plus simples à utiliser).

En tout cas je trouve le concept très intéressant et je regrette de ne pas avoir de temps à lui consacrer...
 
non je ne l'utilise pas. Je n'en ai pas eu besoin.
 
C'est mieux mais il y encore des problèmes.

<0300C2A61D7000400000027200083
<0B40C2A639D0000000000000000BC
<2300C2A64F30100052224000084
>0B40C2A639D0000000000000000BC
<0300C2A7BE4020400000027200083
<0300C2A93F7030400000026200082
<0B40C2A95BD0400000000000000BC
<0300C2AACA4050400000026200082
<0300C2AC4CE060400000026200082
<0B40C2AC7850700000000000000BC
<2300C2AC8DB0800052224000084
<0300C2ADD01090400000026200082
>2300C2A64F30100052224000084
>0300C2A7BE4020400000027200083

on a bien un problème de concurrence même avec l'astuce de Guinness à la lecture du Can.
les deux premières trames, la 030 et la 0B4, lues respectivement aux timestamps 0C2A61D7 et 0C2A639D ont été toutes les deux stockées à la position 00 et seule la deuxième ressort.
Mais cela un effet de bord dévastateur, le programme pense qu'il a en buffer 2 trames (ou plutôt une trame de plus). Et donc si à un moment la lecture du buffer va plus vite que les trames qui arrivent du bus Can dans le buffer, il va lire dans le buffer la trame stockée dans le cycle précédent.

Cela se produit finalement très vite (voila la suite):
>0300C2A93F7030400000026200082
>0B40C2A95BD0400000000000000BC
>0300C2AACA4050400000026200082
>0300C2AC4CE060400000026200082
<0300C2AF5260A0400000026200082
<0B40C2AF7DB0B00000000000000BC
>0B40C2AC7850700000000000000BC
>2300C2AC8DB0800052224000084
>0300C2ADD01090400000026200082
>0300C2AF5260A0400000026200082
<0300C2B0D2F0C0400000026200082
>0B40C2AF7DB0B00000000000000BC
>0300C2B0D2F0C0400000026200082
>03B0149ADD9 0D 000000D919 <=====
<0300C2B2558 0D 0400000026200082 <=====
<0B40C2B2809 0E 00000000000000BC
<2300C2B295E0F00052224000084
>0B40C2B2809 0E 00000000000000BC

Il sort du ring buffer la trame no OD alors qu'il ne va la stocker qu'après
Dans la plupart des cas, cela n'a pas d'importance.
Mais dans certains cas, malheureusement, c'est très embêtant.
Ceci explique les trames perdues, en double, ou inversées.

Mais on peut voir que comme la trame no 0E arrive très vite derrière, elle est bien empilée à temps dans le buffer pour être lue.

Je vais regarder comment résoudre le problème sans mutex, à la Guinness.
 
J'arrive pas, et j'arrive pas à importer la library qui me donnerait les mutex.
Il faut que je réfléchisse plus.
 
A ta place je chercherais à utiliser un vrai mutex car j'ai l'impression à te lire qu'il faut vraiment protéger la lecture et écriture dans le ring buffer contre les accès conccurents et en C je ne sais pas comment me mettre en attente sur un changement de valeur d'un bool sans consommer de ressources (ce que fait très bien un mutex).
Si la librairie est open-source, tu peux regarder le code de mutex_lock pour comment ils font?
 
en analysant le pb mentionné dans le msg 57, je me pose la question suivante:

le pb provient d'écrire 2 fois au même endroit, après effectivement, c'est le souk dans les pointeurs car le nb d'entrées dans le buffer est faux.

or cela se passe, dans le cas que tu montres, avec le pointeur 0.
mon petit doigt me dit qu'il y a un loupé dans l'algo lors du bouclage du ringbuffer.
typiquement le rb_write_pointer qui n'est pas incrémenté dans ce cas...

je vais essayer d'aller jusqu'au bout de cette intuition...
@suivre

en fait, peux tu communiquer ce que tu avais un peu avant, de façon à voir comment est géré le bouclage du buffer ?
 
j'ai changé le test pour ne plus le faire sur le nombre d'entrée dans le buffer, mais sur la position des pointeurs des lecteurs ou d'écritures dans le buffer. Cela risque de me faire perdre la première trame, mais ce n'est pas un problème.

Je ferai des tests aujourd'hui avec cette motif.
 
Il semble que j'ai réglé le pb.
Je perds de 0-3 trames au tout début, puis ensuite sur un enregistrement du pid 230: 3 trames pour 17000 ; bref une bagatelle, même pour d'autres pids sensibles. Et aucune inversion, doublement, ou autre joyeuseté.

A confirmer.
 
Et le pid 520, il vient bien tous les 20 tours maintenant ? Et donne-il un résultat identique à l'ODB ?
 
Sur une autre série de ce matin, 10 trames de perdues, pas d'inversion, pas de double, pour 50000 trames.
 
Et le pid 520, il vient bien tous les 20 tours maintenant ? Et donne-il un résultat identique à l'ODB ?
Il devrait venir tous les 20 tours. C'est à vérifier. Mais les vérifications que j'avais fait même avec les bugs du ring buffer allaient dans ce sens. Je m'étais remis à surveiller le pid230 car il est plus fréquent que le 3C8 et régulier. Sans compter sa capacité à détecter une inversion (en plus de mon timestamp).

Maintenant que j'ai des certitudes sur les enregistrements, je vais pouvoir revenir à l'odb et le pid 520. Mais, j'ai aussi commencé une tentative de record de conso. Donc plus possible de réinitialiser l'odb avant que je termine le plein, ou renonce. J'essaie de voir combien de km je peux tenir 3,6 (voir 3,7) à l'odb.

le mbed me calcule et m'enregistre dans un log local pour chaque trajet les volumes consommés et les distances effectuées suivant les méthodes PCM et Kinetik. J'ai encore quelques réglages à faire pour les méthodes PCM à cause des grands nombres. Mais j'ai bien progressé la semaine dernière. Et j'obtiens des chiffres cohérents avec les resultats dans PCM depuis quelques jours.
 
@Thierryb. Bonnes nouvelles. :jumproll:
As-tu moyen de connaître la puissance de calcul qu'il te reste dans le mbed ?
A par ajouter des calculs jusqu'à avoir des anomalies ?
 
@thierryb bravo pour ta persévérance...

pour ma/notre culture, où se cachait le loup ????
 
@planétaire
Je sais combien il me reste : 40% (quand je ne loggue pas à mort pour trouver les bugs, car là je suis près de 0% quand d'ailleurs je n'explose pas)
C'est ce travail que j'ai fait au début : faire que le buffer n'explose pas. Et pour cela il faut qu'il reste du temps.
Mais on peut descendre probablement à 20-30% en passant à la philosophie de priusfan : peu de données transmises peu souvent

@priusfan, Le loup se cachait (et se cache toujours, mais je lui ai mis des grillages) dans le lancement sur interruption de la lecture du can, avec une gestion des pointeurs du ring buffer qui ne prenait pas en compte ce parallélisme.
Il faudrait mettre en place un mutex ou fonctionner sans interruption, comme dans PCM.
Je te donnerai un lien vers ma "dernière" (jusqu'à la prochaine) version demain.
 
pour compléter, il est difficile avec ce parallélisme de garder cohérent le ring_buffer_size avec le read et le write pointer. Donc le plus simple a été de ne plus l'utiliser.

par ailleurs, il vaut mieux quand il y a concurrence éviter de faire des opérations qui peuvent se croiser, donc je ne fais plus que des incréments ou décréments sur les pointeurs, et plus de & ring buffer size car cela fait 2 opérations, et si elles se parallèlisent mal, le loup s'échappe.

enfin, je n'utilise pas directement la valeur du pointeur, dès que je l'ai, je la stocke, avant que un elf copain du loup vienne la changer, et c'est cette valeur temporaire mais stable que j'utilise pour empiler ou dépiler le buffer.

mais sans mutex, je perds des trames, 10 pour 50000, n'oublions pas qu'il y a 800 trames par seconde. Donc beaucoup d'occasions pour le loup de sortir. Et je trouve que je m'en sors bien et que cela doit suffire. Mais comme je renonce peu, j'irai les chercher un jour.
 
@planétaire, et priusfan, on doit aussi pouvoir gagner du temps cpu en faisant beaucoup moins de copie des données provenant du can, à la PCM : je lis, j'exploite.
 
(Juste une précision. Le Pcm dont tu parles c'est pcm_tactrix. Pour l'autre version pcm_elm_ou_canusb, il y a des interruptions. C'est ainsi qu'avait été écrite de la première version.)
Quand tu dis qu'il y a des copies, je pensais que vous aviez un buffer commun et unique pour l'écriture depuis le can et la lecture vers le bluetooth ?

Juste une question. Est-ce que les interruptions se font pour chaque bit reçu ou une par trame ? ;-)
 
Dernière édition:
Je pense que c'est par trame. Encore que avec la boucle, c'est toutes les 1 à 3 trames car parfois la boucle joue son rôle. Enfin, c'était. Il faudrait que je vérifie après cas modifs.

Concernant les copies, il y en a une de la lecture du Can vers le buffer, puis une du buffer vers un stockage préalable au traitement et l'envoi. En le faisant à la PCM Tactrix, j'économiserais 2 copies. Les seuls cas qui mériteraient un stockage temporaire seraient les multitrames.

Mais je suis déjà très content. Ça marche et c'est l'essentiel.
 
Savoir à quels moments il y a interruptions n'est pas anodin et dépend de:
-est-ce que le côté can a une uart cablée (probable) ou bien y-a-t-il gestion de chaque bit (variation de tension différentielle entre can_h et can_l)
-dépend, si présence d'une uart de la taille de son buffer de lecture, nombre d'octets.

Selon le moment où tu es interrompu fera que tu devra gérer des trames pas encore complètement formées ou pas. C'est un des problèmes que gère pcm_elm_canusb, il a en "permanence" une queue de messages, le dernier pas encore complet.
 
le CAN est en prise directe sur le processeur, il n'y a aucun élément intermédiaire; l'interruption a lieu seulement dans le cas d'une trame reçue complète et valide.
cela simplifie et fiabilise la partie programmation.
 
Effectivement, cette partie là est très fiable. Le message est complet quand on est interrompu. Aucune perte, aucune erreur. J'ai arrêté de contrôler le CRC des trames passives.

J'ai par ailleurs vérifié la transmission bluetooth. Pas non plus de problème. Tout ce qui est envoyé arrive avec zéro erreur sur 100 000 trames ce matin (pid 230 pendant 30 min). Et il me manque 15 trames sur les 100000. D'avoir arrêté les logs à outrance a réduit le % de trames perdues au moment de l'écriture dans le ring buffer à cause de la concurrence.

Je pense que le projet MBED de Priusfan est maintenant stable et robuste.

Je vais donc reprendre les études sur la conso et la distance, et le projet Tripmaster.
 
Pages vues depuis le 20 Oct 2005: 316,276,380
Retour
Haut Bas