Je suis en train de travailler sur un projet étudiant de skateboard électrique et j'ai un problème avec la mémoire RAM de mon arduino Nano. Juste avec trois bibliothèques et quelques lignes de codes, j'ai déjà un message d'alerte qui s'affiche : "Les variables globales utilisent 1628 octets (79%) de mémoire dynamique, ce qui laise 420 octets pour les variables locales... La mémoire disponibles est faible, des porblèmes de stabilité pourraient survenir."
J'ai déjà essayé d'ajuster au mieux mon code mais ce n'est toujours pas suffisant, il en résulte un comportement du code assez aléatoire.
Le but est de piloter un ESC de moteur brushless à travers un bus UART et d'écrire les informations concernant le trajet sur une carte SD.
#include <VescUart.h>
#include <SPI.h>
#include <SD.h>
VescUart UART;
File myFile;
const byte SD_SC_pin = 10;
const byte interruptPin = 2; // pins 2 and 3 are usable for interrupt
void setup() {
Serial.begin(9600);
pinMode(SD_SC_pin, OUTPUT);
SD.begin(SD_SC_pin);
myFile = SD.open("tst.txt", FILE_WRITE);
myFile.print(F("'RPM' "));
myFile.print(F("'Voltage' "));
myFile.print(F("'Batterie' "));
myFile.println(F("'tachometerAbs'"));
UART.setSerialPort(&Serial); // Define which ports to use as UART
myFile.close();
}
void loop() {
myFile = SD.open("test.txt", FILE_WRITE);
if ( UART.getVescValues() ) {
myFile.print(UART.data.rpm);
myFile.print(F(" "));
myFile.print(UART.data.inpVoltage);
}
else
{
myFile.println(F("Failed to get data!"));
}
UART.setRPM(200);
myFile.close();
delay(50);
}
Si vous avez idées pour améliorer la gestion de la mémoire je suis preneur
J'ai déjà essayé d'ajuster au mieux mon code mais ce n'est toujours pas suffisant, il en résulte un comportement du code assez aléatoire.
Je ne vois pas trop ce que tu pourrais ajuster dans ce code pour diminuer l'espace occupé en RAM.
L'espace en RAM est probablement occupé en grande partie par les variables de la librairie SD.
420 octets pour les variables locales cela reste confortable, mais tout dépend du contexte.
Comportement du code assez aléatoire : c'est à dire ?
le titre du message n'est pas cohérent avec son contenu (Flash ou RAM)
la librairie VescUart n'est pas en reste pour l'occupation de la RAM
Il faut envisager d'abandonner la carte Nano si le côté aléatoire de l'exécution apparaît
le titre du message n'est pas cohérent avec son contenu (Flash ou RAM)
Oui désolé je me suis trompé dans le titre !
Comportement du code assez aléatoire : c'est à dire ?
Eh bien des fois un fichier texte est créé et des fois non… Et il n'y a jamais rien d'écrit dedans alors que lorsque je le teste tout seul de son côté, l'écriture dans la carte marche très bien.
Sinon n'est-il pas possible d'enlever ce dont je ne me sert pas dans les bibliothèques ?
Je changerai de carte s'il ny a pas d'autres solutions
Sinon n'est-il pas possible d'enlever ce dont je ne me sert pas dans les bibliothèques ?
Le linker ne prend que ce qui sert effectivement.
Eh bien des fois un fichier texte est créé et des fois non
Ne pas tester les valeurs retournées de SD.open(), SD.print() n'est pas très optimal.
Tu pourrais au moins afficher les erreurs sur la console.
myFile = SD.open("test.txt", FILE_WRITE);
if (myFile) {
if (myFile.print(UART.data.rpm) != sizeof(UART.data.rpm)) {
Serial.println("error writing test.txt");
// etc.
}
} else {
Serial.println("error opening test.txt");
}
Tu t'attends à voir quoi dans ton fichier en écrivant : open(), print(), close() toutes les 50ms ?
A quoi cela sert-il d'écrire X fois le même fichier aussi vite en l'écrasant à chaque fois ?
Récemment j'ai laissé tomber une Kingston 4Gb pour cause de non fiabilité, fichier non trouvé, etc.
J'ai remplacé par une Sandisk et depuis c'est tout bon.
Tu pourrais au moins afficher les erreurs sur la console
Eh bien non Parce que le port Serie est utilisé pour la communication avec l'ESC. J'ai bien essayé de faire passer l'ESC sur un port créé avec SoftwareSerial mais ca ne marche pas
Tu t'attends à voir quoi dans ton fichier en écrivant : open(), print(), close() toutes les 50ms ?
A quoi cela sert-il d'écrire X fois le même fichier aussi vite en l'écrasant à chaque fois ?
Je voudrais écrire mes mesures les unes après les autres dans même fichier. Oui c'est vrai que c'est mal codé mais je ne vois pas comment fermer le fichier juste au moment ou je décide d'éteindre le skate... Je fais une interruption logicielle avec un bouton ?
Récemment j'ai laissé tomber une Kingston 4Gb pour cause de non fiabilité, fichier non trouvé, etc.
J'ai remplacé par une Sandisk et depuis c'est tout bon.
En effet je pourrais essayer de voir si une autre carte fonctionne mieux. J'ai aussi cru comprendre qu'Arduino préfère les petites cartes.
Eh bien non Parce que le port Serie est utilisé pour la communication avec l'ESC. J'ai bien essayé de faire passer l'ESC sur un port créé avec SoftwareSerial mais ca ne marche pas
à 9600 baud ? très étonnant.
Et puis débrancher l'ESC pour chaque chargement logiciel doit être pénible.
Je voudrais écrire mes mesures les unes après les autres dans même fichier.
Alors il faut ouvrir le fichier dans la fonction setup(), en ayant l'objet myFile en variable globale, et fermer le fichier sur détection d'un appui sur un bouton poussoir.
leonardo (l'éternel oublié des softwareserialisateurs !)
il a même un peu + de ram (en espérant qu'elle ne soit pas mangée par la gestion de l'usb ... )
Je reviens vers vous avec de nouveaux problèmes
J'ai effectivement fait le changement vers une Arduino Leonardo car elle a un peu plus de mémoire (il me reste 760 octets de RAM). Et en plus elle a le port Serie Serial1 détaché du port Serial, ce qui me permet de débuguer facilement sur le moniteur série.
J'ai donc amélioré mon code mais je n'arrive pas à fermer le fichier comme l'avait proposé hbachetti... Je met mon code juste en dessous...
A noter aussi que le programme marche bien jusqu'à qu'il s'arrête après un certain nombre de boucles. Mon hypothèse est que le buffer de la bibliothèque SD à mangé toute la RAM... Mais myFile.flush() fait planter aussi le code.
Excusez moi, mais je vois mal une fuite mémoire générée par une librairie de grande diffusion telle que SD.
Toujours pour rester conformiste, je tique un peu en voyant que la fonction de fermeture (qui peut impliquer des opérations complexes) est appelée par une interruption -ce qui interrompt pour le moins les écritures en cours-.
Je verrais plutôt une fonction d'interruption ultra simple, qui mettrait une variable globale volatile à 1 (un uint8_t ne va pas vous manger tant de mémoire que ça)
la boucle de scrutation loop commencerait par tester si cette variable est à 1, et alors, fermerait les fichiers (et ne ferait que ça), puis remettrait cette variable à zero... (valeurs indicatives).
Nota: j'ai mis cette variable globale volatile, pour éviter que l'optimiseur associé à l'arduino ne la ... retire (ça lui fait gagner deux instructions et une place mémoire: le compilateur ne peut trouver de lien entre la routine d'interruption et loop, donc, s'il fait son travail, il la gomme, la pulvérise, la volatilise ... sauf si elle est déclarée "volatile" volatile (computer programming) - Wikipedia -rien à voir avec le Canard Enchaîné-
e verrais plutôt une fonction d'interruption ultra simple, qui mettrait une variable globale volatile à 1
J'ai fait ce que vous m'avez dit et c'est vrai que ca parait mieux codé de cette façon.. Cependant toujours le même genre de bugs : le programme fait quelques tours de boucles avant de s'arrêter. Et si je j'appuie sur le boutton pour éjecter la carte le programme s'arrête.A noter aussi que les informations ne sont jamais écrites dans la carte...
Désolé mais je ne pense vraiment pas que le problème vienne de là. Sachant aussi que mon code marche plus ou moins bien en fonction de si je met des (F("...")) autour de mes Serial.print ou myFile.print .
vous avez pris quelle librairie VescUart ? celle de SolidGeek/VescUart est une version plus récente de celle de RollingGecko et donc plus appropriée sans doute
virez le UART.setRPM( 2500 );de la loop pour le mettre dans le setup(). si ça ne change pas aucune raison de le répéter
déclarez interruptPinSD en mode INPUT_PULLUP dans le setup pinMode(interruptPinSD, INPUT_PULLUP);et câblez pin --- bouton -- GND et changez RISING en FALLING attachInterrupt(digitalPinToInterrupt(interruptPinSD), closeFile, FALLING);(à moins que vous n'ayez déjà mis ce qu'il fallait en pulldown sur le bouton) et mettez bien sûr comme dit au dessus myFile à NULL si vous fermez le fichier
virez le "UART.setRPM( 2500 );" de la loop pour le mettre dans le setup(). si ça ne change pas aucune raison de le répéter
Eh bien non ! Si jamais on ne redonne pas l'instruction toutes les secondes environ, le moteur s'arrête. J'ai vérifié en le mettant dans le setup et avec plusieurs cartes (Nano et Leonardo) et à chaque fois le moteur s'éteint au bout d'une seconde.
Du côté du bouton, j'ai effectivement mis une résistance de pull-down et cela marche correctement.
Enfin, l'instruction "myFile = NULL;" fait planter la compilation.