Attention ! Fermeture imminente du forum d’Elektor (pour en savoir plus, cliquer ici). À partir du vendredi 15er mars il ne sera plus possible de s’identifier sur ce forum, mais son contenu restera disponible en lecture seule jusqu’à la fin du mois. Le 1er avril, il sera fermé définitivement.

Génération de 4PWMs avec un seul TimerC

Postby gatsby94 » Mon Aug 27, 2007 12:00 am

Salut je vous propose un sujet de réfléxion:
Voilà je générer grace au seul timerC du R8C/1B 4 PWMs sur 4 ports différents.

voici mon code :

static void init_timerC(void);
static void trie_PWM(void);
static void test_synchro(void);

unsigned int tab_trie_PWM[5];
unsigned int PWM[36];
unsigned char num_PWM_a_charger;
unsigned char num_PWM_Max;
unsigned int PWM_ROUT;
unsigned int PWM_VOUT;
unsigned int PWM_BOUT;
unsigned int PWM_WOUT;
unsigned int temp;
unsigned long synchro;

int i;

/**********************************************************************************
Function Name : main
Description : Main function
Parameters : none
Return value : none
***********************************************************************************/
void main(void)
{

asm ("fset i");
init_timerC();
PWM[0]= 0x0010;
PWM[1]= 0x0040;
PWM[2]= 0x0070;
PWM[3]= 0x0100;
PWM[4]= 0x0200;
PWM[5]= 0x0600;
PWM[6]= 0x1000;
PWM[7]= 0x1200;
PWM[8]= 0x1300;
PWM[9]= 0x1400;
PWM[10]= 0x1500;
PWM[11]= 0x1700;
PWM[12]= 0x2000;
PWM[13]= 0x2100;
PWM[14]= 0x2200;
PWM[15]= 0x2100;
PWM[16]= 0x2000;
PWM[17]= 0x1500;
PWM[18]= 0x1000;
PWM[19]= 0x0900;
PWM[20]= 0x0800;
PWM[21]= 0x0700;
PWM[22]= 0x0600;
PWM[23]= 0x0500;
PWM[24]= 0x0400;
PWM[25]= 0x0300;
PWM[26]= 0x0200;
PWM[27]= 0x0100;
PWM[28]= 0x0050;
PWM[29]= 0x0040;
PWM[30]= 0x0030;
PWM[31]= 0x0020;
PWM[32]= 0x0010;
p1_4 = 1;
i = 32;
num_PWM_a_charger = 0;
synchro = 0;
tcc00 = 1;



while(1)
{

if (synchro == 0)
{
trie_PWM();
}
test_synchro();
}
}
/**********************************************************************************
End of function main
***********************************************************************************/
void test_synchro(void)
{
if (p1_6 == 1)
{
synchro ++;
}
if (synchro == 1000000)
{
synchro = 0;
}
}

void init_timerC(void)
{
tcc0 = 0x32; //f1=14,7456MHz, rising edge,
tcc1 = 0x0C; // no filter, no reload, output compare mode
cmp0ic = 2;
cmp1ic = 1;
tcout = 0x00;
}

/*------------trie-PWM-----------------------------------*/

void trie_PWM(void)
{

char z,j;
unsigned char num_recherche;
unsigned int tmp; /* variable temporaire*/

num_PWM_Max = 0;
i++;
if (i == 33)
{
i = 0;
}

PWM_ROUT = PWM;
PWM_BOUT = PWM;
PWM_VOUT = PWM[32-i];
PWM_WOUT = PWM[32-i];
tab_trie_PWM[0] = PWM_ROUT;
tab_trie_PWM[1] = PWM_VOUT;
tab_trie_PWM[2] = PWM_BOUT;
tab_trie_PWM[3] = PWM_WOUT;


for(z = 0; z z; j--)
{
if(tab_trie_PWM[j-1]>tab_trie_PWM[j])
{
tmp = tab_trie_PWM[j-1];
tab_trie_PWM[j-1] = tab_trie_PWM[j];
tab_trie_PWM[j] = tmp;
}
}
}
if (abs(tab_trie_PWM[1] - tab_trie_PWM[0]) 0xFF)
{
tab_trie_PWM[num_PWM_Max] = tab_trie_PWM[num_recherche+1];
num_PWM_Max++;
num_recherche++;
}
else
{
num_recherche++;
}
if (abs(tab_trie_PWM[num_recherche+1]- tab_trie_PWM[num_recherche]) > 0xFF)
{
tab_trie_PWM[num_PWM_Max] = tab_trie_PWM[num_recherche+1];
num_PWM_Max++;
num_recherche++;
}
else
{
num_recherche++;
}


num_PWM_a_charger = 0;

tm0 = tab_trie_PWM[0];


}

#pragma INTERRUPT timer_cmp0

void timer_cmp0(void)
{
if (tm0 >= PWM_ROUT)
{
p1_0 = 1;
}
if (tm0 >= PWM_VOUT)
{
p1_1 = 1;
}
if (tm0 >= PWM_BOUT)
{
p1_2 = 1;
}
if (tm0 >= PWM_WOUT)
{
p3_3 = 1;
}
num_PWM_a_charger++;
if(num_PWM_a_charger < num_PWM_Max)
{
tm0 = tab_trie_PWM[num_PWM_a_charger];
}


}

#pragma INTERRUPT timer_cmp1

void timer_cmp1(void)
{
tcc00 = 0;
num_PWM_a_charger = 0;
tm0 = tab_trie_PWM[num_PWM_a_charger];
p1_0 = 0;
p1_1 = 0;
p1_2 = 0;
p3_3 = 0;

tcc00 = 1;


}

;---------------------------------------------------------------
; variable vector section
;---------------------------------------------------------------
.section vector,ROMDATA ; variable vector table
.org VECTOR_ADR

.glb _timer_cmp0
.glb _timer_cmp1

.lword dummy_int ; vector 0
.lword dummy_int ; vector 1
.lword dummy_int ; vector 2
.lword dummy_int ; vector 3
.lword dummy_int ; vector 4
.lword dummy_int ; vector 5
.lword dummy_int ; vector 6
.lword dummy_int ; vector 7
.lword dummy_int ; vector 8
.lword dummy_int ; vector 9
.lword dummy_int ; vector 10
.lword dummy_int ; vector 11
.lword dummy_int ; vector 12
.lword dummy_int ; vector 13
.lword dummy_int ; vector 14
.lword dummy_int ; vector 15
.lword _timer_cmp1 ; vector 16
.lword dummy_int ; vector 17
.lword dummy_int ; vector 18
.lword dummy_int ; vector 19
.lword dummy_int ; vector 20
.lword dummy_int ; vector 21
.lword dummy_int ; vector 22
.lword dummy_int ; vector 23
.lword dummy_int ; vector 24
.lword dummy_int ; vector 25
.lword dummy_int ; vector 26
.lword dummy_int ; vector 27
.lword _timer_cmp0 ; vector 28
.lword dummy_int ; vector 29
.lword dummy_int ; vector 30
.lword dummy_int ; vector 31
.lword dummy_int ; vector 32
.lword dummy_int



Voilà donc le tableau PWM sont les valeurs des duty cycles des PWMS

ensuite je trie les PWMs por qu'ils soient dans l'ordre croissant.
ensuite je charge le CMP0 pour avoir une interruption
lorsqu'il y a interruption je met à 1 les ports qui ont un duty cycle > CMP0.
puis CMP1 et charger à la valeur de de fin de période des PWM et donc les ports sont mis à 0;

LE problème est que ça ne marche pas bien. effet on ne peut arreter le timer sans qu'il se remette à 0.
Donc je ne dois pas l'arreter pour pouvoir faire ma méthode.
le fait est que si je ne l'arrete pas si lorsqueje rentre dans un interruptionCMP0 , le temps que je traite la routine et que je chare la valeur du registre suivant dans CMP0 la valeur de tc a déjà dépasser la valeur suivante charger dans CMP0. donc tout déconne.
j'ai essayé de remedier à ce problème en faisant u calcul de différence entre deux valeur à charger en calculant le temps mis pour effectuer la routine d'interruption. et si la difference entre les deux valeurs est inferieur alors je necompte qu'une seule valeur.
MAis ça ne marche pas top non plus.
qqun aurait til une solution à ce problème brulant ?
gatsby94
 
Posts: 29
Joined: Fri Jan 17, 2014 4:38 pm

Postby sda » Tue Aug 28, 2007 12:00 am

A quelle fréquence tourne tes PWM, quelle est le rapport cyclique mini et maxi (ex: F=10kHz Rmini=10% Rmaxi=90%).
Tu ne pourras pas avoir 2 rapport cyclique trop proche par example : si F=10kHz, demi periode = 50µs, comme il faut environ 20µs entre 2 interruption de ton timer c, il faudra un rapport cyclique avec 40% d'écart (par exemple : une PWM à 10% et une autre à 50% mais pas en dessous).

Une solution pourrait être :
génération d'une IT toutes les 50µs (ou plus), compter le nombre de déclanchement de l'IT jusqu'à 1000, comparer ce compteur aux valeurs de PWM voulu et quand le compteur est supérieur on inverse la pin correspondante. Inconvéniant : la fréquence des PWM est forcement inférieur à 1/(1000*50µs)=20Hz! (mais si tu réduit le pas, la fréquence augmente (200Hz avec 100 pas).
sda
 
Posts: 24
Joined: Fri Jan 17, 2014 4:38 pm

Postby gatsby94 » Tue Aug 28, 2007 12:00 am

ma frequence est de 200Hz etle rapport mini est 0% et max 100% avec un pas de 1% par 1% de rapport cyclique possible.
gatsby94
 
Posts: 29
Joined: Fri Jan 17, 2014 4:38 pm

Postby gatsby94 » Tue Aug 28, 2007 12:00 am

une autre question pourquoi il faut 20uS entre deux interruption de timerC?
gatsby94
 
Posts: 29
Joined: Fri Jan 17, 2014 4:38 pm

Postby sda » Tue Aug 28, 2007 12:00 am

Les 20us que je donne n'ai pas une donnée précise, elles corespondent au temps que met le micro controlleur à quitter la tache en cours et à entrer dans l'IT (c'est une moyenne que je prends pour mes calculs avec un quartz 10 ou 14Mhz).
Attention, la tache en cours peut être une autre IT et il faudra qu'elle se termine pour entrer dans une autre IT moins prioritaire.

Avec la fréquence que tu as besoin, je pense que ma methode est réalisable mais tu risque d'avoir du "jitter", tes rapports cyclique risque de ne pas être stable (+/- 5% j'imagine) surtout si ton micro a plusieurs IT à gérer. Il faudra surement autoriser la ré-entrance dans tes IT pour limiter ce jitter (c-à-d autoriser les autres interruptions quand tu rentre dans une interruption).
sda
 
Posts: 24
Joined: Fri Jan 17, 2014 4:38 pm

Postby gatsby94 » Tue Aug 28, 2007 12:00 am

je n'ai que cette interruptions qui tourne en permence.
La seule autre sera une interruption de reception de l'uart et à ce moment là je n'autoriserai plus l'interruption sur le timerC.
j'essaie ta methode je te dis le résultat.
gatsby94
 
Posts: 29
Joined: Fri Jan 17, 2014 4:38 pm

Postby gatsby94 » Tue Aug 28, 2007 12:00 am

ta méthode marche parfaitement !! sauf que j'ai par moment des scintillement cad que pendant un certain temps je reste à 1 ce quei fait scintiller je ne sais pas pourkoi
gatsby94
 
Posts: 29
Joined: Fri Jan 17, 2014 4:38 pm

Postby gatsby94 » Tue Aug 28, 2007 12:00 am

voici le code :

static void init_timerC(void);
static void trie_PWM(void);
static void test_synchro(void);

unsigned int tab_trie_PWM[5];
unsigned int PWM[36];
unsigned char num_PWM_a_charger;
unsigned char num_PWM_Max;
unsigned int PWM_ROUT;
unsigned int PWM_VOUT;
unsigned int PWM_BOUT;
unsigned int PWM_WOUT;
unsigned int temp;
unsigned long synchro;
unsigned char cmpt;

int i;

/**********************************************************************************
Function Name : main
Description : Main function
Parameters : none
Return value : none
***********************************************************************************/
void main(void)
{

asm ("fset i");
init_timerC();
PWM[0]= 10;
PWM[1]= 12;
PWM[2]= 14;
PWM[3]= 18;
PWM[4]= 20;
PWM[5]= 24;
PWM[6]= 26;
PWM[7]= 28;
PWM[8]= 30;
PWM[9]= 36;
PWM[10]= 40;
PWM[11]= 43;
PWM[12]= 46;
PWM[13]= 53;
PWM[14]= 56;
PWM[15]= 58;
PWM[16]= 60;
PWM[17]= 63;
PWM[18]= 66;
PWM[19]= 70;
PWM[20]= 73;
PWM[21]= 76;
PWM[22]= 80;
PWM[23]= 82;
PWM[24]= 85;
PWM[25]= 87;
PWM[26]= 90;
PWM[27]= 93;
PWM[28]= 95;
PWM[29]= 97;
PWM[30]= 99;



p1_4 = 1;
i = 8;
num_PWM_a_charger = 0;
synchro = 0;
cmpt = 0;
tm0 = 0x45;
tcc00 = 1;



while(1)
{

if (synchro == 0)
{
trie_PWM();
}
test_synchro();
}
}
/**********************************************************************************
End of function main
***********************************************************************************/
void test_synchro(void)
{
if (p1_6 == 1)
{
synchro ++;
}
if (synchro == 2500)
{
synchro = 0;
}
}

void init_timerC(void)
{
tcc0 = 0x32; //f1=14,7456MHz, rising edge,
tcc1 = 0x0C; // no filter, no reload, output compare mode
cmp0ic = 1;
/*cmp1ic = 1;*/
tcout = 0x00;
}

/*------------trie-PWM-----------------------------------*/

void trie_PWM(void)
{


i++;
if (i == 31)
{
i = 0;
}

PWM_ROUT = PWM;
PWM_BOUT = PWM;
PWM_VOUT = PWM[30-i];
PWM_WOUT = PWM[30-i];

}

#pragma INTERRUPT timer_cmp0

void timer_cmp0(void)
{
tcc00 = 0;
cmp0ic = 1;
cmpt++;
if (cmpt == 100)
{
cmpt = 0;
p1_0 = 0;
p1_1 = 0;
p1_2 = 0;
p3_3 = 0;

}
else
{
if (cmpt >= PWM_ROUT)
{
p1_0 = 1;
}
if (cmpt >= PWM_VOUT)
{
p1_1 = 1;
}
if (cmpt >= PWM_BOUT)
{
p1_2 = 1;
}
if (cmpt >= PWM_WOUT)
{
p3_3 = 1;
}
}
tcc00 = 1;

}
gatsby94
 
Posts: 29
Joined: Fri Jan 17, 2014 4:38 pm

Postby gatsby94 » Tue Aug 28, 2007 12:00 am

Le problème vient surement du E8 car lorsque je suis en debugge ce phénomène se produit mais lorsque je charge le programme dans la flsh et que la carte tourne seule et bien ce phénomène disparait.
Serait l'uart1 qui déclencherait une interruption en debugge?
gatsby94
 
Posts: 29
Joined: Fri Jan 17, 2014 4:38 pm

Postby sda » Tue Aug 28, 2007 12:00 am

Exact, tolen le spécialiste nous le confirmera peut-être mais en mode debug le R8 est surement plus chargé qu'en fonctionnement normal et des IT de l'uart peuvent venir perturber le fonctionnement.
sda
 
Posts: 24
Joined: Fri Jan 17, 2014 4:38 pm

Next

Return to R8C/13 (01-2006)

Who is online

Users browsing this forum: No registered users and 0 guests