Go Down

Topic: By the registers how to prohibit to have 2 digital pins at the same time in ON ? (Read 4647 times) previous topic - next topic

Tfou57

Hello,
In my project the DUE will pilot up to 6 three-phase frequency inverters controlling 6 220v tri-geared motors.
Each gearmotor is connected to a crank rod system controlled in position by a 360 ° potentiometer. The normal working stroke will be + 60 ° / 0 ° / -60 °

For the drive control part (out of the internally managed position feedback loop in the Due, I need for each motor to:
1 ADC input (no problem at the moment)
1 PWM output (subject treated on another post http://forum.arduino.cc/index.php?topic=457632.0 )
2 Digital outputs to control the direction of rotation at the input of the drives

Specifications for digital outputs:
 Prohibition of having both outputs of the same ON drive at the same time. This is equivalent to forbidding front and rear control at the same time
 Possibility of having the output pair OFF on the same inverter.
 In order to have the PID management as fast as possible, I wish to use the registers of the SAM AT91SAM 3X8E of the DUE

12 pins reserved for the control of the direction of rotation of the 6 motors:
Direction of drive rotation 1: Pin 31 (PWM L0) and Pin 35 (PWM H0)
Direction of drive rotation 2: Pin 36 (PWM L1) and Pin 37 (PWM H1)
Direction of drive rotation 3: Pin 38 (PWM L2) and Pin 39 (PWM H2)
Direction of drive rotation 4: Pin 40 (PWM L3) and Pin 41 (PWM H3)
Direction of drive rotation 5: Pin 08 (PWM L5) and Pin 44 (PWM H5)
Direction of drive rotation 6: Pin 07 (PWM L6) and Pin 45 (PWM H6)

These 12 pins will be interfaced for power with 3 integrated circuits ULN2803

Do you already have a code using the registers and having this feature to prohibit 2 outputs at ON at the same time
A test does not penalize the speed of the permutation
Certainly the inverter, forbids this possibility by failing.
A solution in code form would be more elegant

For now, I only know how to switch digital pins without any overlapping state check.

Here is my code with other numbers of pins I had taken at random (pins 25 and 45)

Quote
uint32_t pin_25 = (1u << 0);           // masque pour la pin 25 (Port Pin D0)
uint32_t pin_45 = (1u << 18);        // masque pour la pin 45 (Port Pin C18)

 void setup()
 {
  REG_PIOD_OER = pin_25;            // pin 25 est configuré en output au niveau du port D
  REG_PIOC_OER = pin_45;            // pin 45 est configuré en output au niveau du port C
 
  REG_PIOD_CODR = pin_25;         // Basculement pin 25 en OFF  (clear)
  REG_PIOC_CODR = pin_45;        // Basculement pin 45 en OFF  (clear)
  
  Serial.begin(115200);
 }

 void loop()
 {
 //Changement état des pins 25 et 45 avec "Delay"
 //**********************************************
 REG_PIOC_CODR = pin_45;                  // Basculement pin 45 en OFF  (clear)
          delayMicroseconds(1);          // wait for a 1ms
 REG_PIOD_SODR = pin_25;                  // Basculement pin 25 en ON (set)
          delayMicroseconds(1);          // wait for a 1ms
 REG_PIOD_CODR = pin_25;                  // Basculement pin 25 en OFF  (clear)
         delayMicroseconds(1);            /  / wait for a 1ms
 REG_PIOC_SODR = pin_45;                    // Basculement pin 45 en ON (set)
         delayMicroseconds(1);            // wait for a 1ms

Bonjour,
Dans mon projet la DUE pilotera jusqu'à 6 variateurs de fréquences triphasé commandant 6 motoréducteurs 220v tri.
Chaque motoréducteur est relié à un système bielle manivelle contrôlé en position par un potentiomètre à 360°. La course de travail normale sera +60° /0° / -60°

Pour la partie de commande du variateur (hors de la boucle de feedback de position géré en interne dans la Due, j'ai besoin pour chaque moteur de :
1 Entrée ADC (aucun problème pour l'instant)
1 Sortie PWM (sujet traité sur un autre post http://forum.arduino.cc/index.php?topic=457632.0 )
2 Sorties digitales afin de commander le sens de rotation à l'entrée des variateurs

Cahier des charges pour les sorties digitales :
 Interdiction d'avoir les 2 sorties d'un même variateur ON en même temps. Cela revient à interdire la commande avant et la commande arrière en même temps
 Possibilité d'avoir la paire de sortie OFF sur un même variateur.
 Afin d'avoir une gestion du PID la plus rapide possible, je souhaite utiliser les registres du SAM AT91SAM 3X8E de la DUE

12 Pins réservées pour la commande des sens de rotation des 6 moteurs :
Sens rotation du variateur 1 : Pin 31 (PWM L0) et Pin 35 (PWM H0)
Sens rotation du variateur 2 : Pin 36 (PWM L1) et Pin 37 (PWM H1)
Sens rotation du variateur 3 : Pin 38 (PWM L2) et Pin 39 (PWM H2)
Sens rotation du variateur 4 : Pin 40 (PWM L3) et Pin 41 (PWM H3)
Sens rotation du variateur 5: Pin 08 (PWM L5) et Pin 44 (PWM H5)
Sens rotation du variateur 6 : Pin 07 (PWM L6) et Pin 45 (PWM H6)

Ces 12 pins seront interfacées pour la puissance avec 3 circuits intégrés ULN2803

Avez-vous déjà un code utilisant les registres et ayant cette fonctionnalité d'interdire 2 sorties à ON en même temps
Un test ne pénalisant pas la rapidité de la permutation
Certes le variateur, interdit cette possibilité en se mettant en défaut.
Une solution sous forme de code serait plus élégante

Pour l'instant, je ne sais que basculer des pins digitales sans aucune vérification de chevauchement d'état.

Voici mon code avec d'autres numéro de pins que j'avais prise au hasard (pins 25 et 45)

(Voir le code ci-dessus en fin de la partie en anglais)



MorganS

Don't do that.

The chip doesn't have any protection against two pins being on at the same time. How would it know which one to switch off if you did? Maybe they are active-low pins where active is actually "off"?

You write the code in a way that doesn't allow this.
"The problem is in the code you didn't post."

westfw

(Some microcontrollers have timers that are specifically designed for controlling muti-phase motors, with outputs for each of several phases that are configurable to have "off time" in between the on-time of the different phases, so that no two outputs are on at the same time.   It looks like the Due (SAM3X) might have such a feature:

Quote
The PWM macrocell controls 8 channels independently. Each channel controls two complementary square output waveforms. Characteristics of the output waveforms such as period, duty-cycle, polarity and dead-times (also called dead-bands or non-overlapping times) are configured through the user interface.
But I don't think there is any way to get these configured via the Arduino environment.   You could try the Atmel forums for a (hopefully) better answer.


Tfou57

@Morgans
Quote
Do not do that
The test code that I inserted in my previous post is concerned by the above quote
Is it incomplete?
How do you change it to make it compliant?

Quote
Do not do that. ...
You write the code in a way that does not allow this
Do you have an example code to apply to a pair of digital pin to meet my need?


@Morgans
Quote
Don't do that
Le code d'essai que j'ai inséré dans mon post précédent  est concerné par la citation ci-dessus
Est-il incomplet ?
Comment le modifier pour le rendre conforme ?

Quote
Don't do that. …
You write the code in a way that doesn't allow this
Quote
Avez-vous un exemple de code à appliquer sur une paire de pin digitale pour répondre à mon besoin ?

ard_newbie

When I look at the pinout diagram, I can see some différences with your tab:

12 pins reserved for the control of the direction of rotation of the 6 motors:
Direction of drive rotation 1:    Pin 34 (PWM L0) and Pin 35 (PWM H0)
Direction of drive rotation 2:    Pin 36 (PWM L1) and Pin 37 (PWM H1)
Direction of drive rotation 3:    Pin 43 (PWM L2) and Pin 39 (PWM H2)
Direction of drive rotation 4:    Pin 40 (PWM L3) and Pin 41 (PWM H3)
Direction of drive rotation 5:    Pin 08 (PWM L5) and Pin 44 (PWM H5)
Direction of drive rotation 6:    Pin 07 (PWM L6) and Pin 45 (PWM H6)

Here is an example of what I think is dead time programmation for PWM High and Low (not tested) :

Code: [Select]

void setup () {

  // PWM Set-up on pin PC7 and PA20 (Arduino Pin 39 and 43): see Datasheet chap. 38.5.1 page 973
  

  PMC->PMC_PCER1 |= PMC_PCER1_PID36;                   // PWM on

  // Select Instance=PWM; Signal=PWMH2 (channel 2); I/O Line=PC7 (P7, Arduino pine 39, see pinout diagram) ; Peripheral=B
  PIOC->PIO_ABSR |= PIO_ABSR_P7;                        // Set PWM pin perhipheral type B

  PIOC->PIO_PDR |= PIO_PDR_P7;                          // Set PWM pin to an output
  

  // Edit : Select Instance=PWM; Signal=PWML2 (channel 2); I/O Line=PA20 (P20, Arduino pine 43, see pinout diagram) ; Peripheral=B
  PIOA->PIO_ABSR |= PIO_ABSR_P20;                        // Set PWM pin perhipheral type B

  PIOA->PIO_PDR |= PIO_PDR_P20;                          // Set PWM pin to an output
  
  // Enable the PWM channel 2 (see datasheet page 973)

  PWM->PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(42);    // Set the PWM clock rate to 2MHz (84MHz/42). Adjust DIVA for the resolution you are looking for

  PWM->PWM_CH_NUM[2].PWM_CMR = PWM_CMR_CALG | PWM_CMR_CPRE_CLKA;     // The period is  left aligned, clock source as CLKA on channel 2

  PWM->PWM_CH_NUM[2].PWM_CPRD = 1000000;                             // Channel 2 : Set the PWM frequency 2MHz/(2 * CPRD) = F ; 1< CPRD < 2exp24  -1 ; F = 1 Hz

  PWM->PWM_CH_NUM[2].PWM_CDTY = 800000;                              // Channel 2: Set the PWM duty cycle to x%= (CDTY/ CPRD)  * 100 % ; Duty cycle = 80%

  // Dead time between 2 complementary PWM H and L, e.g.:
  PWM->PWM_CH_NUM[2].PWM_CMR |= PWM_CMR_DTE;                          // Enable dead time
  uint32_t DTH = 100;                                                //DTH is between 0 and CPRD - CDTY = 200000
  uint32_t DTL = 100;                                                //DTL is between 0 and CDTY = 800000

  PWM->PWM_CH_NUM[2].PWM_DT = DTH | DTL << 16;                      // Datasheet chap. 38.6.2.4 page 981 and chap. 38.7.43 page 1051
  PWM->PWM_ENA = PWM_ENA_CHID2;

  // Alternately, you can use this format :  REG_PWM_CPRD2 = 1000000;
  // In this example, Frequency is 1 HZ with a DT of 80%

}


void loop() {
  delay(100);
}






MorganS

I mean aside from the dead-time generation in the PWM timers, it's your responsibility not to turn on two pins at the same time. If you don't want two pins on, then don't turn them both on.

(I was assuming with my short comment that you had read the sections of the datasheet that West and Newbie are referring to.)
"The problem is in the code you didn't post."

Tfou57

@Morgans
Quote
If you don't want two pins on, then don't turn them both on.
Of course, I was thinking about the possibility of overlap during some microseconds.

Biensûr , je pensais au risque de chevauchement durant possible durant quelque microsecondes.


@Westfw
Quote
But I don't think there is any way to get these configured via the Arduino environment.   You could try the Atmel forums for a (hopefully) better answer.
The Atmel forum is a good idea, but I will first see the code proposed by ard_newbie that I thank elsewhere.

Le forum Atmel est une bonne idée , mais je vais d'abord voir le code proposé par ard_newbie que je remercie par ailleurs.

Tfou57

@ Ard-newbie, thanks for your comments and your code :smiley-mr-green:

:smiley-mr-green: Thank you for pointing out my mistake: :-X  :-[, it should read:
Quote
Direction of drive rotation 1: Pin 34 (PWM L0) and Pin 35 (PWM H0)
But regarding the second difference, I thought:
       Pin 38 (PWM L2) identical to Pin 43 (PWM L2)
       Pin 39 (PWM H2) identical to Pin53 (PWM H2)
Like Pin 37 (PWM H1) identical to Pin42 (PWM H1)

Thanks again for your code that I will study thanks to the valuable data you have put in comments: smiley-mr-green: (datasheet Atmel-11057C)

In deciphering little by little, I have questions:

Quote
// Enable the PWM channel 2 (see datasheet page 973)
On page 973, I find in the table 3 lines PWMH2 with Peripheral B: PA13, PB14 and PC7
In the file varian.cpp of the Due, I find that a match: pin39 <-> PC7 (used in your code)
What is PA13, PB14 (datasheet page 973)?
What about the CPU tabs AT91SAM3X8E?
Without connection with Due physical pine?

I started studying to study your code using the datasheet and the brave Google!
I also checked / compiled and uploaded your code into Due

Result:
PIN 39 turns ON for 3.3ms before turning OFF. The period of the ON / OFF signal is 17ms
Pin 43 never switches to ON
See screenshot in attachment


I also did not understand why:
- you put an isolated delay in the loop loop().
- Why I have a cyclic tilting of the pin39 while Setup() is supposed to be executed only once when the Due

To clarify the structure of the code I need:
The switching times ON / OFF can be very fast when my actuators arrive and will maintain the target position to reach. (Motor PID)

If the Forward pilot pin 39 and the Reverse pilot pin 43
1) During the setup program the pins 39 (forward) and 43 (reverse) must be every 2 in OFF
2) 2 functions void Forward () and void Reverse () must handle the direction of rotation
3) Before ordering Forward, you would need: Reverse = OFF, Dead time then Forward in ON
4) Before ordering Reverse, you would need: Forward = OFF, Dead time then Reverse in ON



@Ard-newbie,merci pour vos remarques et votre code :smiley-mr-green:

:smiley-mr-green: Merci de m'avoir fait remarquer mon erreur  :-X  :-[ , il faut bien lire :
Quote
Direction of drive rotation 1:    Pin 34 (PWM L0) and Pin 35 (PWM H0)
Mais concernant la seconde différence, je pensais que :
   Pin 38 (PWM L2)   identique à   Pin 43 (PWM L2)
   Pin 39 (PWM H2)   identique à  Pin53 (PWM H2)
Comme   Pin 37 (PWM H1)   identique à  Pin42 (PWM H1)

Merci encore pour votre code que je vais étudier grâce aux précieuses données que vous avez mises en commentaires :smiley-mr-green: (datasheet Atmel-11057C)

En déchiffrant peu à peu, il me vient des questions :

Quote
// Enable the PWM channel 2 (see datasheet page 973)
A la page 973, je trouve dans le tableau 3 lignes PWMH2  avec Peripheral B : PA13, PB14 et PC7
Dans le fichier varian.cpp de la Due, je trouve qu'une correspondance : pin39 <-> PC7(utilisé dans votre code)
A quoi correspond PA13, PB14 (datasheet page 973) ?  
Que des pattes du CPU AT91SAM3X8E ?
Sans liaison avec pin physique de la Due ?

J'ai commencé à étudier à étudier votre code à l'aide du datasheet et du brave Google !
J'ai également vérifié / compilé et téléversé votre code dans la Due

Résultat :
La pin 39 passe ON pendant 3,3ms avant de passer en OFF. La période du signal ON / OFF est de 17ms
La pin 43 ne bascule jamais en ON
Voir copie d'écran en pièce jointe

J'ai également pas compris pourquoi :
- vous avez mis un delay isolé dans la boucle Loop().
- Pourquoi j'ai un basculement cyclique de la pin39 alors que Setup() est censé être exécuté qu'une fois à la mise sous tension de la Due

Pour éclaircir le principe de structure du code dont j'ai besoin :
Les temps de commutations ON / OFF peuvent être très rapide lorsque mes actionneurs arriveront et maintiendront la position cible à atteindre. (PID moteur)

Si la pin 39 pilote Forward et la pin 43 pilote Reverse
1) Lors du programme setup les pin 39 (forward) et 43 (reverse) doivent être toutes les 2 en OFF
2) 2 fonctions void Forward() et void Reverse() doivent gérer le sens de rotation
3) Avant de commander Forward, Il faudrait : Reverse = OFF, Dead time  puis Forward en ON
4) Avant de commander Reverse, Il faudrait : Forward = OFF, Dead time  puis Reverse en ON[/quote]
[/quote]


Tfou57

I forgot to specify an important point in my need

Quote
To clarify the structure of the code I need:
The switching times ON / OFF can be very fast when my actuators arrive and will maintain the target position to reach. (Motor PID)

If the Forward pilot pin 39 and the Reverse pilot pin 43
1) During the setup program the pins 39 (forward) and 43 (reverse) must be every 2 in OFF
2) 2 functions void Forward () and void Reverse () must handle the direction of rotation
3) Before ordering Forward, you would need: Reverse = OFF, Dead time then Forward in ON
4) Before ordering Reverse, you would need: Forward = OFF, Dead time then Reverse in ON
Recall :
Direction of rotation of drive 1: Pin 34 (PWM L0) and Pin 35 (PWM H0)
Direction of rotation of drive 2: Pin 36 (PWM L1) and Pin 37 (PWM H1)
Direction of rotation of drive 3: Pin 43 (PWM L2) and Pin 39 (PWM H2)
Direction of rotation of drive 4: Pin 40 (PWM L3) and Pin 41 (PWM H3)
Direction of rotation of drive 5: Pin 08 (PWM L5) and Pin 44 (PWM H5)
Direction of rotation of drive 6: Pin 07 (PWM L6) and Pin 45 (PWM H6)


Additional requirements:

The time in each of the 12 pins (36, 37, 43, 39, 40, 41, 08, 44, 07 and 45) is ON must vary independently of each other and also for pins using the same channel (Time varying from 0 to infinity)?
Is it possible to generate 2 times on the same channel?
If Yes, how do we do it?

The switching time in ON of the 12 pins mentioned must be able to be controlled independently of each other in functions Void of the Arduino code

The switching time in ON of the aforementioned 12 pins is called to vary continuously as a function of the actual position comparison of each actuator with respect to the target position to be executed.

These target values vary continuously depending on the information received by the serial link



J'ai oublié de préciser un point important dans mon besoin


Pour éclaircir le principe de structure du code dont j'ai besoin :
Quote
Les temps de commutations ON / OFF peuvent être très rapide lorsque mes actionneurs arriveront et maintiendront la position cible à atteindre. (PID moteur)

Si la pin 39 pilote Forward et la pin 43 pilote Reverse
1) Lors du programme setup les pin 39 (forward) et 43 (reverse) doivent être toutes les 2 en OFF
2) 2 fonctions void Forward() et void Reverse() doivent gérer le sens de rotation
3) Avant de commander Forward, Il faudrait : Reverse = OFF, Dead time  puis Forward en ON
4) Avant de commander Reverse, Il faudrait : Forward = OFF, Dead time  puis Reverse en ON
Rappel :
Sens de rotation de l'entraînement 1: Pin 34 (PWM L0) et Pin 35 (PWM H0)
Sens de rotation de l'entraînement 2: Pin 36 (PWM L1) et Pin 37 (PWM H1)
Sens de rotation de l'entraînement 3: Pin 43 (PWM L2) et Pin 39 (PWM H2)
Sens de rotation de l'entraînement 4: Pin 40 (PWM L3) et Pin 41 (PWM H3)
Sens de rotation de l'entraînement 5: Pin 08 (PWM L5) et Pin 44 (PWM H5)
Sens de rotation de l'entraînement 6: Pin 07 (PWM L6) et Pin 45 (PWM H6)

Besoins complémentaires :
Le temps pendant chacune les 12 pins (36, 37, 43, 39, 40, 41, 08, 44, 07 et 45) est en ON doit varier indépendamment  l'une de l'autre et également pour des pins utilisant le même canal  (temps variant de 0 à l'infini) ?
Est-ce possible de générer 2 temps sur le même canal ?
Si Oui, comment fait-on ?

Le temps de commutation en ON des 12 pins citées devront pouvoir être commandé indépendamment  l'un de l'autre dans des fonctions Void du code Arduino

Le temps de commutation en ON des 12 pins citées sa appelé à varier en permanence en fonction de la comparaison de position réelle de chaque actionneur par rapport à la position cible à exécuter.

Ces valeurs cibles varient en permanence en fonction d'information reçues par la liaison série.
[/quote]


ard_newbie

Some of Sam3x pins are not broken out on DUE...I just followed the pinout diagram with PWM indications, so you may be right, some PWM outputs are duplicated and available.

A fix for PWML2 output: I did a copy paste for PA20 with PC7, so obviously it should be this for PWML2:

PIOA->PIO_ABSR |= PIO_ABSR_P20;                        // Set PWM pin perhipheral type B

PIOA->PIO_PDR |= PIO_PDR_P20;                          // Set PWM pin to an output


And delay() in loop is useless.

Tfou57

I corrected the 2 lines according to your indications

With PWM-> PWM_CH_NUM [2] .PWM_CDTY = 800000; , As Duty was 80%, I had only a tension around 2.6v and pins 39 and 49 in High (no opposition of the states on pins 39 and 43!)

I did 2 other tests
PWM-> PWM_CH_NUM [2] .PWM_CDTY = 0; The pine 39 is High and the pine 43 Low and without any Dead Time
PWM-> PWM_CH_NUM [2] .PWM_CDTY = 1000000; Pine 39 is Low and Pine 43 High and without any Dead Time

See 2 screenshots
In yellow the pin39 and in blue the pin43

I do not understand how to use your remark at the bottom of your code
Quote
// Alternately, you can use this format: REG_PWM_CPRD2 = 1000000;

I need 3 different states:

1) Pin39 Low and Pin43 Low (after running Setup and when my actuator reached its target)
2) Pin43 Low + Dead Time + Pin39 High (forward rotation)
3) Pin39 Low + Dead Time + Pin43 High (reverse rotation)

Problem with the suggested sample code:
1) Never at the output of the Setup the 2 pins 39 and 43 are in Low
2) No possibility to my knowledge to have the 2 pins 39 and 43 are Low when the target position is reached
3) The Dead Time between High and Low states and vice versa does not work


J'ai corrigé les 2 lignes selon vos indications

Avec PWM->PWM_CH_NUM[2].PWM_CDTY = 800000; , comme Duty était à 80% , je n'avais qu'une tension aux alentours de  2,6v et les pins 39 et 49 en High   (pas d'opposition des états sur les pins 39 et 43 ! )                         

J'ai fait 2 autres essais En mettant
PWM->PWM_CH_NUM[2].PWM_CDTY = 0; la pin 39 est High et la pin 43 Low et sans aucun Dead Time   
PWM->PWM_CH_NUM[2].PWM_CDTY = 1000000; la pin 39 est Low et la pin 43 High et sans aucun Dead Time   

Voir les 2 copies d'écrans
En jaune la pin39 et en bleu la pin43   

Je ne comprends pas comment utiliser votre remarque en bas de votre code
Quote
// Alternately, you can use this format :  REG_PWM_CPRD2 = 1000000; 

J'ai besoin de 3 états différents :

1) Pin39 Low et Pin43 Low (après l'exécution du Setup et lors mon actionneur a atteint sa cible)
2) Pin43 Low + Dead Time + Pin39 High (rotation avant)
3) Pin39 Low + Dead Time + Pin43 High (rotation arrière)

Problème avec le code d'exemple proposé :

1) Jamais en sortie du Setup les 2 pins 39 et 43 sont en Low
2) Pas de possibilité a ma connaissance d'avoir les 2 pins 39 et 43 sont Low lorsque la position cible est atteinte
3) Le Dead Time entre les états High et Low et vice versa ne fonctionne pas

ard_newbie

I did some modifications in the snippet to show that it works :

Code: [Select]

#define DISABLE_SW_PROT (0)
#define ENABLE_SW_PROT  (1)
#define ENABLE_HW_PROT  (2)
#define PASSWD  (0x50574D)

void setup () {

  // PWM Set-up on pins PC7 and PA20 (Arduino Pins 39(PWMH2) and 43(PWML2)): see Datasheet chap. 38.5.1 page 973
  
  
  PMC->PMC_PCER1 |= PMC_PCER1_PID36;                   // PWM power on

  PWM->PWM_WPCR = PWM_WPCR_WPCMD(DISABLE_SW_PROT)
                | PWM_WPCR_WPRG0
                | PWM_WPCR_WPRG1
                | PWM_WPCR_WPRG2
                | PWM_WPCR_WPRG3
                | PWM_WPCR_WPRG4
                | PWM_WPCR_WPRG5
                | PWM_WPCR_WPKEY(PASSWD);                 // Disable PWM write protect

  PWM->PWM_DIS = PWM_DIS_CHID2;                        // Disable PWM channel 2

  // Select Instance=PWM; Signal=PWMH2 (channel 2); I/O Line=PC7 (P7, Arduino pin 39, see pinout diagram) ; Peripheral=B
  PIOC->PIO_PDR |= PIO_PDR_P7;                          // Set PWM pin to an output
 
  PIOC->PIO_ABSR |= PIO_PC7B_PWMH2;                     // Set PWM pin perhipheral type B
  
  // Select Instance=PWM; Signal=PWML2 (channel 2); I/O Line=PA20 (P20, Arduino pin 43, see pinout diagram) ; Peripheral=B
  PIOA->PIO_PDR |= PIO_PDR_P20;                          // Set PWM pin to an output

  PIOA->PIO_ABSR |= PIO_PA20B_PWML2;                    // Set PWM pin perhipheral type B
  
  
  // Enable the PWM channel 2 (see datasheet page 973)

  PWM->PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(42);    // Set the PWM clock rate to 2MHz (84MHz/42). Adjust DIVA for the resolution you are looking for

  PWM->PWM_CH_NUM[2].PWM_CMR = PWM_CMR_CPRE_CLKA;     // The period is left aligned, clock source as CLKA on channel 2

  PWM->PWM_CH_NUM[2].PWM_CPRD = 1000;                             // Channel 2 : Set the PWM frequency 2MHz/(2 * CPRD) = F ;

  PWM->PWM_CH_NUM[2].PWM_CDTY = 500;                             // Channel 2: Set the PWM duty cycle to x%= (CDTY/ CPRD)  * 100 % ;

  // Dead time between 2 complementary PWM H and L, e.g.:
  PWM->PWM_CH_NUM[2].PWM_CMR |= PWM_CMR_DTE;                       // Enable dead time

  /****  Try with (DTH=500, DTL=0) then (DTH=0,DTL=500)  then (DTH=500,DTL=500)****/
  uint32_t DTH = 0;                                                //DTH is between 0 and CPRD - CDTY BUT MAX value = 2 exp13  - 1 = 8191
  uint32_t DTL = 0;                                              //DTL is between 0 and CDTY BUT MAX value = 2exp13 - 1 = 8191
 /**********************************************************/
 
  PWM->PWM_CH_NUM[2].PWM_DT = DTH | DTL << 16;                     // Datasheet chap. 38.6.2.4 page 981 and chap. 38.7.43 page 1051
  
  PWM->PWM_ENA = PWM_ENA_CHID2;

  // Alternately, you can use this format :  REG_PWM_CPRD2 = 1000000;
  

}


void loop() {
    
}






If you want PWMHx and PWMLx LOW together, you need to adjust dead time accordingly.

If you want to modify dead time "on the fly" you need  PWM_DTUPD (refer to the datasheet)

Tfou57

Hello,
I come back to report my progress after several days during which Google Translate and the datasheet pricked my eyes

Thank you for the time you give me to answer my problems.

1) I uploaded your code to 2Khz as is with the duty at 50% with DTH = 0 - DTL = 0
Result: OK none Dead Time car DTH = 0 - DTL = 0

Reminder for interpretation of attachments:
Yellow curve = Pin 39 (PWMH2) and blue curve = Pin 43 (PWML2)

2) I have passed the value of Dead Time at DTH = 10 - DTL = 10 while keeping the Duty at 50%
Result Duty50%: OK the Dead Time of 5μs is visible
(See 3 attachments 50% - DTH = 10 - DTL = 10)

3) Keeping the Dead Time at DTH = 10 - DTL = 10 keeping the Duty at 100%
Duty100% Result: This looks fine: No Dead Time visible because no state change

4) I passed the frequency PWM from 2Khz to 10Khz
Note:
I think the formula used for the PWM frequency is inappropriate because the period is aligned to the left.
I used the following formula F Pwm = MCK / (CPRD * DIVA)
This is confirmed by observing the PWM signal on the oscilloscope
Result: with a frequency at 10Khz and a Duty at 50%, the Dead Time still works
(See 1 attachment Test Code 0 - Tfou57_PWM L et H à 10Khz et Dead Time DTH 10 et DTL 10 soit 05 micros secondes)

Creation of 3 programs containing the combinations of I will meet to control the direction of my drives:
- void P39_LOW_and_P43_LOW ()
- void P39_HIGH_and_P43_LOW ()
- void P39_LOW_and_P43_HIGH ()
Loop () adds 3 "for" loops of different duration for each of the 3 "Void" functions


My working code See 1 attachment


Problem: "Dead Time" does not work on this code
The "Dead Time" causes me problems when running my 3 programs "Void" used loop in "Loop" and each with different loop lengths

Question 1:
How to set up a 10μs Dead Time between each pins state changeover 39 and 43?
Does the Dead Time have to resume all lines of code in Setup ()?
I need a fastest code with a minimum of code line to best manage the PID of the engines

Question 2:
How can the above code be optimized
- I may have lines repeated unnecessarily apart of course deleting all lines of duplicate code comments

Question 3:
- Tables management of the 2 pins of direction for each of the 6 engines to facilitate the scructure of the final code (management of 12 pins)


Texte original :
Bonjour,
Je reviens faire part de mon avancement après plusieurs jours pendant lesquels Google Translate et le datasheet me piquaient les yeux

Merci pour le temps que vous m'accordez pour répondre à mes problèmes.
1) J'ai téléversé votre code à 2Khz tel quel avec le duty à 50% avec DTH=0 - DTL=0
Résultat : OK aucune Dead Time car DTH=0 - DTL=0

Rappel pour interprétation des pièces jointes:
Courbe jaune = Pin 39 (PWMH2) et courbe bleu = Pin 43 (PWML2)


2) J'ai passé la valeur de Dead Time à DTH=10 - DTL=10 en gardant le Duty à 50%
Résultat Duty50% : OK le Dead Time de 5µs est visible
(voir 3 pièces jointes 50% - DTH=10 - DTL=10)

3) En gardant le Dead Time à DTH=10 - DTL=10 en gardant le Duty à 100%
Résultat Duty100% : Cela semble correct : Aucun Dead Time visible car pas de changement d'état

4) J'ai passé la fréquence PWM de 2Khz à 10Khz
Nota :
Je pense que la formule utilisée pour la fréquence PWM est non appropriée car la période est alignée à gauche.
J'ai utilisé la formule suivante F Pwm =  MCK /(CPRD * DIVA)
Cela se vérifie à l'observation du signal PWM à l'oscilloscope
Résultat : avec une fréquence à 10Khz et un Duty à 50%, le Dead Time fonctionne toujours
( voir 1 pièce jointe Test Code 0 - Tfou57_PWM L et H à 10Khz et Dead Time DTH 10 et DTL 10 soit 05 micros secondes)

Création de 3 programmes reprenant les combinaisons de je vais rencontrer pour commander le sens de mes variateurs :
- void P39_LOW_and_P43_LOW()
- void P39_HIGH_and_P43_LOW()
- void P39_LOW_and_P43_HIGH()
Rajout dans Loop() de 3 boucles « for » d'une durée différente pour chacune des 3 fonctions « Void »

Mon code de travail ( voir pièce jointe)

Problème : « Dead Time »ne fonctionne pas sur ce code

Le « Dead Time » me pose des problèmes lors de l'exécution de mes 3 programmes « Void « utilisés en boucle dans « Loop » et chacun avec des longueurs de boucle différentes

Question 1:
Comment mettre en place une Dead Time de 10µs entre chaque basculement d'état des pins 39 et 43 ?
Faut-il pour fonctionner le Dead Time reprendre toutes les lignes de code du Setup() ?Il me faut un code le plus rapide avec un minimum de ligne de code afin gérer au mieux le PID des moteurs

Question 2:
Comment le code ci-dessus peut-il être optimisé
- J'ai peut-être des lignes répétées inutilement à part bien sûr la suppression de toutes les lignes de code en doubles mises en commentaires

Question 3:
- Gestion par  tableaux des 2 pins de direction pour de chacun des 6 moteurs afin de faciliter la scructure du code final (gestion de 12 pins)





Tfou57

The signal obtained by the code is not regular over time.

I can observe high and low state width variations depending on the trigger of the oscilloscope trigger (variations of pin 43 High blue curve - up to 37μs)

On this screenshot, I also observe 2 areas with the pine 39 High (yellow curve) for no reason for a duration of 40μs left and 16μs in the center of the screenshot
Delay of pine 39 to change to LOW state

Do you have a correction to offer me for
1) Restore a cyclic regularity of the Loop loop ()
2) To activate the Dead Time between each state change (High and Low)

All ideas will be the goods that came

see Attachment


Le signal obtenu par le code n'est pas régulier dans le temps .

Je peux observer des variations de largeur d'état High et Low selon le déclenchement du trigger de l'oscilloscope ( variations de pin 43 High  courbe bleu - allant jusqu'à 37µs)

Sur cette copie d'écran ,j'observe également des 2 zones parasistes avec la pin 39 High ( courbe jaune ) sans raison durant une durée de 40µs à gauche et de 16µs au centre de la capture d'écran
Retard de la pin 39 à passer à l'état LOW

Avez vous une correction à me proposer pour
1 ) Rétablir une régularité cyclique du fonctionnent de la boucle Loop()
2)  Pour activer le Dead Time entre chaque changement d'état ( High et Low)

Toute les idées seront les biens venues

voir pièce jointe




ard_newbie



Some thoughts and précisions :

Chap. 38.6.2.2 page 978

…This channel parameter is defined in the CPRD field of the PWM_CPRDx register.
If the waveform is left aligned, then the output waveform Frequency depends on the counter source clock and can be calculated:

Mck / (CPRD * DIVA)


Chap. 38.7.37 page 1044

CALG bit = 0 : The period is left aligned


PWM->PWM_CH_NUM[2].PWM_CPRD = 1000;
Channel 2 : Set the PWM frequency 2MHz/(2 * CPRD) = F AND 0<= CPRD<= 2exp16  -1 = 65535


PWM->PWM_CH_NUM[2].PWM_CDTY = 500;                            
Channel 2: Set the PWM duty cycle to x%= (CDTY/ CPRD)  * 100 % AND 0<= CDTY <= CPRD AND 2exp16  -1 = 65535


uint32_t DTH = 500;
DTH is between 0 and CPRD - CDTY BUT MAX value = 2 exp13  - 1 = 8191
uint32_t DTL = 500;
DTL is between 0 and CDTY BUT MAX value = 2exp13 - 1 = 8191


As I understand PWM datasheet section, once you have set dead time in your setup() function, you can update dead time ONLY by using PWM_DTUPD  while channel is enabled (idem for PWM_CPRDUPD and PWM_CDTYUPD ) :

38.6.5.3 Changing the Duty-Cycle, the Period and the Dead-Times page 997 (i.e. in void loop()  or PWM_Handler())

Use PWM_CDTYUPDx, PWM_CPRDUPDx and PWM_DTUPDx to change waveform parameters while the channel is still enabled.

If the channel is an asynchronous channel (SYNCx = 0 in "PWM Sync Channels Mode register"
(PWM_SCM)), these registers hold the new period, duty-cycle and dead-times values until the end of the current PWM period and update the values for the next period.


Go Up