微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

stm32 smbus 上的 PEC 不可靠

如何解决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 举报,一经查实,本站将立刻删除。