/** Configure I2C as slave or master. * @param obj The I2C object * @param data The buffer for sending * @param length Number of bytes to write * @return non-zero if a value is available */ int i2c_slave_write(i2c_t *obj, const char *data, int length) { struct i2c_s *obj_s = I2C_S(obj); int count = 0; int timeout = 0; i2c_ack_config(obj_s->i2c, I2C_ACK_ENABLE); /* wait until ADDSEND bit is set */ while (!i2c_flag_get(obj_s->i2c, I2C_FLAG_ADDSEND)) { timeout++; if (timeout > 100000) { return -1; } } /* clear ADDSEND bit */ i2c_flag_clear(obj_s->i2c, I2C_FLAG_ADDSEND); while (length > 0) { /* wait until the TBE bit is set */ timeout = 0; while (!i2c_flag_get(obj_s->i2c, I2C_FLAG_TBE)) { timeout++; if (timeout > 100000) { return -1; } } i2c_data_transmit(obj_s->i2c, *data); data++; length--; count++; } /* the master doesn't acknowledge for the last byte */ timeout = 0; while (!i2c_flag_get(obj_s->i2c, I2C_FLAG_AERR)) { timeout++; if (timeout > 100000) { return -1; } } /* clear the bit of AERR */ i2c_flag_clear(obj_s->i2c, I2C_FLAG_AERR); /* disable acknowledge */ i2c_ack_config(obj_s->i2c, I2C_ACK_DISABLE); return count; }
/** Configure I2C as slave or master. * @param obj The I2C object * @param data The buffer for receiving * @param length Number of bytes to read * @return non-zero if a value is available */ int i2c_slave_read(i2c_t *obj, char *data, int length) { struct i2c_s *obj_s = I2C_S(obj); int count = 0; int timeout = 0; i2c_ack_config(obj_s->i2c, I2C_ACK_ENABLE); /* wait until ADDSEND bit is set */ while (!i2c_flag_get(obj_s->i2c, I2C_FLAG_ADDSEND)) { timeout++; if (timeout > 100000) { return -1; } } /* clear ADDSEND bit */ i2c_flag_clear(obj_s->i2c, I2C_FLAG_ADDSEND); while (0 < length) { /* wait until the RBNE bit is set */ timeout = 0; while (!i2c_flag_get(obj_s->i2c, I2C_FLAG_RBNE)) { timeout++; if (timeout > 100000) { return -1; } } *data = i2c_data_receive(obj_s->i2c); data++; length--; count++; } /* wait until the STPDET bit is set */ timeout = 0; while (!i2c_flag_get(obj_s->i2c, I2C_FLAG_STPDET)) { timeout++; if (timeout > 100) { return count; } } /* clear the STPDET bit */ i2c_enable(obj_s->i2c); i2c_ack_config(obj_s->i2c, I2C_ACK_DISABLE); return count; }
/*! \brief handle I2C1 error interrupt request \param[in] none \param[out] none \retval none */ void I2C1_ErrorIRQ_Handler(void) { /* no acknowledge received */ if(i2c_flag_get(I2C1, I2C_AERR)){ i2c_flag_clear(I2C1, I2C_AERR); } /* SMBus alert */ if(i2c_flag_get(I2C1, I2C_SMBALTS)){ i2c_flag_clear(I2C1, I2C_SMBALTS); } /* bus timeout in SMBus mode */ if(i2c_flag_get(I2C1, I2C_SMBTO)){ i2c_flag_clear(I2C1, I2C_SMBTO); } /* over-run or under-run when SCL stretch is disabled */ if(i2c_flag_get(I2C1, I2C_OUERR)){ i2c_flag_clear(I2C1, I2C_OUERR); } /* arbitration lost */ if(i2c_flag_get(I2C1, I2C_LOSTARB)){ i2c_flag_clear(I2C1, I2C_LOSTARB); } /* bus error */ if(i2c_flag_get(I2C1, I2C_BERR)){ i2c_flag_clear(I2C1, I2C_BERR); } /* CRC value doesn't match */ if(i2c_flag_get(I2C1, I2C_PECERR)){ i2c_flag_clear(I2C1, I2C_PECERR); } /* disable the error interrupt */ i2c_interrupt_disable(I2C1,I2C_CTL1_ERRIE | I2C_CTL1_BUFIE | I2C_CTL1_EVIE); }
/** Send START command * * @param obj The I2C object */ int i2c_start(i2c_t *obj) { int timeout; struct i2c_s *obj_s = I2C_S(obj); /* clear I2C_FLAG_AERR Flag */ i2c_flag_clear(obj_s->i2c, I2C_FLAG_AERR); /* wait until I2C_FLAG_I2CBSY flag is reset */ timeout = FLAG_TIMEOUT; while ((i2c_flag_get(obj_s->i2c, I2C_FLAG_I2CBSY)) == SET) { if ((timeout--) == 0) { return (int)GD_BUSY; } } /* ensure the i2c has been stopped */ timeout = FLAG_TIMEOUT; while ((I2C_CTL0(obj_s->i2c) & I2C_CTL0_STOP) == I2C_CTL0_STOP) { if ((timeout--) == 0) { return (int)GD_ERROR; } } /* generate a START condition */ i2c_start_on_bus(obj_s->i2c); /* ensure the i2c has been started successfully */ timeout = FLAG_TIMEOUT; while ((i2c_flag_get(obj_s->i2c, I2C_FLAG_SBSEND)) == RESET) { if ((timeout--) == 0) { return (int)GD_ERROR; } } return (int)GD_OK; }
/** Blocking sending data * * @param obj The I2C object * @param address 7-bit address (last bit is 0) * @param data The buffer for sending * @param length Number of bytes to write * @param stop Stop to be generated after the transfer is done * @return * zero or non-zero - Number of written bytes * negative - I2C_ERROR_XXX status */ int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) { struct i2c_s *obj_s = I2C_S(obj); gd_status_enum status = GD_OK; uint32_t count = 0; int timeout = 0; if (obj_s->global_trans_option == I2C_FIRST_AND_LAST_FRAME || obj_s->global_trans_option == I2C_LAST_FRAME) { if (stop) { obj_s->global_trans_option = I2C_FIRST_AND_LAST_FRAME; } else { obj_s->global_trans_option = I2C_FIRST_FRAME; } } else if (obj_s->global_trans_option == I2C_FIRST_FRAME || obj_s->global_trans_option == I2C_NEXT_FRAME) { if (stop) { obj_s->global_trans_option = I2C_LAST_FRAME; } else { obj_s->global_trans_option = I2C_NEXT_FRAME; } } if (obj_s->global_trans_option == I2C_FIRST_AND_LAST_FRAME || obj_s->global_trans_option == I2C_FIRST_FRAME) { /* wait until I2C_FLAG_I2CBSY flag is reset */ timeout = FLAG_TIMEOUT; while ((i2c_flag_get(obj_s->i2c, I2C_FLAG_I2CBSY)) == SET) { if ((timeout--) == 0) { i2c_stop(obj); return I2C_ERROR_BUS_BUSY; } } } if (obj_s->global_trans_option == I2C_FIRST_AND_LAST_FRAME || obj_s->global_trans_option == I2C_FIRST_FRAME || obj_s->previous_state_mode != I2C_STATE_MASTER_BUSY_TX) { /* generate a START condition */ i2c_start_on_bus(obj_s->i2c); /* ensure the i2c has been started successfully */ timeout = FLAG_TIMEOUT; while ((i2c_flag_get(obj_s->i2c, I2C_FLAG_SBSEND)) == RESET) { if ((timeout--) == 0) { i2c_stop(obj); return I2C_ERROR_BUS_BUSY; } } /* send slave address */ i2c_master_addressing(obj_s->i2c, address, I2C_TRANSMITTER); /* wait until I2C_FLAG_ADDSEND flag is set */ while (!i2c_flag_get(obj_s->i2c, I2C_FLAG_ADDSEND)) { timeout++; if (timeout > 100000) { i2c_stop(obj); return I2C_ERROR_NO_SLAVE; } } /* clear ADDSEND */ i2c_flag_clear(obj_s->i2c, I2C_FLAG_ADDSEND); } obj_s->state = (operation_state_enum)I2C_STATE_MASTER_BUSY_TX; for (count = 0; count < length; count++) { status = (gd_status_enum)i2c_byte_write(obj, data[count]); if (status != 1) { i2c_stop(obj); return count; } } obj_s->previous_state_mode = obj_s->state; /* if not sequential write, then send stop */ if (stop) { i2c_stop(obj); } return count; }
/** Blocking reading data * * @param obj The I2C object * @param address 7-bit address (last bit is 1) * @param data The buffer for receiving * @param length Number of bytes to read * @param stop Stop to be generated after the transfer is done * @return Number of read bytes */ int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) { struct i2c_s *obj_s = I2C_S(obj); uint32_t count = 0U; int timeout = 0; if (obj_s->global_trans_option == I2C_FIRST_AND_LAST_FRAME || obj_s->global_trans_option == I2C_LAST_FRAME) { if (stop) { obj_s->global_trans_option = I2C_FIRST_AND_LAST_FRAME; } else { obj_s->global_trans_option = I2C_FIRST_FRAME; } } else if (obj_s->global_trans_option == I2C_FIRST_FRAME || obj_s->global_trans_option == I2C_NEXT_FRAME) { if (stop) { obj_s->global_trans_option = I2C_LAST_FRAME; } else { obj_s->global_trans_option = I2C_NEXT_FRAME; } } if (obj_s->global_trans_option == I2C_FIRST_AND_LAST_FRAME || obj_s->global_trans_option == I2C_FIRST_FRAME) { /* wait until I2C_FLAG_I2CBSY flag is reset */ timeout = FLAG_TIMEOUT; while ((i2c_flag_get(obj_s->i2c, I2C_FLAG_I2CBSY)) == SET) { if ((timeout--) == 0) { i2c_stop(obj); return I2C_ERROR_BUS_BUSY; } } } if (obj_s->global_trans_option == I2C_FIRST_AND_LAST_FRAME || obj_s->global_trans_option == I2C_FIRST_FRAME || obj_s->previous_state_mode != I2C_STATE_MASTER_BUSY_RX) { /* generate a START condition */ i2c_start_on_bus(obj_s->i2c); /* ensure the i2c has been started successfully */ timeout = FLAG_TIMEOUT; while ((i2c_flag_get(obj_s->i2c, I2C_FLAG_SBSEND)) == RESET) { if ((timeout--) == 0) { i2c_stop(obj); return I2C_ERROR_BUS_BUSY; } } /* send slave address */ i2c_master_addressing(obj_s->i2c, address, I2C_RECEIVER); if (1 == length) { /* disable acknowledge */ i2c_ack_config(obj_s->i2c, I2C_ACK_DISABLE); /* send a stop condition to I2C bus*/ } else if (2 == length) { /* send a NACK for the next data byte which will be received into the shift register */ i2c_ackpos_config(obj_s->i2c, I2C_ACKPOS_NEXT); /* disable acknowledge */ i2c_ack_config(obj_s->i2c, I2C_ACK_DISABLE); } else { /* enable acknowledge */ i2c_ack_config(obj_s->i2c, I2C_ACK_ENABLE); } /* wait until I2C_FLAG_ADDSEND flag is set */ while (!i2c_flag_get(obj_s->i2c, I2C_FLAG_ADDSEND)) { timeout++; if (timeout > 100000) { i2c_stop(obj); return I2C_ERROR_NO_SLAVE; } } /* clear ADDSEND */ i2c_flag_clear(obj_s->i2c, I2C_FLAG_ADDSEND); } obj_s->state = (operation_state_enum)I2C_STATE_MASTER_BUSY_RX; for (count = 0; count < length; count++) { if (length > 2 && count == length - 3) { while (RESET == i2c_flag_get(obj_s->i2c, I2C_FLAG_BTC)); i2c_ack_config(obj_s->i2c, I2C_ACK_DISABLE); } else if (2 == length && count == 0) { while (RESET == i2c_flag_get(obj_s->i2c, I2C_FLAG_BTC)); } while (RESET == i2c_flag_get(obj_s->i2c, I2C_FLAG_RBNE)); data[count] = i2c_data_receive(obj_s->i2c); } obj_s->previous_state_mode = obj_s->state; /* if not sequential read, then send stop */ if (stop) { i2c_stop(obj); } return count; }