I am working on an SMD hobby project (2 layer board) where I use a STM32F405 MCU running at 3.3V, clocked from a 25MHz external crystal. Being impatient, I hastily designed a board and ordered it. However I have apparently missed a whole lot of points regarding PCB design in regards to the external crystal.

The result did not work so well, as you might expect. When I switch to the external oscillator, the CPU seems to run. But the MCU clock is very slow, and switching a GPIO ON and OFF in the main loop yields an approximate 1 kHz square wave (I've not had time to check the frequency using a clock out pin yet).

The crystal is oscillating at 25 Mhz, but I only measure a sine wave with slightly below 500mV p-p amplitude (using a x10 Oscilloscope probe). I would expect this to be closer to the 3.3V supply voltage (I cannot find much documentation which states what is to be expected.) I also do not understand how the MCU is running at all, as it definitely does not halt in the loop waiting for the oscillator to start. But it does not run at the correct speed at least. So any hints at what's going on would be appreciated.

After studying the topic of MCU crystal PCB design in more detail, I've got a fairly good idea about what I got right and where I failed spectacularly. But I am still quite confused to what is the definitive correct way to do this.

The stuff I got correct:

  • Traces to the crystal is short, at around 6 mm from the MCU.
  • Traces are symmetric.

The stuff I got very wrong is:

  • I used a ground plane under the crystal and the tracks to the MCU, likely causing a very high stray capacitance.

  • I completely misunderstood the "guard ring" concept. I added a top layer fill zone (surrounding the the crystal), stitching it to the ground plane instead.

  • Using a 25 MHz crystal instead of an 8 Mhz one. The PLL setup suggested by STMCubeMx seems to divide the input down to 1 Mhz, before multiplying it up to 168 Mhz. So an 8 MHz crystal should work fine I guess.

  • The reset line runs right under the crystal. However, that in turn is connected to the JTAG and a button, and is otherwise passive.

I thus suspect the stray capacitance of the design explains the low Vp-p in the 25MHz oscillator. So as a first remedy, I'm planning to switch to a 8MHz crystal in order to just get it working. Does my assumption here make sense, and would an 8 MHz crystal have a better chance of working on my bad board? (I would like to get the current board working, even if the design is sub-optimal/really bad).

Of course, the final plan is to make a second revision board where the design is fixed. But there are a couple of things which I still find confusing in documents I've read so far:

  • Some documents recommend NOT using a ground plane under the crystal, but place a guard ring around the circuit and connect it to the nearest MCU ground pin. This makes sense to me, however:

  • Some other documents recommend placing a separate ground plane under the crystal (in addition to the top layer ring), and connect this to the nearest MCU ground in one place. However, I do not quite see how this would be better than my current design capacitance wise, as the "separate" plane would then also be connected to the main ground plane. I do understand that RF noise wise it would be way better. But it contradicts my assumption that stray capacitance is the reason my current design produces such weak oscillation output.

So any explanation regarding this apparent contradiction would be appreciated. Also, any other pointers to me regarding the "best way" to lay out my Rev2 board would be greatly appreciated.

EDIT: Pictures of the PCB are found below. C3 and C4 are the capacitors and R6 (which is in between the Caps) is Rext. (Sorry for the bad contrast).

PCB Top Layer PCB Bottom Layer

  • 4
    \$\begingroup\$ Can you post a picture of your old layout? Whole and zoomed in to the oscillator would be useful :) \$\endgroup\$
    – awjlogan
    Dec 18, 2018 at 10:40
  • 1
    \$\begingroup\$ To get the real frequency you could use a timer and toggle a GPIO on overflow / underflow. In addition, check the output for consistent timing (if it jumps around a bit the oscillator amplitude would definitely be suspect). \$\endgroup\$ Dec 18, 2018 at 10:42
  • 4
    \$\begingroup\$ I think you are jumping to conclusions when you suspect that the oscillator amplitude is too low. It may very well be that the X1 and X2 pins on the MCU just operate that way. Anyway check the frequency of this signal (preferably the X2 pin) and see if it is near the correct frequency. \$\endgroup\$ Dec 18, 2018 at 10:56
  • 3
    \$\begingroup\$ You could also have a problem with the programming of the clock selection and PLL configuration registers. Unless you have a 1::1 direct comparison with some known working reference board programming is one detail you have to check and double check. \$\endgroup\$ Dec 18, 2018 at 10:59
  • 1
    \$\begingroup\$ Congratualtion on the working oscillator. The reason to have a small region of GROUND under the crystal and its traces, with that GROUNDED foil not used for anything else ---- is to avoid injecting fast spikes into the circuit that will cause upsets to the waveform and cause zero-crossing-timing-errors. This is called jitter (or non-random phase noise). \$\endgroup\$ Dec 18, 2018 at 16:48

3 Answers 3


If the crystal is oscillating at 25MHz then your apparent problem is elsewhere, perhaps configuration of the clock divider, PLL or whatever that particular chip incorporates. Make sure your measurement is not affecting the oscillation.

None of the items you mention are likely deal killers. It’s quite normal for the voltages at the crystal to be small relative to the supply voltage, even when properly measured with a FET probe.

Sometimes a series resistor is even used to reduce the drive in order to avoid damaging the crystal with excessive drive power, especially for small SMT crystals that are limited to 100uW or less drive.

  • \$\begingroup\$ Thanks for your input. For the test code I used an example based on the libopemcm3 library for setting up the clock (as this lib is very simple to use). But I will try to generate code from STMCubeMX and run this in stead, just to verify if I get the same result. The used lib may of course be broken. As mentioned I will also try to enable the MCO1 output pin, which should give me a way to measure the actual clock used by the MCU. \$\endgroup\$ Dec 18, 2018 at 14:26

As pointed out in both previous answers and several comments, it turns out the problem was caused all along by wrong PLL configuration. The problem seems to be in "libopencm3" which I used for it's simplicity for clock setup. I've used it with success on several dev boards, but it seems to have some issues with 25 MHz crystal configuration for STM32F405 at least. (I will notify the developers).

I created a very basic setup using STM32CubeMX, and the board now purrs like a kitten. I've also enabled the MCO1 for HSE, and it gives me a stable 24.9998Mhz output on PA8.

A great thank you to all contributors on this post, for taking their time to point me in the right direction. I would likely have spent a lot more hours, and probably decimated my board completely without your help. Also, I now have some very valuable input on design changes for my next revision, and I've learned a lot of very useful stuff :-)

EDIT: It turns out that the root problem was neither caused by my original code, nor LibOpenCm3. The problem was caused by the Meson build system, and it's the first time I attempt to use it on an STM32 project. By default, it injects the "-fPIC" gcc compiler flag, which in turn resulted in a NULL pointer being passed to the libopencm3 clock setup function (unsure why, but it may be a GCC bug).

So the clock setup function ended up configuring the PLL from data located at memory address 0x00000000. I am quite amazed that this actually resulted in a PLL output of 2.44 Mhz, and did not crash.

It's quite simple to turn this flag off by passing the following meson default options when defining the project in the root meson.build file: 'b_staticpic=false', 'b_pie=false'

Then I deleted and regenerated the ninja build script, and everything was in order. My original test code now runs at the wanted 168Mhz clock rate :-)


For your pcb design:

  • I used a Ground Plane under the crystal and the tracks to the MCU, likely causing a very high stray capacitance.

This is probably not a big issue and unlikely to be your problem

  • I completely misunderstood the "Guard Ring" concept. I added a top layer fill zone (surrounding the the crystal), stitching it to the Ground plane instead.

Also not critical and probably not your issue.

  • Using a 25 MHz crystal instead of an 8 Mhz one. The PLL setup suggested by STMCubeMx seems to divide the input down to 1 Mhz, before multiplying it up to 168 Mhz. So an 8 MHz crystal should work fine I guess.

This you need to check with your microcontroller datasheet, usually you can setup the PLLs so that it would fit your crystal, but for sure this can be an issue. The frequencies has to stay within a range at each step of the PLL (dividor, multiplier).

  • The reset line runs right under the crystal. However, that in turn is connected to the JTAG and a button, and is otherwise passive.

Unlikely to be the issue either, and seems you do not have "reset" happening.

On newly designed board, the crystal is often a pain, not only the design but also the correct configuration of the chip, because it's difficult to debug and it's more a trial and error process until it works.

On a hardware level, first you should check your load capacitor, it is likely you have an issue there (especially if you changed the crystal). Some crystal with some MCU also needs a serial resistor, but I've never seen "rules" on to define when it needs to be used or the values, it seems more a trial and error process.

Try to change the load cap of the crystal with different values, they should be around twice the value of the one of the datasheet because they are effectively in serie. Here is more details about it.

Also very likely you should check the configuration and code for clock switching.

I stopped using crystal when I can and use external clock instead, it is usually less a pain.

  • \$\begingroup\$ Thank you very much for your input. I've actually tried changing the Load Caps already. I used some which where too small initially, and replaced them with 33pF onces. This increased the Vpp to sligly below 500mV as I mentioned in my post (it was around 300mV before I did this). The CL of the crystal is stated to be 20pF. After googling more just now, it may seem the STM32 Xin pin required at least 1.2Vpp in order to function, but I've yet to find this in any official STM docs :-/ \$\endgroup\$ Dec 18, 2018 at 13:01
  • 1
    \$\begingroup\$ @JohnnyEgeland - Check that 1.2Vpp requirement carefully. Very likely this applies to the use of an external clock attached to the Xin pin. \$\endgroup\$ Dec 18, 2018 at 21:23
  • \$\begingroup\$ @MichaelKaras - You are absolutely correct. I assumed this was the case also when using an external crystal, thus deducing my measured oscillation was too weak for the HSE to work. I really expected that the MCU was using some fallback mechanism (once more, something I read in a non-official doc), but was unable to confirm this in the STM docs. Turns out, the Oscillator was working all along, even with very wrong load caps (which I've already corrected). The problem turned out to be the PLL configuration set up by libopencm3 :-/ \$\endgroup\$ Dec 18, 2018 at 22:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.