aboutsummaryrefslogtreecommitdiff
path: root/examples/lpc43xx/hackrf-jellybean/i2c/i2cdemo.c
blob: 88bbec4f6d8254eefff555188f7012374141b87b (plain)
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/*
 * This file is part of the libopencm3 project.
 *
 * Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
 * Copyright (C) 2012 Michael Ossmann <mike@ossmann.com>
 *
 * This library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/cgu.h>
#include <libopencm3/lpc43xx/i2c.h>

void gpio_setup(void)
{
	GPIO2_DIR |= (1 << 1); /* Configure GPIO2[1] (P4_1) as output. */
}

//FIXME generalize and move to drivers

#define SCU_SFSI2C0_SCL_EFP (1 << 1)  /* 3 ns glitch filter */
#define SCU_SFSI2C0_SCL_EHD (1 << 2)  /* Fast-mode Plus transmit */
#define SCU_SFSI2C0_SCL_EZI (1 << 3)  /* Enable the input receiver */
#define SCU_SFSI2C0_SCL_ZIF (1 << 7)  /* Disable input glitch filter */
#define SCU_SFSI2C0_SDA_EFP (1 << 8)  /* 3 ns glitch filter */
#define SCU_SFSI2C0_SDA_EHD (1 << 10) /* Fast-mode Plus transmit */
#define SCU_SFSI2C0_SDA_EZI (1 << 11) /* Enable the input receiver */
#define SCU_SFSI2C0_SDA_ZIF (1 << 15) /* Disable input glitch filter */

#define I2C_CONCLR_AAC   (1 << 2) /* Assert acknowledge Clear */
#define I2C_CONCLR_SIC   (1 << 3) /* I2C interrupt Clear */
#define I2C_CONCLR_STAC  (1 << 5) /* START flag Clear */
#define I2C_CONCLR_I2ENC (1 << 6) /* I2C interface Disable bit */

#define I2C_CONSET_AA   (1 << 2) /* Assert acknowledge flag */
#define I2C_CONSET_SI   (1 << 3) /* I2C interrupt flag */
#define I2C_CONSET_STO  (1 << 4) /* STOP flag */
#define I2C_CONSET_STA  (1 << 5) /* START flag */
#define I2C_CONSET_I2EN (1 << 6) /* I2C interface enable */

#define CGU_SRC_32K       0x00
#define CGU_SRC_IRC       0x01
#define CGU_SRC_ENET_RX   0x02
#define CGU_SRC_ENET_TX   0x03
#define CGU_SRC_GP_CLKIN  0x04
#define CGU_SRC_XTAL      0x06
#define CGU_SRC_PLL0USB   0x07
#define CGU_SRC_PLL0AUDIO 0x08
#define CGU_SRC_PLL1      0x09
#define CGU_SRC_IDIVA     0x0C
#define CGU_SRC_IDIVB     0x0D
#define CGU_SRC_IDIVC     0x0E
#define CGU_SRC_IDIVD     0x0F
#define CGU_SRC_IDIVE     0x10

#define CGU_BASE_CLK_PD        (1 << 0)  /* output stage power-down */
#define CGU_BASE_CLK_AUTOBLOCK (1 << 11) /* block clock automatically */
#define CGU_BASE_CLK_SEL_SHIFT 24        /* clock source selection (5 bits) */

void i2c0_init()
{
	/* enable input on SCL and SDA pins */
	SCU_SFSI2C0 = (SCU_SFSI2C0_SCL_EZI | SCU_SFSI2C0_SDA_EZI);

	/* use PLL1 as clock source for APB1 (including I2C0) */
	CGU_BASE_APB1_CLK = (CGU_SRC_PLL1 << CGU_BASE_CLK_SEL_SHIFT);

	//FIXME assuming we're on IRC at 96 MHz

	/* 400 kHz I2C */
	//I2C0_SCLH = 120;
	//I2C0_SCLL = 120;

	/* 100 kHz I2C */
	I2C0_SCLH = 480;
	I2C0_SCLL = 480;
	//FIXME not sure why this appears to run at about 290 kHz

	/* clear the control bits */
	I2C0_CONCLR = (I2C_CONCLR_AAC | I2C_CONCLR_SIC
			| I2C_CONCLR_STAC | I2C_CONCLR_I2ENC);

	/* enable I2C0 */
	I2C0_CONSET = I2C_CONSET_I2EN;
}

/* transmit start bit */
void i2c0_tx_start()
{
	I2C0_CONCLR = I2C_CONCLR_SIC;
	I2C0_CONSET = I2C_CONSET_STA;
	while (!(I2C0_CONSET & I2C_CONSET_SI));
	I2C0_CONCLR = I2C_CONCLR_STAC;
}

/* transmit data byte */
void i2c0_tx_byte(u8 byte)
{
	if (I2C0_CONSET & I2C_CONSET_STA)
		I2C0_CONCLR = I2C_CONCLR_STAC;
	I2C0_DAT = byte;
	I2C0_CONCLR = I2C_CONCLR_SIC;
	while (!(I2C0_CONSET & I2C_CONSET_SI));
}

/* receive data byte */
u8 i2c0_rx_byte()
{
	if (I2C0_CONSET & I2C_CONSET_STA)
		I2C0_CONCLR = I2C_CONCLR_STAC;
	I2C0_CONCLR = I2C_CONCLR_SIC;
	while (!(I2C0_CONSET & I2C_CONSET_SI));
	return I2C0_DAT;
}

/* transmit stop bit */
void i2c0_stop()
{
	if (I2C0_CONSET & I2C_CONSET_STA)
		I2C0_CONCLR = I2C_CONCLR_STAC;
	I2C0_CONSET = I2C_CONSET_STO;
	I2C0_CONCLR = I2C_CONCLR_SIC;
}

#define SI5351C_I2C_ADDR (0x60 << 1)
#define I2C_WRITE        0
#define I2C_READ         1

/* write to single register */
void si5351c_write_reg(uint8_t reg, uint8_t val)
{
	i2c0_tx_start();
	i2c0_tx_byte(SI5351C_I2C_ADDR | I2C_WRITE);
	i2c0_tx_byte(reg);
	i2c0_tx_byte(val);
	i2c0_stop();
}

/* read single register */
uint8_t si5351c_read_reg(uint8_t reg)
{
	uint8_t val;

	/* set register address with write */
	i2c0_tx_start();
	i2c0_tx_byte(SI5351C_I2C_ADDR | I2C_WRITE);
	i2c0_tx_byte(reg);

	/* read the value */
	i2c0_tx_start();
	i2c0_tx_byte(SI5351C_I2C_ADDR | I2C_READ);
	val = i2c0_rx_byte();
	i2c0_stop();

	return val;
}

int main(void)
{
	int i;

	gpio_setup();
	i2c0_init();

	while (1) {
		if (si5351c_read_reg(0) == 0x10)
			gpio_set(GPIO2, GPIOPIN1); /* LED on */
		else
			gpio_clear(GPIO2, GPIOPIN1); /* LED off */

		for (i = 0; i < 1000; i++)    /* Wait a bit. */
			__asm__("nop");
	}

	return 0;
}