简体   繁体   中英

Unreliable PEC on stm32 smbus

I've got a problem with PEC on STM32 SMBUS, which i use to read data from a MLX90614 IR thermometer. When i start the device, either the PECERR flag is set and continues to be set, for all transmissions, even though the data from the IR thermometer seems to be correct. Or the PECERR is never set and all the data from the IR thermometer is still correct.

When i study the data on my oscilloscope i can see no difference between the signals when the PECERR is set or not. As stated earlier data seems to be good either way.

I could of course just ignore the PECERR flag, but i'd lige to be able to filter out any eventual garbled transmissions. Anyone have an idea what i am doing wrong here?

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;

}

Found the bug. PECERR must be cleared by software. The first transmission after power on occasionally fails.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM