Go Down

Topic: Generating 1 MHZ PWM on Due (Read 1 time) previous topic - next topic

kmahapatra

I need to be able to create a >1 MHZ Signal using the Arduino due. I have very little experience with Arduinos, but I read the article at
https://www.arduino.cc/en/Tutorial/SecretsOfArduinoPWM
Using the following code:

void setup() {
  pinMode(3, OUTPUT);
TCCR2A = 0x23;
TCCR2B = 0x09;
OCR2A = 3;
OCR2B = 1;
}

void loop () {
 
}


ard_newbie


You have several ways to generate a PWM pulse:

- For a fixed 50% duty cycle, you can use PMC_PCKx up to 480 MHz
- For different duty cycles, you can use either Timer Counters (section 36 of Sam3x datasheet), or PWMHx/Lx (section 38 of Sam3x datasheet).

See below a snippet to generate a 1 MHz PWM with a 50% duty cycle:

Code: [Select]

/******************************************************************************/
/***               1MHz/ 50% Duty cycle PWM thru TIOA0                      ***/
/******************************************************************************/

void setup() {

/*************  Timer Counter 0 Channel 0 to generate PWM pulses thru TIOA0  ************/
  PMC->PMC_PCER0 |= PMC_PCER0_PID27;                      // Timer Counter 0 channel 0 IS TC0, TCO power ON
  PMC->PMC_PCER0 |= PMC_PCER0_PID12;                      // PIOB power ON, page 38
 
  PIOB->PIO_PDR |= PIO_PDR_P25;
  PIOB->PIO_ABSR |= PIO_ABSR_P25;                        // PB25 is driven by the TC, peripheral type B, page 858

  TC0->TC_CHANNEL[0].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK1  // MCK/2, clk on rising edge
                              | TC_CMR_WAVE               // Waveform mode
                              | TC_CMR_WAVSEL_UP_RC        // UP mode with automatic trigger on RC Compare
                              | TC_CMR_ACPA_CLEAR          // Clear TIOA0 on RA compare match
                              | TC_CMR_ACPC_SET;           // Set TIOA0 on RC compare match


  TC0->TC_CHANNEL[0].TC_RC = 42;  //<*********************  Frequency = (Mck/2)/TC_RC  = 1 MHz
  TC0->TC_CHANNEL[0].TC_RA = 21;  //<********************   Duty cycle = (TC_RA/TC_RC) * 100 = 50 %

  TC0->TC_CHANNEL[0].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Software trigger TC0 counter and enable

}

void loop() {
 
}





alimzia

You have several ways to generate a PWM pulse:

- For a fixed 50% duty cycle, you can use PMC_PCKx up to 480 MHz
- For different duty cycles, you can use either Timer Counters (section 36 of Sam3x datasheet), or PWMHx/Lx (section 38 of Sam3x datasheet).

See below a snippet to generate a 1 MHz PWM with a 50% duty cycle:

Code: [Select]

/******************************************************************************/
/***               1MHz/ 50% Duty cycle PWM thru TIOA0                      ***/
/******************************************************************************/

void setup() {

/*************  Timer Counter 0 Channel 0 to generate PWM pulses thru TIOA0  ************/
  PMC->PMC_PCER0 |= PMC_PCER0_PID27;                      // Timer Counter 0 channel 0 IS TC0, TCO power ON
  PMC->PMC_PCER0 |= PMC_PCER0_PID12;                      // PIOB power ON, page 38
 
  PIOB->PIO_PDR |= PIO_PDR_P25;
  PIOB->PIO_ABSR |= PIO_ABSR_P25;                        // PB25 is driven by the TC, peripheral type B, page 858

  TC0->TC_CHANNEL[0].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK1  // MCK/2, clk on rising edge
                              | TC_CMR_WAVE               // Waveform mode
                              | TC_CMR_WAVSEL_UP_RC        // UP mode with automatic trigger on RC Compare
                              | TC_CMR_ACPA_CLEAR          // Clear TIOA0 on RA compare match
                              | TC_CMR_ACPC_SET;           // Set TIOA0 on RC compare match


  TC0->TC_CHANNEL[0].TC_RC = 42;  //<*********************  Frequency = (Mck/2)/TC_RC  = 1 MHz
  TC0->TC_CHANNEL[0].TC_RA = 21;  //<********************   Duty cycle = (TC_RA/TC_RC) * 100 = 50 %

  TC0->TC_CHANNEL[0].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Software trigger TC0 counter and enable

}

void loop() {
 
}





I have so many questions. I have a tiny bit of experience with atmega avr, however none when it comes to the Atsam ARM. (Using a DUE)

You said up to 480 MHz frequency could be generated by PMC_PCKx, did you mean 48MHz? And how come you didn't use this method for the example of 1Mhz PWM?

Would setting the counters this way disable the functions delay() and millis()? In Atmega88p these functions are controlled by TC0 and so changing anything with TC0 would disable them, however, changing the other timers has no influence on these functions. Is it the same with my DUE as well?

ard_newbie

#3
Feb 13, 2019, 01:44 pm Last Edit: Feb 13, 2019, 01:44 pm by ard_newbie
In fact, PMC_PCKx allows you to output one of the internal clocks divided by a prescaler, and re-reading the datasheet, the maximum frequency output can be 480 MHz/2 = 240 MHz. Note that 480 MHz is the frequency needed by USB 2.0 High speed (see page 552, Sam3x datasheet).

To output a 1 MHz frequency, it should be more convenient to use a Timer Counter or a PWM channel. In either cases, search in the DUE sub forum for example sketches, or use TC-lib or PWM-lib from antodom.





antodom

Hi there,

The Arduino DUE's ATSAM3X8E micro-controller has its own PWM channels, in order to generate PWM signals without using any of the timers available in the micro-controller. Thus, there is no any conflicts with millis() or delay().

For generating a 1 MHz PWM signal, you can use pwm_lib (available at https://github.com/antodom/pwm_lib). This is a library which allows you to genereate PWM signals using those channels, concretely the eight PMW channels available in the ATSAM3X8E. Have a look to the documentation and the examples which come with the library. This is an open source library, so you are also free to have a look to the code, if what you prefer is doing things at low level.

I hope it helps.
------------
antodom

alimzia

In fact, PMC_PCKx allows you to output one of the internal clocks divided by a prescaler, and re-reading the datasheet, the maximum frequency output can be 480 MHz/2 = 240 MHz. Note that 480 MHz is the frequency needed by USB 2.0 High speed (see page 552, Sam3x datasheet).

To output a 1 MHz frequency, it should be more convenient to use a Timer Counter or a PWM channel. In either cases, search in the DUE sub forum for example sketches, or use TC-lib or PWM-lib from antodom.

Hey thanks for your reply. I am aware of prescalers, but isn't the main clock (and the other internal clocks) of the DUE clocked at 84Mhz max?

Hi there,

The Arduino DUE's ATSAM3X8E micro-controller has its own PWM channels, in order to generate PWM signals without using any of the timers available in the micro-controller. Thus, there is no any conflicts with millis() or delay().

For generating a 1 MHz PWM signal, you can use pwm_lib (available at https://github.com/antodom/pwm_lib). This is a library which allows you to genereate PWM signals using those channels, concretely the eight PMW channels available in the ATSAM3X8E. Have a look to the documentation and the examples which come with the library. This is an open source library, so you are also free to have a look to the code, if what you prefer is doing things at low level.

I hope it helps.
Thanks Ill have a look!

Go Up