如何解决stm32 smbus 上的 PEC 不可靠
我在 STM32 SMBUS 上遇到 PEC 问题,我用它从 MLX90614 IR 温度计读取数据。当我启动设备时,即使来自 IR 温度计的数据似乎是正确的,对于所有传输,PECERR 标志都已设置并继续设置。或者 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 deviceAddress,uint8_t 命令) {
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,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,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),timeout)) {
DEBUG_PUTS("Timeout while waiting for repeted start bit set");
return ERROR_CODE;
}
// Send the read command to the slave address
sendAddress(h,I2C_READ);
// Wait for address bit set
if (!waitFlag((&h->SR1),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),timeout)) {
DEBUG_PUTS("Timeout while waiting for Byte Transfer Finished");
return ERROR_CODE;
}
}
// Wait for Byte Transfer ready
if (!waitFlag((&h->SR1),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;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。