Pages: [1]   Go Down
Author Topic: ~10MHz clock generation with the Due  (Read 1306 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

I am trying to have ~10-MHz output clock from the Due board for my sensor boards.

Is there way to divide the main clock, and use the divided clock  as an output.
Since the clock for the Due 84 MHz, divide-by 8 will give 10.5MHz (84M/8).
(I guess PWM frequency is much lower than 10MHz.)

I will appreciate any suggestions.
Thanks,
Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 42
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

PWM will work!
It goes well above 10MHz depending on the clock divider you choose for the PWM channel
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi schwingkopf,

Thanks for the reply.
Could you be more specific for the registers I need to adjust ?
or which .h file should I look into?

http://arduino.cc/en/Tutorial/SecretsOfArduinoPWM
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have tried to change PWM_FREQUENCY to different values in "variant.h".

It does work at low freq. (10s of KHz).
However, It won't go above 1MHz. --- the PWM pins does not produce rectangular pulse on a scope.

With a simple error probe, an error message is obtained below.
 Serial.print("PWM_FREQUENCY, ");
 Serial.println(PWM_FREQUENCY);

VARIANT_MCKassertion "frequency < mck" failed: file "../source/pwmc.c", line 107, function: FindClockConfiguration
Exiting with status 1.

I guess I need to set the divider property for a specific pin, that support a high clock.

Any suggestions..?
Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 42
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

don't change anything in the variant.h file.. all can be done in your sketch code.

To use PWM on the DUE there are two ways. First one is using the general purpose timer counter (TC) channels and the second one is using the internal PWM functionality of the SAM3X8E. Both of them work equally fine but you need to modify different registers in the two cases. Here is some code that uses the internal PWM channels:

Quote
int32_t mask_PWM_pin = digitalPinToBitMask(7);
REG_PMC_PCER1 = 1<<4;               // activate clock for PWM controller
REG_PIOC_PDR |= mask_PWM_pin;  // activate peripheral functions for pin (disables all PIO functionality)
REG_PIOC_ABSR |= mask_PWM_pin; // choose peripheral option B   
REG_PWM_CLK = 0;                     // choose clock rate, 0 -> full MCLK as reference 84MHz
REG_PWM_CMR6 = 0<<9;             // select clock and polarity for PWM channel (pin7) -> (CPOL = 0)
REG_PWM_CPRD6 = 8;                // initialize PWM period -> T = value/84MHz (value: up to 16bit), value=8 -> 10.5MHz
REG_PWM_CDTY6 = 4;                // initialize duty cycle, REG_PWM_CPRD6 / value = duty cycle, for 8/4 = 50%
REG_PWM_ENA = 1<<6;               // enable PWM on PWM channel (pin 7 = PWML6)

The code enables PWM with a frequency of 10.5MHz and a duty cycle of 50% on digital pin number 7. The code like it is only works for this pin. If you want to change the pin, you have to check in the pinout diagramm for the pins labeled PWMHx or PWMLx and go through the section for PWM in the datasheet to set the good registers. I can help you with that if needed.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi schwingkopf,

It works like a charm !
Would you mind telling me which documents should I dig up for all those registers and settings?

The code I googled below won't work when I change the value of REG_PWM_CPRD0 from 5000 (works OK), to 500.
Many thanks..


 
Quote
   // Let's say we want to configure PWM channel 0, PWML0 which is on pin34 Due board, and corresponds to the port C.2
    // First the peripheral must be activated instead off the general GPIO
    REG_PIOC_PDR = 4;
    // Moreover it's peripheral B (not A), which means we have to change PIO_ABSR[2]
    REG_PIOC_ABSR = REG_PIOC_ABSR | 4;
    // Now concerning PWM settings...
    // activation of the clock dedicated to PWM peripheral (id36), which is fifth bit of PMC_PCSR1
    REG_PMC_PCER1 = REG_PMC_PCER1 | 16;
    // activation of PWM_ENA register with channel 0
    REG_PWM_ENA = REG_PWM_SR | 1;
    // setting the period (which can take any 16 bit value...)
    REG_PWM_CPRD0 = 500;
    // note : with this 5000 setting, we have thus 1/5000 resol, with a frequency of 16khz, if we use the defaut main clock : that's good
    // Finally, setting the duty cycle to the value you want (between 0 and the period, of course)
    REG_PWM_CDTY0 = 1000;
    // And here we can check at the oscilloscope that we get a nice PWM on pin 34, with a period of 60usec... nice!
Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 42
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

First of all, when you want to change the values in the registers REG_PWM_CPRD0 and REG_PWM_CDTY0 during your programm code, you need to use REG_PWM_CPRDUPD0 and REG_PWM_CDTYUPD0 to update the values (the direct write to the registers works only once, for initialization).

The way PWM works in principle is that you have one register that counts clock cycles. It counts up until a cerntain value is hit that is written in a compare register (here REG_PWM_CDTY0), then the state of your output pin gets inverted. Then the counter continues to count until the value of a second register is hit (here REG_PWM_CPRD0), inverts again the state of the output pin and resets your counter. Then everything starts again.

This creates a signal that has a total period given by the value in the REG_PWM_CPRD0 register. During this full period, there is the choice after how many clock cycles the output state should toggle (which determines the duty cycle), that is given by the value in REG_PWM_CDTY0. Therefore, if the value in REG_PWM_CDTY0 is larger than the one in REG_PWM_CPRD0, the output state never toggles and you have a constant signal.

This is why setting "REG_PWM_CPRD0 from 5000  to 500." doesnt work as long as you dont change the duty cycle register to something below 500 (to 250 for 50% duty cycle). So if you want a 50% duty cycle PWM the value in CPRD should always be twice as large as the one in CDTY. With the value in CPRD you set the PWM period because it simply determines how many clock cycles should be counted during one PWM period.

You can read more about this in chapter 39 in the datasheet of the SAM3X8E. (http://www.atmel.com/Images/doc11057.pdf)
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi schwingkopf,
Thank for the clear explanation and the document.
It is very helpful
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 1
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

int32_t mask_PWM_pin = digitalPinToBitMask(7);
REG_PMC_PCER1 = 1<<4;               // activate clock for PWM controller
REG_PIOC_PDR |= mask_PWM_pin;  // activate peripheral functions for pin (disables all PIO functionality)
REG_PIOC_ABSR |= mask_PWM_pin; // choose peripheral option B    
REG_PWM_CLK = 0;                     // choose clock rate, 0 -> full MCLK as reference 84MHz
REG_PWM_CMR6 = 0<<9;             // select clock and polarity for PWM channel (pin7) -> (CPOL = 0)
REG_PWM_CPRD6 = 8;                // initialize PWM period -> T = value/84MHz (value: up to 16bit), value=8 -> 10.5MHz
REG_PWM_CDTY6 = 4;                // initialize duty cycle, REG_PWM_CPRD6 / value = duty cycle, for 8/4 = 50%
REG_PWM_ENA = 1<<6;               // enable PWM on PWM channel (pin 7 = PWML6)

I would like to use this in my code, but I'm not quite sure how to integrate.  Should I put it in setup(), loop(), global?  Simply put, I just want to get a 10 MHz PWM on a pin (preferably one of 10-13).  I just don't quite understand how to bring this code snippet into my code in order to get that PWM signal.  Could someone help me with this?
« Last Edit: November 30, 2013, 12:40:35 pm by krkelly » Logged

Pages: [1]   Go Up
Jump to: