Arduino frequency synthesiser using 160mhz si5351
Содержание
- 1 Constraints
- 2 Changes from v1 to v2
- 3 Миниатюрный синтезатор (Si5351)
- 4 Using the VCXO (Si5351B)
- 5 Phase
- 6 Introduction: Arduino Frequency Synthesiser Using 160MHz Si5351
- 7 Hardware Requirements and Setup
- 8 Using an External Reference (Si5351C)
- 9 Simple example code
- 10 Changelog
- 11 Two of three
- 12 A note on Low Frequency operation
- 13 Features
- 14 Hardware Requirements and Setup
- 15 CLK Output Options
- 16 Example 3: Arduino sketch example
Constraints
- Two multisynths cannot share a PLL with when both outputs are >= 100 MHz. The library will refuse to set another multisynth to a frequency in that range if another multisynth sharing the same PLL is already within that frequency range.
- Setting phase will be limited in the extreme edges of the output tuning ranges. Because the phase register is 7-bits in size and is denominated in units representing 1/4 the PLL period, not all phases can be set for all output frequencies. For example, if you need a 90° phase shift, the lowest frequency you can set it at is 4.6875 MHz (600 MHz PLL/128).
- The frequency range of Multisynth 6 and 7 is ~18.45 kHz to 150 MHz. The library assigns PLLB to these two multisynths, so if you choose to use both, then both frequencies must be an even divisor of the PLL frequency (between 6 and 254), so plan accordingly. You can see the current PLLB frequency by accessing the pllb_freq public member.
- VCXO pull range can be ±30 to ±240 ppm
Changes from v1 to v2
The public interface to the v2 library is similar to the v1 library, but a few of the most-used methods have had their signatures changed, so your old programs won’t compile right out-of-the-box after a library upgrade. Most importantly, the init() and set_freq() methods are different, so you’ll at least need to change these calls in your old sketches.
The init() method now has three parameters: the crystal load capacitance, the reference frequency, and the frequency correction value (with this last parameter being a new addition). You’ll need to add that third parameter to your old init() calls, but then you can delete any set_correction() calls after that (unless you explicitly are changing the frequency correction after the initialization).
The set_freq() method is now more streamlined and only requires two parameters: the desired output frequency (from 4 kHz to 225 MHz) and clock output. In your old code, you can delete the 2nd parameter in set_freq(), which was the PLL frequency. In case you want to do things manually, there is now a new method called set_freq_manual() (see below for details).
Those two changes should cover nearly all upgrade scenarios, unless you were doing some lower-level use of the Si5351.
Миниатюрный синтезатор (Si5351)
Andrew Woodfield, ZL2PD
Cинтезаторы частоты на основе микросхемы Si5351 достаточно популярны, благодаря низкой стоимости и широкому диапазону частот (вплоть до УКВ диапазона). На своем сайте я уже рассказывал о синтезаторе на этой микросхеме. А здесь хочу рассказать ещё об одной очень простой конструкции.
Радиолюбитель и программист из Новой Зеландии Andrew Woodfield (ZL2PD) представил на своем сайте очередную версию синтезатора весьма компактного размера, не превышающего размер кубика сахара, что и послужило его названию «SugarCube Si5351 VFO».
Управление синтезатором осуществляется микропроцессором ATtiny85, а информация отображается на миниатюрном OLED дисплее. Несмотря на малый объем памяти процессора и весьма ограниченное количество портов, автору удалось создать полноценный синтезатор для трансивера с весьма богатым набором функций:
Информация, выводимая на дисплей синтезатора:
В качестве примера автор предложил три разные версии программного обеспечения с несколькими возможностями:
Версия A: Стандартный VFO для типичного приемопередатчика с ПЧ 8,87 МГц
Версия B: Стандартный VFO для типичного трансивера, который не требует смещения ПЧ
Версия C: VFO для УКВ для приемника с ПЧ 10,7 МГц
Программное обеспечение написано на языке Bascom для семейства микроконтроллеров Atmel. Его компилятор достаточно эффективен, и, как можно видеть, полученный код довольно компактен. Исходники автор не выложил. Доступны только HEX-файлы для прошивки трех версий.
В связи с ограниченным количеством выводов у микропроцессора, пришлось задействовать вывод RESET. Поэтому следует помнить, что перепрограммировать процессор стандартным способом не получится — потребуется высоковольтный программатор (HV).
Также в статье автора подробно описан процесс сборки синтезатора. Приводится документация для изготовления печатной платы (Gerber-файлы). Также приведены подробные примеры оспользования синтезатора.
Моя конструкция (RA3TOX)
Собрал этот синтезатор за один вечер. Малое количество деталей позволяет выполнить всё устройство на макетной плате. Микросхемы распаяны на отдельных переходниках. OLED дисплей на разъеме. Конструкция у меня получилась размером со спичечный коробок. Прошивку микроконтроллера сделал программатором USBASP. Запитал синтезатор от USB адаптера через микросхему стабилизатора ASM1117-3,3V. Всё заработало без проблем! Как недостаток, можно отметить отсутствие переключателя диапазов. Приходится устанавливать шаг настройки в 1 МГц и переключать выше или ниже по частоте. Возможно автору не хватило ресурсов процессора для реализации данной функции.
Материал перевёл и подготовил Николай Большаков (RA3TOX).
Сентябрь 2019 .
Using the VCXO (Si5351B)
Please see the example sketch si5351_vcxo.ino
The Si5351B variant has a VCXO feature which can be used to provide voltage-tunable clock outputs, with a voltage control input on pin 3 of the IC. This functionality is provided on the PLLB oscillator internal to the Si5351, so you must assign any clock outputs that you wish to voltage control to PLLB.
The library has a method named set_vcxo() that allows you to set the PLLB frequency and the amount of pull range that you wish to use on that oscillator (from 30 to 240 parts-per-million). Using the VCXO is similar to manually setting an output frequency. First, call the set_vcxo() method:
Next, we assign the desired VCXO clock output to PLLB:
Finally, we use the set_freq_manual() method to set the clock output center frequency:
Phase
Please see the example sketch si5351_phase.ino
The phase of the output clock signal can be changed by using the set_phase() method. Phase is in relation to (and measured against the period of) the PLL that the output multisynth is referencing. When you change the phase register from its default of 0, you will need to keep a few considerations in mind.
Setting the phase of a clock requires that you manually set the PLL and take the PLL frequency into account when calculation the value to place in the phase register. As shown on page 10 of Silicon Labs Application Note 619 (AN619), the phase register is a 7-bit register, where a bit represents a phase difference of 1/4 the PLL period. Therefore, the best way to get an accurate phase setting is to make the PLL an even multiple of the clock frequency, depending on what phase you need.
If you need a 90 degree phase shift (as in many RF applications), then it is quite easy to determine your parameters. Pick a PLL frequency that is an even multiple of your clock frequency (remember that the PLL needs to be in the range of 600 to 900 MHz). Then to set a 90 degree phase shift, you simply enter that multiple into the phase register. Remember when setting multiple outputs to be phase-related to each other, they each need to be referenced to the same PLL.
You can see this in action in a sketch in the examples folder called si5351phase. It shows how one would set up an I/Q pair of signals at 14.1 MHz.
Introduction: Arduino Frequency Synthesiser Using 160MHz Si5351
By lingibFollow
More by the author:
About: 55+ years in electronics, computers, and teaching … now retired.
More About lingib »
This Instructable describes the construction, and operation, of a stand-alone frequency synthesiser suitable for use as a signal generator, or for use as the local oscillator in an amateur band transmitter or receiver.
My prototype was built on a piece of «Vero» board. The ATmega328P must be socketed if you choose to make your own «Vero» board Arduino. The Arduino source code is well annotated and contains links to all of the required «libraries». Construction is not critical.
Adafruit Si5351A Clock Generator:
The heart of this frequency synthesiser is the «Adafruit Si5351A Clock Generator Breakout Board» which can generate up to three outputs in the frequency range of 8KHz to 160MHz. The Si5351 breakout board is designed to run off 5 volts and has an I2C interface which makes it easy to connect to an Arduino. All that you need is an Arduino, a rotary encoder, a 16 character x 2 line I2C LCD display, and some software. The output level from this synthesiser is approximately 3 volts peak-to-peak.
Rotary Encoder:
The second most important component is the rotary encoder which outputs the following two-bit «Gray» code pattern:
11 (indent — CCW)
10
00
01
11 (indent — reference )
10
00
01
11 (indent — CW)
The encoder always rests at an indent (pattern 11) when the tuning knob is stationary. If the tuning knob is turned CCW (counter clock-wise) then the pattern sequence between indents is 01, 00, 10, 11. If, however, the tuning knob is turned CW (clock-wise) then the pattern sequence between indents is 10, 00, 01, 11. This pattern reversal allows us to determine the tuning direction. The new frequency is determined by multiplying the number of «indents» by the tuning step-size and adding/subtracting this offset to/from the current frequency.
The rotary encoder comes fitted with a single-pole push switch which I use to control the tuning step-size in increments of 10, 100, 1000, 10000, and 100000 Hz. A brief push on the tuning knob increases the tuning step-size. A longer push on the tuning knob causes the step-size to decrease.
All mechanical switches suffer from contact bounce which makes for erratic tuning. Instead of «debouncing» each switch with hardware I am using a software integrator.
A SPST band-change switch has been included. When the switch is activated it is possible to cycle through each of the amateur radio bands by rotating the tuning knob. The tuning knob behaves normally when the switch is deactivated.
Programming:
Programming the ATmega328P microcontroller is relatively simple. First install the «libraries» documented in «source_code.txt». Paste the contents of «source_code.txt» into a new arduino sketch and save it as «signal_generator.ino». Click «file/upload» and, all going well, «signal _generator.ino» will compile then upload to your Arduino R3 UNO. Once the file has been uploaded, unplug the ATmega328P microcontroller from your Arduino R3 UNO and insert it into your «Vero» board socket. Apply 9 volts and everything should light up.
Important:
Even though the breakout board runs off 5 volts, the Si5351 chip itself runs off 3.3 volts. This means that the maximum voltage from each output is 3.3 volts. A buffer is therefore required when interfacing to 5 volt logic circuits.
Click here to view my other instructables.
Hardware Requirements and Setup
An 8-bit AVR microcontroller with the TWI peripheral is required for this library. It has currently only been tested with the ATmega328P microcontroller, but should be portable to at least the ATmega88 and ATmega168, although the code size is currently about 8 kB (due to the math in the PLL calculations), so you will most likely need at least 16 kB of program space.
The Si5351 is a +3.3 V only part, so if you are not using a +3.3 V microcontroller, be sure you have some kind of level conversion strategy.
Wire the SDA and SCL pins of the Si5351 to the corresponding pins on the AVR. Since the I2C interface is set to 400 kHz, use 1 kΩ pullup resistors from +3.3 V to the SDA and SCL lines.
Connect a 25 MHz or 27 MHz crystal with a load capacitance of 6, 8, or 10 pF to the Si5351 XA and XB pins. Locate the crystal as close to the Si5351 as possible and keep the traces as short as possible. Please use a SMT crystal. A crystal with leads will have too much stray capacitance.
Using an External Reference (Si5351C)
Please see the example sketch si5351_ext_ref.ino
The Si5351C variant has a CLKIN input (pin 6) which allows the use of an alternate external CMOS clock reference from 10 to 100 MHz. Either PLLA and/or PLLB can be locked to this external reference. The library tracks the referenced frequencies and correction factors individually for both the crystal oscillator reference (XO) and external reference (CLKIN).
The XO reference frequency is set during the call to init(). If you are going to use the external reference clock, then set its nominal frequency with the set_ref_freq() method:
A correction factor for the external reference clock may also now be set:
The set_pll_input() method is used to set the desired PLLs to reference to the external reference signal on CLKIN instead of the XO signal:
Once that is set, the library can be used as you normally would, with all of the frequency calculations done based on the reference frequency set in set_ref_freq().
Simple example code
The example code is written in C for AVR microcontrollers, I use the GCC compiler in AVR Studio. It should be easy to use this on any AVR, or on the Arduino platform. Only minor changes would be needed for other microcontrollers.
There are TWO examples here. The first example allows you to use ANY I/O pins of the processor to bit-bang as I2C. That gives a lot of flexibility, if you happen to be using I/O pins other than the AVR’s onboard I2C peripheral (they call it the Two Wire interface in the Atmel datasheets and application notes), or if you are using an AVR device that doesn’t have an I2C peripheral onboard: not all support I2C. In this example we use a very nice assembly language library by Peter Fleury to take care of the I2C bit-banging. It works perfectly!
The second example uses the AVR’s internal I2C peripheral (which they call the Two Wire interface, TWI, in the datasheets and application notes). That assumes that in your application, your chosen AVR does have a TWI peripheral, and that you aren’t using those particular I2C pins of the processor for something else, so you can afford to dedicate them to I2C purposes. This is the ideal situation.
Changelog
-
v2.1.4
Fix warning «reg may be uninitialized»
-
v2.1.3
Correct error in si5351_example.ino sketch
-
v2.1.2
Correct error in si5351_calibration.ino sketch
-
v2.1.1
Add bool return value to init() indicating whether a device is on the I2C bus
-
v2.1.0
Add support for reference frequencies and corrections for both the XO and CLKIN
-
v2.0.7
Change set_freq() behavior so that the output is only automatically enabled the very first time that set_freq() is called
-
v2.0.6
Call set_pll() in set_correction() to ensure that the new correction factor is applied
-
v2.0.5
Remove PLL reset from set_freq() when not necessary
-
v2.0.4
Fix error in VCXO algorithm
-
v2.0.3
Fix regression in set_freq() that wiped out proper R div setting, causing errors in setting low frequency outputs
-
v2.0.2
- Increase maximum frequency in set_freq() to 225 MHz
- Change SI5351_MULTISYNTH_SHARE_MAX from 112.5 MHz to 100 MHz due to stability issues
- Add explicit reset of VCXO param in reset()
- Add I2C bus address parameter and default to class constructor
- Update si5351_calibration example sketch
-
v2.0.1
Fix logic error in set_freq() which causes errors in setting multiple clocks >100 MHz
-
v2.0.0
- Complete rewrite of tuning algorithm
- Add support for setting CLK6 and CLK7
- Add support for VCXO (on Si5351B)
- Change interface of init() and set_freq()
- Add set_freq_manual() method
- Add reset() method
- Added many new example sketches
-
v1.1.2
Fix error where register 183 is not pre-loaded with correct value per AN619. Add define for SI5351_CRYSTAL_LOAD_0PF (undocumented in AN619 but present in the official ClockBuilder software).
-
v1.1.1
Fix if statement eval error in set_clock_disable()
-
v1.1.0
Added set_pll_input() method to allow toggling the PLL reference source for the Si5351C variant and added support to init() for different PLL reference frequencies from 10 to 100 MHz.
-
v1.0.0
Initial release
Two of three
Yes, there is a tittle catch here with CLK1 and CLK2: both share PLL_B and as we use our own algorithm to calculate the frequencies and minimize phase noise you can only use one of them at a time.
Note: In practice you can, but the other will move from the frequency you set, which is an unexpected behavior, so I made them mutually exclusive (CLK1 and CLK2).
This are the valid combinations for independent clocks output.
- CLK0 and CLK1
- CLK0 and CLK2
Again: You can’t use CLK1 and CLK2 at the same time, as soon as you set one of them the other will shut off. That’s why you get two of three and one of them must be always CLK0.
A note on Low Frequency operation
The limits of the Si5351A configuration registers for the fractional PLL multiplier and the Multi-Synth divider means that you need to make some small changes if you wish to generate lower frequencies, in the range 8kHz to 1MHz. In order to generate lower frequencies you must use the final division stage, which is configurable to divide by 8 powers of 2 from 0 (divide-by-1) which is the default, to 7 (divide-by-128).
In the example code above you will see the call to the function setupMultisynth passes a parameter «SI_R_DIV_1». This is a constant defined in the .h file to set the final state to divide-by-1, the default state. You can change this to SI_R_DIV_2, or SI_R_DIV_4 etc up to SI_R_DIV_128. There are 8 possible division ratios: 1, 2, 4, 8, 16, 32, 64, 128. In this case you setup a frequency the multiple higher than you really want, and then divide it back again using this division ratio.
For example, suppose you want to generate an output frequency of 136kHz. This is a lot lower than 1MHz and the Si5351A cannot reach it directly. So you use the final division stage, by passing the parameter SI_R_DIV_8 into the function call setupMultisynth instead of SI_R_DIV_1. Then you call the function si5351ASetFrequency with 1088000Hz (1.088MHz), which is 8x the desired 136kHz output.
It should be noted that although the datasheet specifies that the lowest Si5351A output frequency is 8kHz, the register configurations do allow you to configure lower values, all the way down to 3.5kHz; and it DOES work.
Features
This are so far the implemented features (Any particular wish? use the Issues tab for that):
- Custom XTAL passing on init (Default is 27.000 MHz (See Si.init() )
- You can pass a correction to the xtal while running (See Si.correction() )
- You have a fast way to power off all outputs of the Chip at once. (See Si.off() )
- You can enable/disable any output at any time (See Si.enable(clk) and Si.disable(clk) )
- By default all outputs are off after the Si.init() procedure. You has to enable them by hand.
- You can only have 2 of the 3 outputs running at any moment (See «Two of three» section below)
- Power control on each output independently (See Si.setPower(clk, level) on the lib header)
- Initial power defaults to the lowest level (2mA) for all outputs.
- You don’t need to include and configure the Wire (I2C) library, this lib do that for you already.
- Frequency limits are not hard coded on the lib, so you can stress your hardware to it’s particular limit (You can move usually from ~3kHz to ~225 MHz, far away from the 8kHz to 160 MHz limits from the datasheet)
- You has a way to verify the status of a particular clock (Enabled/Disabled by the Si.clkOn var)
- From v0.5 and beyond we saved more than 1 kbyte of your precious firmware space due to the use of all integer math now (Worst induced error is below +/- 1 Hz)
- Overclock, yes, you can move the limits upward up to ~250MHz (see the «OVERCLOCK» section below)
- Improved the click noise algorithm to get even more click noise reduction (see Click noise free section below)
- Fast frequency changes as part of the improved click noise algorithm (see Click noise free section below)
Hardware Requirements and Setup
This library has been written for the Arduino platform and has been successfully tested on the Arduino Uno and an Uno clone. There should be no reason that it would not work on any other Arduino hardware with I2C support.
The Si5351 is a +3.3 V only part, so if you are not using a +3.3 V microcontroller, be sure you have some kind of level conversion strategy.
Connect a 25 MHz or 27 MHz crystal with a load capacitance of 6, 8, or 10 pF to the Si5351 XA and XB pins. Locate the crystal as close to the Si5351 as possible and keep the traces as short as possible. Please use a SMT crystal. A crystal with leads will have too much stray capacitance.
CLK Output Options
Please see the example sketch si5351_outputs.ino
In most cases, you will most likely end up using the multisynth associated with a CLK output, but the Si5351 has some other options available as well. The reference clocks (both the crystal oscillator and the CLKIN signal) can be mirrored to any CLK output. Also CLK1 through CLK3 can mirror the MS0 (CLK0) output, and likewise the CLK5 through CLK7 outputs can mirror the MS4 (CLK4) output.
If you choose to use one or more of these output options, you first need to enable the fanout option for that particular signal:
Once that is done, you can use the set_clock_source() method to choose the output option you desire. Since the CLK outputs by default are turned off, you may need to turn your CLK output on as well:
Example 3: Arduino sketch example
This example is very similar to Example 2 above, just re-organised a bit as an Arduino sketch. It was sent in by Alf VK2YAC (thanks Alf!).
Click to download files. Save them all in the same directory as the .ino sketch:
si5351a.ino | the si5351a demo sketch, that calculates and sets the si5351a registers, and sets the Clk- frequency to 10MHz |
si5351a.h | header file for the si5351a demo sketch |
i2c.c | my simple I2C library, based on the ATmega datasheets |
i2c.h | header file for the I2C library |
The example should run on an Arduino with the Si5351A SDA and SCL pins connected to the AVR’s SDA and SCL pins.
si5351a.ino is the Arduino sketch file. It contains a call to i2cInit() to set up the AVR’s TWI interface; and a call to si5351aSetFrequency(10000000); which sets the frequency to 10MHz. You can specify any value from 1MHz to 150MHz. It also includes te former example’s si5351a.c file, where all the hard work goes on. It determines the correct register entries to configure the Si5351A to get the desired output frequency. There are some comments in the code to explain it. The comments are nicely tab-indented to character column 37 in my AVR Studio, but they might not line up so nicely in your editor or your internet browser.
si5351a.h is just the header file for the sketch, it is the same as the one in the previous example. Note that I kept it minimal. I have not created a #define for every register the Si5351A has, or tried to cater for all the functionality or variants of the Si5351 chip. Unlike other Si5351A demo libraries, I want to keep this one as simple and easy to understand as possible. So I only created #defines for things I needed. You do have #defines for the clock configuration registers, for the base address for PLL A and B, and for the base addresses for multisynth 0, 1 and 2; as well as the R-Divider definitions for division ratios 1..128. There is also XTAL_FREQ which is defined as 27,000,000 to match the 27MHz crystal on the Si5351A Synth module kit. The actual oscillation frequency will be different. I have one here which measures 27,004,417 for example. If precision is important to your application, you will want to measure and put in the actual oscillation frequency here.
i2c.c is my simple I2C library, based mainly on the ATmega datasheet description.
i2c.h is the header file for i2c.c
NOTE: Some people have reported compilation errors, which appear to come from using multiple files in the Arduino IDE. There is a tutorial on this topic here: https://arduino.land/FAQ/content/7/43/en/breaking-a-sketch-into-multiple-files.html (thanks Alf VK2YAC).
Alf VK2YAC also provided a single file sketch, it is the same as the above collection of four files but all in one. Konstantinos SV1ONW has tested this and found it necessary to alter some formatting. The final file is made available here, and should make it all easy:
si5351a-test.ino | All above four files, but arranged into a single Arduino sketch file to make it easy |