-
Notifications
You must be signed in to change notification settings - Fork 0
/
i2c.c
142 lines (128 loc) · 4.06 KB
/
i2c.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
/* i2c.c */
#include "hello.h"
#include "i2c.h"
//#define I2C_FASTMODEPLUS
#define I2C_EXTRA
#ifdef I2C_EXTRA
# define I2CPINCONFIG (IOCON_FUNC1 | IOCON_FASTI2C_EN)
# define I2C_SPEED 2600000
# define SCL_LOWDUTY 75
#elif defined(I2C_FASTMODEPLUS)
# define I2CPINCONFIG (IOCON_FUNC1 | IOCON_FASTI2C_EN)
# define I2C_SPEED 1000000
#elif defined(I2C_FAST)
# define I2CPINCONFIG (IOCON_FUNC1 | IOCON_STDI2C_EN)
# define I2C_SPEED 400000
#else
# define I2CPINCONFIG (IOCON_FUNC1 | IOCON_STDI2C_EN)
# define I2C_SPEED 100000
#endif
#define I2C_PCLK 48000000
#define SCL_PERIOD (I2C_PCLK / I2C_SPEED)
#ifndef SCL_LOWDUTY
# define SCL_LOWDUTY 50
#endif
#define SCL_HIGHDUTY (100 - (SCL_LOWDUTY))
#define SCLL_VALUE (SCL_LOWDUTY * SCL_PERIOD / 100)
#define SCLH_VALUE (SCL_HIGHDUTY * SCL_PERIOD / 100)
void i2c_init(void)
{
LPC_IOCON->REG[IOCON_PIO0_4] = I2CPINCONFIG;
LPC_IOCON->REG[IOCON_PIO0_5] = I2CPINCONFIG;
Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_I2C);
Chip_SYSCTL_DeassertPeriphReset(RESET_I2C0);
LPC_I2C->CONSET = I2C_I2CONSET_I2EN;
LPC_I2C->SCLH = SCLH_VALUE;
LPC_I2C->SCLL = SCLL_VALUE;
NVIC_EnableIRQ(I2C0_IRQn);
}
volatile struct {
uint8_t *data;
int len;
int header;
int offset;
int address;
volatile int result;
i2c_fn fn;
} i2c_state;
#define I2C_SUCCESS 0
#define I2C_BUSY 1
#define I2C_FAIL_BUS_ERROR 2
#define I2C_FAIL_NACK 3
#define I2C_FAIL_ARBITRATION 4
#define I2C_FAIL_NOTIMPLEMENTED 5
bool i2c_busy(void)
{
return i2c_state.result == I2C_BUSY;
}
bool i2c_transmit(uint8_t address, uint8_t header, uint8_t *data, int len, i2c_fn fn)
{
if (i2c_busy())
return false;
i2c_state.address = address << 1;
i2c_state.header = header;
i2c_state.data = data;
i2c_state.len = len;
i2c_state.offset = -1;
i2c_state.result = I2C_BUSY;
i2c_state.fn = fn;
LPC_I2C->CONSET = I2C_I2CONSET_STA;
return true;
}
int i2c_result(void)
{
return i2c_state.result;
}
void I2C0_IRQHandler(void)
{
int state = LPC_I2C->STAT;
switch (state) {
case 0x00: // Bus error
LPC_I2C->CONSET = I2C_I2CONSET_STO | I2C_I2CONSET_AA;
LPC_I2C->CONCLR = I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC;
i2c_state.result = I2C_FAIL_BUS_ERROR;
break;
case 0x08: // START has been transmitted
case 0x10: // Repeated START has been transmitted
LPC_I2C->DAT = i2c_state.address;
LPC_I2C->CONSET = I2C_I2CONSET_AA;
LPC_I2C->CONCLR = I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC;
break;
case 0x18: // SLA+W has been transmitted, ACK has been received
case 0x28: // Data has been transmitted, ACK has been received
if (i2c_state.offset < 0) {
LPC_I2C->DAT = i2c_state.header;
i2c_state.offset++;
LPC_I2C->CONSET = I2C_I2CONSET_AA;
LPC_I2C->CONCLR = I2C_I2CONCLR_SIC;
} else if (i2c_state.offset < i2c_state.len) {
LPC_I2C->DAT = i2c_state.data[i2c_state.offset++];
LPC_I2C->CONSET = I2C_I2CONSET_AA;
LPC_I2C->CONCLR = I2C_I2CONCLR_SIC;
} else {
LPC_I2C->CONSET = I2C_I2CONSET_STO | I2C_I2CONSET_AA;
LPC_I2C->CONCLR = I2C_I2CONCLR_SIC;
i2c_state.result = I2C_SUCCESS;
if (i2c_state.fn)
i2c_state.fn();
}
break;
case 0x20: // SLA+W has been transmitted, NACK has been received
case 0x30: // Data has been transmitted, NACK has been received
LPC_I2C->CONSET = I2C_I2CONSET_STO | I2C_I2CONSET_AA;
LPC_I2C->CONCLR = I2C_I2CONCLR_SIC;
i2c_state.result = I2C_FAIL_NACK;
break;
case 0x38: // Arbitration lost
LPC_I2C->CONSET = I2C_I2CONSET_STO | I2C_I2CONSET_AA;
LPC_I2C->CONCLR = I2C_I2CONCLR_SIC;
i2c_state.result = I2C_FAIL_ARBITRATION;
break;
default:
LPC_I2C->CONSET = I2C_I2CONSET_STO | I2C_I2CONSET_AA;
LPC_I2C->CONCLR = I2C_I2CONCLR_SIC;
i2c_state.result = I2C_FAIL_NOTIMPLEMENTED;
break;
}
// LPC_I2C->CONCLR = I2C_I2CONCLR_SIC;
}