c-stm32 smbus上的PEC不可靠



我在STM32 SMBUS上的PEC遇到问题,我用它来读取MLX90614 IR温度计的数据。当我启动设备时,PECERR标志被设置并继续被设置,用于所有传输,即使来自IR温度计的数据似乎是正确的。或者PECERR从未设置,并且来自IR温度计的所有数据仍然正确。

当我在示波器上研究数据时,我看不到PECERR设置与否时信号之间的差异。如前所述,无论哪种方式,数据似乎都是好的。

我当然可以忽略PECERR标志,但我希望能够过滤掉任何最终的混乱传输。有人知道我在这里做错了什么吗?

void I2C_SMBUS_Initialize(I2C_TypeDef *h) {
h->CR2 &= ~I2C_CR2_FREQ;                // Clear frequency part of register
h->CR2 |= 0x8;                          // Clock speed in Mhz
h->OAR1 = 0x4000;
h->CCR = 0;
h->CCR &= ~I2C_CCR_DUTY;
h->CCR |= 0x190;
h->TRISE &= ~I2C_TRISE_TRISE;           // Clear TRISE bits
h->TRISE |= 0x9;                        // Set TRISE
h->CR1 |= I2C_CR1_ENPEC;                // Enable packet error check
h->CR1 |= I2C_CR1_SMBTYPE;              // SMBUS host
h->CR1 |= I2C_CR1_SMBUS;                // SMBUS Mode
h->CR1 |= I2C_CR1_PE;  // Start i2c

}

uint16_t I2C_SMBUS_ReadWord(I2C_TypeDef*h,uint8_t设备地址,uint8kt命令({

static const uint16_t ERROR_CODE = 0x3BFF;
//static const uint8_t deviceAddress = 0x5A;
static const uint8_t timeout = 100;
uint16_t temp = 0;
h->CR1 &= ~I2C_CR1_POS;
// Generate start bit 
sendStartBit(h);
// Wait for start bit set
if (!waitFlag((&h->SR1), I2C_SR1_SB, BIT_SET, timeout)) {                                          
DEBUG_PUTS("Timeout while waiting for start bit set");
return ERROR_CODE;
}
// Address byte. 7 bit. Shifted one lefet
sendAddress(h, deviceAddress, I2C_WRITE);
// Wait for address bit set
if (!waitFlag((&h->SR1), I2C_SR1_ADDR, BIT_SET, timeout)) {                                        
DEBUG_PUTS("Timeout while waiting for address bit set");
return ERROR_CODE;
}
// Clear ADDR bit
clearAddressFlag(h);
sendData(h, command);
// wait for tx buffer empty
if (!waitFlag((&h->SR1), I2C_SR1_TXE, BIT_SET, timeout)) {
DEBUG_PUTS("Timeout while waiting for buffer empty");
return ERROR_CODE;
}   

uint8_t length = 3;
uint8_t tmpBuffer[length+1];
memset(tmpBuffer, 0x00, 4);
// Enable automatic ACK generation
enableAutomaticACK(h);
// Generate start bit
sendStartBit(h);
// Wait for start bit set
if (!waitFlag((&h->SR1), I2C_SR1_SB, BIT_SET, timeout)) {                                          
DEBUG_PUTS("Timeout while waiting for repeted start bit set");
return ERROR_CODE;
}
// Send the read command to the slave address
sendAddress(h, deviceAddress, I2C_READ);

// Wait for address bit set
if (!waitFlag((&h->SR1), I2C_SR1_ADDR, BIT_SET, timeout)) {
DEBUG_PUTS("Timeout while waiting for address bit set");
return ERROR_CODE;
}
// Clear ADDR bit by reading status register 
clearAddressFlag(h);
// Now we must read the data from the slave 
if (length > 2) {
// Receive the first n-2 bytes
for (uint8_t i=0; i < length-2; i++) {                                             
// Wait for Byte Transfer ready
if (!waitFlag((&h->SR1), I2C_SR1_BTF, BIT_RESET, timeout))  {                                
DEBUG_PUTS("Timeout while waiting for Byte Transfer ready");
return ERROR_CODE;
} 
tmpBuffer[i] = h->DR;                                                 

// Wait for Byte Transfer Finished
if (!waitFlag((&h->SR1), I2C_SR1_BTF, BIT_SET, timeout))  {                                
DEBUG_PUTS("Timeout while waiting for Byte Transfer Finished");
return ERROR_CODE;
}
}                                                                           
// Wait for Byte Transfer ready
if (!waitFlag((&h->SR1), I2C_SR1_BTF, BIT_RESET, timeout))  {                                
DEBUG_PUTS("Timeout while waiting for Byte Transfer ready");
return ERROR_CODE;
} 
// Disable automatic ACK generation
disableAutomaticACK(h);
// Read the second last byte 
tmpBuffer[length-1] = h->DR;                                             
// Send stop bit
sendStopBit(h);
// Enable packet error check
h->CR1 |= I2C_CR1_PEC;
// Read the last byte
tmpBuffer[length] = h->DR;                                                    
temp = tmpBuffer[3]*256 + tmpBuffer[2]; 
uint8_t pec = h->SR2 &= I2C_SR2_PEC_Msk;
if ((h->SR1 & I2C_SR1_PECERR) != 0) {
puts("PEC ERROR");
}
}
return temp;

}

发现错误。PECERR必须由软件清除。上电后的第一个变速器偶尔会出现故障。

if ((h->SR1 & I2C_SR1_PECERR) != 0) {
DEBUG_PUTS("PEC ERROR");
h->SR1 &= ~I2C_SR1_PECERR;
return ERROR_CODE;
}

最新更新