Pages: [1] 2   Go Down
Author Topic: [Tests] Temps pour faire changer d'état une pin (niveau Haut/Bas)  (Read 2939 times)
0 Members and 1 Guest are viewing this topic.
France S-O
Offline Offline
Edison Member
*
Karma: 41
Posts: 2182
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

En continuant à chercher à approfondir mes connaissances sur le fonctionnement d'un microcontroleur et de l'IDE Arduino j'ai obtenu des résultats très surprenants.
Principe : on fait un grand nombre de fois un cycle constitué d'une écriture "état haut" suivie d'une écriture "état bas", le tout sans délai intermédiaire.
Ce cycle est répété 100 000 fois et les mesures sont en ms.
Points remarquables :
1) Avec l'IDE Arduino l'écriture est 10 fois plus lente qu'avec l'utilisation directe des registres.
2) Avec l'IDE Arduino TOUTES les sorties PWM présentent des résultats "perturbés" alors qu'on ne constate aucune perturbation avec l'écriture directe dans les registres.

Je m'attendais à un temps légèrement plus long avec l'IDE arduino mais quand même pas 10 fois. Par contre je ne m'attendais absolument pas à la "perturbation" sur les sorties PWM.

Ci dessous le tableau de résultats et le code utilisé.
Rappel les résultats sont en ms pour un total de 100 000 cycles de double écriture.
 
  Numéro de pin                     Mesures                  Type de pin
Arduino   Atmega             Arduino        AtMega         
    0           PD0                  ND               ND               RX
    1           PD1                  ND               ND               RX
    2           PD2                1025             107               Digitale
    3           PD3                1314             107               PWM
    4           PD4                1025             107               Digitale
    5           PD5                1290             107               PWM
    6           PD6                1277             107               PWM
    7           PD7                1025             107               Digitale   

    8           PB0                1025             107               Digitale
    9           PB1                1251             107               PWM
   10          PB2                1352             107               PWM
   11          PB3                1290             107               PWM

   12          PB4                1025             107               Digitale
   13          PB5                1025             107               Digitale
   
   A0          PC0                1025             107               Et analogique
   A1          PC1                1025             107               Et analogique
   A2          PC2                1025             107               Et analogique
   A3          PC3                1025             107               Et analogique
   A4          PC4                1025             107               Et analogique
   A5          PC5                1025             107               Et analogique

Le code :
(Pour l'utilisation des registres -> origine : Open Silicium n:2 page 69)
Code:
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <util/delay.h>
#include <avr/io.h>

#define Pin_DDR DDRD
#define Pin_PORT PORTD
// affectation de la pin en mesure avec les registres
#define Pin_reg PD7
// affectation de la pin en mesure avec la bibliothèque de l'IDE arduino
const int Pin_ardui = 7 ;

void setup()
{
  Serial.begin(9600); 
  Serial.println("Temps d'écriture sur pin");
 
  //Bibli arduino
  pinMode(Pin_ardui, OUTPUT);
}

void loop()
{
  unsigned long i;
  unsigned long imax;
  unsigned long temps ;
  unsigned long t1;
  unsigned long t2;
 
  imax=100000;

// Utilisation Bibliothèque arduino---------------------------------------------------
  t1=millis();
  for(i=0; i<imax; i++)
  {
    digitalWrite(Pin_ardui, HIGH);
    digitalWrite(Pin_ardui, LOW);
  }
  t2=millis();
  temps= t2-t1;
  Serial.print("Delta T bibli ardiuno = ");
  Serial.print(temps); 
  Serial.print("\n");

// Utilisation des Registres------------------
  t1=millis();
  for(i=0; i<imax; i++)
  {
    Pin_PORT |= _BV(Pin_reg);
    Pin_PORT &= ~_BV(Pin_reg);
  }
  t2=millis();
  temps= t2-t1;
  Serial.print("Delta T Registres= ");
  Serial.print(temps);
  Serial.print("\n");
}
Logged

Offline Offline
Sr. Member
****
Karma: 2
Posts: 259
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Très intéressant comme test, merci bien!

Il fallait s'en douter qu'avec le langage Arduino, ces écritures prennent plus de temps.
Je pense que c'est en grande partie parce que le code n'est pas optimisé à fond pour raccourcir ce temps (que ce soit mal fait, ou dans l'impossibilité de faire mieux).

Alors que dans l'utilisation des registres, le langage se rapproche un peu plus de l'Assembleur.

Il faudrait approfondir ce test en testant avec le langage Assembleur pur, je suis sûr que l'on pourrait encore un peu réduire ce temps.

Motivé? smiley-wink
Logged

France S-O
Offline Offline
Edison Member
*
Karma: 41
Posts: 2182
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Assembleur ->> Jocker

Je débute dans les microcontroleurs à 65 ans et je n'ai pas l'intention de m'emouscailler.
Je n'ai plus de patron sur le dos (1) tout doit rester un plaisir.

(1) A part (comme beaucoup, je pense) à la maison une chef de projet jamais à court d'idées, mais c'est un autre problème.
Logged

Offline Offline
Sr. Member
****
Karma: 2
Posts: 259
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Je te comprends, l'Assembleur est plus que... rébarbatif à la longue! Surtout quand on commence avec smiley

Pour info: on doit tourner à quelques microsecondes pour un changement d'état sur une broche en Assembleur.
Logged

France S-O
Offline Offline
Edison Member
*
Karma: 41
Posts: 2182
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Je ne suis pas sur que l'on gagne beaucoup avec l'assembleur.
Si on regarde les chiffres 107 ms pour 10^5 cycles cela fait 1,07 µs par cycle soit 0,535 µs pour une écriture en faisant l'hypothèse que les temps pour passer d'un niveau à bas et bas vers haut sont égaux.
Le µcontroleur fonctionne à 16MHz d'horloge soit une période de 62.5 ns.
Avec les registres le temps d'écriture correspondrait à 8 cycles d'horloge (le calcul d'après les résultats de mesure donne 8,56 cycles d'horloge).

Il faudrait entrer dans le détail du fonctionnement du µcontroleur pour déterminer le nombre exact de cycles nécessaires pour faire changer d'état une sortie mais à mon avis le jeu n'en vaux pas la chandelle.
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 84
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Bonsoir,

Je vous recommande la librairie digitalWriteFast.
C'est un fait une série de grosses macros qui permettent de réduire fortement le temps de commutation et/ou de lecture des pins lorsque le numéro des pins est connu à la compilation.

Il suffit d'ajouter un #include "digitalWriteFast.h" dans les fichiers où vous souhaitez l'utiliser. Ensuite, il faut utiliser les fonctions digitalWriteFast, digitalReadFast, pinModeFast à la place de digitalWrite, digitalRead, pinMode.

Ci-dessous, ma version :


Code:
#ifndef DIGITAL_WRITE_FAST_H
#define DIGITAL_WRITE_FAST_H
 /**
 * \file
 * \brief Macros to use digitalWrite style syntax with most of the speed of PORT
 *
 * This library consists of a complex header file that translates
 * digitalWriteFast, pinModeFast, digitalReadFast into the corresponding PORT
 * commands.
 *
 * It provides syntax that is as novice-friendly as the arduino's pin
 * manipulation commands but an order of magnitude faster.
 *
 * It can speed things up when the pin number is known at compile time, so that
 * digitalWrite(9,HIGH); is speeded up. On the other hand a loop with
 * digitalWrite(i,HIGH); or a called function with the pin number as a passed
 * argument will not be faster.
 *
 * For more information visit <http://code.google.com/p/digitalwritefast/>.
 */
#include <WProgram.h>
#include <wiring.h>
//------------------------------------------------------------------------------
// bit operations
#define BIT_READ(value, bit) (((value) >> (bit)) & 0x01)
#define BIT_SET(value, bit) ((value) |= (1UL << (bit)))
#define BIT_CLEAR(value, bit) ((value) &= ~(1UL << (bit)))
#define BIT_WRITE(value, bit, bitvalue) \
(bitvalue ? BIT_SET(value, bit) : \BIT_CLEAR(value, bit))
//------------------------------------------------------------------------------
#if !defined(digitalPinToPortReg)
//------------------------------------------------------------------------------
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// ATmega1280, ATmega2560
#define digitalPinToPortReg(P) \
(((P) >= 22 && (P) <= 29) ? &PORTA : \
((((P) >= 10 && (P) <= 13) || ((P) >= 50 && (P) <= 53)) ? &PORTB : \
(((P) >= 30 && (P) <= 37) ? &PORTC : \
((((P) >= 18 && (P) <= 21) || (P) == 38) ? &PORTD : \
((((P) >= 0 && (P) <= 3) || (P) == 5) ? &PORTE : \
(((P) >= 54 && (P) <= 61) ? &PORTF : \
((((P) >= 39 && (P) <= 41) || (P) == 4) ? &PORTG : \
((((P) >= 6 && (P) <= 9) || (P) == 16 || (P) == 17) ? &PORTH : \
(((P) == 14 || (P) == 15) ? &PORTJ : \
(((P) >= 62 && (P) <= 69) ? &PORTK : &PORTL))))))))))
#define digitalPinToDDRReg(P) \
(((P) >= 22 && (P) <= 29) ? &DDRA : \
((((P) >= 10 && (P) <= 13) || ((P) >= 50 && (P) <= 53)) ? &DDRB : \
(((P) >= 30 && (P) <= 37) ? &DDRC : \
((((P) >= 18 && (P) <= 21) || (P) == 38) ? &DDRD : \
((((P) >= 0 && (P) <= 3) || (P) == 5) ? &DDRE : \
(((P) >= 54 && (P) <= 61) ? &DDRF : \
((((P) >= 39 && (P) <= 41) || (P) == 4) ? &DDRG : \
((((P) >= 6 && (P) <= 9) || (P) == 16 || (P) == 17) ? &DDRH : \
(((P) == 14 || (P) == 15) ? &DDRJ : \
(((P) >= 62 && (P) <= 69) ? &DDRK : &DDRL))))))))))
#define digitalPinToPINReg(P) \
(((P) >= 22 && (P) <= 29) ? &PINA : \
((((P) >= 10 && (P) <= 13) || ((P) >= 50 && (P) <= 53)) ? &PINB : \
(((P) >= 30 && (P) <= 37) ? &PINC : \
((((P) >= 18 && (P) <= 21) || (P) == 38) ? &PIND : \
((((P) >= 0 && (P) <= 3) || (P) == 5) ? &PINE : \
(((P) >= 54 && (P) <= 61) ? &PINF : \
((((P) >= 39 && (P) <= 41) || (P) == 4) ? &PING : \
((((P) >= 6 && (P) <= 9) || (P) == 16 || (P) == 17) ? &PINH : \
(((P) == 14 || (P) == 15) ? &PINJ : \
(((P) >= 62 && (P) <= 69) ? &PINK : &PINL))))))))))
#define __digitalPinToBit(P) \
(((P) >=  7 && (P) <=  9) ? (P) - 3 : \
(((P) >= 10 && (P) <= 13) ? (P) - 6 : \
(((P) >= 22 && (P) <= 29) ? (P) - 22 : \
(((P) >= 30 && (P) <= 37) ? 37 - (P) : \
(((P) >= 39 && (P) <= 41) ? 41 - (P) : \
(((P) >= 42 && (P) <= 49) ? 49 - (P) : \
(((P) >= 50 && (P) <= 53) ? 53 - (P) : \
(((P) >= 54 && (P) <= 61) ? (P) - 54 : \
(((P) >= 62 && (P) <= 69) ? (P) - 62 : \
(((P) == 0 || (P) == 15 || (P) == 17 || (P) == 21) ? 0 : \
(((P) == 1 || (P) == 14 || (P) == 16 || (P) == 20) ? 1 : \
(((P) == 19) ? 2 : \
(((P) == 5 || (P) == 6 || (P) == 18) ? 3 : \
(((P) == 2) ? 4 : \
(((P) == 3 || (P) == 4) ? 5 : 7)))))))))))))))
#define __digitalPinToTimer(P) \
(((P) == 13 || (P) ==  4) ? &TCCR0A : \
(((P) == 11 || (P) == 12) ? &TCCR1A : \
(((P) == 10 || (P) ==  9) ? &TCCR2A : \
(((P) ==  5 || (P) ==  2 || (P) ==  3) ? &TCCR3A : \
(((P) ==  6 || (P) ==  7 || (P) ==  8) ? &TCCR4A : \
(((P) == 46 || (P) == 45 || (P) == 44) ? &TCCR5A : 0))))))
#define __digitalPinToTimerBit(P) \
(((P) == 13) ? COM0A1 : (((P) ==  4) ? COM0B1 : \
(((P) == 11) ? COM1A1 : (((P) == 12) ? COM1B1 : \
(((P) == 10) ? COM2A1 : (((P) ==  9) ? COM2B1 : \
(((P) ==  5) ? COM3A1 : (((P) ==  2) ? COM3B1 : (((P) ==  3) ? COM3C1 : \
(((P) ==  6) ? COM4A1 : (((P) ==  7) ? COM4B1 : (((P) ==  8) ? COM4C1 : \
(((P) == 46) ? COM5A1 : (((P) == 45) ? COM5B1 : COM5C1))))))))))))))
//------------------------------------------------------------------------------
#else // ATmega8, ATmega168, ATmega328
#define digitalPinToPortReg(P) \
(((P) >= 0 && (P) <= 7) ? &PORTD : (((P) >= 8 && (P) <= 13) ? &PORTB : &PORTC))
#define digitalPinToDDRReg(P) \
(((P) >= 0 && (P) <= 7) ? &DDRD : (((P) >= 8 && (P) <= 13) ? &DDRB : &DDRC))
#define digitalPinToPINReg(P) \
(((P) >= 0 && (P) <= 7) ? &PIND : (((P) >= 8 && (P) <= 13) ? &PINB : &PINC))
#define __digitalPinToBit(P) \
(((P) >= 0 && (P) <= 7) ? (P) : (((P) >= 8 && (P) <= 13) ? (P) - 8 : (P) - 14))
//------------------------------------------------------------------------------
#if defined(__AVR_ATmega8__) // ATmega8
#define __digitalPinToTimer(P) \
(((P) ==  9 || (P) == 10) ? &TCCR1A : (((P) == 11) ? &TCCR2 : 0))
#define __digitalPinToTimerBit(P) \
(((P) ==  9) ? COM1A1 : (((P) == 10) ? COM1B1 : COM21))
//------------------------------------------------------------------------------
#else // ATmega168, ATmega328
#define __digitalPinToTimer(P) \
(((P) ==  6 || (P) ==  5) ? &TCCR0A : \
(((P) ==  9 || (P) == 10) ? &TCCR1A : \
(((P) == 11 || (P) ==  3) ? &TCCR2A : 0)))
#define __digitalPinToTimerBit(P) \
(((P) ==  6) ? COM0A1 : (((P) ==  5) ? COM0B1 : \
(((P) ==  9) ? COM1A1 : (((P) == 10) ? COM1B1 : \
(((P) == 11) ? COM2A1 : COM2B1)))))
#endif  // ATmega8
#endif  // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#endif  // !defined(digitalPinToPortReg)
//------------------------------------------------------------------------------
#define __atomicWrite__(A,P,V) \
if ( (int)(A) < 0x40) { \
bitWrite(*((volatile uint8_t*) A), __digitalPinToBit(P), (V) );} \
else { \
uint8_t register saveSreg = SREG; \
cli(); \
bitWrite(*((volatile uint8_t*)A), __digitalPinToBit(P), (V) ); \
SREG=saveSreg; \
}
//------------------------------------------------------------------------------
#ifndef digitalWriteFast
#define digitalWriteFast(P, V) \
do { \
if (__builtin_constant_p(P) && __builtin_constant_p(V)) \
__atomicWrite__(digitalPinToPortReg(P),P,V) \
else  digitalWrite((P), (V)); \
} while (0)
#endif
//------------------------------------------------------------------------------
#if !defined(pinModeFast)
#define pinModeFast(P, V) \
do { \
if (__builtin_constant_p(P) && __builtin_constant_p(V)) \
__atomicWrite__(digitalPinToDDRReg(P),P,V) \
else pinMode((P), (V)); \
} while (0)
#endif
//------------------------------------------------------------------------------
#ifndef noAnalogWrite
#define noAnalogWrite(P) \
do {if (__builtin_constant_p(P) )  __atomicWrite(__digitalPinToTimer(P),P,0) \
else turnOffPWM((P)); \
} while (0)
#endif
//------------------------------------------------------------------------------
#ifndef digitalReadFast
#define digitalReadFast(P) ( (int) _digitalReadFast_((P)) )
#define _digitalReadFast_(P ) \
(__builtin_constant_p(P) ) ? ( \
( BIT_READ(*digitalPinToPINReg(P), __digitalPinToBit(P))) ) : \
digitalRead((P))
#endif
//------------------------------------------------------------------------------
#endif // DIGITAL_WRITE_FAST
« Last Edit: October 28, 2011, 01:11:52 pm by Benvenuto » Logged

Bretagne
Offline Offline
Edison Member
*
Karma: 16
Posts: 1392
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

j'ai (comme 68tjs) fait cette remarque. pour ma part, je remplace souvent un digitalwrite() par un PORTB |=..., un pinmode par un DDRD &=...

De plus, il serait intéressant de voir ce que donne la compilation d'un petit programme en arduino et du même en registres, niveau taille flash. je crois qu'on y gagnerait énormément! (je pense à JF qui n'arrive pas à faire tourner une SD sur un 168... smiley-grin)

Le moindre appel d'une fonction inclut la pile, le jump, les tests dans la fonction qui la rendent universelle, re la pile et le rtn. tout ça, on le gagne avec une écriture directe dans les registres.

L'assembleur est très intéressant quand on sait exactement ce que doit faire le proc!
Logged

Forum Moderator
Geneva
Offline Offline
Faraday Member
*****
Karma: 30
Posts: 3228
Yoplait... le pt'it suisse
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

je pense à JF qui n'arrive pas à faire tourner une SD sur un 168... smiley-grin

J'suis pas loin... et j'ai tout lu  smiley-lol
Logged

MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

France S-O
Offline Offline
Edison Member
*
Karma: 41
Posts: 2182
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ce qui me gène le plus ce n'est pas l'excès de temps avec l'IDE arduino, ce sont les perturbations des sorties PWM.
Cela sent très fort la rustine  sur la rustine sur la rustine.
Logged

Bretagne
Offline Offline
Edison Member
*
Karma: 16
Posts: 1392
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ce qui me gène le plus ce n'est pas l'excès de temps avec l'IDE arduino, ce sont les perturbations des sorties PWM.
Cela sent très fort la rustine  sur la rustine sur la rustine.
C'est un peu le souci avec l'open source, c'est que celui qui améliore une fonction ne réécrit pas le code, mais se contente trop souvent d'en rajouter. Si aujourd'hui on tourne avec la version 22, il doit y avoir une vingtaine d'intervention sur les fonctions, 20 lignes de code en trop quoi...

Pour le PWM, j'ai ça si tu veux, c'est ce que j'avais développé pour gérer un servo sur MEGA2560, mais c'est transposable sur UNO en changeant le nom des registres. Pour l'exemple, j'ai viré un peu de code, car avec un timer sur méga2560, on peut gérer 3 servos (ou PWM) :

Code:
const byte servo1_pin = 6;                   // Servo 1 attahcé à pin N°6 (OC4A)
const word servo1_min = 6500;                   // Servo 1 valeur max
const word servo1_max = 17500;                    // Servo 1 valeur min
volatile word servo1_val = servo1_min;             // contient la valeur actuelle du servo1

void servo_init (){                               // initialise T4 pour gestion servo1 en PWM sur OC4A
  TCCR4B = 0x10;                                          // désactiver timer T4
  TCCR4A = 0x02;                                         // WGM(4) = b1010 = 10 : PWM pahse correct, compte de 0 à ICR4
  pinMode (servo1_pin, OUTPUT);
  TCCR4A += 0x80;                                      // activer la sortie en PWM sur OC4A
  OCR4A = servo1_max;                               // amener le servo dans sa position de repos au démarrage de T4
  ICR4H = 0xFF;
  ICR4L = 0xFF;                                         // TOP=65536 / T(pwm) = 8,192ms, précision PWM : 0,125µs / env. 14 000 pas servo
  TCCR4B += 0x01;                             // Activer timer4, prescaler = F_CPU/1  

// autre config timer :
//  ICR4H = 0x3A;
//  ICR4L = 0x98;                                      // TOP=15000 / T(pwm) = 15ms, précision PWM : 1 µs / env. 1850 pas servo
//  TCCR4B += 0x02;                         // Activer timer4, prescaler = F_CPU/8  

}

//------------------------
void servo_write(word val){
      if (val < servo1_min) servo1_val = servo1_min;                    // test de fourchette de valeur min / max
        else if (val > servo1_max) servo1_val = servo1_max;
        else servo1_val = val;
      OCR4A = servo1_val;                                                     // écrire la nouvelle valeur sur OCR
}

Le gros avantage de ce code, c'est que pour changer le rapport cyclique, il suffit de faire un OCR4A = valeur (16 bits). Le test de validité de valeur dans servo_write(val) n'est pas nécessaire pour une PWM de 0 à 100%, dans ce cas, on oublie la void et on écrit dans OCR4A...

J'ai tenté d'utiliser la librairie servo, mais l'innocent qui a pondu ça utilise un timer qui appelle une ISR (routine d'interruption) qui est appelée toutes les µs et qui :
- désactive le timer et toutes les interruptions,
- incrémente un compteur,
- et quand le compteur correspond à la valeur servo voulue en appelle une seconde qui fait un digitalwrite() sur la pin du servo,
- relance le timer et les interruptions.

En gros, le servo tremble dans tous les sens avec cette librairie, avec mon code, la PWM est d'une stabilité à toute épreuve, car le CPU n'intervient jamais dans la génération PWM.

C'est dommage d'avoir des fonctions hardware super stables sous la main et de les supplanter par des ISR à tout va!
« Last Edit: October 29, 2011, 02:02:15 am by Super_Cinci » Logged

France S-O
Offline Offline
Edison Member
*
Karma: 41
Posts: 2182
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Je te remercie, je mets ton code de coté pour le cas ou j'aurais besoin de PWM.
En fait ma remarque était théorique qu'est ce qui peut produire cette perturbation qui de plus n'est pas identique sur toutes les sorties PWM ?
J'aurais besoin d'une tension analogique, vraie, commandable. J'ai regardé la PWM mais à ce que j'ai compris elle se fait à une fréquence d'environ 500Hz, autant dire que c'est infiltrable avec des valeurs raisonnables de composant.
Je pensais ensuite modifier la configuration de l'AtMega328p pour passer à la vitesse maximale de PWM mais je ne suis pas arrivé à voir tout ce qui d'autre pourrait également être modifié.
Comme je n'ai pas besoin d'une grande précision j'ai eu une autre idée : un registre à décalage 8 bits, le réseau de résistances qui va bien, un condo pour filtrer et l'affaire est jouée (tout du moins au jour d'aujourd'hui sur Spice).
Deux pins seulement sont nécessaires (clock et data) il n'est pas utile de "latcher" les sorties, les combinaisons intermédiaires qui apparaîtront à fréquence élevée devraient être lissées par le condo.
Quote
C'est un peu le souci avec l'open source, c'est que celui qui améliore une fonction ne réécrit pas le code, mais se contente trop souvent d'en rajouter.
Désolé de te contredire mais c'est un état d'esprit qui n'est pas lié à l'Opensource, au contraire, c'est largement pire dans le milieu professionnel car le patron est toujours pressé de sortir le produit même s'il n'est pas fini, ce qui compte c'est faire rentrer le max de pognon et le plus vite possible.
Avec l'expérience quand je sentais qu'on risquait de m'imposer de faire passer le produit (électronique) en fabrication je maquillais mes résultats pour récupérer quelques mois supplémentaires de développement et au moins quand je lachais le produit il fonctionnait et il n'y avait pas de retour.
Logged

Bretagne
Offline Offline
Edison Member
*
Karma: 16
Posts: 1392
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

avec ce code, on peut très bien faire tourner la PWM à des fréquences intéressantes, il suffit juste de changer la valeur de ICR4. la période de la PWM est directement proportionnelle à ICR4 et au prescaler. Tu peux même doubler la fréquence (T4 est configuré ici pour compter en "triangle"), ce qui fait que si tu veux une simple résolution de 8 bits, tu peux donc mettre :

ICR4H = 0;
ICR4L = 255;

ton ratio cyclique sera sur OC4AL (= 0 à 255), et tu auras une PWM à 31KHz, voire 62KHz si tu mets le timer en dents de scie. là, tu peux commencer à envoyer de l'audio assez proprement (faudrait que j'essaie tiens!)

En jouant avec les deux autres comparateurs du timer 4, ça te fait 3 PWM dont je te garanti la stabilité! Tu peux pousser le bouchon et diminuant la précision (par exemple pour une PWM commandée par une valeur de 0 à 25, tu montes à 310KHz ou 630KHz). mais pour aller jusque là, faut en vouloir!
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 84
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

j'ai (comme 68tjs) fait cette remarque. pour ma part, je remplace souvent un digitalwrite() par un PORTB |=..., un pinmode par un DDRD &=...

De plus, il serait intéressant de voir ce que donne la compilation d'un petit programme en arduino et du même en registres, niveau taille flash. je crois qu'on y gagnerait énormément! (je pense à JF qui n'arrive pas à faire tourner une SD sur un 168... smiley-grin)

Justement, les macros que j'ai postées ci-dessus prennent en charge toute la gymnastique de traduction d'un numéro de pin arduino en un couple (Port + Adresse sur le port), de façon transparente ; elles sont strictement équivalentes à écrire PORTB |= (1 << PINBn). Et comme ce sont des macros elles sont résolues à la compilation, donc aucun appel de fonction  smiley-grin
Logged

Bretagne
Offline Offline
Edison Member
*
Karma: 16
Posts: 1392
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Oui, mais si tu fais directement PORTB |= 0x04, par exemple, tu gagnes une instruction par rapport à PORTB |= (1 << 2), donc du temps... c'est surtout une question d'habitude... à l'école, on codait en ASM (dans le temps), c'était bien plus transparent...
Logged

Celtic Kingdom
Offline Offline
Sr. Member
****
Karma: 2
Posts: 455
hard oui no!!!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

C'est un peu le souci avec l'open source, c'est que celui qui améliore une fonction ne réécrit pas le code, mais se contente trop souvent d'en rajouter. Si aujourd'hui on tourne avec la version 22, il doit y avoir une vingtaine d'intervention sur les fonctions, 20 lignes de code en trop quoi...
(...)
Sans être au parfum de tout, je plussoie aussi que ce n'est pas ce qui se pratique en général dans le monde de l'Open Source.
Justement car la multiplicité des intervenants fait que le nombre d'heure de développement n'est pas un facteur réducteur; une bibliothèque est souvent totalement réécrite afin d'évoluer ou des partie sont entièrement remplacées afin de corriger le(s) soucis.
A noté que j'ai déjà vu des bibliothèques "rétrécirent" après une mise à jour afin d'optimiser celle-ci.

Sinon, pour en revenir au sujet principal que je trouve très intéressant; super d'avoir fait ses tests -.^

Et pour le code sur la génération de PWM hyper stable, même si je n'ai pas encore tout compris, c'est excellent aussi : Cela fait pas mal de temps que je me *** à trouver quelque chose de très précis pour de la commande de moteur PàP ! Il y a souvent des "irrégularités" qui font que piloter un moteur PàP en micro-pas à haute précision/vitesse est très compliqué. 1/4 de pas cela va, 1/8 cela passe encore à certaines conditions, mais si l'on demande 100000 micro-pas en 1/8 d'un seul coup assez vite "y'a plus personne". Là, si l'on peut directement faire un pilotage en 16bits et très stable, c'est le bonheur.
Logged

Pages: [1] 2   Go Up
Jump to: