stm32/pyb_i2c: Fix failing pyb.I2C(dma=True) after receiving 1 byte.

Excuting the code:

    i2c = I2C(1, I2C.CONTROLLER, dma=True)
    tmp = i2c.recv(1, i2c_addr)
    recv_data = bytearray(56)
    i2c.recv(recv_data, i2c_addr)

The second i2c.recv() fails with OSError: [Errno 110] ETIMEDOUT.  When
receiving greater than or equal to 2 bytes at first i2c.recv(), the second
i2c.recv() succeeds.  This issue does not occur without DMA.

Details of change: when executing I2C with DMA:

- Bit 11 of I2Cx_CR2 (DMA Request Enable) should be 1 to indicate that DMA
  transfer is enabled.  This bit is set after I2C event interrupt is
  enabled in HAL_I2C_Master_Transmit_DMA()/HAL_I2C_Master_Receive_DMA(), so
  DMA Request Enable bit might be 0 in IRQHandler.

- In case of data receive:
    - When only 1 byte receiption, clear I2Cx_CR1's bit 10 (ACK).
    - When only 2 byte receiption, clear I2Cx_CR1's bit 10 (ACK) and set
      bit 11 (POS).
    - When greater than or equal to 2 byte receiption, bit 12 of I2Cx_CR2
      (DMA Last Transfer) should set to generate NACK when DMA transfer
      completed.

Otherwise, the I2C bus may be busy after received data from peripheral.
This commit is contained in:
yn386 2022-09-14 15:29:15 +09:00 committed by Damien George
parent 4dcfd19bbf
commit 65d82066a8
1 changed files with 12 additions and 0 deletions

View File

@ -478,8 +478,20 @@ void i2c_ev_irq_handler(mp_uint_t i2c_id) {
} else {
hi2c->Instance->DR = I2C_7BIT_ADD_READ(hi2c->Devaddress);
}
hi2c->Instance->CR2 |= I2C_CR2_DMAEN;
} else if (hi2c->Instance->SR1 & I2C_FLAG_ADDR) {
__IO uint32_t tmp_sr2;
if (hi2c->State == HAL_I2C_STATE_BUSY_RX) {
if (hi2c->XferCount == 1U) {
hi2c->Instance->CR1 &= ~I2C_CR1_ACK;
} else {
if (hi2c->XferCount == 2U) {
hi2c->Instance->CR1 &= ~I2C_CR1_ACK;
hi2c->Instance->CR1 |= I2C_CR1_POS;
}
hi2c->Instance->CR2 |= I2C_CR2_LAST;
}
}
tmp_sr2 = hi2c->Instance->SR2;
UNUSED(tmp_sr2);
} else if (hi2c->Instance->SR1 & I2C_FLAG_BTF && hi2c->State == HAL_I2C_STATE_BUSY_TX) {