i2c: improve communication with i2c devices in i2c_write_blocking
This commit is contained in:
parent
18c39856bd
commit
8f3c3ff12a
@ -43,7 +43,8 @@ uint i2c_init(i2c_inst_t *i2c, uint baudrate) {
|
|||||||
I2C_IC_CON_SPEED_VALUE_FAST << I2C_IC_CON_SPEED_LSB |
|
I2C_IC_CON_SPEED_VALUE_FAST << I2C_IC_CON_SPEED_LSB |
|
||||||
I2C_IC_CON_MASTER_MODE_BITS |
|
I2C_IC_CON_MASTER_MODE_BITS |
|
||||||
I2C_IC_CON_IC_SLAVE_DISABLE_BITS |
|
I2C_IC_CON_IC_SLAVE_DISABLE_BITS |
|
||||||
I2C_IC_CON_IC_RESTART_EN_BITS;
|
I2C_IC_CON_IC_RESTART_EN_BITS |
|
||||||
|
I2C_IC_CON_TX_EMPTY_CTRL_BITS;
|
||||||
|
|
||||||
// Set FIFO watermarks to 1 to make things simpler. This is encoded by a register value of 0.
|
// Set FIFO watermarks to 1 to make things simpler. This is encoded by a register value of 0.
|
||||||
i2c->hw->tx_tl = 0;
|
i2c->hw->tx_tl = 0;
|
||||||
@ -145,7 +146,7 @@ static int i2c_write_blocking_internal(i2c_inst_t *i2c, uint8_t addr, const uint
|
|||||||
bool abort = false;
|
bool abort = false;
|
||||||
bool timeout = false;
|
bool timeout = false;
|
||||||
|
|
||||||
uint32_t abort_reason;
|
uint32_t abort_reason = 0;
|
||||||
int byte_ctr;
|
int byte_ctr;
|
||||||
|
|
||||||
int ilen = (int)len;
|
int ilen = (int)len;
|
||||||
@ -158,17 +159,50 @@ static int i2c_write_blocking_internal(i2c_inst_t *i2c, uint8_t addr, const uint
|
|||||||
bool_to_bit(last && !nostop) << I2C_IC_DATA_CMD_STOP_LSB |
|
bool_to_bit(last && !nostop) << I2C_IC_DATA_CMD_STOP_LSB |
|
||||||
*src++;
|
*src++;
|
||||||
|
|
||||||
|
// Wait until the transmission of the address/data from the internal
|
||||||
|
// shift register has completed. For this to function correctly, the
|
||||||
|
// TX_EMPTY_CTRL flag in IC_CON must be set. The TX_EMPTY_CTRL flag
|
||||||
|
// was set in i2c_init.
|
||||||
do {
|
do {
|
||||||
// Note clearing the abort flag also clears the reason, and this
|
|
||||||
// instance of flag is clear-on-read!
|
|
||||||
abort_reason = i2c->hw->tx_abrt_source;
|
|
||||||
abort = (bool) i2c->hw->clr_tx_abrt;
|
|
||||||
if (timeout_check) {
|
if (timeout_check) {
|
||||||
timeout = timeout_check(ts);
|
timeout = timeout_check(ts);
|
||||||
abort |= timeout;
|
abort |= timeout;
|
||||||
}
|
}
|
||||||
tight_loop_contents();
|
tight_loop_contents();
|
||||||
} while (!abort && !(i2c->hw->status & I2C_IC_STATUS_TFE_BITS));
|
} while (!timeout && !(i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_TX_EMPTY_BITS));
|
||||||
|
|
||||||
|
// If there was a timeout, don't attempt to do anything else.
|
||||||
|
if (!timeout) {
|
||||||
|
abort_reason = i2c->hw->tx_abrt_source;
|
||||||
|
if (abort_reason) {
|
||||||
|
// Note clearing the abort flag also clears the reason, and
|
||||||
|
// this instance of flag is clear-on-read! Note also the
|
||||||
|
// IC_CLR_TX_ABRT register always reads as 0.
|
||||||
|
i2c->hw->clr_tx_abrt;
|
||||||
|
abort = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (abort || (last && !nostop)) {
|
||||||
|
// If the transaction was aborted or if it completed
|
||||||
|
// successfully wait until the STOP condition has occured.
|
||||||
|
|
||||||
|
// TODO Could there be an abort while waiting for the STOP
|
||||||
|
// condition here? If so, additional code would be needed here
|
||||||
|
// to take care of the abort.
|
||||||
|
do {
|
||||||
|
if (timeout_check) {
|
||||||
|
timeout = timeout_check(ts);
|
||||||
|
abort |= timeout;
|
||||||
|
}
|
||||||
|
tight_loop_contents();
|
||||||
|
} while (!timeout && !(i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_STOP_DET_BITS));
|
||||||
|
|
||||||
|
// If there was a timeout, don't attempt to do anything else.
|
||||||
|
if (!timeout) {
|
||||||
|
i2c->hw->clr_stop_det;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Note the hardware issues a STOP automatically on an abort condition.
|
// Note the hardware issues a STOP automatically on an abort condition.
|
||||||
// Note also the hardware clears RX FIFO as well as TX on abort,
|
// Note also the hardware clears RX FIFO as well as TX on abort,
|
||||||
|
Loading…
Reference in New Issue
Block a user