Continuous Background I2C process

Hi Nordic,

We are migrating an older mesh project from nrfSDK 17 to zephyr and have a question about what is the BEST way to have a continuous I2C process running in zephyr. The application has 3 mesh models, uses 2 PWM modules, ADC reads every roughly every 3 seconds, and TWIM reads 100 times per second. 

In the old codebase the I2C sensor is read with the TWIM triggered over a PPI channel connected to a timer. We need to read data at least 100 times per second. Each read is followed by some processing and based on the data events are generated and passed over to other parts of the application. This all works well.

For our zephyr projects we have yet to use a timer in any of them. We use delayable work and submit to the system workqueue recursively for repeated tasks at a cadence. 

My question is should we submit work to the system workqueue at a rate of 100/second or is there a better way to do this? Would it be less intrusive to the other parts of the application to create a dedicated workqueue (and thus its own thread) for this process alone? Or would a simple timer trigger be best to avoid the hardware effort of supporting another queue?

If there is some other way that would be best suited for this application to run smooth we would like to hear it. Looking forward to suggestions!

  • My question is should we submit work to the system workqueue at a rate of 100/second or is there a better way to do this? Would it be less intrusive to the other parts of the application to create a dedicated workqueue (and thus its own thread) for this process alone? Or would a simple timer trigger be best to avoid the hardware effort of supporting another queue?

    I depends a bit on your latency requirements for the I2C sensor data, and whether you need to process the sensor samples at the same thread priority as the system workqueue or if you need a higher/lower priority.


    Can you process samples in batches or do you need every sample to be processed before the next sample is ready? 
    If so how long can you wait? 


    Do you need a driver for the I2C communication or can a basic Master repeated start sequence get the sensor info?
    If so, using a TIMER to trigger a TWIM transfer instead of an RTOS timer will probably reduce the scheduling overhead a fair bit, as well as remove lots of time-scale jitter from your data.  

  • You might also be interrested in the zephyr\samples\kernel\metairq_dispatch sample, as it can give you valueable insight into the latencies of your sample processing under various system loads.

  • Hi Haakonsh,

    Thank you for your insightful reply. From researching your comments I think the direction we want to go is using a TIMER to trigger transfers. Reading i2c data at a consistent cadence is important.

    I like the idea of batch processing samples. Processing the read data is less important. I think we want to run timed i2C reads from the main thread and queue the read data in their own thread for processing? This makes good sense to me. 

    Thank you for pointing out the metairq sample, we will adapt to use as a tool to measure latency within our processing. 

    A couple more questions on I2C and timer in Zephyr: 

    A basic master repeat start sequence is good for us, in our application we write 1 byte to read 6 bytes. Is i2c_read() from i2c.h in the zephyr library sufficient for us? 

    For processing we want to call k_msgq_put() with the read data shortly after i2c_read(). How do we know when the transfer has completed? When we did this with the nrfx library using nrfx_twim_rx() there is an event handler that flags when the transfer completes. We use this handler to move the data into processing. I don't think I see an event handler in the zephyr i2c.h library. Do we need to register a handler to capture that event somehow?

    The metairq sample uses a resetting z_add_timeout() for the timer. Is this ok to use system timer or do we need to  look at a different timer module that can be setup to run in background?

    Thanks!

  • mneber said:
    A basic master repeat start sequence is good for us, in our application we write 1 byte to read 6 bytes. Is i2c_read() from i2c.h in the zephyr library sufficient for us? 

    Yes I believe so.

    mneber said:
    How do we know when the transfer has completed?

    i2c_read() is synchronous, it will return 0 if the transfer has completed successfully. 

    mneber said:
    The metairq sample uses a resetting z_add_timeout() for the timer. Is this ok to use system timer or do we need to  look at a different timer module that can be setup to run in background?

    I'll get back to you regarding this question asap.

  • mneber said:
    The metairq sample uses a resetting z_add_timeout() for the timer. Is this ok to use system timer or do we need to  look at a different timer module that can be setup to run in background?

    I think you might want to use a TIMER peripheral for this application, as the 32.768kHz system timer will have at best 0.0 - 30.51us resolution. Though you can always try it with the system timer, i think you will be able to spot issues if you are aware of they can manifest. 

    See modules\hal\nordic\nrfx\samples\src\nrfx_timer\timer\README.md

Related