cancel
Showing results for 
Search instead for 
Did you mean: 

I think I am enabling packet error checking on specific I2C reads from a peripheral device. I do this by setting CR1 bits PEC, POS, and ENPEC, then doing a HAL_I2C_Mem_Read. I get expected results from the register read. Should PEC be zero?

TAnde.5
Associate II

I look at SR2 PEC contents (most significant 8 bits), and they always are zero. Is that normal?

9 REPLIES 9
TAnde.5
Associate II

I went back and printed full SR2 register contents, and I am seeing different PEC values in the PEC bits.

Sorry, should have done that sooner...

TAnde.5
Associate II

Another question: When using HAL_I2C_Mem_Read to read a register from an external device, I am setting a value of 2 for the number of bytes to read (16-bit register).

I am getting proper value of the register being written. But do I need to set a different value when I am also getting PEC, or is that done by the setup?

Pavel A.
Evangelist III
TAnde.5
Associate II

Is PEC not available when using HAL_I2C_Mem_Read if I have set the following bits in CR2: PEC, POS, ENPEC? Or do I need to be in SMBUS mode for PEC to be functional? Is there an appnote that explains how to make use of PEC?

I am interfacing with an external device that differs from EEPROM in the protocol.

EEPROM

Master S AD+W RA S AD+R NACK P

Slave ACK ACK ACK DATA

GAUGE

Master S AD+W RA S AD+R ACK NACK P

Slave ACK ACK ACK DATA PEC

It is my understanding that setting the POS bit in CR2 enables the Master to generate ACK prior to receiving PEC, correct?

TAnde.5
Associate II

Sorry, formatting got messed up after pressing "Answer" button.

TAnde.5
Associate II

Here is my code for working with PEC - it assumes that I2C is already in use, and adds code for PEC (and then subtracts...)

  // 1. Clear PE bit.

  CLEAR_BIT(reqB->hi2c->Instance->CR1, I2C_CR1_PE);

  __asm__ __volatile__("nop");

  // 2. Set PEC bit in I2Cx_CR1 register.

  SET_BIT(reqB->hi2c->Instance->CR1, I2C_CR1_PEC);

  __asm__ __volatile__("nop");

  /* 3. Set POS bit in I2Cx_CR1 register. */

  SET_BIT(reqB->hi2c->Instance->CR1, I2C_CR1_POS);

  __asm__ __volatile__("nop");

  /* 4. Set PECEN bit in I2Cx_CR1 register. */

  SET_BIT(reqB->hi2c->Instance->CR1, I2C_CR1_ENPEC);

  __asm__ __volatile__("nop");

  /* 5. Set SMBTYPE bit in I2Cx_CR1 register. */

  SET_BIT(reqB->hi2c->Instance->CR1, I2C_CR1_SMBTYPE);

  __asm__ __volatile__("nop");

  /* 6. Set SMBUS bit in I2Cx_CR1 register. */

  SET_BIT(reqB->hi2c->Instance->CR1, I2C_CR1_SMBUS);

  __asm__ __volatile__("nop");

  /* 7. Enable the I2C peripheral by setting the PE bit in I2Cx_CR1 register */

  SET_BIT(reqB->hi2c->Instance->CR1, I2C_CR1_PE);

  __asm__ __volatile__("nop");

  iRet = HAL_I2C_Mem_Read(reqB->hi2c, BQ_ADDR, reg, 1, bVal, sizeof(bVal)+1,pdMS_TO_TICKS(B_I2C_TIMEOUT));

  osDelay(5); // Delay 5 milliseconds

  sr2val = reqB->hi2c->Instance->SR2;

  if(reqB->hi2c->Instance->SR1&0x1000)

  {

   DbgPrintf("PEC error\r\n");

  }

  else

  {

   DbgPrintf("PEC good, PEC=%x\r\n",sr2val);

  }

  // 1. Clear PE bit.

  CLEAR_BIT(reqB->hi2c->Instance->CR1, I2C_CR1_PE);

  __asm__ __volatile__("nop");

  // 2. Clear PEC bit in I2Cx_CR1 register.

  CLEAR_BIT(reqBatt->hi2c->Instance->CR1, I2C_CR1_PEC);

  __asm__ __volatile__("nop");

  /* 3. Clear POS bit in I2Cx_CR1 register. */

  CLEAR_BIT(reqB->hi2c->Instance->CR1, I2C_CR1_POS);

  __asm__ __volatile__("nop");

  /* 4. Clear ENPEC bit in I2Cx_CR1 register. */

  CLEAR_BIT(reqB->hi2c->Instance->CR1, I2C_CR1_ENPEC);

  __asm__ __volatile__("nop");

  /* 5. Clear SMBTYPE bit in I2Cx_CR1 register. */

  CLEAR_BIT(reqB->hi2c->Instance->CR1, I2C_CR1_SMBTYPE);

  __asm__ __volatile__("nop");

  /* 6. Clear SMBUS bit in I2Cx_CR1 register. */

  CLEAR_BIT(reqB->hi2c->Instance->CR1, I2C_CR1_SMBUS);

  __asm__ __volatile__("nop");

  /* 7. Enable the I2C peripheral by setting the PE bit in I2Cx_CR1 register */

  SET_BIT(reqB->hi2c->Instance->CR1, I2C_CR1_PE);

  __asm__ __volatile__("nop");

The code above works, but I am not sure if I need everything that is here. For instance, does PE need to be disabled, enabled or can I remove those?

Existing code had NOPs included - are those necessary?

TAnde.5
Associate II

Any answers to my questions?

  1. Do I need to clear/set PE bit?
  2. Do I need to include NOPs between register writes?

Are there any other things regarding PEC that I need to know?

TAnde.5
Associate II

Experimentation - NEED CONFIRMATION! I have removed NOPs and PE bit reset/set, and this appears to work.

  // 1. Set PEC bit in I2Cx_CR1 register.

  SET_BIT(reqB->hi2c->Instance->CR1, I2C_CR1_PEC);

  /* 2. Set POS bit in I2Cx_CR1 register. */

  SET_BIT(reqB->hi2c->Instance->CR1, I2C_CR1_POS);

  /* 3. Set PECEN bit in I2Cx_CR1 register. */

  SET_BIT(reqB->hi2c->Instance->CR1, I2C_CR1_ENPEC);

  /* 4. Set SMBTYPE bit in I2Cx_CR1 register. */

  SET_BIT(reqB->hi2c->Instance->CR1, I2C_CR1_SMBTYPE);

  /* 5. Set SMBUS bit in I2Cx_CR1 register. */

  SET_BIT(reqB->hi2c->Instance->CR1, I2C_CR1_SMBUS);

  iRet = HAL_I2C_Mem_Read(reqB->hi2c, BQ_ADDR, reg, 1, bVal, sizeof(bVal)+1,pdMS_TO_TICKS(B_I2C_TIMEOUT));

  osDelay(5); // Delay 5 milliseconds

  if(reqB->hi2c->Instance->SR1&0x1000)

  {

   DbgPrintf("PEC error\r\n");

  }

  else

  {

   DbgPrintf("PEC good, PEC=%x\r\n",sr2val);

  }

  // 1. Clear PEC bit in I2Cx_CR1 register.

  CLEAR_BIT(reqBatt->hi2c->Instance->CR1, I2C_CR1_PEC);

  /* 2. Clear POS bit in I2Cx_CR1 register. */

  CLEAR_BIT(reqB->hi2c->Instance->CR1, I2C_CR1_POS);

  /* 3. Clear ENPEC bit in I2Cx_CR1 register. */

  CLEAR_BIT(reqB->hi2c->Instance->CR1, I2C_CR1_ENPEC);

  /* 4. Clear SMBTYPE bit in I2Cx_CR1 register. */

  CLEAR_BIT(reqB->hi2c->Instance->CR1, I2C_CR1_SMBTYPE);

  /* 5. Clear SMBUS bit in I2Cx_CR1 register. */

  CLEAR_BIT(reqB->hi2c->Instance->CR1, I2C_CR1_SMBUS);

Bfdgr.1
Associate

Another question: When the use of HAL_I2C_Mem_Read to read a check in from an outside tool, I am setting a cost of 2 for the wide variety of bytes to examine here. I am getting right price of the sign up being written.