c++operator-overloadingstm32i2clibopencm3

Using operators for I2c operations


I have a STM32F2 controller and a FRAM device FM24V10-G connected to it via I2C. Usually, in order to communicate with I2C devices I use a library, based on libopencm3. However, using FRAM requires a slightly different order of I2C actions(like sending start, 7 bit address, etc), meaning I can't use standard library functions like read and write, which helped me with other I2C devices. In this library I2C is implemented as a class, and it has stream operators overloaded in order to send those I2C commands in a desired order.

For example:

I2c& I2c::operator<< (operation_t operation)
{
    switch (operation) {
        case Start:
            i2c_send_start(_reg);
            while (!checkEvent(SR2(I2C_SR2_BUSY | I2C_SR2_MSL) | I2C_SR1_SB));
            break;
        case Stop:
            i2c_send_stop(_reg);
            break;
        case Wait_End:
            while (!checkEvent(I2C_SR1_TxE));
            break;
    return *this;
}

Sometimes, some of these commands fail to be executed, resulting in the CPU waiting for some flag(like in case of Wait_End), stopping the whole system from functioning.

So here's my question: Is there a way to return some kind of a timeout flag in the code above? For me, it's crucial to have the system functioning at all times, just skipping one command if the I2C operation fails and reaches timeout is OK.

Thanks to everyone who is reading this!


Solution

  • You can do a very basic timeout like this:

    I2c& I2c::operator<< (operation_t operation)
    {
        int count = 0;
        const int TIMEOUT = 4242;
        switch (operation) {
            case Start:
                i2c_send_start(_reg);
                while (!checkEvent(SR2(I2C_SR2_BUSY | I2C_SR2_MSL) | I2C_SR1_SB) 
                        && count != TIMEOUT) {
                    count++;
                }
                break;
            case Stop:
                i2c_send_stop(_reg);
                break;
            case Wait_End:
                while (!checkEvent(I2C_SR1_TxE) && count != TIMEOUT) {
                    count++;
                }
                break;
        }
        if (count == TIMEOUT) {
            //error handling
            return -1;
        }
        return *this;
    }
    

    Of course if you need accurate timeout and don't want to waste processing time increasing the count variable you should use hardware timers.