Go Down

Topic: Best microcontroller for frequency counter up to 30MHz (Read 3367 times) previous topic - next topic

MartinL

Quote
... but how do I do this, and where do you get the information? I noticed in your earlier code the "non Arduino" Port defines syntax, where did you get this information?
The CMSIS register definitions for the SAMD51 are buried (on my Windows machine) at:

C:\Users\Computer\AppData\Local\Arduino15\packages\arduino\tools\CMSIS-Atmel\1.2.0\CMSIS\Device\ATMEL\samd51\include\...

Here you'll find the directories "component", "instance" and "pio".

The component directory contains the register definitions and bitfields for each peripheral type, for example adc.h, tc.h, tcc.h, etc...

These definitions can be used to specify the entire register (in the "tcc.h" file):

Code: [Select]
TCC0->CTRLA.reg |= TCC_CTRLA_ENABLE;  // Enable the TCC0 timer
Or alternatively a bit or bitfield in the register:

Code: [Select]
TCC0->CTRLA.bit.ENABLE = TCC_CTRLA_ENABLE_Pos;  // Enable the TCC0 timer
or alternatively:

Code: [Select]
TCC0->CTRLA.bit.ENABLE = 1;  // Enable the TCC0 timer
These "component" definitions are usually the preferred method of specifying registers.

An alternative notation is specified in the "instance" directory, which contains an instance of each periperal, for example tc0.h, tc1.h, tc2.h, tcc0.h, tcc1.h etc...

These defintions can also be used to specify an entire register (in the "tcc0.h" file):

Code: [Select]
REG_TCC0_CTRLA |= TCC_CTRLA_ENABLE;  // Enable the TCC0 timer
However, this notation is less commonly used.

The "pio" register is used for GPIO definitions. Personally, I rarely use it.

Quote
Also, why are the ports different between the Metro M4 and Grand Central M4? according to the Atmel datasheets although they are different IC packages, the ports should still be the same (where available) - is there some software define which is redefining these ports / pins?
There are three sets of pin numbers: the IC pin numbers (1, 2, 3, etc..), the port pin numbers (PA00, PA01, PA02, etc...) and the Arduino pin numbers (D0, D1, D2, etc...).

As you mention, the SAMD51 microcontrollers themselves maintain port pin continuity across the different size chip variants. However, unlike on their SAMD21 (M0) boards, Adafruit doesn't mantain port pin to Arduino pin continuity on their SAMD51 (M4) series: the Metro M4, Feather M4, Itsy Bitsy M4 and Metro M4 Grand Central port pins do not go to the same Arduino board pins. This means for example that port pin PB13 on the Metro M4 is connected to D4, while the same port pin on the Grand Central is connected to UART RX1.

This means that it's possible to write register code for the Adafruit Metro M0 and have it work on the same Arduino pins on the Feather M0, the same is sadly not true for the Metro M4 and Feather M4.

Quote
I have an Arduino Due - did you have to modify the your earlier software for this board (over the Metro M4 version)?
The code I used for the Arduino Due, that generates a 28MHz PWM pulse on D9 is as follows, I just connected the grounds between the boards and plugged D9 output on the Due into the D4 input on my Metro M4:

Code: [Select]
// Output a 28MHz PWM waveform on pin D9 (PWML4)
void setup() {
  PMC->PMC_PCER1 |= PMC_PCER1_PID36;                            // Enable the PWM Controller
  PIOC->PIO_ABSR |= PIO_ABSR_P21;                               // Set PWM pin perhipheral type A or B, in this case B
  PIOC->PIO_PDR |= PIO_PDR_P21;                                 // Set PWM pin to an output
  PWM->PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(1);             // Set the PWM clock rate to 84MHz (84MHz/1=84MHz)
  PWM->PWM_CH_NUM[4].PWM_CMR = PWM_CMR_CPRE_CLKA;               // Enable single slope PWM and set the clock source as CLKA
  PWM->PWM_CH_NUM[4].PWM_CPRD = 3;                              // Set the PWM frequency 84MHz/28MHz = 3
  PWM->PWM_CH_NUM[4].PWM_CDTY = 2;                              // Set the PWM duty cycle
  PWM->PWM_ENA = PWM_ENA_CHID4;                                 // Enable the PWM channel 4
}

void loop() {}

johnwestlake

#16
Dec 19, 2020, 11:49 pm Last Edit: Dec 20, 2020, 06:35 am by johnwestlake
Martin,

Thank you for your concise reply, sorry for the delay in replying -  I needed to digest how much I still need to learn to move forward.

I was unsure of the command syntax eg. "PMC->PMC_PCER1 |= PMC_PCER1_PID36;  "

I've only learnt that the -> "operator" is pure C - not proprietary or unique to CMSIS syntax...

So "PMC" above is a pointer to a structure,

So PMC->PMC_PCER1 refers to an element called PMC_PCER1 of a structured pointed to by PMC.

Now that I understand this I can read up more about C structures etc... before I try to work with what currently appears to me as just "obscure" code...

I'm still lost as to where you get the info about these structures - is there a document that describes these structures and there defines / syntax (with regards to configuring the hardware registers of the SAM in software)... how does one know these "commands"?

I cannot see how the Datasheet info on the SAMD hardware registers is then translated into commands that the C compiler understands... as you can see I really still have a lot to learn here...

Its times like this where hardware design seems so much more simple - with software having so many layers that you need to understand... which I currently have very little insight!

MartinL

Hi johnwestlake,

The primary source of register information is usually the microcontroller's datasheet. Normally, each microcontroller has a set of files defining each register.

Most microcontroller manufacturers provide some sort of library as a hardware abstraction layer, such as Atmel's ASF (Advanced Software Framework), but personally I find this it easier to just use the datasheet in conjuction with the register definition files opened in a file editor like Notepad++.

It takes a little while to become familiar with the definitions and how they relate to the datasheet. Each microcontroller is different from the next, but it does gradually become easier with time.

Each of the microcontroller's peripherals are mapped in memory at specific locations (memory addresses). The definitions simply provide a human readable name for each these locations.

For example to use the Arduino Due's PWM controller, it's necessary to first turn it on.

This information is provided by the SAM3X8E microcontroller datasheet, in the PWM Controller section 39, 39.5.2 Power Managment is states that the peripheral must first be enabled in the Power Management Controller (PMC).

Not obvious this one, but in section 11, 11.1 Peripheral Identifiers states that the PWM Controller's identifier is 36. (The later SAMD datasheets are a bit easier to follow in this respect).

Going to the Power Management Controller (PMC) section, there's a register table that includes a set of Peripheral Clock Enable Registers (PCER). PMC_PCER1 contains the PID (Peripheral ID) for peripheral 36.

The register definitions for the SAM3X8E are found here:

C:\Users\Computer\AppData\Local\Arduino15\packages\arduino\tools\CMSIS-Atmel\1.2.0\CMSIS\Device\ATMEL

Entering the "sam3xa" and "include" directories then opening the "sam3x8e.h" definition file there's an entry for the PMC peripheral base address:

Code: [Select]
#define PMC        ((Pmc    *)0x400E0600U) /**< \brief (PMC       ) Base Address */
The PMC definition is simply a pointer to the base address of the PMC peripheral struct (structure) in C code.

The structure it points to, is located by entering the "component" directory and opening the "pmc.h" file. In the structure there's an entry for the PMC_PCER1 register, offset from the base address by 0x0100(hex). This structure maps the memory location of all the PMC peripheral's registers.

Code: [Select]
__O  uint32_t PMC_PCER1;     /**< \brief (Pmc Offset: 0x0100) Peripheral Clock Enable Register 1 */
To access this register using C, we call on the pointer to the structure PMC, then use the arrow operator (again in C), to access the contents of the specified structure's member PMC_PCER1:

Code: [Select]
PMC->PMC_PCER1
However, to activate the PWM controller we neet to set the bit PID36. In the same "pmc.h" file there are definitions for each PMC's register bitfields. The bit(field) we require is PMC_PCER1_PID36. To set it without disturbing all the other bits settings in the register, we do a read-modify-write by reading the PMC->PMC_CER1 register, ORing it the PMC_PCER1_PID36 bitfield then writing the result back to the register (using the symbols |=):

Code: [Select]
PMC->PMC_PCER1 |= PMC_PCER1_PID36;
This line activates the PWM controller.

Hope this describes the process, I can be quite tedious, but does become faster with time. Often I find it necessary think about what I would like to achieve, read the datasheet chapter on the peripheral in question, concentrate on the registers that do what I need (ignoring those that don't), then search out the associated register definitions.

johnwestlake

#18
Dec 31, 2020, 05:38 pm Last Edit: Dec 31, 2020, 05:43 pm by johnwestlake
Martin,

Merry belated Christmas and best wishes for the New Year!!

Wow, once again a very informative reply, thank you  for taking the time to explain and try to help me out here.

Sorry for the delay in reply - I didn't receive a notification from the forum about your latest post.

I set a target to teach myself Verilog over the Christmas period so I can start working with FPGA's and although its still very early days I find Verilog easier then working with MCU's and C.

I'm glad that I taught myself the basics of C as one can see that Verilog is "C Like" in many ways.

I did order a Metro M4Express which has arrived yesterday, so I'll try your original code.. I plan to use the 64pin packaged SAMD51 on my PCB anyway so maybe its better to work with the M4 Express over the larger Grand Central I originally had on hand.

At this time for the PCB design, I just need to know which I/O pins I need for the Ref Clock and Freq (Input) to be counted... then later I can pull my hairout trying to understand the Atmel internal registers... I still dont understand how to access the registers one finds in the device datasheets from the Arduino software - my C level is still very basic and I need to understand the "layers" between software and the hardware registers... I should start with understanding how C "Structures" work...

MartinL

Hi John,

Happy New Year!

Quote
...how to access the registers one finds in the device datasheets from the Arduino software...
Fortunately the SAMD51's frequency meter one of the simpler peripherals. To get an understanding of how the frequency meter code relates to the register definitions, it's probably worth looking at it's register definitions in the file: "freqm.h" and how they relate to the SAMD51's frequency meter code above:

C:\Users\Computer\AppData\Local\Arduino15\packages\arduino\tools\CMSIS-Atmel\1.2.0\CMSIS\Device\ATMEL\samd51\include\component\freqm.h.

Quote
I just need to know which I/O pins I need for the Ref Clock and Freq (Input) to be counted...
The other thing with the SAMD family of microcontrollers, is that the on-chip peripherals can be driven with clocks that are asynchronous to the main CPU clock. This allows for complete peripheral flexibility, at the expense of extra complexity. This means that it's often necessary to route an on-chip or external clock source to a perhipheral via the SAMD's generic clock system, before it can be used.

In the case of the frequency meter, it's necessary to configure two generic clocks, one as the measurement clock and the other as the refrence clock. As the Arduino core code uses generic clocks 0 to 4 for the SAMD51's 120MHz, 48MHz, 100MHz, 32.768kHz and 12MHz clock sources respectively and the fact that only generic clocks  0 to 7 can be routed to the microcontroller's IO pins, I chose generic clocks 6 and 7.

Generic clock 6 acts as a the reference, and in the example code above is generated from Metro M4's external 32.768kHz crystal clock source. It's also possible to alternatively supply this clock source from an external input pin as well, if you have a more accurate reference. In this case, generic clock 6 is on port pin PB12, that's physical pin 25 on the 64-pin chip variant, or pin D7 on the Adafruit Metro M4. The on-board 32.768kHz crystal is most likely accurate to around ±20ppm.

Generic clock 7 is the measurement signal and is configured to be supplied from an external input, in this case  generic clock 7 is on port pin PB13, or physical pin 26 (again on the 64-pin variant), or D4 on the Metro M4.

johnwestlake

#20
Jan 01, 2021, 01:24 pm Last Edit: Jan 01, 2021, 07:46 pm by johnwestlake
Hi Martin,


So for my design (which is an Audio DAC) I plan to have the MCU clocked from a Low phase noise and also accurate reference 96MHz "Master Clock". The design has basically two Clock domains, the Audio Master Clock (which is FS based 44.1KHz / 48KHz) and the USB / system Clock which is 96MHz based (this 96MHz "system" reference is then divided by two for the USB / MCU 48MHz Clocks).

It might be a good start to try and configure the M4Express to operate from an external 48MHz Clock (rather then the poorer performance 32KHz derived clock). Once the MCU has been switched to the 48MHz External clock, it be then desirable to shutdown the 32KHz clock (and all other non synchronous internal clock sources such as DFLL48M) to reduce non-synchronous system Phase Noise (resulting in unwanted extra EMC and potential clock beating / mixing etc).

Are there any other system dependencies on the 32KHz / DFLL48M clocks that would need to be selected to use the 48MHz External clock?

I understand that XOSC1 (XIN PB22) is the External Clock input pin, so how to configure this to be the MCU Main clock once the MCU has "Booted" using its internal DFLL48M clock?

According to the Datasheet, upon powerup the SAMD51 uses its internal DFLL48M clock for the "initial clock cycles" then one can configure SAMD51's clock block registers - the trouble is I dont have an overview of the "Arduinio system" related clock dependencies...

e.g. is the DPLL48M still used for the USB peripheral, or is this also derived from the 32KHz clock after "switch over".

I'm hoping that the 32KHz Clock Crystal is multiplied to the System clock frequency and everything is then divided down from this higher system frequency, so that I just need to replace the 32KHz clock block (+ its PLL multiplier) with the external 48MHz Clock.

Would you have any code examples that will configure the SAMD51 (GCLK_MAIN) to use the external 48MHz XOSC1 (XIN PB22) Clock - I can then confirm that everything still functions correctly with an external system clock (and with the 32KHz clock removed).

Ideally, it be preferable that the MCU NEVER requires the 32KHz clock, so that on powerup (well more correctly, after the first few operations where the MCU uses its internal DFLL48M clock) the system Main Clock (GCLK_MAIN) is switched to the External 48MHz clock on (PB22) and hopefully all other system dependencies clocks are then derived from this clock...

For testing, I can modify my M4Express with a 48MHz Clock on PB22 - having such "example" code would be a great place to start to understand how to configure the clock blocks...

Heres to hoping...  :)

MartinL

Hi John,

The SAMD51's clock configuration is complex. On Adafruit's boards, the 48MHz Digitial Frequency Locked Loop (DFLL48M) operates standalone using the less accurate open loop mode, (rather than closed loop mode).

In Adafruit's clock configuration core code, the SAMD51's on-chip 120MHz and 100MHz fractional digital phase locked loops (FDPLL200M0 and FDPLL200M1) are also ultimately derived from the open loop DFLL48M.

I believe Adafruit didn't use the DFLL in closed loop mode, because the 120MHz main clock and the DFLL48M closed loop, low frequency reference clock both require the same generic clock on channel 0 (GCLK0). In theory they could have improved the clock precision, by employing the 32.768kHz external crystal as the reference for the 120MHz digital phase locked loop (FDPLL200M0) instead, however their current configuration is more than adequate for most users.

As you mention, if you're making a custom board, it's also possible to drive the SAMD51 with up to two 8-48MHz crystals on the microcontroller's XIN0/XIN1 and XOUT0/XOUT1 pins, that's in addition to the 32.768kHz crystal.

The Adafruit core clock configuration code is stored in the "startup.c" file, located (on my machine) at:

C:\Users\Computer\AppData\Local\Arduino15\packages\adafruit\hardware\samd\1.6.4\cores\startup.c

Making changes to the code however, will require familiarity with the SAMD51's Oscillator Controller (OSCCTRL) peripheral, as well as register programming.

MartinL

Hi John,

Taking a closer look at the SAMD51 datasheet, I think that there's a mistake. It states that the closed loop reference clock for the 48MHz DFLL uses generic clock 0, however this contradicts another section that states that the generic clock 0 is reserved for the CPU main clock. Digging a bit deeper, it is does actually appear possible to route the DFLL reference clock to any of the generic clock channels.

This it means it should be possible to run the DFLL in closed loop mode using the 32.768kHz external crystal, to hopefully improve the accuracy and precision of the clocks. Wouldn't be as accurate as a 8MHz-48MHz external crystal on a custom board though.

MartinL

Looks like the SAMD21, M0 boards handle the clocks in more sophisticated way. If there's an on-board crystal the 48MHz DFLL is derived from the 32.768kHz external crystal clock source. If however the board is crystalless, then the clock is derived from the USB Start Of Frame (SOF) at 1kHz. In both instances, the DFLL is operated in closed loop mode.

The SAMD51, M4 boards by contrast, simply run the 48MHz DFLL in open loop mode, irrespective of whether the board has an external crystal or not. The 48MHz DFLL in open loop mode must be accurate enough to clock the USB peripheral, without having to derive the signal from the USB SOF.

johnwestlake

#24
Jan 02, 2021, 11:33 pm Last Edit: Jan 02, 2021, 11:34 pm by johnwestlake
Well that answers one question I had at the back of my mind - how they meet the USB clock PPM offset limits with an internal generated clock...

Its a clever idea to lock to the USB SOF.... it explains why there is so much reference to the USB SOF in the SAMD51  clock block documentation.. I wondered why they had the USB 1KHz SOF clock "floating around" in the clock block!

Sadly I've not had a chance to look at the M4Express yet - I'm still working with getting my first full Verilog design working... I will say that I'm sure when I look back at my first attempts at Verilog code it will be with a mixture of smiling and shame!!!

What I really need is a big yellow "Dummies guide to Verilog book"!!

I plan to use external CMOS clock input on port PB22 (So I do not need the full Crystal oscillator block) - I could quickly add the clock (48MHz) on PB22 if you had a some code to try...

MartinL

Hi John,

Quote
Its a clever idea to lock to the USB SOF.... it explains why there is so much reference to the USB SOF in the SAMD51  clock block documentation.. I wondered why they had the USB 1KHz SOF clock "floating around" in the clock block!
Yes, it allows crystalless boards, such as the Itsy Bitsy M0, to generate a more accurate clock signal while the USB is connected.

Quote
I plan to use external CMOS clock input on port PB22 (So I do not need the full Crystal oscillator block) - I could quickly add the clock (48MHz) on PB22 if you had a some code to try...
Unfortunately, I don't have any code. Adding a 48MHz oscillator input effectively entails reconfiguring the SAMD51's start-up sequence.

An easier option would be to drive one of the microcontroller's timer with an external clock.

johnwestlake

An easier option would be to drive one of the microcontroller's timer with an external clock.
Sadly this will not work for me as I need to keep all system clocks / I/O transitions synchronous to the System Reference clock to eliminate potential spurie products breaking though into the Analogue domain - so I'm going to have to reconfigure the SAMD51 Startup configuration... :(

MartinL

Hi John,

The thing is, on the SAMD51 the process of register synchronisation between the synchronous main clock and asynchronous peripheral generic clock takes place, even if the peripheral's generic clock is using the main clock as its clock source.

Here's the quote from the SAMD51 datasheet, section 13.3.1 Register Synchronization Overview:

Quote
Communication between these clock domains must be synchronized. This mechanism is implemented in
hardware, so the synchronization process takes place even if the peripheral generic clock is running from
the same clock source and on the same frequency as the bus interface.
The bus interface being the synchronous main clock.

johnwestlake

#28
Jan 04, 2021, 06:50 pm Last Edit: Jan 05, 2021, 01:50 am by johnwestlake
Hi Martin,

I'm afraid your post went way over my head - but maybe we are saying the same thing.

My application is extremely sensitive to any "external" EMC sources - the System MCU is a significant source of EMC.

The System clock has a phase noise of greater then -170dBc at 10KHz offset and trends to -180dBc higher up and great effort is required to prevent degradation.

One good (I'd say essential) design practice is to insure all "switching / clocked" devices / components within the enclosure operate synchronizes to the system Master clock (this includes any switching PSUs regulators etc).

So the requirement for external clock input to the MCU is for two reasons:-

Increased counter accuracy - the external Master clock is accurate to ppt (typically 100 - 200 parts per trillion) and to insure that the noise (EMC / Ground bounce / PSU modulation etc.) introduced by the system MCU is fully synchronous to the master clock.

For sure I dont expect or need ppt resolution from the SAMD51 FREQM counter - I just need the SAM51 synchronized to the master clock for lowest system noise, and I also gain the benefit of extra Frequency counter accuracy as a bonus.

I'm a hardware designer - and I just need to confirm hardware functionality which requires "get me going software" - then maybe I will find a real software guy who will be "polite" :) about my software attempts - but atleast the hardware has been debugged and I will have a good idea whats required from the software (everything configured and any software "work arounds" understood).

MartinL

Hi John,

Quote
I'm afraid your post went way over my head -
On the contrary, after reading your exacting hardware requirements, I think I'm the one out of my depth.

Go Up