nox771 / i2c_t3

Enhanced I2C library for Teensy 3.x devices
157 stars 44 forks source link

Using Wire with multiple devices #17

Open ttlappalainen opened 6 years ago

ttlappalainen commented 6 years ago

Tanks for the great enchances. That solved my problem with my 1-wire library, which needs to run i2c tasks under isr (callbacks).

Now I have questions. Basically I build classes, which are independent of each other. So then they does not know about others and their use of wire.

The first problem is that each device class has its own initialization for Wire. So each of them will call begin, which causes situation that several device classes may call begin. So is there reliable way to check that has begin has been called and that it matches the request the other device will use?

1-wire runs with isr, when task has been started. Others normally as blocked but can also use irs in future. So do have any way to mark wire "locked" for some system? So if I start 1-wire tasks, I should have a way to tell that this Wire is now locked for me (e.g. pointer of callback handler). Then if other class tries to use it, it needs to wait until other class has finished its tasks.

Currently I have both problems by having own Wire extension, which just adds functionality. But if there is currently no functions for above, would it be possible to add functionality to your extension?

nox771 commented 6 years ago

There is currently no built-in method to check a new set of begin() settings against existing settings. Calling begin() more than once is allowed, as it provides a way to reconfigure the bus. So the library itself cannot tell if calling begin() multiple times is allowed or not for an application. This is really something that should be controlled at a higher level in the program.

The same applies for the mutex/lock situation. The library isn't built for multi-threaded operation on a single interface, so it does not include any management for this.

The solution for both of these is to create a class to manage the buses at a higher level including retaining the relevant begin() settings, and handling mutex/locks.

There are different (more complex) ways of handling locks to prevent stalls, such as using outgoing/incoming FIFO queues to handle traffic (so submit to FIFO instead of talking to I2C lib directly). This would require adding a Master address to the protocol to correctly send incoming data to the proper receiver.

But all of this is outside the scope of this library. It would have to be implemented at the application level.

tonton81 commented 6 years ago

you could set a static bool for the begin method thats default 0, if its called its set to 1, further calls to same object would return

nox771 commented 6 years ago

Certainly you can embed flags into the library, but I would argue that these flags are just as easily put into the main application. I would not want to set a flag to reject further begin() calls, as calling begin() more than once is allowed.

A different way to handle locks is just to stall until bus ready, eg: while( !Wire.done() ); But I've never tested that in a multi-thread context, and I don't know if I would trust it (it could stall one thread indefinitely, while a different one always runs). This gets into a whole mess of application specific problems which I don't want to bundle into the library.

ttlappalainen commented 6 years ago

Thanks for response. Implementing them on higher lever class is what I am having. Currently the class is rather simple and that why I thought these could be implemented on lower level. But you explanation sounds reasonable.

Byt the way while( !Wire.done() ); does not work with e.g. 1-wire. After requesting something from 1-wire device, it will answer immediately, which you have to catch. In case other system would just wait until Wire.done(), it could start to use Wire while 1-wire handler still needs it.