forked from ttrftech/CentSDR
-
Notifications
You must be signed in to change notification settings - Fork 2
/
si5351_low.c
107 lines (91 loc) · 2.72 KB
/
si5351_low.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
#include "hal.h"
#include "si5351.h"
#define SI5351_I2C_ADDR (0x60<<1)
static void
rcc_gpio_init(void)
{
// Reset AHB,APB1,APB2
RCC->AHBRSTR |= 0xffffffff;
RCC->AHBRSTR = 0;
RCC->APB1RSTR |= 0xffffffff;
RCC->APB1RSTR = 0;
RCC->APB2RSTR |= 0xffffffff;
RCC->APB2RSTR = 0;
RCC->APB1ENR |= RCC_APB1ENR_PWREN | RCC_APB1ENR_I2C1EN;
RCC->AHBENR |= RCC_AHBENR_GPIOBEN;
RCC->CFGR3 |= RCC_CFGR3_I2C1SW_HSI;
GPIOB->AFRH = 0x55550044; // PB8,PB9 Alternate Function 4
GPIOB->OTYPER |= 0x0300; // PB8,PB9 Open drain
GPIOB->MODER |= 0x000A0000;//
GPIOB->OSPEEDR |= 0x00050000;//
}
static void
i2c_init(I2C_TypeDef* i2c)
{
// Disable the I2Cx peripheral
i2c->CR1 &= ~I2C_CR1_PE;
while (i2c->CR1 & I2C_CR1_PE);
// 100kHz @ 8MHz
i2c->TIMINGR = 0x10420F13;
// Use 7-bit addresses
i2c->CR2 &=~ I2C_CR2_ADD10;
// Enable the analog filter
i2c->CR1 &= ~I2C_CR1_ANFOFF;
// Disable NOSTRETCH
i2c->CR1 |= I2C_CR1_NOSTRETCH;
// Enable I2Cx peripheral clock.
// Select APB1 as clock source
if (i2c == I2C1) {
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
} else if (i2c == I2C2) {
RCC->APB1ENR |= RCC_APB1ENR_I2C2EN;
}
// Enable the I2Cx peripheral
i2c->CR1 |= I2C_CR1_PE;
}
static void
i2cSendByte(I2C_TypeDef* i2c, uint8_t addr, const uint8_t *buf, uint8_t len)
{
i2c->CR2 = (I2C_CR2_SADD & addr) // Set the slave address
| (I2C_CR2_NBYTES & (len << 16)) // Send one byte
| I2C_CR2_START // Generate start condition
| I2C_CR2_AUTOEND; // Generate stop condition after sent
// Send the data
while (len-- > 0) {
while (!(i2c->ISR & I2C_ISR_TXIS));
i2c->TXDR = (I2C_TXDR_TXDATA & *buf++);
}
}
// register addr, length, data, ...
const uint8_t si5351_configs[] = {
2, SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xff,
4, SI5351_REG_16_CLK0_CONTROL, SI5351_CLK_POWERDOWN, SI5351_CLK_POWERDOWN, SI5351_CLK_POWERDOWN,
2, SI5351_REG_183_CRYSTAL_LOAD, SI5351_CRYSTAL_LOAD_8PF,
// setup PLL
// setup PLL (26MHz * 32 = 832MHz : 32/2-2=14)
9, SI5351_REG_26_PLL_A, /*P3*/0, 1, /*P1*/0, 14, 0, /*P3/P2*/0, 0, 0,
// RESET PLL
2, SI5351_REG_177_PLL_RESET, SI5351_PLL_RESET_A | SI5351_PLL_RESET_B,
// setup multisynth (832MHz/8MHz=104,104/2-2=50)
9, SI5351_REG_58_MULTISYNTH2, /*P3*/0, 1, /*P1*/0, 50, 0, /*P2|P3*/0, 0, 0,
2, SI5351_REG_18_CLK2_CONTROL, SI5351_CLK_DRIVE_STRENGTH_2MA | SI5351_CLK_INPUT_MULTISYNTH_N | SI5351_CLK_INTEGER_MODE,
2, SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0,
0 // sentinel
};
void
si5351_init_bulk(void)
{
const uint8_t *p = si5351_configs;
while (*p) {
uint8_t len = *p++;
i2cSendByte(I2C1, SI5351_I2C_ADDR, p, len);
p += len;
}
}
void
si5351_setup(void)
{
rcc_gpio_init();
i2c_init(I2C1);
si5351_init_bulk();
}