summaryrefslogtreecommitdiff
path: root/mcc_generated_files/mssp2_i2c.c
blob: 89851539ddea5e0b24b6912e7b0d49a34a80952f (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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
#include "mssp2_i2c.h"

/**
 Section: Data Types
*/

/**
  I2C Slave Driver State Enumeration

  @Summary
    Defines the different states of the i2c slave.

  @Description
    This defines the different states that the i2c slave
    used to process transactions on the i2c bus.
*/
typedef enum
{
    S_SLAVE_IDLE,
    S_SLAVE_RECEIVE_MODE,
    S_SLAVE_TRANSMIT_MODE,
    S_SLAVE_LOW_BYTE_ADDRESS_DETECT,

} I2C_SLAVE_STATES;

/**
  I2C uint16_t union 

  @Summary
    Defines the data type to easily manage the slave addresses.
 
  @Description
    This defines the data type to easily swap between lsb and msb
    of the slave address when doing 10-bit addressing.
 */
typedef union
{
    uint8_t  uint168BitValue[2];
    uint16_t uint16Value;
}UINT16_UNION;

/**
 Section: Macro Definitions
*/

/* defined for MSSP2_I2C */

#define MSSP2_I2C_TRANSMIT_REG                       SSP2BUF                 // Defines the transmit register used to send data.
#define MSSP2_I2C_RECEIVE_REG                        SSP2BUF                 // Defines the receive register used to receive data.

#define MSSP2_I2C_MASK_REG                           SSP2MSK                 // Defines the address mask register.
#define MSSP2_I2C_ADDRESS_REG                        SSP2ADD                 // Defines the address register. 

// The following control bits are used in the I2C state machine to manage
// the I2C module and determine next states.
#define MSSP2_I2C_SERIAL_PORT_ENABLE_BIT             SSP2CON1bits.SSPEN      // I2C port enable control bit.
#define MSSP2_I2C_MODE_SELECT_BITS                   SSP2CON1bits.SSPM       // I2C Slave Mode control bit.
#define MSSP2_I2C_RELEASE_SCL_CLOCK_CONTROL_BIT      SSP2CON1bits.CKP        // I2C clock stretch/release control bit.
#define MSSP2_I2C_RECEIVE_OVERFLOW_STATUS_BIT        SSP2CON1bits.SSPOV      // I2C receive buffer overflow status bit.
#define MSSP2_I2C_ACKNOWLEDGE_STATUS_BIT             SSP2CON2bits.ACKSTAT    // I2C ACK status bit.

// The following status bits are used in the I2C state machine to determine
// the next states.
#define MSSP2_I2C_READ_NOT_WRITE_STATUS_BIT          SSP2STATbits.R_NOT_W    // I2C current transaction read/write status bit.
#define MSSP2_I2C_DATA_NOT_ADDRESS_STATUS_BIT        SSP2STATbits.D_NOT_A    // I2C last byte receive was data/address status bit.

/**
 Section: Local Functions
*/

inline void __attribute__ ((always_inline)) MSSP2_I2C_TransmitProcess(void);
inline void __attribute__ ((always_inline)) MSSP2_I2C_ReceiveProcess(void);

/**
 Section: Local Variables
*/

static I2C_SLAVE_STATES   mssp2_i2c_slave_state;
static uint8_t                *p_mssp2_i2c_write_pointer;
static uint8_t                *p_mssp2_i2c_read_pointer;
static UINT16_UNION           mssp2_i2c_slave_address;
uint8_t yeah;

#define ARRAY_CNT 6 // Number of bytes in array
uint8_t slaveAddress = 0x30; // 7-bit slave address
uint8_t index = 0; // Array pointer
static uint8_t I2C_timeout = 10; //Number of timer iterations since clear
uint8_t temp = 0; // Temp register
uint8_t regAdd = 1; // First data byte was reg add
uint8_t i2cArray[ARRAY_CNT] =
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00};


/**
  Prototype:        void MSSP2_I2C_Initialize(void)
  Input:            none
  Output:           none
  Description:      MSSP2_I2C_Initialize is an
                    initialization routine that takes inputs from the GUI.
  Usage:            MSSP2_I2C_Initialize();
*/
void MSSP2_I2C_Initialize(void)
{

    // initialize the state
    mssp2_i2c_slave_state = S_SLAVE_IDLE;

    MSSP2_I2C_ReadPointerSet(NULL);
    MSSP2_I2C_WritePointerSet(NULL);

    // initialize the hardware
    // SMP Standard Speed; CKE Idle to Active; 
    SSP2STAT = 0x80;
    // SSPEN enabled; WCOL no_collision; CKP Clock Stretch; SSPM 7 Bit; SSPOV no_overflow; 
    SSP2CON1 = 0x2E & 0x26;
    // ACKEN disabled; GCEN disabled; PEN disabled; ACKDT acknowledge; RSEN disabled; RCEN disabled; SEN enabled; 
    SSP2CON2 = 0x01;
    // SBCDE disabled; BOEN enabled; SCIE disabled; PCIE disabled; DHEN disabled; SDAHT 300ns; AHEN disabled; 
    SSP2CON3 = 0x18 | 0x01;
    // AMSK 0; 
    SSP2MSK = 0x00;
    // Set up the slave address: SSPADD 7; 
    //MSSP2_I2C_SlaveAddressSet(0x07);    
    
    SSP2ADD = 0x30;
    IFS3bits.BCL2IF = 0; // Clear Bus Collision IF
    

    /* MSSP2 - I2C/SPI Interrupt */
    // clear the master interrupt flag
    IFS3bits.SSP2IF = 0;
    // enable the master interrupt
    IEC3bits.SSP2IE = 1;
}

void __attribute__((interrupt, no_auto_psv)) _MSSP2Interrupt(void) {
    if (IFS3bits.SSP2IF) // Check for SSPIF
    {
        if (SSP2STATbits.R_NOT_W == 1) // Master read (slave transmit)
        {
            temp = SSP2BUF;
            SSP2BUF = i2cArray[1]; // Load array value
            SSP2CON1bits.CKP = 1; // Release clock stretch
        }
        if (SSP2STATbits.R_NOT_W == 0) // Master write (slave receive)
        {
            resetTimeoutCounter(); //Reset our counter when a message is received.
            if (SSP2STATbits.D_NOT_A == 0) // Last byte was an address
            {      
                //resetTimeoutCounter(); //Reset our counter when a message is received.                
                _LATB7 = !_LATB7;
                regAdd = 1; // Next byte register address
                temp = SSP2BUF; // Clear BF
                SSP2CON1bits.CKP = 1; // Release clock stretch
            }
            if (SSP2STATbits.D_NOT_A == 1) // Last byte was data
            {
                //resetTimeoutCounter(); //Reset our counter when a message is received.
                if (regAdd == 1) // Last byte was register add
                {
                    index = SSP2BUF; // Load register address
                    regAdd = 0; // Next byte will be true data
                } else {
                    if (index < ARRAY_CNT) // Within boundaries?
                    {
                        i2cArray[index] = SSP2BUF; // Yes, read SSP1BUF
                    } else {
                        temp = SSP2BUF; // No, discard data
                    }
                }
                SSP2CON1bits.CKP = 1; // Release clock stretch
            }
        }
    }
    if ((IFS3bits.BCL2IF == 1) || (SSP2CON1bits.SSPOV == 1)) {
        temp = SSP2BUF; // Clear BF
        IFS3bits.BCL2IF = 0; // Clear BCLIF
        SSP2CON1bits.SSPOV = 0;
        SSP2CON1bits.CKP = 1; // Release clock stretching
    }
    IFS3bits.SSP2IF = 0; // Clear SSP1IF
    _LATB8 = !SSP2CON1bits.SSPOV;
}

uint8_t* getTimeoutCounter()
{
    return &I2C_timeout;
}

void incrementTimeoutCounter()
{
    I2C_timeout++;
}
void resetTimeoutCounter()
{
    I2C_timeout = 0x00;
}
void setI2CArray(uint8_t index, uint8_t value)
{
    if(index < ARRAY_CNT) i2cArray[index] = value;
}
uint8_t getI2CArray(uint8_t index)
{
    if(index < ARRAY_CNT)return i2cArray[index];
    else return 0;
}

void MSSP2_I2C_ReadPointerSet(uint8_t *p)
{
    p_mssp2_i2c_read_pointer = p;
}


void MSSP2_I2C_WritePointerSet(uint8_t *p)
{
    p_mssp2_i2c_write_pointer = p;
}


uint8_t *MSSP2_I2C_ReadPointerGet(void)
{
    return (p_mssp2_i2c_read_pointer);
}


uint8_t *MSSP2_I2C_WritePointerGet(void)
{
    return (p_mssp2_i2c_write_pointer);
}

void MSSP2_I2C_SlaveAddressMaskSet(
                                uint16_t mask)
{
    MSSP2_I2C_MASK_REG = mask;
}

void MSSP2_I2C_SlaveAddressSet(
                                uint16_t address)
{
    UINT16_UNION add;

    add.uint16Value = address;

    if (address > 0xFF)
    {
        // use 10 bit address
        add.uint168BitValue[1] = (0xF0 | ((add.uint168BitValue[1] << 1) & 0x06));
        MSSP2_I2C_ADDRESS_REG = add.uint168BitValue[1];
    }
    else
    {
        // use 7 bit address
        MSSP2_I2C_ADDRESS_REG = add.uint168BitValue[0];
    }
    mssp2_i2c_slave_address.uint16Value = add.uint16Value;

}

inline void __attribute__ ((always_inline)) MSSP2_I2C_TransmitProcess(void)
{
    // get the data to be transmitted

    // sanity check (to avoid stress)
    if (p_mssp2_i2c_read_pointer == NULL)
        return;

    //MSSP2_I2C_TRANSMIT_REG = *p_mssp2_i2c_read_pointer;
    MSSP2_I2C_TRANSMIT_REG = yeah;

    // set the SCL clock to be released
    MSSP2_I2C_RELEASE_SCL_CLOCK_CONTROL_BIT = 1;

}

inline void __attribute__ ((always_inline)) MSSP2_I2C_ReceiveProcess(void)
{   
    // store the received data 
    
    // sanity check (to avoid stress)
    if (p_mssp2_i2c_write_pointer == NULL)
        return;

    *p_mssp2_i2c_write_pointer = MSSP2_I2C_RECEIVE_REG;

}

/* Note: This is an example of the MSSP2_I2C_StatusCallback()
         implementation. This is an emulated EEPROM Memory
         configured to act as a I2C Slave Device.
         For specific slave device implementation, remove
         or modify this function to the specific slave device
         behavior.
*/

static uint8_t mssp2_i2c_slaveWriteData = 0xAA;

bool MSSP2_I2C_StatusCallback(MSSP2_I2C_SLAVE_DRIVER_STATUS status)
{

    // this emulates the slave device memory where data written to slave
    // is placed and data read from slave is taken
    static uint8_t EMULATE_EEPROM_Memory[5] =
            {
                0x30, 0x31, 0x32, 0x33, 0x34
            };

    static uint16_t address = 0;
    static bool     addressState = true;

    switch (status)
    {
        case MSSP2_I2C_SLAVE_TRANSMIT_REQUEST_DETECTED:

            // set up the slave driver buffer transmit pointer
            //MSSP2_I2C_ReadPointerSet(&EMULATE_EEPROM_Memory[address]);
            //address++;
            //if(address > 5) address = 0;
            SSP2BUF = yeah;
            
            break;

        case MSSP2_I2C_SLAVE_RECEIVE_REQUEST_DETECTED:

            addressState = true;

            // set up the slave driver buffer receive pointer
            MSSP2_I2C_WritePointerSet(&mssp2_i2c_slaveWriteData);

            break;

        case MSSP2_I2C_SLAVE_RECEIVED_DATA_DETECTED:

           /* if (addressState == true)
            {

                    address = mssp2_i2c_slaveWriteData;
                    addressState = false;
                    if(address > 31) _LATB6=0;
                else _LATB6=1;
            }
            else // if (addressState == false)
            {
                // set the memory with the received data
                EMULATE_EEPROM_Memory[address] = mssp2_i2c_slaveWriteData;
                
            }*/
            yeah = SSP2BUF;
            if(yeah > 100) _LATB6=0;
                else _LATB6=1;

            break;

        case MSSP2_I2C_SLAVE_10BIT_RECEIVE_REQUEST_DETECTED:

            // do something here when 10-bit address is detected

            // 10-bit address is detected

            break;

        default:
            break;

    }

    return true;
}