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;
    }

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...