Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 20/03/2010, à 21:27

gilbert

[Résolu ?] [C] calculs avec le pré-processeur (avant compilation)

Hello,

voilà, je suis entrain d'écrire un petit programme en C et j'aimerai bien réaliser des calculs avec le préprocesseur. J'explique par mon cas :

Je suis entrain d'écrire une routine de temporisation qui attend un certain nombre de microsecondes. La durée minimale est 16 us et la résolution est de 6 us. Ma fonction d'attente est une boucle qui attend qu'un compteur ait parcouru un cycle de comptage complet. Son argument actuellement est le nombre d'itération à faire.

prototype actuel de ma fonction :

void waitUS(uint32_t numberOfIterations);

1 itération prend 16 us. 2 itérations 22 us. 3 itérations 28 us etc... Je l'ai bien mesuré à l'oscilloscope.

Simplement appeler la fonction avec le nombre d'itérations n'a pas beaucoup de sens et il serait plus compréhensible de passer comme argument la durée à attendre en microsecondes.

Ainsi, mon prototype désiré pour ma fonction serait :

void waitUS(uint32_t timeInUs);

Aussi, est-ce possible de créer une macro WAIT_US(x) et dans mon code j'appelle cette macro qui calcule le nombre d'itération correspondant à la durée x (en us) afin que le compilateur compile un appel de la fonction avec le nombre d'itérations et ainsi le temps sera correctement respecté ?

Le nombre d'itérations est 1 si l'argument est inférieur ou égal à 16 et (l'argument - 16 ) / 6 dans tous les autres cas.

Sauf que si je fais ce calcul dans mon code... ça prend du temps processeur... et donc ça fausse la durée de la temporisation (surtout qu'une division c'est lent).

Alors voilà, comment faire cela ?

Je sais pas si je suis clair... Enfin demandez-moi d'expliquer mieux si vous ne comprenez pas tout...

merci beaucoup pour votre aide.

Dernière modification par gilbert (Le 20/03/2010, à 22:57)


Simplement moi-même..

Hors ligne

#2 Le 20/03/2010, à 21:37

geenux

Re : [Résolu ?] [C] calculs avec le pré-processeur (avant compilation)

Tu peux simplement créer une macro pour passer le temps en secondes, mais tu ne pourra pas éviter la division. Le compilateur ne connait pas la valeur du temps que tu lui passera à la compilation, donc il sera obligé de faire les calculs à l'exécution.

#define WAIT_US(time) if(time <= 16) wait_US(1) 
                            else wait_US(...);

Hors ligne

#3 Le 20/03/2010, à 21:44

gilbert

Re : [Résolu ?] [C] calculs avec le pré-processeur (avant compilation)

mmh c'est gênant. Mais par exemple en assembleur je peux faire ça (exemple avec de l'atmel) :

;imaginons que la durée soit à passer dans le registre r16
ldi    r16, 1+ (temps-16)/6
; si temps vaut 37, p.ex., alors le préassembleur va remplacer la ligne ci-dessus par :
; ldi    r16,3 ; et ça sera cette ligne là qui sera traduite en langage machine
call   __waitUS
; suite du code

C'est pas possible de faire la même chose en C ????

EDIT: ah oui, j'ai oublié de préciser un truc.. J'aimerai écrire une fonction qui n'accepte que des valeurs immédiates..

Dernière modification par gilbert (Le 20/03/2010, à 21:49)


Simplement moi-même..

Hors ligne

#4 Le 20/03/2010, à 22:15

geenux

Re : [Résolu ?] [C] calculs avec le pré-processeur (avant compilation)

En fait, j'ai pas été assez précis dans mon autre message.
Si tu appelle la macro avec une constante, genre WAIT_US(30), c'est bien le préprocesseur qui fera les calculs.
Si tu appelle la macro avec une variable, là c'est à l'exécution que ça sera déterminé, à moins que la variable ne soit déclarée constante.

[edit] Je suppose qu'il faut aussi utiliser #if ...  #else ... #endif à la place de if, else dans la macro, sinon le préprocesseur rajoutera le test au code, ce que tu veux éviter.

Dernière modification par geenux (Le 20/03/2010, à 22:18)

Hors ligne

#5 Le 20/03/2010, à 22:23

gilbert

Re : [Résolu ?] [C] calculs avec le pré-processeur (avant compilation)

ahh ok excellent :-) je pensais qu'il fallait utiliser #if #else #endif pour pas que ça ne soit ajouté dans le code...

Donc si je veux n'accepter que des valeurs immédiates, il faut que mon prototype n'accepte que des constantes :

void waitUs(const uint32 timeInUs);

Je teste tout ça et je regarde les temps que j'obtiens..


Simplement moi-même..

Hors ligne

#6 Le 20/03/2010, à 22:29

gilbert

Re : [Résolu ?] [C] calculs avec le pré-processeur (avant compilation)

Bon voilà mon code... j'arrive pas à définir correctement la macro, j'ai lerreur suivante :

../main.c:21:24: error: '#' is not followed by a macro parameter
#include "main.h"

void waitUs(const uint32 timeInUs);

#define WAIT_US(time) #if(time <= 16) waitUs(1) #else waitUs(((time)-16)/6) #endif

int main(int argc, char** argv) {

	/* LEDs are on GPIO1 3 downto 0*/

	/* set GPIO1 3 downto 0 as output */
	*GPIO1_DATAOUT_EN = (1 << LED3) | (1 << LED2) | (1 << LED1) | (1 << LED0);
	/* first, clear all the LEDs */
	*GPIO1_DATAOUT_W1C = (1 << LED3) | (1 << LED2) | (1 << LED1) | (1 << LED0);

	while(1) {
		/* core of the code here */

                /* test with a pulse */
		*GPIO1_DATAOUT_W1S = 1 << LED3; /* LED 3 on : high state */
		waitUs(45);
		*GPIO1_DATAOUT_W1C = 1 << LED3; /* LED 3 off : low state */
		waitUs(5);

	}

	return 0;
}

/* a very simple wait procedure using the timer */
void waitUs(const uint32 timeInUs) {

	/* one iteration is 6 us long.. */
	/* minimal time is 16 us */

	/* enable the timer */
	*TIMER1_COUNTER_EN = 1;

	/* runs n times */
	for(uint32 i=0; i<timeInUs; i++) {

		do {} /* wait */
		while ( (*TIMER1_STATUS & 1) == 0); /* the timer reach the end if the LSB of TIMER1_STATUS is set */

		/* clear the "counter limit reached" flag */
		*TIMER1_STATUS = 1;
	}

	/*disable the timer */
	*TIMER1_COUNTER_EN = 0;
	return;
}

EDIT: en utilisant exactement ce que tu as proposé en #2 ça à l'air de fonctionner pas mal.

pour ce code :

		WAIT_US(250);
		WAIT_US(500);

voici l'assembleur que j'obtiens :

.LM5:
	movil r7, #39
	sjsr _waitUs
	nop
.LM6:
	movil r7, #80
	sjsr _waitUs
	nop

or (250-16)/6 = 39 et (500-16)/6 = 80. Il ne rajoute donc pas le if en code.. big_smile

Dernière modification par gilbert (Le 20/03/2010, à 22:56)


Simplement moi-même..

Hors ligne

#7 Le 21/03/2010, à 00:15

geenux

Re : [Résolu ?] [C] calculs avec le pré-processeur (avant compilation)

Oui, c'est parceque tu appelle la fonction avec une constante, donc le compilateur optimise de lui-même, quand il peut faire les calculs il le fait, si tu lui passe une variable (non constante à la place) il compilera avec le if.

Hors ligne

#8 Le 21/03/2010, à 00:57

TatrefThekiller

Re : [Résolu ?] [C] calculs avec le pré-processeur (avant compilation)

Conseil : évite de faire ce genre d'optimisations, et laisse faire le compilateur !
Si tu penses vraiment que ton programme à des problèmes de performances, utilise déjà un profiler pour voir où ton programme passe du temps à calculer.
L'optimisation ne vient que après !

Sinon, le petit calcul que tu fais au début prendra un temps constant, donc je ne pense pas que ça soit un problème.

Tu fais ça sur un processeur classique, ou un microcontrôleur ?

Hors ligne

#9 Le 21/03/2010, à 01:01

gilbert

Re : [Résolu ?] [C] calculs avec le pré-processeur (avant compilation)

hello,

en fait je n'optimise rien du tout... je dois écrire des routines de temporisation et je voulais simplement qu'elles aient un temps pas trop trop moche et donc à peu près correct : +/- 1%

je n'ai ni un processeur classique ni un dsp ni un microcontrôleur. J'ai un processeur modulable, mais c'est un peu comme un processeur classique.

EDIT : en effet le calcul prend un temps assez constant, mais malheureusement lent... et ça me condamnerai à avoir une temporisation minimale de 50 us à peu près.. alors que là je peux avoir 16 us.. C'est pas mal mieux. Ma résolution est en fait de 630 ns à l'oscilloscope.

Dernière modification par gilbert (Le 21/03/2010, à 01:04)


Simplement moi-même..

Hors ligne