Go Down

Topic: [solved]PWM inittiation on registers (Read 2446 times) previous topic - next topic

lolakr

May 10, 2017, 06:12 pm Last Edit: May 17, 2017, 02:29 pm by lolakr
Hello all,
I have read many topics but none of them suited me 100%.
On most topics there are plenty of lines of code that (probably) I do not need.
I would like to get PWM signal with 12 bit resolution and a 100kHz frequency on pin 3.
How to do it in the simplest way?
I do not mean to modify the variant.h file.

Please help and greet :)

ard_newbie


A few thoughts:

For a 100 KHz frequency, with the Timer Counter controller, the max resolution will be 42MHZ/100KHz = 420, and with a PWM(H or L) the max resolution will be 84MHz/100KHz = 840 ---> far from a 12 bit resolution = 2 exp12 = 4096.

The second point is that Arduino pin 3 is TIOA7 ---> It is the output of the Timer Counter 2 channel1 (TC7) limited to a max resolution of 420.

lolakr

So it is impossible? I thought that the Arduino Due is a very powerful - in arduino uno (atmega328) its no problem to make pwm 10bit about 65kHz. Maybe on another pin ?

ard_newbie


in arduino uno (atmega328) its no problem to make pwm 10bit about 65kHz.
I don't think so. 10-bit resolution gives you 2 exp10 = 1024, and 16 MHz/1024 = 15625 Hz, far from 65 KHz.

The main point to consider is the precision you need. With a DUE, and a PWM frequency of 100 KHz, your duty will be programmable in a range between 0 and 840. The PWM_CDTY register is a 23_bit register, although only the first 16-bit are significant, AND 0<PWM_CDTY<PWM_CPRD = 840 in this example.

See Sam3x datasheet page 1046.

lolakr

Ok, I understand.

I don't think so. 10-bit resolution gives you 2 exp10 = 1024, and 16 MHz/1024 = 15625 Hz, far from 65 KHz.
Sorry for this mistake. This value probably was related to the ADC.

So I have to reduce the frequency or resolution?
Maybe new example ~82kHz and 10bit resolution. Now it is correct with the equation.
What is the diffrence of PWM(H or L) and what is the difference with PWM and Timer Counter controller ?

ard_newbie


The most obvious difference is that the Timer Counter controller produces PWM pulses thru TIOAx/TIOBx pins and the PWM controller produces PWM pulses thru PWMHx/PWMLx pins (see pinout diagram).

There are important differences, e.g.: the TC controller provides a quadrature decoder feature and the PWM controller has a synchro feature.

Read (several times) Timer Counter and PWM sections of Sam3x datasheet.







lolakr

This is over 50 pages but I will try as long as necessary :)
Sam3x8 is a very powerful uC and I did not expect so many possibilities of configuration.
So far, I have come up with something like that:
Quote
PWM->PWM_CLK = 0x10001;
PWM->PWM_CPRD0 = 1024;
PWM->PWM_CDTY0 = 0;
PWM->PWM_ENA = 1;
Is it a good way? Please help, it is not easy for a beginner :)

ard_newbie


Header files for all peripherals are included in your IDE, it is much better to use them rather than magic numbers.

For every peripheral you are using, you need first to power on, then (for safety) you disable the part of the peripheral you will be using, then you set all registers according to your requirements, and finally you enable the part of the peripheral you selected.

As an example, I choose PWML2 that you can find on your pinout diagram on arduino pin 43.
I selected a 100 KHz frequency (note that you have several possibilities to achieve this frequency depending on the divisor DIVA), I selected a duty cycle of 50%.

Code: [Select]

/*******************************************************************************/
/*          PWML2 on Arduino pin 43 - F = 100 KHz , Duty cycle = 50%           */
/******************************************************************************/

void setup () {
 
  // Datasheet page 973
  // Select Instance=PWM; Signal=PWML2 (channel 2); I/O Line=PA20 (P20, Arduino pin 43, see pinout diagram) ; Peripheral=B
  PMC->PMC_PCER1 |= PMC_PCER1_PID36;                    // PWM power on , see datasheet page 38
 
  PWM->PWM_DIS = PWM_DIS_CHID2;         // Disable PWM channel 2

  // Select Instance=PWM; Signal=PWML2 (channel 2); I/O Line=PA20 (P20, Arduino pin 43, see pinout diagram) ; Peripheral=B
  PMC->PMC_PCER0 |= PMC_PCER0_PID11;                    // PIOA power on
 
  PIOA->PIO_PDR |= PIO_PDR_P20;                         // The GPIO don't drive the pin, this is the peripheral

  PIOA->PIO_ABSR |= PIO_ABSR_P20;                       // Set PWM pin perhipheral type B , datasheet page 974

  // Set registers for PWM channel 2
  PWM->PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(1);    // Set the PWM clock rate to 84MHz (84MHz/1). 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 = 840;                  // Channel 2 : Set the PWM frequency (84MHz/1)/PWM_CPRD = 100KHz ;

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

  PWM->PWM_ENA = PWM_ENA_CHID2;

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

}


void loop() {
 
}





lolakr

#8
May 13, 2017, 11:11 pm Last Edit: May 13, 2017, 11:17 pm by lolakr
Thank you very much :)
What if I want to simultaneously use PWML2 PWMH2? Are they dependent?
And if I wanted to use another pwm channel should it look like that:
Code: [Select]
void setup () {
 
  // Datasheet page 973
  // Select Instance=PWM; Signal=PWML2 (channel 2); I/O Line=PA20 (P20, Arduino pin 43, see pinout diagram) ; Peripheral=B
  PMC->PMC_PCER1 |= PMC_PCER1_PID36;                    // PWM power on , see datasheet page 38
 
  PWM->PWM_DIS = PWM_DIS_CHID2;         // Disable PWM channel 2

  // Select Instance=PWM; Signal=PWML2 (channel 2); I/O Line=PA20 (P20, Arduino pin 43, see pinout diagram) ; Peripheral=B
  PMC->PMC_PCER0 |= PMC_PCER0_PID11;                    // PIOA power on
 
  PIOA->PIO_PDR |= PIO_PDR_P20;                         // The GPIO don't drive the pin, this is the peripheral

  PIOA->PIO_ABSR |= PIO_ABSR_P20;                       // Set PWM pin perhipheral type B , datasheet page 974

  // Set registers for PWM channel 2
  PWM->PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(1);    // Set the PWM clock rate to 84MHz (84MHz/1). 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 = 840;                  // Channel 2 : Set the PWM frequency (84MHz/1)/PWM_CPRD = 100KHz ;

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

  PWM->PWM_ENA = PWM_ENA_CHID2;

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


PWM->PWM_DIS = PWM_DIS_CHID3; 
// Select Instance=PWM; Signal=PWMH3 (channel 3); I/O Line=PA9
PIOA->PIO_PDR |= PIO_PDR_PA9;
PIOA->PIO_ABSR |= PIO_ABSR_PA9;
PWM->PWM_CH_NUM[3].PWM_CMR = PWM_CMR_CPRE_CLKA;
PWM->PWM_CH_NUM[3].PWM_CPRD = 840;
PWM->PWM_CH_NUM[2].PWM_CDTY = 420;
PWM->PWM_ENA = PWM_ENA_CHID3;


And now when I want to modify duty cycle in loop() i have to change only this ? e.g.
PWM->PWM_CH_NUM[2].PWM_CDTY = 300;

ard_newbie


You can use simultaneously PWMHx/PWMLx provided you set properly the I/O lines.

Your code for PWMH3 seems correct, although you choose PA9 which is the TX0 for Serial (RX/TX). Better choose e.g. PC9, Arduino pin 42.

Writing in PWM_CDTYx register is possible while the channel is disabled. After validation of the channel, you must use PWM_CDTYUPDx register to update the duty cycle  idem for CPRD with PWM_CPRDUPDx.

lolakr

Code: [Select]
void setup () {
 
  // Datasheet page 973
  // Select Instance=PWM; Signal=PWML2 (channel 2); I/O Line=PA20 (P20, Arduino pin 43, see pinout diagram) ; Peripheral=B
  PMC->PMC_PCER1 |= PMC_PCER1_PID36;                    // PWM power on , see datasheet page 38
 
  PWM->PWM_DIS = PWM_DIS_CHID2;         // Disable PWM channel 2

  // Select Instance=PWM; Signal=PWML2 (channel 2); I/O Line=PA20 (P20, Arduino pin 43, see pinout diagram) ; Peripheral=B
  PMC->PMC_PCER0 |= PMC_PCER0_PID11;                    // PIOA power on
 
  PIOA->PIO_PDR |= PIO_PDR_P20;                         // The GPIO don't drive the pin, this is the peripheral

  PIOA->PIO_ABSR |= PIO_ABSR_P20;                       // Set PWM pin perhipheral type B , datasheet page 974

  // Set registers for PWM channel 2
  PWM->PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(1);    // Set the PWM clock rate to 84MHz (84MHz/1). 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 = 1024;                  // Channel 2 : Set the PWM frequency (84MHz/1)/PWM_CPRD = 100KHz ;

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

  PWM->PWM_ENA = PWM_ENA_CHID2;

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


PWM->PWM_DIS = PWM_DIS_CHID3;
// Select Instance=PWM; Signal=PWMH3 (channel 3); I/O Line=PC9
 PMC->PMC_PCER0 |= PMC_PCER0_PID13;
PIOC->PIO_PDR |= PIO_PDR_P9;
PIOC->PIO_ABSR |= PIO_ABSR_P9;
    // Set the PWM clock rate to 84MHz (84MHz/1). Adjust DIVA for the resolution you are looking for

PWM->PWM_CH_NUM[3].PWM_CMR = PWM_CMR_CPRE_CLKA;
PWM->PWM_CH_NUM[3].PWM_CPRD = 1024;
PWM->PWM_CH_NUM[3].PWM_CDTY = 0;
PWM->PWM_ENA = PWM_ENA_CHID3;
}
void loop() {
  // put your main code here, to run repeatedly:
  for (int i =0 ; i<1024;i++)
  {
  REG_PWM_CDTYUPD2=i;
  REG_PWM_CDTYUPD3=i;
  delay(50);
  }
}


I started this code and the signal on PA9 is inverted relative to PA20 and on PC9 there is no signal. Where did I make a mistake?

ard_newbie

#11
May 14, 2017, 05:23 pm Last Edit: May 14, 2017, 06:05 pm by ard_newbie
You first enable PWM channel 2 with PWM->PWM_ENA = PWM_ENA_CHID2; then you enable PWM channel 3 with PWM->PWM_ENA = PWM_ENA_CHID3; Therefore channel 2 is no more enable !!

Edit : your sketch works fine, code is correct !!




lolakr

I'm not sure. Because of channel 2 is disabled it should not be signal on PA20?
In order to rapair this I should change this
Code: [Select]
PWM-> PWM_ENA = PWM_ENA_CHID3;
to
Code: [Select]
PWM-> PWM_ENA | = PWM_ENA_CHID3; ?
Why there are inverted?
I wanted to do 2 non-inverted,Independent channels on PA20 and PC9.

ard_newbie


PWM High  x is the invert of PWM Low x. When the output of PWMH2 = 1, the output of PWML2 = 0.

If you want two non inverted signals, select e.g. PWMH2 (pin 39) and PWMH3 (pin 41) with  same clock divisor and prescaler.

lolakr

So there is no way to set PWMH 1 to a 30% duty cycle and PWML1 to 30% duty cycle in the same time?
And when I set:
Code: [Select]
PWM_CPRD = 1024;
PWM_CDTY = 256;
25% duty cycle
for PWMH it mean 25% LOW , 75% HIGH
When it's PWML its 25% HIGH, 75% LOW?

Go Up