So (thinking aloud) perhaps this is where the issue lies (IMHO) - in single threaded mode, access is no issue as all access is happening “sequentially” in the same thread but when is SYSTEM_THREAD(ENABLED) - there is concurrent access to the LittleFS library and the issue arises - same problem for example, when using this mode and the LCD library and software timers - it causes corruption as the underlying drivers are not thread aware and can be ungraciously interrupted as DeviceOS assumes its in control. Even though SYSTEM_THREAD(ENABLED) works well in most cases, all built in libraries (like EEPROM, WIRE, SPI etc) would need to have “transactional” support refined going forward.
@shanevanj, yup, thread safe behaviour for shared resources in the DeviceOS seems to not be consistent. Transnational devices (SPI, I2C, etc) also need to be protected, which seems to be lacking (eg the LCD example).
Wild thought here - could we start a tutorial type exercise to convert the current wire library to a transactional based one - I for one would love to learn how to do something like this as my code skills are not much beyond pointers, never mind classes and transactional code etc. I could not contribute in terms of code but would be happy to destructively test …
@shanevanj, I’m not sure why you think the existing Wire support in DeviceOS is not transactional. Remember that it is tied to the hardware and may be implemented in the Nordic SoftDevice stack. Furthermore, I2C is intrinsically transactional. Perhaps you can explain more about what you want to achieve?
SPI API does have a locking semantic.
Wire I2C API does as well via
Wire.lock/unlock but I can’t see it in the latest API documentation unless I’m missing something.
I may have used the wrong layer here :-), and I may also have mangled some concepts - on reflection, if I take the issue I had with LCD corruption - I see now that the issue is going to be in the I2C LCD library and not the wire library - so this requirement of mine should change to say how do we make the I2C LCD library “transactional” i.e. if app thread is updating LCD and software timer (system thread) fires an lcd update - the two somehow play nice so you don’t end up with a corrupted display - an example would be a software timer updating the time of day in top left corner of LCD, while the app thread updates values from a sensor in the second line of the LCD. Currently with system_thread(enabled) this results in a corrupted display as the (in my understanding) LCD library is not thread aware (if thats even possible) nor is there a way to “take exclusive” ownership of the lcd. Perhaps it is as simple as implementing a few new functions like
- bool lcd.available() - returns a boolean if not locked.
- int lcd.lock() - returns a int (lockNumber) if completed, -1 if locked already
- bool lcd.release(int lockNumber) - true completed, false lock number not found
@shanevanj, I2C is transactional. The problem is when the software timer interrupts an ongoing transaction being done by the user application. The typical solution is to create a MUTEX which prevents the single resource, the I2C hardware, from being interrupted in the middle of a transaction until it is complete. Thus “with lock” and “release” you mention.
Another solution, a la @rickkas7, is to create a thread that handles all display transactions with a buffer whose elements are built in the user application and/or software timer. This way ONLY the thread transacts with the I2C device.