【问题标题】:Unreliable PEC on stm32 smbusstm32 smbus 上不可靠的 PEC
【发布时间】:2021-01-04 12:16:04
【问题描述】:

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

当我在示波器上研究数据时,无论是否设置了 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 command) {

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;

}

【问题讨论】:

    标签: c stm32 smbus


    【解决方案1】:

    发现错误。 PECERR 必须由软件清零。开机后第一次传输偶尔会失败。

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

    【讨论】:

      猜你喜欢
      • 2021-10-05
      • 2020-06-17
      • 2018-09-24
      • 2019-06-06
      • 2021-11-01
      • 1970-01-01
      • 2014-11-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多