Go Down

Topic: Reduire taille core libs (Read 262 times) previous topic - next topic

captainmac40

Bonjour, je suis à la recherche d'un moyen de réduire la taille des libs intégrés par défaut dans un sketch.

Je dois écrire un prog pour un Attiny10 et vu le peu de place dispo je cherche un moyen simple pour réduire la taille du sketch.

Basiquement j'ai besoin juste de ces fonctions:
- AnalogRead
- DigitalWrite
- Millis
- PinMode


Je sais qu'on peut le faire en C pur mais j'ai un peu de mal encore avec les registres et leur utilisations et pas trop le temps de m'y pencher dessus.

Donc l'idée serai d'avoir un "core" arduino réduit avec juste les fonctions dont j'ai besoin

Si quelqu'un à une idée...

Merci !!

hbachetti

Quote
Donc l'idée serai d'avoir un "core" arduino réduit avec juste les fonctions dont j'ai besoin
Lorsque l'on utilise une librairie seules les fonctions réellement utilisées sont liées à l'exécutable en plus de ton propre code.

Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

68tjs

L'optimisation sans utiliser les registres va être difficile.
L'optimisation sans lire la datasheet d'un atmega 10 pour en connaitre ses possibilités exactes va être difficile.

Les fonctions arduino sont destinées aux non professionnel de la programation et comportent de nombreuses lignes de code destinées à détecter et à corriger des "conneries". Elles ne sont absolument pas optimisée.
Une grosse source de "pertes", au moins en temps d'exécution, est la corespondance entre les dénominations des sorties "Atmel", qui est la seule que le micro comprend, et la dénomination introduite par Wiring/arduino.

Registres.
Les fonction digitalWrite et pinMode sont triviales à remplacer.
Registre DDRx pour sens entrée ou sortie
Registre PORTx pour écrire dans une sortie

analogRead() est un peu moins simple mais cela reste relativement facile.
Quand je dis "moins simple" c'est parce que les possibilités pour la lecture analogique sont limitées volontairement par Arduino et que de nombreux réglages sont ignorés alors qu'ils peuvent être intéressants.

millis()
As tu des besoins précis en terme de pas de mesure et de valeurs maximale ?
Parce que le coeur de millis c'est de lire un registre d'un timer. Tout le reste du code ne sert qu'à obtenir une valeur de débordement (passage à 0) de 49 jours.

La lecture directe d'un timer dont le diviseur d'horloge aura été adapté à tes besoins peut largement suffire à condition de connaitre ses besoins.

trimarco232

tu peux aussi supprimer les libs : tu y pompes les fonctions qu'il te faut et tu les intègres à ton .ino
(c'est ce que je fais quand je veux réécrire une fonction pour + d'efficacité)

toutefois, là, tu rames à contre courant : les efforts principaux sont faits pour développer et généraliser les bibliothèques afin de faciliter l'accès des choses au + grand nombre
ce n'est pas en enlevant quelques lignes ça et là dans des fichiers que tu feras un progrès quelconque pour toi ou pour la planète

68tjs

Quote
ce n'est pas en enlevant quelques lignes ça et là dans des fichiers que tu feras un progrès quelconque pour toi ou pour la planète
Oh là , il a un problème particulier avec un atmega10 , il n'est pas interdit de le traiter sur le forum.
L'universalité est une gageure, tout le monde un jour ou l'autre aura un problème spécifique qui ne pourra pas être réglé avec les méthodes classiques, il est préférable de s'y préparer.
Le truc qui fait tout est obèse et on va droit sur les méthodes du couple infernal Microsoft/Intel. Bientôt il faudra 1 Mega octets de mémoire pour faire clignoter une Del. Je suis sérieux sur ce coup il suffit de voir la taille minimale du programme Blink sur ESP8266 ou ESP32.

Et je suis certain que quelques esprits curieux seront intéressés

Quote
tu peux aussi supprimer les libs : tu y pompes les fonctions qu'il te faut et tu les intègres à ton .ino
Le gain ne sera pas énorme, voir ce qu'à dit hbachetti et que Skywood m'avait expliqué il y a quelques temps : dans bibliothèque statique ( crée par l'IDE dans le répertoire provisoire  : core.a ) seul ce qui est utilisé est conservé.

La question que je me pose : est-ce que les interminables #define truc qui ne servent jamais (voir PI; PI/2; la litanie de B0000000x alors que la notation 0b0000000x existe, etc....) occupent de la place en mémoire ? Il semblerait que non mais  une confirmation serait la bienvenue.
 

supercc

#define truc est traité par le préprocesseur, avant la phase de compilation. Ils ne prennent donc pas de place spécifique en soit dans un exécutable.

captainmac40

Merci pour les précisions.

Voilà le montage prévu pour aider à comprendre ce que je cherche :
- 1 bouton poussoir
- 1 mosfet N-Channel qui coupe un circuit de puissance
- 2 led

Ce que je veux faire :
- 3 clics sur le bouton = blocage / déblocage de la commande du mosfet et blink de la led (millis)
- ensuite en fonction de la tension batterie 1 appui sur le bouton ferme le mosfet si la batterie est suffisante et si c'est pas désactiver par les 3 clics (analogread et digital write) + allumage des leds
- si la batterie est trop faible pas de fermeture du mosfet et blink rapide des LEDs.

Je cherche pas le code pour faire tout ça juste les fonctions pour les entrées/sorties. Pour la précision de millis c'est pas une grosse précision vu qu'il va servir juste pour le blink des LEDs et le debounce du bouton.

Voilà ! Merci !

68tjs

#7
Aug 19, 2019, 04:56 pm Last Edit: Aug 19, 2019, 04:58 pm by 68tjs
Tu as maintenant un aperçu de ce qu'il est possible de faire :
  • rester avec les fonctions arduino
  • simplifier les fonctions arduino
  • utiliser les registres.


Première question : est-ce que cela passe avec la solution 1 ?
Si oui ce n'est pas la peine de se prendre la tête avec les solutions 2 et 3.

Si cela ne passe pas de peu voir si avec la solution 2 cela ne suffirait pas.
Par exemple il existe une fonction (chercher sur internet) digitalFastRead ou Write. Ces fonctions simplifiées suppriment des contrôles anti conneries et s'exécutent deux fois plus vite et donc "pourraient" prendre deux fois moins de place.

Sinon c'est clair que la solution 3 va demander un investissement faisable mais non négligeable.


Remarque préalable :
Pour le debouncing l'anti rebonds il n'est pas utile de le faire de façon logicielle. Cela fonctionne très bien avec un condensateur de 100 nF soudé en parallèle sur le contact et cela prend 0 lignes de code
L'électronique c'est génial ! :smiley-mr-green: .


Il reste le cas des leds dels :
Je découvre la datasheet de l'attyny 10.
J'y vois que la fréquence horloge est 12 MHz, le préscaler max est 1024 et le timer est sur 16 bits.
Ce qui donne un temps max avant débordement de 5,6 secondes.
Fréquence du timer 12MHz/1024 soit 11,7 kHz
Temps max = (216) / (11,7 103) = 5,59
S'il est possible de baisser la fréquence horloge le temps max de 5,6 secondes augmentera dans les mêmes proportions.

Pour gérer  dans une fonction une Entrée/Sortie par les registres voir ce lien  :
https://www.microchip.com/webdoc/AVRLibcReferenceManual/FAQ_1faq_port_pass.html

al1fch

#8
Aug 19, 2019, 05:01 pm Last Edit: Aug 19, 2019, 05:45 pm by al1fch
AT Tiny10  sans le core Arduino ?


Avec sa mémoire Flash de 1ko et ses 32 octets de RAM la question se pose, naturellement !
Le recours à l'assembleur vient à l'esprit.

Et sous IDE Aduino en C/C++ ?
Voir içi l'utilisation  d'un "At Tiny Core' et des exemples d'accès aux registres pour pallier l'absence de PinMode, DIgitalWrite/Read, AnalogRead......
Ce core particulier est une coquille presque vide, il faut écrire ses fonctions en fonction des besoins en vue d'avoir l'occupement mémoire minimal.
http://www.technoblogy.com/show?1YQY

içi un thermometre avec un DS18B20 et une fonction DelayMicros()
http://www.technoblogy.com/show?2G8A


Içi un pendentif avec une led RGB (interruptions par Timer 16 bits)
http://www.technoblogy.com/show?201J


Avec la page de présentation + les deux exempelles on déjà quelques fonctions permettant de  gérer un BP, le temps, des leds et un DS12B20.. les autres il faut les écrire avec la Data Sheet di Tiny10
On est la dans l'esprit des réponses #2 et #3

68tjs

Quote
Le recours à l'assembleur vient à l'esprit.
J'osais par le dire vu que je ne connais rien à l'assembleur si ce n'est que c'est le plus efficace.

dbrion06

" ses 32 octets de RAM "
Est ce qu'il a assez de RAM pour pouvoir invoquer une fonction (je ne parle même pas de variables internes)?

supercc

Il suffit normalement de 2 octets sur la pile (adresse de retour) pour faire un appel de fonction.

al1fch

#12
Aug 19, 2019, 06:23 pm Last Edit: Aug 19, 2019, 06:24 pm by al1fch
je pense que les 32 octets de RAM sont la contrainte la plus forte
ça impose sans doute un soin extrème au niveau du codage (appels de fonctions imbriqués ? pile pendant les interruptions? ) , ca me fait penser à un travail  d'équilibriste...

(pas facile avec un IDE qui ne donne pas accès à une simulation ou une exécution pas à pas avec  suivi de la RAM et la pile en particulier)

dbrion06

"Il suffit normalement de 2 octets sur la pile (adresse de retour) pour faire un appel de fonction."
IIRC, il s'agit alors d'un appel de fonction
sans arguments
sans variables internes
....
Bonne nouvelle: il faut effectivement 2 octets pour l'adresse de retour (s'il n'avait que 256 octets de flash, un octet suffirait)....

trimarco232

au temps pour moi, j'avais zappé l'extrême tinysité de la chose :smiley-red:

en effet, programmer en assembleur permet de garder la main sur l'utilisation de la ram + les 16 registres -> ~ 50% de la ram ...

mais rien n'empêche de tenter le coup en arduino
et de jeter un œil sur ce qui a été compilé


Go Up