Skip to content

Commit 0f5e93c

Browse files
committed
Refactor I2C initialization and communication functions for improved error handling and clarity
1 parent 4a080dc commit 0f5e93c

File tree

1 file changed

+119
-71
lines changed

1 file changed

+119
-71
lines changed

pic18f26k83/i2c.c

Lines changed: 119 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -56,105 +56,148 @@ static w_status_t wait_for_idle(void) {
5656
}
5757

5858
w_status_t i2c_init(uint8_t clkdiv) {
59-
// CSTR Enable clocking; S Cleared by hardware after Start; MODE 7-bit address; EN enabled; RSEN
60-
// disabled;
61-
I2C1CON0 = 0x84;
62-
// TXU 0; CSD Clock Stretching enabled; ACKT 0; RXO 0; ACKDT Acknowledge; ACKSTAT ACK received;
63-
// ACKCNT Not Acknowledge;
64-
I2C1CON1 = 0x80;
65-
// ABD enabled; GCEN disabled; ACNT disabled; SDAHT 300 ns hold time; BFRET 8 I2C Clock pulses;
66-
// FME disabled;
67-
I2C1CON2 = 0x00;
68-
// Setup clock reference to be base (500khz)/32
69-
CLKRCON = 0b10010000 | clkdiv;
70-
CLKRCLK = 0b00000011;
71-
// CLK clock reference
72-
I2C1CLK = 0x04;
73-
I2C1PIR = 0; // ;Clear all the error flags
59+
// Disable module for configuration
60+
I2C1CON0bits.EN = 0;
61+
62+
// Setup and verify clock configuration
63+
CLKRCON = 0b10010000 | (clkdiv & 0x07);
64+
CLKRCLK = 0b00000011; // MFINTOSC source
65+
66+
// Wait for clock to stabilize
67+
unsigned int timeout = 1000;
68+
while (!CLKRCONbits.CLKRDY && --timeout)
69+
;
70+
if (!timeout) {
71+
return W_IO_ERROR;
72+
}
73+
74+
// Select I2C clock source
75+
I2C1CLK = 0x04; // Clock reference
76+
77+
// Configure I2C module registers
78+
I2C1CON0 = 0x04; // 7-bit master mode
79+
I2C1CON1 = 0x80; // Enable ACK, clock stretching
80+
I2C1CON2 = 0x00; // Standard timing
81+
82+
// Clear all flags
83+
I2C1PIR = 0;
7484
I2C1ERR = 0;
7585

76-
return W_SUCCESS;
86+
// Enable module and verify bus is free
87+
I2C1CON0bits.EN = 1;
88+
return wait_for_idle();
7789
}
7890

7991
static w_status_t i2c_write(uint8_t address, const uint8_t *data, uint8_t len) {
80-
I2C1ADB1 = (uint8_t)(address << 1);
92+
// Verify bus state and prepare for transfer
93+
w_status_t status = check_i2c_state();
94+
if (status != W_SUCCESS) {
95+
return status;
96+
}
97+
98+
clear_i2c_buffers();
99+
I2C1PIR = 0;
100+
I2C1ERR = 0;
101+
102+
// Configure transfer
103+
I2C1ADB1 = (uint8_t)(address << 1); // Write address
81104
I2C1CNT = len;
82-
I2C1PIRbits.PCIF = 0;
83-
I2C1ERRbits.NACKIF = 0;
105+
106+
// Start transfer
84107
I2C1CON0bits.S = 1;
85108

86-
unsigned int timeout;
109+
// Send each byte
87110
while (len--) {
88-
I2C1TXB = *data++;
89-
timeout = 0;
90-
while (!I2C1STAT1bits.TXBE && !I2C1ERRbits.NACKIF) {
91-
if (timeout >= I2C_POLL_TIMEOUT) {
111+
unsigned int timeout = 0;
112+
// Wait for transmit buffer to be ready
113+
while (!I2C1STAT1bits.TXBE) {
114+
if (I2C1ERRbits.NACKIF || I2C1ERRbits.BCLIF) {
115+
return W_IO_ERROR;
116+
}
117+
118+
// Handle clock stretching
119+
if (I2C1CON0bits.CSTR) {
120+
__delay_us(I2C_STRETCH_DELAY);
121+
timeout = 0;
122+
} else if (timeout++ >= I2C_POLL_TIMEOUT) {
92123
return W_IO_TIMEOUT;
93124
}
94-
timeout++;
95-
}
96-
if (I2C1ERRbits.NACKIF) {
97-
return W_IO_ERROR;
98125
}
126+
127+
I2C1TXB = *data++;
99128
}
100129

101-
timeout = 0;
130+
// Wait for transfer completion
131+
unsigned int timeout = 0;
102132
while (!I2C1PIRbits.PCIF) {
103-
if (timeout >= I2C_POLL_TIMEOUT) {
133+
if (timeout++ >= I2C_POLL_TIMEOUT) {
104134
return W_IO_TIMEOUT;
105135
}
106-
timeout++;
107-
}
108-
109-
I2C1PIRbits.PCIF = 0;
110-
I2C1STAT1bits.CLRBF = 1;
111-
112-
if ((I2C1ERR & 0x70) != 0) {
113-
return W_IO_ERROR;
114136
}
115137

116138
return W_SUCCESS;
117139
}
118140

119141
static w_status_t i2c_read(uint8_t address, uint8_t *data, uint8_t len) {
120-
I2C1ADB1 = (uint8_t)((address << 1) | 1);
142+
// Verify bus state and prepare for transfer
143+
w_status_t status = check_i2c_state();
144+
if (status != W_SUCCESS) {
145+
return status;
146+
}
147+
148+
clear_i2c_buffers();
149+
I2C1PIR = 0;
150+
I2C1ERR = 0;
151+
152+
// Configure transfer
153+
I2C1ADB1 = (uint8_t)((address << 1) | 0x01); // Read address
121154
I2C1CNT = len;
122-
I2C1PIRbits.PCIF = 0;
123-
I2C1ERRbits.NACKIF = 0;
155+
156+
// Configure acknowledgment behavior
157+
I2C1CON1bits.ACKDT = 0; // ACK bytes
158+
if (len == 1) {
159+
I2C1CON1bits.ACKCNT = 1; // NACK last byte
160+
}
161+
162+
// Start transfer
124163
I2C1CON0bits.S = 1;
125164

126-
unsigned int timeout;
165+
// Receive each byte
127166
while (len--) {
128-
timeout = 0;
129-
while (!I2C1STAT1bits.RXBF && !I2C1ERRbits.NACKIF) {
130-
if (timeout >= I2C_POLL_TIMEOUT) {
167+
unsigned int timeout = 0;
168+
// Wait for receive buffer to have data
169+
while (!I2C1STAT1bits.RXBF) {
170+
if (I2C1ERRbits.NACKIF || I2C1ERRbits.BCLIF) {
171+
return W_IO_ERROR;
172+
}
173+
174+
// Handle clock stretching
175+
if (I2C1CON0bits.CSTR) {
176+
__delay_us(I2C_STRETCH_DELAY);
177+
timeout = 0;
178+
} else if (timeout++ >= I2C_POLL_TIMEOUT) {
131179
return W_IO_TIMEOUT;
132180
}
133-
timeout++;
134-
}
135-
if (I2C1ERRbits.NACKIF) {
136-
return W_IO_ERROR;
137181
}
182+
138183
*data++ = I2C1RXB;
139184
}
140185

141-
timeout = 0;
186+
// Wait for transfer completion
187+
unsigned int timeout = 0;
142188
while (!I2C1PIRbits.PCIF) {
143-
if (timeout >= I2C_POLL_TIMEOUT) {
189+
if (timeout++ >= I2C_POLL_TIMEOUT) {
144190
return W_IO_TIMEOUT;
145191
}
146-
timeout++;
147-
}
148-
I2C1PIRbits.PCIF = 0;
149-
I2C1STAT1bits.CLRBF = 1;
150-
151-
if ((I2C1ERR & 0x70) != 0) {
152-
return W_IO_ERROR;
153192
}
154193

155194
return W_SUCCESS;
156195
}
157196

197+
/*
198+
* Public interface functions
199+
* These provide the high-level API for I2C communication
200+
*/
158201
w_status_t i2c_write_data(uint8_t address, const uint8_t *data, uint8_t len) {
159202
return i2c_write(address, data, len);
160203
}
@@ -169,35 +212,40 @@ w_status_t i2c_write_reg8(uint8_t address, uint8_t reg, uint8_t val) {
169212
}
170213

171214
w_status_t i2c_write_reg16(uint8_t address, uint8_t reg, uint16_t val) {
172-
uint8_t data[3] = {reg, (uint8_t)(val >> 8), (uint8_t)val};
215+
uint8_t data[3] = {
216+
reg,
217+
(uint8_t)(val >> 8), // MSB first
218+
(uint8_t)(val & 0xFF) // LSB second
219+
};
173220
return i2c_write(address, data, 3);
174221
}
175222

176223
w_status_t i2c_read_reg8(uint8_t address, uint8_t reg, uint8_t *value) {
224+
// Write register address
177225
w_status_t status = i2c_write(address, &reg, 1);
178226
if (status != W_SUCCESS) {
179-
return W_IO_ERROR;
227+
return status;
180228
}
181229

182-
uint8_t data;
183-
status = i2c_read(address, &data, 1);
184-
if (status != W_SUCCESS) {
185-
return W_IO_ERROR;
186-
}
187-
*value = data;
188-
return W_SUCCESS;
230+
// Read register value
231+
return i2c_read(address, value, 1);
189232
}
190233

191234
w_status_t i2c_read_reg16(uint8_t address, uint8_t reg, uint16_t *value) {
235+
// Write register address
192236
w_status_t status = i2c_write(address, &reg, 1);
193237
if (status != W_SUCCESS) {
194-
return W_IO_ERROR;
238+
return status;
195239
}
240+
241+
// Read register value
196242
uint8_t data[2];
197243
status = i2c_read(address, data, 2);
198244
if (status != W_SUCCESS) {
199-
return W_IO_ERROR;
245+
return status;
200246
}
201-
*value = (uint16_t)(data[0]) << 8 | data[1];
247+
248+
// Combine bytes (MSB first)
249+
*value = ((uint16_t)data[0] << 8) | data[1];
202250
return W_SUCCESS;
203-
}
251+
}

0 commit comments

Comments
 (0)