Report
9 months, 1 week ago.

I2C read in Timer/Timeout

I have a library to communitace with I2C sensor. I request some data and then I need to wait 60ms and then read data from sensor. Since i'm not allowed to use I2C object in Timer/Timeout, how do I wait and then read? I don't want to use wait()

void Test::isConversionFinished() {
    i2c->lock();
    i2c->read(_address, _Buffer, _requested_bytes);
    i2c->unlock();

    if ((_Buffer[_requested_bytes - 1] >> 7) == 0) {
        process();

    } else {
       // timeout.attach_us(callback(this, &Test::isConversionFinished), 60000); // not allowed to use this method as this will use I2C in ISR
        Thread::wait(60);
        isConversionFinished();
    }
}

Thank you

Comment on this question

1 Answer

9 months, 1 week ago.

60ms is an eternity. Why do you not want to release to the rtos scheduler? This would be the normal way to do it. If you insert some sort of other wait, the rtos system tick is going to come in anyway after 10ms and do the same thing basically. You would have to disable the rtos in the build or maybe there is a way to disable rtos interrupts in the wait section). I think this code snippet will disable rtos interrupts, but someone can correct me.

core_util_critical_section_enter();
// your 60ms wait
core_util_critical_section_exit();

If you want to implement your own timer easiest way is to use Timer class.

Timer t;

t.reset();
t.start();
while(t.read_ms() < 60);

I don't want to disable rtos. The way you showed me will be blocking way, i need to read I2C after 60ms but non blocking way. The way i wanted it to work is that i request data from main program->class will send I2C request->, main program continues and once 60 ms pass(which would be handled in library) I read data (in class) and result will be pushed to callback-> callback is picked up in main and do some stuff with it. As you can see i don't want to use any blocking delay and can't use I2C in interrupt

posted by Pavel S 13 Feb 2018

Okay I think I understand better. I'll give you a couple obvious ideas. Can you put the I2C stuff in its own thread? Threads are good for solving weird asynchronous communication issues like this. Could feed it with a queue. This way a simple blocking call will not affect the rest of the program.

Or, the classic (non-rtos) way to handle this in a single thread is just polling. So say main is 10ms long, your class has a function you call from main (call it update()) that tracks the state of the I2C module (idle, waiting to receive, received, etc) and counts up to that 60ms delay.

You could take a look at RtosTimer class and EventQueue class which seem to be for handling timing outside ISR context. I have not used either so can't comment.

Your function, isConversionFinished() seems to call itself. Was this intended? That seems like it could cause problems.

posted by Graham S. 13 Feb 2018

Thank you I will have look at the queue and see if that works. Calling isConversionFinished() was intended - it will try to read data again and again until they are ready

posted by Pavel S 16 Feb 2018

I have done it through mbed_events, thank you. Just for reference in case somebody finds it useful here is finished library https://github.com/pilotak/MCP342X

posted by Pavel S 12 Mar 2018

To post an answer, please log in.