6 years, 1 month ago.

Call i2c function from ticker

I can't call any function that call i2c write or read from ticker callback. Is there any workaround to call i2c composed function by time interval without using ticker?

Main program

#include "mbed.h"
#include "TPA81.h"

Serial pc (USBTX, USBRX);
TPA81 tpa(PB_4,PA_8, 0xD2);
Ticker tick;
uint8_t ver;

void read_i2c(){
	ver = 111;
	ver = tpa.firmware_ver();
}

int main() {
	tick.attach(&read_i2c,0.5f);
	while(1){
		pc.printf("%d\n", ver);
	}
}

and tpa.firmware_ver() call this function

TPA81 's i2c code

uint8_t TPA81::_access_register(uint8_t i) {
	_cmd[0] = i;
	_TPA.write(_addr, _cmd, 1);
	_TPA.read(_addr, _cmd, 1);
	return _cmd[0];
}

It always print 111, but when I call tpa.firmware_ver() directly inside while loop it prints 7 as intended.

1 Answer

6 years, 1 month ago.

The _TPA object is an mbed I2C object. Like most mbed libraries, I2C uses a mutex to protect resources. It is not safe to use mutexes from an ISR context. It's possible this is your problem. You could build from the source code and take them out if you want - assuming you only access I2C bus in this one place. You could rollback to mbed 2 that doesn't have the mutexes in place for multithreading. I think there is a way to disable rtos in mbed-os, but I've never done it. That may be a way to bypass the mutex issue.

If you want to poll the tpa thing at regular intervals just put it in a loop and poll it. You could give it it's own thread which is very easy to control timing, but then you have to deal with sharing data between threads. As long as functions run fast enough it often makes sense to build a program in main as one big superloop with fixed looptime, maybe 10ms base. Then just count your loops to dispatch functions at required time intervals. For example, this should call that firmware get function every 100 loops * 10ms = 1 second.

#include "mbed.h"
#include "TPA81.h"

Serial pc (USBTX, USBRX);
TPA81 tpa(PB_4,PA_8, 0xD2);
uint8_t ver = 0;

void updateTpa() {
    static int counter = 0;
    counter++;

    if (counter > 100) {
        ver = firmware_ver();
        counter = 0;
    }
}

int main() {
    while(true) {
        updateTpa();
        // call next function
        // call more functions
        Thread::wait(10);
    }
}

Accepted Answer