static void I2CM_IRQHandler(uint32_t instance) { i2c_master_t *im = &i2c_master_state[instance]; mxc_i2cm_regs_t *regs = MXC_I2CM_GET_I2CM(instance); mxc_i2cm_intfl_t intfl = regs->intfl_f; mxc_i2cm_inten_t inten = regs->inten_f; regs->intfl_f = intfl; if(intfl.tx_done && inten.tx_done) { if(!im->bytes_left) { if(im->stop_bit) { I2CM_WriteToTxFifo(im->index, MXC_S_I2CM_TRANS_TAG_STOP); } inten.tx_done = 0; regs->inten_f = inten; im->buf = NULL; if(im->callback_fn) { im->callback_fn(0); } } else { do_xmit(im); } } if((intfl.rx_fifo_not_empty || intfl.rx_fifo_full || intfl.rx_fifo_2q_full || intfl.rx_fifo_3q_full ) && inten.rx_fifo_empty) { volatile uint16_t *rx_fifo = (uint16_t *)(MXC_I2CM_GET_BASE_FIFO(im->index) + 0x800); uint8_t bytes_to_read = regs->bb_f.rx_fifo_cnt; uint32_t i; if(im->bytes_index < im->bytes_left) { for(i = 0; i < bytes_to_read; i++) { im->buf[im->bytes_index++] = *rx_fifo; } } if(im->bytes_index == im->bytes_left) { inten = regs->inten_f; inten.rx_fifo_2q_full = 0; inten.rx_fifo_3q_full = 0; inten.rx_fifo_full = 0; inten.rx_fifo_empty = 0; regs->inten_f = inten; im->buf = NULL; if(im->callback_fn) { im->callback_fn(im->bytes_index); } } } }
void i2c_init(i2c_t *obj, PinName sda, PinName scl) { // determine the I2C to use I2CName i2c_sda = (I2CName)pinmap_peripheral(sda, PinMap_I2C_SDA); I2CName i2c_scl = (I2CName)pinmap_peripheral(scl, PinMap_I2C_SCL); mxc_i2cm_regs_t *i2c = (mxc_i2cm_regs_t*)pinmap_merge(i2c_sda, i2c_scl); MBED_ASSERT((int)i2c != NC); obj->i2c = i2c; obj->fifos = (mxc_i2cm_fifo_regs_t*)MXC_I2CM_GET_BASE_FIFO(MXC_I2CM_GET_IDX(i2c)); obj->start_pending = 0; obj->stop_pending = 0; // configure the pins pinmap_pinout(sda, PinMap_I2C_SDA); pinmap_pinout(scl, PinMap_I2C_SCL); // enable the clock MXC_CLKMAN->sys_clk_ctrl_9_i2cm = MXC_S_CLKMAN_CLK_SCALE_DIV_1; // reset module i2c->ctrl = MXC_F_I2CM_CTRL_MSTR_RESET_EN; i2c->ctrl = 0; // set default frequency at 100k i2c_frequency(obj, 100000); // set timeout to 255 ms and turn on the auto-stop option i2c->timeout = (0xFF << MXC_F_I2CM_TIMEOUT_TX_TIMEOUT_POS) | MXC_F_I2CM_TIMEOUT_AUTO_STOP_EN; // enable tx_fifo and rx_fifo i2c->ctrl |= (MXC_F_I2CM_CTRL_TX_FIFO_EN | MXC_F_I2CM_CTRL_RX_FIFO_EN); }
static void do_xmit(i2c_master_t *im) { volatile uint16_t *tx_fifo = (uint16_t *)MXC_I2CM_GET_BASE_FIFO(im->index); mxc_i2cm_regs_t *regs = MXC_I2CM_GET_I2CM(im->index); if(im->bytes_left && im->buf) { do { *tx_fifo = (MXC_S_I2CM_TRANS_TAG_TXDATA_ACK | im->buf[im->bytes_index++]); --im->bytes_left; } while(im->bytes_left && regs->intfl_f.tx_fifo_3q_empty); } }
inline static int32_t I2CM_WriteToTxFifo(uint8_t index, const uint16_t data) { volatile uint16_t *tx_fifo = (uint16_t *)MXC_I2CM_GET_BASE_FIFO(index); mxc_i2cm_regs_t *regs = MXC_I2CM_GET_I2CM(index); mxc_i2cm_intfl_t intfl; while(*tx_fifo) { intfl = regs->intfl_f; if((intfl.tx_nacked) || (intfl.tx_timeout) || (intfl.tx_lost_arbitr)) { return -1; } } *tx_fifo = data; return 0; }
static int32_t I2CM_Rx(uint8_t index, uint8_t addr, uint8_t *data, uint32_t bytes) { mxc_i2cm_regs_t *regs = MXC_I2CM_GET_I2CM(index); volatile uint16_t *rx_fifo = (uint16_t *)(MXC_I2CM_GET_BASE_FIFO(index) + 0x800); uint32_t i = bytes; /* start + addr (read) */ if(I2CM_WriteToTxFifo(index, (MXC_S_I2CM_TRANS_TAG_START | addr | I2C_SLAVE_ADDR_READ_BIT))) { return -1; } while(i > 256) { if(I2CM_WriteToTxFifo(index, (MXC_S_I2CM_TRANS_TAG_RXDATA_COUNT | 255))) { return -1; } i -= 256; } if (i > 1) { if(I2CM_WriteToTxFifo(index, (MXC_S_I2CM_TRANS_TAG_RXDATA_COUNT | (i - 2)))) { return -1; } } mxc_i2cm_trans_t trans = regs->trans_f; /* start the transaction if it wasn't already started */ if (!trans.tx_in_progress) { trans.tx_start = 1; regs->trans_f = trans; } if(I2CM_WriteToTxFifo(index, MXC_S_I2CM_TRANS_TAG_RXDATA_NACK)) { /* NACK last data byte */ return -1; } if(I2CM_WriteToTxFifo(index, MXC_S_I2CM_TRANS_TAG_STOP)) { /* stop condition */ return -1; } int32_t timeout = MXC_I2CM_RX_TIMEOUT; uint16_t temp; i = 0; while(i < bytes) { while (!regs->intfl_f.rx_fifo_not_empty && (regs->bb_f.rx_fifo_cnt == 0)) { if ((timeout-- < 0) || !regs->trans_f.tx_in_progress) { return -1; } } timeout = MXC_I2CM_RX_TIMEOUT; mxc_i2cm_intfl_t intfl = regs->intfl_f; intfl.rx_fifo_not_empty = 1; regs->intfl_f = intfl; temp = *rx_fifo; if(temp & MXC_S_I2CM_RSTLS_TAG_EMPTY) { continue; } data[i++] = (uint8_t) temp; } return i; }