-
Notifications
You must be signed in to change notification settings - Fork 2
/
test.c
144 lines (123 loc) · 4.98 KB
/
test.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include <stdlib.h>
#include <stdio.h>
#include <pigpio.h>
#include <inttypes.h>
#include "si5351a.h"
#define I2C_WRITE 0x60
#define I2C_READ 0x61
#define I2C_BUS 1
//
// Set up specified PLL with mult, num and denom
// mult is 15..90
// num is 0..1,048,575 (0xFFFFF)
// denom is 0..1,048,575 (0xFFFFF)
//
void setupPLL(int i2c, uint8_t pll, uint8_t mult, uint32_t num, uint32_t denom)
{
uint32_t P1; // PLL config register P1
uint32_t P2; // PLL config register P2
uint32_t P3; // PLL config register P3
P1 = (uint32_t)(128 * ((float)num / (float)denom));
P1 = (uint32_t)(128 * (uint32_t)(mult) + P1 - 512);
P2 = (uint32_t)(128 * ((float)num / (float)denom));
P2 = (uint32_t)(128 * num - denom * P2);
P3 = denom;
i2cWriteByteData(i2c, pll + 0, (P3 & 0x0000FF00) >> 8);
i2cWriteByteData(i2c, pll + 1, (P3 & 0x000000FF));
i2cWriteByteData(i2c, pll + 2, (P1 & 0x00030000) >> 16);
i2cWriteByteData(i2c, pll + 3, (P1 & 0x0000FF00) >> 8);
i2cWriteByteData(i2c, pll + 4, (P1 & 0x000000FF));
i2cWriteByteData(i2c, pll + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16));
i2cWriteByteData(i2c, pll + 6, (P2 & 0x0000FF00) >> 8);
i2cWriteByteData(i2c, pll + 7, (P2 & 0x000000FF));
}
//
// Set up MultiSynth with integer divider and R divider
// R divider is the bit value which is OR'ed onto the appropriate register, it
// is a #define in si5351a.h
//
void setupMultisynth(int i2c, uint8_t synth, uint32_t divider, uint8_t rDiv)
{
uint32_t P1; // Synth config register P1
uint32_t P2; // Synth config register P2
uint32_t P3; // Synth config register P3
P1 = 128 * divider - 512;
P2 = 0; // P2 = 0, P3 = 1 forces an integer value for the divider
P3 = 1;
i2cWriteByteData(i2c, synth + 0, (P3 & 0x0000FF00) >> 8);
i2cWriteByteData(i2c, synth + 1, (P3 & 0x000000FF));
i2cWriteByteData(i2c, synth + 2, ((P1 & 0x00030000) >> 16) | rDiv);
i2cWriteByteData(i2c, synth + 3, (P1 & 0x0000FF00) >> 8);
i2cWriteByteData(i2c, synth + 4, (P1 & 0x000000FF));
i2cWriteByteData(i2c, synth + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16));
i2cWriteByteData(i2c, synth + 6, (P2 & 0x0000FF00) >> 8);
i2cWriteByteData(i2c, synth + 7, (P2 & 0x000000FF));
}
//
// Switches off Si5351a output
// Example: si5351aOutputOff(SI_CLK0_CONTROL);
// will switch off output CLK0
//
void si5351aOutputOff(uint8_t clk)
{
int i2c = i2cOpen(I2C_BUS, I2C_WRITE, 0);
i2cWriteByteData(i2c, 0x80, clk);
i2cClose(i2c);
}
//
// Set CLK0 output ON and to the specified frequency
// Frequency is in the range 1MHz to 150MHz
// Example: si5351aSetFrequency(10000000);
// will set output CLK0 to 10MHz
//
// This example sets up PLL A and MultiSynth 0 and produces the output on CLK0
//
void si5351aSetFrequency(uint32_t frequency)
{
uint32_t pllFreq;
uint32_t xtalFreq = XTAL_FREQ;
uint32_t l;
float f;
uint8_t mult;
uint32_t num;
uint32_t denom;
uint32_t divider;
int i2c = i2cOpen(I2C_BUS, I2C_WRITE, 0);
divider = 900000000 / frequency;// Calculate the division ratio. 900,000,000 is the maximum internal
// PLL frequency: 900MHz
if (divider % 2) divider--; // Ensure an even integer division ratio
pllFreq = divider * frequency; // Calculate the pllFrequency: the divider * desired output frequency
mult = pllFreq / xtalFreq; // Determine the multiplier to get to the required pllFrequency
l = pllFreq % xtalFreq; // It has three parts:
f = l; // mult is an integer that must be in the range 15..90
f *= 1048575; // num and denom are the fractional parts, the numerator and denominator
f /= xtalFreq; // each is 20 bits (range 0..1048575)
num = f; // the actual multiplier is mult + num / denom
denom = 1048575; // For simplicity we set the denominator to the maximum 1048575
// Set up PLL A with the calculated multiplication ratio
setupPLL(i2c, SI_SYNTH_PLL_A, mult, num, denom);
// Set up MultiSynth divider 0, with the calculated divider.
// The final R division stage can divide by a power of two, from 1..128.
// reprented by constants SI_R_DIV1 to SI_R_DIV128 (see si5351a.h header file)
// If you want to output frequencies below 1MHz, you have to use the
// final R division stage
setupMultisynth(i2c, SI_SYNTH_MS_0, divider, SI_R_DIV_1);
// Reset the PLL. This causes a glitch in the output. For small changes to
// the parameters, you don't need to reset the PLL, and there is no glitch
i2cWriteByteData(i2c, SI_PLL_RESET, 0xA0);
// Finally switch on the CLK0 output (0x4F)
// and set the MultiSynth0 input to be PLL A
i2cWriteByteData(i2c, SI_CLK0_CONTROL, 0x4F | SI_CLK_SRC_PLL_A);
i2cClose(i2c);
}
int main(int argc, char **argv) {
unsigned freq;
if (argc != 2) {
puts("one argument required");
return 1;
}
freq = atoi(argv[1]) * 4;
gpioInitialise();
si5351aSetFrequency(freq);
gpioTerminate();
}