Go Down

### Topic: Arduino Due What is the MCK (master clock) precision ? (Read 1 time)previous topic - next topic

#### Bisiaux

##### Aug 14, 2017, 08:08 pm
Hi,

I think about buying an Arduino Due for an inertial motorbike power bench. It's in fact a big roll (around 500 kg) that a bike accelerates... and measuring its acceleration, since we know its inertia, we can compute the power applied by the wheel of the motorbike.

I would need to know how precise is the Master Clock (MCK) of the Due, in ppm or % ?
I would need a precision of at least 0.1 % or better 0.01% (and to be sure of this precision)

I thank you a lot for your help,

Ulysse

#### Bisiaux

#1
##### Aug 14, 2017, 09:44 pm
I also have a second question, I wanted to be sure of the following thing:
- with an Arduino Due it's not possible to use an external clock input for timer, isn't it ?

#### ard_newbie

#2
##### Aug 15, 2017, 08:41 am

The new version of Arduino DUE has an external crystal, unlike the previous ones which have or not the external crystal. This external crystal is more precise than the internal RC oscillator, however even the external crystal is not as stable as a temperature compensated oscillator.

See section PMC of Sam3x datasheet for uc capability to use an external clock input.

#### Bisiaux

#3
##### Aug 16, 2017, 08:38 am
Hi,

Thank's for your answer. It seems that when using peripheral clock for timers, this external clock has to have a 2.5 lower freqeuncy than the peripheral one.
Do I say something wrong by saying : epriphal clock can be set to main clock (Figure 28-2. page 527) with:
- CSS = MAINCK
- PRES = 1

So could it be correct to plug a TCX0 on XC0 pin to increment Timer0 with a 1/MCK period ? (in fact I would need a lower period, around 1/1MHz)

I thank you again for your precious help !

#### Bisiaux

#4
##### Aug 16, 2017, 08:43 am
Sorry, I forgot the link (Figure 28-2. page 527 of this datasheet) :
http://www.atmel.com/Images/Atmel-11057-32-bit-Cortex-M3-Microcontroller-SAM3X-SAM3A_Datasheet.pdf

#### ard_newbie

#5
##### Aug 16, 2017, 05:13 pm

It seems that you would need a Timer Capture (See section 36.6.7 page 863 ).

You will find some examples of timer capture codes in the DUE sub-section of this forum.

#### Bisiaux

#6
##### Aug 16, 2017, 06:49 pm
Hey again,

I found the Due section but isn't it possible to make a research in this to find subjects speaking of Timer Capture ? I am quite new to the forum and surprised not to find this possibility in fact

#### ard_newbie

#7
##### Aug 16, 2017, 08:26 pm

Here is an example of a Timer Capture to detect frequency and duty cycle of a PWM signal:

Code: [Select]
`// a jumper needs to be installed between pin 7 (PWM output) and pin A7 (TC0 channel 1 TIOA pin)volatile uint32_t CaptureCountA, CaptureCountB, Period, Duty, TimerCount;volatile boolean CaptureFlag;void setup() {  Serial.begin(250000);                                   // initilize serial port to 250000 baud  analogWriteResolution(12); // From 0 to 2exp12  - 1 = 4095  analogWrite(7, 1024);                                   // Duty cycle is 25% with 12 bits resolution  PMC->PMC_PCER0 |= PMC_PCER0_PID28;                      // Timer Counter 0 channel 1 IS TC1  TC0->TC_CHANNEL[1].TC_CCR = TC_CCR_CLKDIS ;            // disable internal clocking while setup regs  TC0->TC_CHANNEL[1].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK1 // capture mode, MCK/2, clk on rising edge                              | TC_CMR_ABETRG              // TIOA is used as the external trigger                              | TC_CMR_LDRA_RISING         // load RA on rising edge of trigger input                              | TC_CMR_LDRB_FALLING;       // load RB on falling edge of trigger input  TC0->TC_CHANNEL[1].TC_IER |= TC_IER_LDRAS | TC_IER_LDRBS; // Trigger interruption on Load RA and load RB  TC0->TC_CHANNEL[1].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Software trigger and enable  //NVIC_DisableIRQ(TC1_IRQn);  //NVIC_ClearPendingIRQ(TC1_IRQn);  //NVIC_SetPriority(TC1_IRQn, 0);                      // Give TC1 interrupt the highest urgency  NVIC_EnableIRQ(TC1_IRQn);                           // Enable TC1 interrupts  Serial.println("Timer Capture begins");}void loop() {  if (CaptureFlag) {    CaptureFlag = 0;   }}void TC1_Handler() {   static uint32_t _CaptureCountA = 0;  //Registers A and B (RA and RB) are used as capture registers. They are loaded with  //the counter value TC_CV when a programmable event occurs on the signal TIOA.  // TimerCount = (uint32_t) TC0->TC_CHANNEL[1].TC_CV;            // save the timer counter register, for testing  uint32_t status = TC0->TC_CHANNEL[1].TC_SR;       // Read & Save satus register -->Clear status register  // If TC_SR_LOVRSRA is set, RA or RB have been loaded at least twice without any read  // of the corresponding register since the last read of the Status Register,  // We are losing some values,trigger of TC_Handler is not fast enough !!  //if (status & TC_SR_LOVRS) abort();  if (status & TC_SR_LDRAS) {  // If ISR is fired by LDRAS then ....    CaptureCountA = (uint32_t) TC0->TC_CHANNEL[1].TC_RA;        // get data from capture register A for TC0 channel 1  }  else { /*if ((status & TC_SR_LDRBS) == TC_SR_LDRBS)*/  // If ISR is fired by LDRBS then ....    CaptureCountB = (uint32_t) TC0->TC_CHANNEL[1].TC_RB;         // get data from caputre register B for TC0 channel 1    CaptureFlag = 1;                      // set flag indicating a new capture value is present  }  Period = CaptureCountA - _CaptureCountA;  Duty = CaptureCountB - _CaptureCountA;  _CaptureCountA = CaptureCountA;}`

#### Bisiaux

#8
##### Aug 16, 2017, 11:48 pm
So since my initial wish is to use an external frequence to get more precise time measurements, what I could do is to measure the number of rising edges (I could use TC_CV) of a "perfect" frequence coming from an external device (for example a TCX0) to measure the elapsed time between two instants, isn't it ?

If what I say is true, I just learnt the interest of the counters =)

P.S. In your example code, each rising edge what kind of value is retained by CaptureCountA (timer 0 value or the number of counts) ? If it was the number of counts, Period=CaptureCountA-CaptureCountA variable should always be 1 I think since it is calculated each rising edge. I think there is still something I nee to understand in this example.

#### ard_newbie

#9
##### Aug 17, 2017, 08:16 pm

After  reading the datasheet for an external clock selection in the TC datasheet section:

In TC_BMR, set e.g. TC0XC0S to 0 if you are using Timer Counter 0 to select an external clock input (TCLK0 = pin 22 = PB26 ),

In in TC_CMR, set TCCLKS = 5 = TC_CMR_TCCLKS_XC0 to select XC0 as the clock selection.

Note that the external clock should be 2.5 lower than the TC peripheral clock (42 MHz)

In capture mode, you should time very precisely edges rising or falling if your input clock IS very precise.

#### Bisiaux

#10
##### Aug 17, 2017, 10:36 pm
All correct for me, thank you a lot =)

#### MarkT

#11
##### Aug 22, 2017, 10:52 am
Hi,

I think about buying an Arduino Due for an inertial motorbike power bench. It's in fact a big roll (around 500 kg) that a bike accelerates... and measuring its acceleration, since we know its inertia, we can compute the power applied by the wheel of the motorbike.

I would need to know how precise is the Master Clock (MCK) of the Due, in ppm or % ?
I would need a precision of at least 0.1 % or better 0.01% (and to be sure of this precision)

I thank you a lot for your help,

Ulysse
The original Due derives its 84MHz system clock from a 12MHz quartz crystal multiplied up by a PLL,
so the accuracy depends on that crystal's specs.  The phase noise will depend on the on-chip PLL,
should timing jitter matter to you that much.

Typical series resonant crystals used for logic clocks are 50, 30, 20 or 10ppm rated.
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

#### Bisiaux

#12
##### Aug 30, 2017, 10:31 pm
Hi again,

MarkT I understand your point of view but I always prefer to know exactly the quality of my hardware, for this reason the TCX0 corresponds to mu need.

ard_newbie, I coded the following, but I still have a problem with the registers parametrization, one line does not compile with the message: "'struct TcChannel' has no member named 'TC_BMR'"

Code:
Code: [Select]
`volatile boolean CaptureFlag;int counterXC0=0;void setup() {  Serial.begin(250000);                             PMC->PMC_PCER0 |= PMC_PCER0_PID28;                    // Timer Counter TC0 channel 1 IS TC1  TC0->TC_CHANNEL[1].TC_CCR = TC_CCR_CLKDIS;            // counter clock disabled      TC0->TC_CHANNEL[1].TC_CMR = TC_CMR_TCCLKS_XC0         // XC0 clock selected                             | TC_CMR_ETRGEDG_RISING;    // external trigger interrupts on rising edge  TC0->TC_CHANNEL[1].TC_IER = TC_IER_ETRGS;             // external trigger interrupts enabled  TC0->TC_CHANNEL[1].TC_BMR = TC_BMR_TC0XC0S_TCLK0;   // signal connected to XC0 (THIS LINE DOES NOT COMPILE)  TC0->TC_CHANNEL[1].TC_CCR = TC_CCR_CLKEN;             // counter clock enabled      NVIC_EnableIRQ(TC1_IRQn);                             // TC1 interrupts enabled}void loop() {  if (CaptureFlag) {    Serial.println(counterXC0);    CaptureFlag = 0;  }}void TC1_Handler() {  counterXC0++;  CaptureFlag=1;}`

#### ard_newbie

#13
##### Aug 31, 2017, 06:39 pm

TC_BMR is for all Timer Counter x channels, i.e.:

TC0->TC_BMR = TC_BMR_TC0XC0S_TCLK0; // Should compile !!

#### Bisiaux

#14
##### Sep 02, 2017, 03:37 pm
Here is the most basic code for a counter implementation on an Arduino Due SAM3X8E, I think it could help =)

Thank you all !!

Code: [Select]
`void setup() {  Serial.begin(250000);                              PMC->PMC_PCER0 = PMC_PCER0_PID27;                // interrupt line TC0 selected                  TC0->TC_CHANNEL[0].TC_CCR = TC_CCR_CLKDIS ;      // counter clock disabled for initialization  TC0->TC_CHANNEL[0].TC_CMR = TC_CMR_TCCLKS_XC0;   // counter clock selected : XC0  TC0->TC_BMR = TC_BMR_TC0XC0S_TCLK0;              // signal connected to XC0: TCLK0=PB26=Arduino_Due_Digital_Pin_22 https://www.arduino.cc/en/Hacking/PinMappingSAM3X  TC0->TC_CHANNEL[0].TC_CCR = TC_CCR_SWTRG         // sowftware trigger: reset counter, start clock                            | TC_CCR_CLKEN;        // counter clock enabled}void loop() {  delay(500);  Serial.println(TC0->TC_CHANNEL[0].TC_CV);}`

Go Up