Bar Logo 3.8/7.6 kw Totem pole Demonstration Application (Part-No. (not specified))
 
Content
     
Loading...
Searching...
No Matches
i2c2.c
1
25/*
26 (c) 2022 Microchip Technology Inc. and its subsidiaries. You may use this
27 software and any derivatives exclusively with Microchip products.
28
29 THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
30 EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
31 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
32 PARTICULAR PURPOSE, OR ITS INTERACTION WITH MICROCHIP PRODUCTS, COMBINATION
33 WITH ANY OTHER PRODUCTS, OR USE IN ANY APPLICATION.
34
35 IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
36 INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
37 WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS
38 BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE
39 FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN
40 ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
41 THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
42
43 MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE OF THESE
44 TERMS.
45*/
46
47#include "i2c2.h"
48
63typedef enum
64{
65 S_SLAVE_IDLE,
66 S_SLAVE_RECEIVE_MODE,
67 S_SLAVE_TRANSMIT_MODE,
68 S_SLAVE_LOW_BYTE_ADDRESS_DETECT,
69
70} I2C_SLAVE_STATES;
71
75/* defined for I2C2 */
76#define I2C2_TRANSMIT_REG I2C2TRN // Defines the transmit register used to send data.
77#define I2C2_RECEIVE_REG I2C2RCV // Defines the receive register used to receive data.
78
79#define I2C2_MASK_REG I2C2MSK // Defines the address mask register.
80#define I2C2_ADDRESS_REG I2C2ADD // Defines the address register.
81
82// The following control bits are used in the I2C state machine to manage
83// the I2C module and determine next states.
84#define I2C2_GENERAL_CALL_ENABLE_BIT I2C2CONLbits.GCEN // I2C General Call enable control bit.
85#define I2C2_10_BIT_ADDRESS_ENABLE_BIT I2C2CONLbits.A10M // I2C Address Mode (7 or 10 bit address) control bit.
86#define I2C2_RELEASE_SCL_CLOCK_CONTROL_BIT I2C2CONLbits.SCLREL // I2C clock stretch/release control bit.
87
88// The following status bits are used in the I2C state machine to determine
89// the next states.
90
91#define I2C2_READ_NOT_WRITE_STATUS_BIT I2C2STATbits.R_W // I2C current transaction read/write status bit.
92#define I2C2_DATA_NOT_ADDRESS_STATUS_BIT I2C2STATbits.D_A // I2C last byte receive was data/address status bit.
93#define I2C2_RECEIVE_OVERFLOW_STATUS_BIT I2C2STATbits.I2COV // I2C receive buffer overflow status bit.
94#define I2C2_GENERAL_CALL_ADDRESS_STATUS_BIT I2C2STATbits.GCSTAT // I2C General Call status bit.
95#define I2C2_ACKNOWLEDGE_STATUS_BIT I2C2STATbits.ACKSTAT // I2C ACK status bit.
96#define I2C2_STOP_STATUS_BIT I2C2STATbits.P // I2C STOP status bit
97
98#define EMULATE_EEPROM_SIZE 64
103static inline void __attribute__ ((always_inline)) I2C2_TransmitProcess(void);
104static inline void __attribute__ ((always_inline)) I2C2_ReceiveProcess(void);
105
110static I2C_SLAVE_STATES i2c2_slave_state;
111static uint8_t *p_i2c2_write_pointer;
112static uint8_t *p_i2c2_read_pointer;
113
114
124void I2C2_Initialize(void)
125{
126
127 // initialize the hardware
128 // ACKEN disabled; STRICT disabled; STREN disabled; GCEN disabled; SMEN disabled; DISSLW enabled; I2CSIDL disabled; ACKDT Sends ACK; SCLREL Holds; RSEN disabled; A10M 7 Bit; PEN disabled; RCEN disabled; SEN disabled; I2CEN enabled;
129 I2C2CONL = 0x8000;
130 // BCL disabled; P disabled; S disabled; I2COV disabled; IWCOL disabled;
131 I2C2STAT = 0x00;
132 // ADD 32;
133 I2C2_SlaveAddressSet(0x20);
134 // AMSK 0;
135 I2C2_SlaveAddressMaskSet(0x00);
136
137 // make sure this is set first
138 i2c2_slave_state = S_SLAVE_IDLE;
139
140 I2C2_ReadPointerSet(NULL);
141 I2C2_WritePointerSet(NULL);
142
143 // generate interrupt on STOP
144 // CH: setting this bit in MCC doesn't work!
145 I2C2CONHbits.PCIE = 1;
146
147}
148
149
150void I2C2_SlaveTasks ( void )
151{
152 static bool prior_address_match = false;
153 static bool not_busy = true;
154 uint8_t dummy;
155
156 // NOTE: The slave driver will always acknowledge
157 // any address match.
158
159 switch (i2c2_slave_state)
160 {
161 case S_SLAVE_IDLE:
162 case S_SLAVE_RECEIVE_MODE:
163
164 /* When at S_SLAVE_RECEIVE_MODE this mode there
165 will be two types of incoming transactions:
166 1. Data sent by master
167 2. A restart or start detection
168
169 But from the point of view of the firmware, there is
170 no difference between S_SLAVE_IDLE and S_SLAVE_RECEIVE_MODE
171 states, since the types of incoming transactions will be
172 the same so we share the code here.
173 */
174
175 if (
176 // case of 7-bit address detected
177 ( (I2C2_10_BIT_ADDRESS_ENABLE_BIT == 0) &&
178 (I2C2_DATA_NOT_ADDRESS_STATUS_BIT == 0)
179 )
180 ||
181 // case of general address call detected
182 ( (I2C2_GENERAL_CALL_ENABLE_BIT == 1) &&
183 (I2C2_GENERAL_CALL_ADDRESS_STATUS_BIT == 1)
184 )
185 )
186 {
187 if (I2C2_READ_NOT_WRITE_STATUS_BIT == 0)
188 {
190
191 // it is a write, go to receive mode
192 I2C2_StatusCallback(I2C2_SLAVE_RECEIVE_REQUEST_DETECTED);
193
194 // Receive the data if valid
195 I2C2_ReceiveProcess();
196 i2c2_slave_state = S_SLAVE_RECEIVE_MODE;
197 }
198 else
199 {
200 // read the receive register only when
201 // we are ready for the next transaction.
202 // this one is a dummy read
203 dummy = I2C2_RECEIVE_REG;
204
205 // it is a read, go to transmit mode
206
207 I2C2_StatusCallback(I2C2_SLAVE_TRANSMIT_REQUEST_DETECTED);
208
209 // during this portion, the master is expecting the
210 // slave for a reply. So the returned status of
211 // the callback at this point cannot be used to
212 // delay the reply if needed.
213 // In other words, the slave has to reply to the master.
214 // Therefore, the transmit will be performed.
215
216 I2C2_TransmitProcess();
217 i2c2_slave_state = S_SLAVE_TRANSMIT_MODE;
218 }
219
220 }
221
222 else if
223 (
224 // case of 10-bit high address detected
225 ( (I2C2_10_BIT_ADDRESS_ENABLE_BIT == 1) &&
226 (I2C2_DATA_NOT_ADDRESS_STATUS_BIT == 0)
227 )
228 )
229 {
230 if (I2C2_READ_NOT_WRITE_STATUS_BIT == 0)
231 {
232 // it is the detection of high byte address of
233 // 10-bit address, go to detection of low byte address
234 prior_address_match = false;
235 i2c2_slave_state = S_SLAVE_LOW_BYTE_ADDRESS_DETECT;
236
237 }
238 else // if (I2C2_READ_NOT_WRITE_STATUS_BIT == 1)
239 {
240 if (prior_address_match == true)
241 {
242 // it is the detection of high byte
243 // address of 10-bit address, but the next
244 // transaction is read transaction (so it
245 // is a restart).
246 // set the transmit register with the data
247 // to transmit then go to transmit mode
248
249 I2C2_StatusCallback(I2C2_SLAVE_TRANSMIT_REQUEST_DETECTED);
250
251 // during this portion, the master is expecting the
252 // slave for a reply. So the returned status of
253 // the callback at this point cannot be used to
254 // delay the reply if needed.
255 // In other words, the slave has to reply to the master.
256 // Therefore, the transmit will be performed.
257
258 I2C2_TransmitProcess();
259 i2c2_slave_state = S_SLAVE_TRANSMIT_MODE;
260 }
261 else
262 {
263 // it is the detection of high byte address of
264 // 10-bit address, but next transaction is a write.
265 // go to detection of low byte address
266 prior_address_match = false;
267 i2c2_slave_state = S_SLAVE_LOW_BYTE_ADDRESS_DETECT;
268
269 }
270 }
271
272 // dummy read is needed
273 dummy = I2C2_RECEIVE_REG;
274 }
275
276 // this if statement is to make sure we only save incoming
277 // data when we are truly in receiving mode
278 if (i2c2_slave_state == S_SLAVE_RECEIVE_MODE)
279 {
280 // case of data received
281 if (I2C2_STOP_STATUS_BIT == 1)
282 {
283 I2C2_StatusCallback(I2C2_SLAVE_STOP_BIT_DETECTED);
284 }
285 else if (I2C2_DATA_NOT_ADDRESS_STATUS_BIT == 1)
286 {
287 // check if we are overflowing the receive buffer
288 if (I2C2_RECEIVE_OVERFLOW_STATUS_BIT != 1)
289 {
290 I2C2_ReceiveProcess();
291 not_busy = I2C2_StatusCallback(I2C2_SLAVE_RECEIVED_DATA_DETECTED);
292 }
293 else
294 {
295 // overflow detected!
296 // read the buffer to reset the buffer full flag
297 // and clear the overflow bit
298 // then do nothing so the master
299 // will resend the data
300 dummy = I2C2_RECEIVE_REG;
301 I2C2_RECEIVE_OVERFLOW_STATUS_BIT = 0;
302 }
303 }
304
305 }
306
307 break;
308
309 case S_SLAVE_LOW_BYTE_ADDRESS_DETECT:
310 // Note that this state will only get
311 // executed when 10-bit address is set
312
313 // we send receive request but we do not actually know
314 // if the next one is a data from master since the
315 // next one can be a restart with a transmit request.
316 // When that happens, the next state will take care of it.
317 // This is just the nature of i2c bus protocol.
318 not_busy = I2C2_StatusCallback(I2C2_SLAVE_10BIT_RECEIVE_REQUEST_DETECTED);
319
320 // set this flag to indicate we have
321 // full 10-bit address detection
322 prior_address_match = true;
323
324 if (not_busy)
325 {
326 // dummy read is needed
327 dummy = I2C2_RECEIVE_REG;
328 }
329
330 i2c2_slave_state = S_SLAVE_RECEIVE_MODE;
331
332 break;
333
334 case S_SLAVE_TRANSMIT_MODE:
335
336 // this is the state where an ACK or NACK is expected
337 // to occur after the slave has placed data to the
338 // transmit register.
339
340 // if the transaction was ACK'ed, more data needs to be sent
341 // if the transaction was NACK'ed then we don't need to send
342 // more data
343 if (I2C2_ACKNOWLEDGE_STATUS_BIT == 0)
344 {
345 // prepare next data
346 I2C2_StatusCallback(I2C2_SLAVE_TRANSMIT_REQUEST_DETECTED);
347
348 // transmit more data
349 I2C2_TransmitProcess();
350
351 }
352 else //if (I2C2_ACKNOWLEDGE_STATUS_BIT == 1)
353 {
354 // no more data to be sent so we go to idle state
355 i2c2_slave_state = S_SLAVE_IDLE;
356 }
357 break;
358
359
360 default:
361 // should never happen, if we ever get here stay here forever
362 while(1);
363 break;
364 }
365
366
367 // clear the slave interrupt flag
368 IFS2bits.SI2C2IF = 0;
369
370}
371
372void I2C2_ReadPointerSet(uint8_t *p)
373{
374 p_i2c2_read_pointer = p;
375}
376
377void I2C2_WritePointerSet(uint8_t *p)
378{
379 p_i2c2_write_pointer = p;
380}
381
382uint8_t *I2C2_ReadPointerGet(void)
383{
384 return (p_i2c2_read_pointer);
385}
386
387uint8_t *I2C2_WritePointerGet(void)
388{
389 return (p_i2c2_write_pointer);
390}
391
392void I2C2_SlaveAddressMaskSet(
393 uint16_t mask)
394{
395 I2C2_MASK_REG = mask;
396}
397
398void I2C2_SlaveAddressSet(
399 uint16_t address)
400{
401 if (address > 0x7F)
402 {
403 // use 10 bit address
404 I2C2_10_BIT_ADDRESS_ENABLE_BIT = true;
405 }
406 else
407 {
408 // use 7 bit address
409 I2C2_10_BIT_ADDRESS_ENABLE_BIT = false;
410 }
411 i2c2_slave_state = S_SLAVE_IDLE;
412 I2C2_ADDRESS_REG = address;
413
414}
415
416static inline void __attribute__ ((always_inline)) I2C2_TransmitProcess(void)
417{
418 // get the data to be transmitted
419
420 // sanity check (to avoid stress)
421 if (p_i2c2_read_pointer == NULL)
422 return;
423
424 I2C2_TRANSMIT_REG = *p_i2c2_read_pointer;
425
426 // set the SCL clock to be released
427 I2C2_RELEASE_SCL_CLOCK_CONTROL_BIT = 1;
428
429}
430
431static inline void __attribute__ ((always_inline)) I2C2_ReceiveProcess(void)
432{
433 // store the received data
434
435 // sanity check (to avoid stress)
436 if (p_i2c2_write_pointer == NULL)
437 return;
438
439 *p_i2c2_write_pointer = I2C2_RECEIVE_REG;
440
441}
442
443/* Note: This is an example of the I2C2_StatusCallback()
444 implementation. This is an emulated EEPROM Memory
445 configured to act as a I2C Slave Device.
446 For specific slave device implementation, remove
447 or modify this function to the specific slave device
448 behavior.
449*/
bool I2C2_StatusCallback(I2C2_SLAVE_DRIVER_STATUS status)
Definition drv_i2c.c:82