Si5351 - is mine a dud? [SOLVED] - Page 1
Forum section: electronics / projects

author: MisterHeadache
author_rank: Regular Contributor
timestamp: March 12, 2022, 11:06:22 pm
content: Working on a now common radio design to use the Adafruit Si5351 board and I just cannot get it to output accurate frequency. And by accurate, I mean after calibration at 10MHz, it is off by ~3.15kHz for every MHz away from 10Mhz. Meaning its 3.15kHz high when set to 9MHz, 3.15kHz low at 11Mhz, 6.30kHz low at 12Mhz, and so on.Clearly this is a slope error but it is driving me crazy to find out if (1) is there something stupid that I'm doing or (2) is my particular board a dud? Things that I have done include:1. Using the Warren/Milldrum sketch from GitHub to do the 10Mhz calibration (first clue - the value it spits out is HUGE: -1199700, it is way off out of the box at 10MHz.2. Try different CRYSTAL_LOAD parameters from 2pF to 10pF. That does have a tiny effect but nothing on the order of kHz.3. Try different sketches, just to make sure it isn't in my software. No effect, no matter whose sketch I use it is off by that ~3.15kHz per MHz.4. Try setting the crystal frequency directly. The crystal on my board is marked 25MHz, so it's not a 27MHz by mistake. By setting the crystal frequency to 24970000 (which I found by experiment) in the init() command, I can reduce the calibration number down to -300 at 10MHz. But problem remains - still a gross slope error.My calibration routine is solid - I have two references to compare the Si5351 against (an HF radio and a known good HP 8657A to zero beat against).Sure hope this is something that I'm overlooking, otherwise I'm just gonna do the 'replace parts until the problem is fixed' solution.What else would anyone suggest I look at?Thanks.

author: fourfathom
author_rank: Super Contributor
timestamp: March 12, 2022, 11:39:38 pm
content: If it's a slope error, then you are configuring the dividers incorrectly. Can you tell us what the values are for the PLL feedback and the output dividers?With a nominal 25 MHz xtal I would begin the calibration by setting the PLL A feedback divider to 36 (integer, set the fractional numerator to 0 and the denominator to anything -- might as well be 1).This should give you an approx 900 MHz PLL frequency (xtal frequency times 36).Then set your Channel 0 to use PLL A and set the output divider to 90 (integer). This should give you approx 10 MHz output. The actual frequency will be determined by the xtal freq.You can then use the known actual xtal frequency to modify the dividers appropriately. It might be easiest to change the PLL feedback divider to give you an actual 900 MHz PLL frequency (or whatever frequency you like). Then the output divider calculations are a bit easier.Again, there should be no slope error and I can't imagine a fault (other than incorrect divider settings) that would cause this.

author: MisterHeadache
author_rank: Regular Contributor
timestamp: March 13, 2022, 12:30:10 am
content: @fourfathom - thanks very much for the quick response, and you've put me on the right track!I wrote from scratch code (using the Adafruit_SI5351 library) and set it up as follows, with the noted results:10MHz:Code:clockgen.setupPLLInt(SI5351_PLL_A, 36);clockgen.setupMultisynth(0, SI5351_PLL_A, 90, 0, 1);OUTPUT FREQUENCY: 9,999,510 Hz [error: -490Hz]12MHz:Code:clockgen.setupPLLInt(SI5351_PLL_A, 36);clockgen.setupMultisynth(0, SI5351_PLL_A, 75, 0, 1);OUTPUT FREQUENCY: 11,999,420 Hz [error: -580Hz]MUCH BETTER, a tiny slope and an (almost) equal offsetI'd also add my HP 8657A least sig digit is 10Hz, so that limits my resolution of zero beating.That was the foundation check, so to speak, that I needed. Now I know it's a code issue, not hardware. Which remains puzzling - the issue happens with two standard libraries from GitHub (etherkit and Si5351mcu).Thanks!

author: fourfathom
author_rank: Super Contributor
timestamp: March 13, 2022, 02:00:52 am
content: Glad to hear it!FWIW, that slope is just the xtal error multiplied by the dividers. If you change the PLL divisors to compensate for the xtal error then the rest will come out dead-on.So, apparently your xtal oscillates at 24.99877 MHz. Set your PLL divider to 36 + 1764 / 1000000 and you will be pretty close to a 900 MHz PLL freq. You can get closer with Farey-derived numerator and denominator (see below).I'm using the '5351 for a couple of projects, and using Arduino-compatible boards (ItsyBitsy-M0, and a custom board of my own design that contains the essentials of the ItsyBitsy). I took the Adafruit 5351 library and modified it to give me access to other registers and dividers. I know there are several other libraries out there, but haven't looked into them.Those fractional dividers are really useful. You might want to look into using the Farey algorithms for finding the best-fit fractional divider. Of course you can just set the denominator to 1,000,000 to keep the math easy, but if you want more precision it's nice to find that something like 7359/95524 (random numbers in this case) is a much closer fit. I'd be happy to help as you figure out this stuff.[edit: Farey-calculated dividers for 900 MHz PLL from a 24.998775 MHz xtal = 36 + 912 / 518569 -- but the xtal likely drifts over temperature so much that this level of precision is unlikely to matter.]

author: MisterHeadache
author_rank: Regular Contributor
timestamp: March 15, 2022, 06:02:48 pm
content: Well, the problem runs much deeper. There's something going on here that I can induce through software. I noticed a LOT of spurious output when I listened to the Si5351 output on my HF receiver and decided to connect it to my homebuilt SA. See the attached BAD signal image. It looks like there’s horrible jitter, but at very regular periods. The tallest peak is at appx 8.957MHz and the others are regularly spaced at appx 31kHz intervals. The barely visible smaller peak nested inside the pattern is from my 9MHz signal generator that is multiplexed with the Si5351 signal. Ignore the ugly ripple at the tops of the peaks – that’s just artifacts from my poorly tuned 30kHz resolution filter.What’s even weirder, depending on my code, I can get clean output from my Si5351 board. See the CLEAN signal image attached, taken at the same vertical (dB) and horizontal (frequency) scale, but with it better centered. Notice the single peak. Again, the faint nested peak is multiplexed from my 9MHz signal generator.I’ve done a lot of software trials between the Adafruit and Etherkit libraries and, depending on which library I use,I can turn the problem on and off.For example, using this code with the “Adafruit_SI5351.h” library to generate a 9,004,392 Hz signal on CLK0, I get a CLEAN signalCode:#include <Adafruit_SI5351.h>#include <asserts.h>#include <errors.h>Adafruit_SI5351 clockgen = Adafruit_SI5351();void setup() {if (clockgen.begin() != ERROR_NONE){/* There was a problem detecting the IC ... check your connections */while(1);}clockgen.setupPLL(SI5351_PLL_A, 35, 1, 7);clockgen.setupMultisynth(0, SI5351_PLL_A, 97, 4, 7);clockgen.enableOutputs(true);}void loop() {}However, using this code with the commonly used Etherkit Si5351 library (it's the one Charlie Morris uses on his YouTube channel), I get the BAD output -but not right away(see below)Code:#include <si5351.h>Si5351 si5351;void setup() {si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);si5351.set_freq((9000000 * 100ULL), 0);}void loop() {}By 'not right away' what I mean is, immediately after compiling and uploading this code, the Arduino goes to a reset and I get a CLEAN signal. But after I cycle power (meaning just unplug and replug in the USB cable to the PC), I get BAD output. And it stays BAD until I reload the Adafruit code which restores a CLEAN signal. And...with the Adafruit code loaded, I can power it up and down multiple times and the signal remains CLEAN.For the Adafruit code I've tried many different frequencies and integer versus fractional modes and it consistently works fine. I've also played around with the CRYSTAL_LOAD values in the Etherkit init statement (by default the Adafruit uses 10pF) and the oscillator frequency and offset parameters - nothing fixes the issue.At this point I’ve got two explanations for the problem:(1) my board is bad and I need to trash it, which is a bummer because I bought it from Digikey so I doubt it would be counterfeit, and they are out of stock everywhere I look so getting a replacement is impossible at the moment.(2) there is some deeply buried error in the Etherkit library and I am the first (huh??) to ever find it.Looking for some more suggestions please, something more sane than my second explanation. At the moment I am justThanks

author: fourfathom
author_rank: Super Contributor
timestamp: March 15, 2022, 06:46:22 pm
content: Can you look at the etherkit source code to see what it is actually writing to the 5351 registers? Since you get clean outputs with the Adafruit library, and the problem using etherkit only shows up after a restart I suspect that your hardware is OK. The Adafruit library source code is fairly easy to review.

author: MisterHeadache
author_rank: Regular Contributor
timestamp: March 15, 2022, 08:58:17 pm
content: @fourfathom - thanks, yes - you did suggest I do that early on and I'll do that next. I'm only using the Arduino IDE so there's no debug or I2c monitor, but I've started looking at the library files and made my own copies, so I can insert Serial.print() commands to spit out the registers and values just before they send them over the I2C bus.Will take a bit of coding, but what the heck - I've dug this far so I might as well keep digging

author: thm_w
author_rank: Super Contributor
timestamp: March 15, 2022, 09:37:45 pm
content: If you get deep into debugging Arduino, you can use something like VisualGDB or VisualMicro instead of the stock IDE.Assuming the chip you are using is compatible and you have an appropriate programmer.

author: fourfathom
author_rank: Super Contributor
timestamp: March 16, 2022, 01:40:32 am
content: I glanced at the Etherkit source code, and the init() function calls a reset() function which looks like a thorough clearing of all the registers. I don't think your problem is the code, per se, but more likely a power-up timing issue. Possibly the microcontroller starts up more quickly than the 5351 which isn't yet ready for the init()? You might try simply putting a "Delay(1000);" to wait one second for things to settle down before you try accessing the 5351. In must of my programs that use the 5351 I the first thing I do is wait for a connection to the USB serial port. If there's no connection this times out after a few seconds, and connection or not I then send program name and version# out the USB serial port. This burns a fair bit of time. Only then do I try to set up the 5351.Of course this is just a guess!

author: MisterHeadache
author_rank: Regular Contributor
timestamp: March 16, 2022, 07:59:22 pm
content: I tried a two second delay before calling the init() and there was no effect unfortunately.Added a few lines of code to those libraries and was able to capture all of the read and writes going on to the Si5351 and have been spending a few hours going through them. Immediately there is a huge difference between the libraries - the Adafruit pretty much follows the flowchart (figure 10 on page 21 of the Si5351 datasheet) and the Etherkit isn't anywhere near it. So right away that is very suspicious.Learning a lot about how this device works, that's for sure.

author: fourfathom
author_rank: Super Contributor
timestamp: March 16, 2022, 11:04:27 pm
content: Quote from: MisterHeadache on March 16, 2022, 07:59:22 pmDamn! And I was so confident that this was the problem! I guess I was lucky that I started out with the Adafruit library.The '5351 is a pretty remarkable chip. There are devices and methods that can give you a more spectrally-pure output, but this chip is much cleaner than you might expect from a fractional divider that uses a 600-900 MHz VCO. The '5351 has some sort of delay-line interpolator that smooths out the differences in the N and N+1 division, resulting in dramatically lower spurs.

author: MisterHeadache
author_rank: Regular Contributor
timestamp: March 17, 2022, 11:46:27 pm
content: I've SOLVED the problem! And as it turns out, my title for this thread is partially correct.The issue is the spread spectrum mode on my specific Si5351 chip is ENABLED in the default configuration loaded from NVM to RAM on startup. Meaning bit 7 of register 149 is set HIGH on startup, which per the AN619 register map, turns on the spread spectrum mode. All I had to do was add this bit of code to run during initialization of the Si5351 and the problem is gone.Code:uint8_t regval;regval = i2cRead(149);regval &= ~0x80; // set bit 7 LOW to turn OFF spread spectrum modei2cWrite(149, regval);But boy, did I have to sort through a lot of chaff to get to the kernels on this investigation. And as always, in hindsight the evidence looks a lot sharper once you know the answer. Specifically, these two clues turned out to be critical:1. My SA plot of the BAD output had the peaks occurring at 31kHz intervals. Per the datasheet, the spread spectrum modulation is 31kHz. However, I am not sure those are directly equivalent, as I would have assumed 31kHz meant the frequencies were changed 31k times per second, not spaced 31kHz apart. But they're too close to be just mere coincidence.2. I did a line by line comparison of the initialization and frequency set code between the Adafruit library, the Etherkit library, and a sized-reduced fork of Etherkit written by pavelmc. There were many differences in the sequences that each library used, and only the Adafruit set bit7 of register 149 to LOW during startup.So I DID have a bit of a unicorn here with my Si5351, as I am astonished that I could be the only one who ever saw this behavior on startup (at least judging by the lack of any other reports on the internet that I could find). Perhaps my chip came from a batch that had been factory programmed in NVM for some other customer?? Who knows, I am just happy to have fixed the issue. And as a bonus, I now know a lot more about this chip and PLL frequency synthesis in general.Thanks fourfathom for the help along the way.

author: fourfathom
author_rank: Super Contributor
timestamp: March 18, 2022, 12:22:34 am
content: Quote from: MisterHeadache on March 17, 2022, 11:46:27 pmCongratulations! And thank you for letting us know what you discovered. Even though I'm a big fan of SS, and have used pseudonoise in digital filtering, I've never turned on the SS mode in the '5351. Now I'm going to have to play with it!

author: fourfathom
author_rank: Super Contributor
timestamp: March 18, 2022, 12:37:52 am
content: Quote from: MisterHeadache on March 17, 2022, 11:46:27 pmIt's no coincidence. Changing the frequency 31K times per second is indeed a 31k FM modulation. The deltaF looks to be quasi-random, jumping from one freq to another at a 31k rate. This will produce the noise spectrum, repeated every 31k and falling off in amplitude at (probably) sin(x)/x. I don't know if the interpolator is in effect -- if so it probably falls off more quickly than that.[EDIT:]Actually, the effective modulation frequency is more like 31k/2 -- it's a Nyquist thing. There should be a null at +/- 15.5 KHz, a peak at +/= 31 KHz, all repeating up and down from the nominal (unmodulated) carrier frequency every 31 KHz. This is for symmetrical modulation, I don't know if the '5351 has a "downward-only" SS mode -- some chips do.