I2C err

Discussions and support about ChibiOS/HAL, the MCU Hardware Abstraction Layer.
BreederBai
Posts: 19
Joined: Tue Aug 14, 2018 3:57 pm

Re: I2C err

Postby BreederBai » Tue Sep 18, 2018 3:23 am

Giovanni wrote:On F1 (GPIOv1) there are no alternate numbers, just alternate or not.

The driver is very old and proved to work, probably the problem is not where you are looking, I would bet on some HW issue (because bus locked).

Giovanni


I modified the following code

Code: Select all

msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
                                      const uint8_t *txbuf, size_t txbytes,
                                      uint8_t *rxbuf, size_t rxbytes,
                                      systime_t timeout) {
  I2C_TypeDef *dp = i2cp->i2c;
  systime_t start, end;

#if defined(STM32F1XX_I2C)
  osalDbgCheck((rxbytes == 0) || ((rxbytes > 0) && (rxbuf != NULL)));
#endif

  /* Resetting error flags for this transfer.*/
  i2cp->errors = I2C_NO_ERROR;

  /* Initializes driver fields, LSB = 0 -> transmit.*/
  i2cp->addr = (addr << 1);

Code: Select all

msg_t chThdSuspendTimeoutS(thread_reference_t *trp, systime_t timeout) {
  thread_t *tp = chThdGetSelfX();

  chDbgAssert(*trp != NULL, "not NULL");

  if (TIME_IMMEDIATE == timeout) {
    return MSG_TIMEOUT;
  }

  *trp = tp;
  tp->p_u.wttrp = trp;

  return chSchGoSleepTimeoutS(CH_STATE_SUSPENDED, timeout);
}

The test found that the thread will block in "osalThreadSuspendTimeoutS".
The following is my relevant code to use I2C.

Code: Select all

I2C.thread = chThdGetSelfX();
i2cMasterTransmitTimeout(&I2C,
                               HAL_COMPASS_IST8310_I2C_ADDR,
                               tx_buf.data(),
                               tx_buf.size(),
                               rx_buf.data(),
                               rx_buf.size(),
                               US2ST(2000)));
                               
msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
                                      const uint8_t *txbuf, size_t txbytes,
                                      uint8_t *rxbuf, size_t rxbytes,
                                      systime_t timeout) {
  I2C_TypeDef *dp = i2cp->i2c;
  systime_t start, end;

#if defined(STM32F1XX_I2C)
  osalDbgCheck((rxbytes == 0) || ((rxbytes > 0) && (rxbuf != NULL)));
#endif

  /* Resetting error flags for this transfer.*/
  i2cp->errors = I2C_NO_ERROR;

  /* Initializes driver fields, LSB = 0 -> transmit.*/
  i2cp->addr = (addr << 1);

  /* Releases the lock from high level driver.*/
  osalSysUnlock();

  /* TX DMA setup.*/
  dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode);
  dmaStreamSetMemory0(i2cp->dmatx, txbuf);
  dmaStreamSetTransactionSize(i2cp->dmatx, txbytes);

  /* RX DMA setup.*/
  dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
  dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
  dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);

  /* Calculating the time window for the timeout on the busy bus condition.*/
  start = osalOsGetSystemTimeX();
  end = start + OSAL_MS2ST(STM32_I2C_BUSY_TIMEOUT);

  /* Waits until BUSY flag is reset or, alternatively, for a timeout
     condition.*/
  while (true) {
    osalSysLock();

    /* If the bus is not busy then the operation can continue, note, the
       loop is exited in the locked state.*/
    if (!(dp->SR2 & I2C_SR2_BUSY) && !(dp->CR1 & I2C_CR1_STOP))
      break;

    /* If the system time went outside the allowed window then a timeout
       condition is returned.*/
    //if (!osalOsIsTimeWithinX(osalOsGetSystemTimeX(), start, end))
    if (ST2MS(osalOsGetSystemTimeX()-start) > STM32_I2C_BUSY_TIMEOUT)
      return MSG_TIMEOUT;

    osalSysUnlock();
  }

  /* Starts the operation.*/
  dp->CR2 |= I2C_CR2_ITEVTEN;
  dp->CR1 |= I2C_CR1_START;

  /* Waits for the operation completion or a timeout.*/
  return osalThreadSuspendTimeoutS(&i2cp->thread, timeout);
  //return 0;
}

static inline msg_t osalThreadSuspendTimeoutS(thread_reference_t *trp,
                                              systime_t timeout) {

  return chThdSuspendTimeoutS(trp, timeout);
}

msg_t chThdSuspendTimeoutS(thread_reference_t *trp, systime_t timeout) {
  thread_t *tp = chThdGetSelfX();

  chDbgAssert(*trp != NULL, "not NULL");

  if (TIME_IMMEDIATE == timeout) {
    return MSG_TIMEOUT;
  }

  *trp = tp;
  tp->p_u.wttrp = trp;

  return chSchGoSleepTimeoutS(CH_STATE_SUSPENDED, timeout);
}

According to the parameter "US2ST(2000)" that I passed in, the program should not block. It feels like "chThdSuspendTimeoutS" hangs the program.

User avatar
Giovanni
Site Admin
Posts: 11386
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 430 times
Been thanked: 363 times
Contact:

Re: I2C err

Postby Giovanni » Tue Sep 18, 2018 8:24 am

Exactly what would be the modified code?

Giovanni

BreederBai
Posts: 19
Joined: Tue Aug 14, 2018 3:57 pm

Re: I2C err

Postby BreederBai » Tue Sep 18, 2018 9:41 am

Giovanni wrote:Exactly what would be the modified code?

Giovanni

I may have solved this problem. I added i2cStart(&I2C,&I2CCfg) before calling i2cMasterTransmitTimeout to solve the thread blocking problem.

Code: Select all

template <unsigned RxSize>
std::array<uint8_t, RxSize> read(const std::uint8_t first_reg)
{
    i2cStart(&I2C,&I2CCfg);
    static std::array<uint8_t, 1> tx_buf;
    static std::array<uint8_t, RxSize> rx_buf;
    std::fill(tx_buf.begin(), tx_buf.end(), 0);
    std::fill(rx_buf.begin(), rx_buf.end(), 0);
    tx_buf[0] = first_reg;
 
    i2cAcquireBus(&I2C);

    i2cMasterTransmitTimeout(&I2C,
                               HAL_COMPASS_IST8310_I2C_ADDR,
                               tx_buf.data(),
                               tx_buf.size(),
                               rx_buf.data(),
                               rx_buf.size(),
                               TIME_INFINITE);

    i2cReleaseBus(&I2C);

    return rx_buf;
}

BreederBai
Posts: 19
Joined: Tue Aug 14, 2018 3:57 pm

Re: I2C err

Postby BreederBai » Tue Sep 18, 2018 9:48 am

Giovanni wrote:Exactly what would be the modified code?

Giovanni

I think the I2C driver has a bug.Below is the original code,When reading a byte," osalDbgCheck((rxbytes == 0) || ((rxbytes > 1) && (rxbuf != NULL)));"Will report an error and block the current thread.

Code: Select all

msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
                                      const uint8_t *txbuf, size_t txbytes,
                                      uint8_t *rxbuf, size_t rxbytes,
                                      systime_t timeout) {
  I2C_TypeDef *dp = i2cp->i2c;
  systime_t start, end;

#if defined(STM32F1XX_I2C)
  osalDbgCheck((rxbytes == 0) || ((rxbytes > 1) && (rxbuf != NULL)));
#endif

  /* Resetting error flags for this transfer.*/
  i2cp->errors = I2C_NO_ERROR;

  /* Initializes driver fields, LSB = 0 -> transmit.*/
  i2cp->addr = (addr << 1);

I think it is more appropriate to change it to this way.

Code: Select all

osalDbgCheck((rxbytes == 0) || ((rxbytes > 0) && (rxbuf != NULL)));

User avatar
Giovanni
Site Admin
Posts: 11386
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 430 times
Been thanked: 363 times
Contact:

Re: I2C err

Postby Giovanni » Tue Sep 18, 2018 12:49 pm

Hi,

The check is correct, there is a silicon bug on F1s that make it impossible to transfer one byte using DMA.

Giovanni

BreederBai
Posts: 19
Joined: Tue Aug 14, 2018 3:57 pm

Re: I2C err

Postby BreederBai » Wed Sep 19, 2018 2:07 am

Giovanni wrote:Hi,

The check is correct, there is a silicon bug on F1s that make it impossible to transfer one byte using DMA.

Giovanni

Is it impossible for all DMAs to transfer 1 byte? Does this mean that I2C cannot read or write 1 byte? What should I do if I want to read and write a byte?

BreederBai
Posts: 19
Joined: Tue Aug 14, 2018 3:57 pm

Re: I2C err

Postby BreederBai » Wed Sep 19, 2018 2:29 am

Giovanni wrote:Hi,

The check is correct, there is a silicon bug on F1s that make it impossible to transfer one byte using DMA.

Giovanni

After deleting "osalDbgCheck((rxbytes == 0) || ((rxbytes > 1) && (rxbuf != NULL)))"), I tried to read a byte and no exception occurred. The DMA bug looks very Surprising, sometimes not.


Return to “ChibiOS/HAL”

Who is online

Users browsing this forum: No registered users and 1 guest