I’ve refreshed my memory of Mozzi and its
twi_nonblock API for non-blocking I2C operations, the next step is to write a relatively simple Hello World to verify I can communicate with an AS7341 with that API. While reading AS7341 datasheet I noted a great candidate for this operation: product ID and revision ID registers.
In order to use
twi_nonblock we need to break a blocking
read() up to at least three non-blocking steps in order to avoid glitching Mozzi sound:
- We start with an I2C write to tell the chip which register we want to start from. Once we set parameters, I2C hardware peripheral can do the rest. In the meantime, we return control to the rest of the sketch so Mozzi can do things like
updateAudio(). During each execution of
updateControl()we check I2C hardware status to see if the write had completed. If it’s still running, we resume doing other work in our sketch and will check again later.
- If step 1 is complete and address had been sent, we configure I2C hardware peripheral to receive data from A7341. Once that has been kicked off, we return control to the rest of the sketch for
updateAudio()and such. During each execution of
updateControl()we check I2C hardware status to see if data transfer had completed. If it’s not done yet, we resume running other code and will check again later.
- If data transfer from AS7341 is complete, we copy the transferred data into our sketch and our application logic can take it from there.
My MMA_7660 sketch tracked above states #1-3 within
updateControl(), following precedence set by Mozzi’s ADXL354 example. But that was a simple sensor to use, we just had to read three registers in a single operation. AS7341 is a lot more complex with multiple different read operations, so I pulled that state machine out of
updateControl() and into its own method
async_read(). The caller can keep calling
async_read() on every
updateControl() until the state reaches
ASYNC_COMPLETE, at which point the process stops waiting for data to be copied and processed. Whenever the caller is ready to make another asynchronous read, they can set the state to
ASYNC_IDLE and the next
async_read() will start the process again.
As a test of this revamped system, I used it to read two bytes from AS7341 starting at register 0x91. 0x91 is for revision ID and the following byte 0x92 is the product ID. I wasn’t sure what to expect for revision ID, I got zero. But according to the datasheet product ID is supposed to be 0x09, and that matches what I retrieved. A great start! Now I can dig deeper and figure out how to read its sensors with nonblocking I2C.
Code for this project is publicly available on GitHub.