2021-08-25 02:29 PM
I look at SR2 PEC contents (most significant 8 bits), and they always are zero. Is that normal?
2021-08-25 02:33 PM
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...
2021-08-25 02:56 PM
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?
2021-08-25 04:35 PM
For PEC, use the SMBUS API: HAL_SMBUS_Init etc.
2021-08-26 07:18 AM
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?
2021-08-26 07:19 AM
Sorry, formatting got messed up after pressing "Answer" button.
2021-08-26 07:56 AM
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?
2021-09-13 07:34 AM
Any answers to my questions?
Are there any other things regarding PEC that I need to know?
2021-09-13 02:38 PM
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);
2021-10-21 04:00 AM
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.