#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; }