cancel
Showing results for 
Search instead for 
Did you mean: 

I2C problem (full story with pics)

DCarr.1
Senior

Hello,

I have a custom STM32F439VITx board running at 60MHz clocked from the HSI. I have three devices on I2C3, two of which function correctly, the third, an mb85rc64 non-volatile memory, fails on both read and write operations.

The I2C is configured like this:

void MX_I2C3_Init(void)
{
  hi2c3.Instance = I2C3;
  hi2c3.Init.ClockSpeed = 100000;
  hi2c3.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c3.Init.OwnAddress1 = 0;
  hi2c3.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c3.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c3.Init.OwnAddress2 = 0;
  hi2c3.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c3.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c3) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Analogue filter
  */
  if (HAL_I2CEx_ConfigAnalogFilter(&hi2c3, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Digital filter
  */
  if (HAL_I2CEx_ConfigDigitalFilter(&hi2c3, 0) != HAL_OK)
  {
    Error_Handler();
  }
 
}

I'm sending the I2C command like this:

static const uint8_t DevAddress = 0b10100000;	// preshifted
static const uint16_t MemAddress = 0;
static const uint16_t MemAddSize = I2C_MEMADD_SIZE_16BIT;
static const uint16_t Size = 1;
uint8_t Data[Size];
static const uint32_t Timeout = 1000;
 
Data[0] = 1;
HAL_StatusTypeDef hal =  HAL_I2C_Mem_Write(&hi2c3, DevAddress, MemAddress, MemAddSize, Data, Size, Timeout);

Tracing through the source, HAL_I2C_Mem_Write() gets as far as calling I2C_WaitOnMasterAddressFlagUntilTimeout without any problem:

HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
  /* Init tickstart for timeout management*/
  uint32_t tickstart = HAL_GetTick();
 
  /* Check the parameters */
  assert_param(IS_I2C_MEMADD_SIZE(MemAddSize));
 
  if (hi2c->State == HAL_I2C_STATE_READY)
  {
    /* Wait until BUSY flag is reset */
    if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK)
    {
      return HAL_BUSY;
    }
 
    /* Process Locked */
    __HAL_LOCK(hi2c);
 
    /* Check if the I2C is already enabled */
    if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE)
    {
      /* Enable I2C peripheral */
      __HAL_I2C_ENABLE(hi2c);
    }
 
    /* Disable Pos */
    CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS);
 
    hi2c->State     = HAL_I2C_STATE_BUSY_TX;
    hi2c->Mode      = HAL_I2C_MODE_MEM;
    hi2c->ErrorCode = HAL_I2C_ERROR_NONE;
 
    /* Prepare transfer parameters */
    hi2c->pBuffPtr    = pData;
    hi2c->XferCount   = Size;
    hi2c->XferSize    = hi2c->XferCount;
    hi2c->XferOptions = I2C_NO_OPTION_FRAME;
 
    /* Send Slave Address and Memory Address */
    if (I2C_RequestMemoryWrite(hi2c, DevAddress, MemAddress, MemAddSize, Timeout, tickstart) != HAL_OK)

I2C_RequestMemoryWrite gets as far as calling I2C_WaitOnMasterAddressFlagUntilTimeout without anything suspsicious looking happening:

static HAL_StatusTypeDef I2C_RequestMemoryWrite(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint32_t Timeout, uint32_t Tickstart)
{
  /* Generate Start */
  SET_BIT(hi2c->Instance->CR1, I2C_CR1_START);
 
  /* Wait until SB flag is set */
  if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart) != HAL_OK)
  {
    if (READ_BIT(hi2c->Instance->CR1, I2C_CR1_START) == I2C_CR1_START)
    {
      hi2c->ErrorCode = HAL_I2C_WRONG_START;
    }
    return HAL_TIMEOUT;
  }
 
  /* Send slave address */
  hi2c->Instance->DR = I2C_7BIT_ADD_WRITE(DevAddress);
 
  /* Wait until ADDR flag is set */
  if (I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, Timeout, Tickstart) != HAL_OK)

I2C_WaitOnMasterAddressFlagUntilTimeout then immediately enters the if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET) condition and fails.

static HAL_StatusTypeDef I2C_WaitOnMasterAddressFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Flag, uint32_t Timeout, uint32_t Tickstart)
{
  while (__HAL_I2C_GET_FLAG(hi2c, Flag) == RESET)
  {
    if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET)
    {
      /* Generate Stop */
      SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP);
 
      /* Clear AF Flag */
      __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF);
 
      hi2c->PreviousState       = I2C_STATE_NONE;
      hi2c->State               = HAL_I2C_STATE_READY;
      hi2c->Mode                = HAL_I2C_MODE_NONE;
      hi2c->ErrorCode           |= HAL_I2C_ERROR_AF;
 
      /* Process Unlocked */
      __HAL_UNLOCK(hi2c);
 
      return HAL_ERROR;
    }

Which looks to me to be a failure to receive the address ACK.

So much for the code. the data sheet tells me that to write 1 to address 0 I should send this:

S10100000A00000000A00000000A00000001AP

Where S and P are the start and stop conditions set by me and A the acknowledge set by the mb85rc64 and with a possibly suspsicious footnote "it is not necessary to take a period for internal write operation cycles from the buffer to the memory after the stop condition is generated." which I'm assuming isn't relevant since I'm not getting as far as actually writing into the memory.

The oscilloscope for the failed transaction looks like this:

0693W00000JMNgZQAX.jpg 

The clock signal seems possibly a little grubby, but other than that is there anything obviously causing WaitOnMasterAddressFlag to fail?

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Guru

> Some of those SLC/SDA transitions seem pretty much simultaneous and neither SLC nor SDA really have time to get pulled up properly: is that a potential problem?

The scope trace is fine apart from the device not ACKing, which is a hardware problem or addressing issue. Your slave address looks correct, which suggests a hardware issue.

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

13 REPLIES 13

The memory does not ACK. Make sure your connections are all OK, memory has all Ax pins at low. Measure directly on pins of the memory.

JW

Thanks.

After a little confusion about the number, the A0,A1 and A2 pins on the mb85rc64 are physically wired to ground on the chip itself so I'm pretty sure about those (plus I've checked them on the oscilloscope) and we're pretty sure for the I2C wiring to the chip (although I'll check one more time). We actually have three of these boards all with the same symptoms so if there's an electrical problem it would pretty much have to be something systemic to the board itself so I'm really trying to eliminate as many of the unknowns as possible.

Some of those SLC/SDA transitions seem pretty much simultaneous and neither SLC nor SDA really have time to get pulled up properly: is that a potential problem?

MM..1
Chief III

Try no preshifted

static const uint8_t DevAddress = 0b10100000;	// preshifted

TDK
Guru

> Some of those SLC/SDA transitions seem pretty much simultaneous and neither SLC nor SDA really have time to get pulled up properly: is that a potential problem?

The scope trace is fine apart from the device not ACKing, which is a hardware problem or addressing issue. Your slave address looks correct, which suggests a hardware issue.

If you feel a post has answered your question, please click "Accept as Solution".

If the traffic from the CPU is good and the bus itself is clean enough then that eliminates pretty much everything except something electrical related to the mb85rc64 chip itself.

What a brilliant answer, thanks a lot.

MM..1
Chief III

Try read operation first, maybe you have WP pin H= write protect.

> Some of those SLC/SDA transitions seem pretty much simultaneous

Yes, SDA changes at falling edge of SCL. That's OK, as tHD:DAT (i.e. data hold time that is measured from the falling edge of SCL) is 0ns, see I2C specification.

The basic requirement is, that during data transmission, SDA doesn't change while SCL is high (if they do, that means START or STOP).

JW

That's a good idea. I tried reads with the same result, but apart from checking the signals yet one more time I'm pretty much out of ideas :(

I've used the SPI versions of these devices on other boards without any problems, I think I'm going to have to switch back to SPI for this board.

I'd check all the memory pins first, supply voltage okay, ... ?

Then replace the memory with one from some trusted supplier.

BTW, if I'm not mistaken the I2C frequency seems pretty much lower than 100 kHz.

Not that I have seen a device that didn't run way below 100 kHz, but who knows...