Is there a Zephyr example somewhere for using non-blocking I2C writes?
I was able to get a basic I2C read/write command working using the blocking function i2c_write_read(). However, this is a blocking function, and I want to free up the CPU to do other tasks while the I2C transaction is being clocked out.
I am trying to implement the asynchronous version i2c_write_read_cb() by following along with the Zephyr documentation here. My code builds, but I am getting errors at runtime reporting -22 = invalid argument. Having a working example of non-blocking I2C reads, including the callback function implementation, would be a big help to setting this up.
Does such an example exist? If not, could someone help identify what I need to do to get this function working?
Note that I have my I2C interface running in its own thread. The thread runs fine, so I'm only including the code for this thread. I only intend to run my init_tas2563 function once, but I put it into the thread's while loop on a 5 second timer to help debug in the short term.
init_tas2563 runs every 5 seconds, and it calls i2c_write_read_cb(). I want to observe the I2C traffic on my oscilloscope, and see my callback function process_temp_reading_cb() run and print out the value that is read over I2C.
/*
* Based on the echo I2S driver sample in the Nordic SDK.
* Found at: ncs/v2.5.0/zephyr/samples/drivers/i2s/echo/
*/
#include <zephyr/kernel.h>
#include "flare_codec.h"
#include <zephyr/sys/printk.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/logging/log.h>
#if DT_ON_BUS(TAS2563_NODE, i2c)
#define TAS2563_I2C_NODE DT_BUS(TAS2563_NODE)
#define TAS2563_I2C_ADDR DT_REG_ADDR(TAS2563_NODE)
#define FLARE_AUDIO_TASK_PRIORITY CONFIG_SIDEWALK_THREAD_PRIORITY
LOG_MODULE_REGISTER(audio_task, CONFIG_SIDEWALK_LOG_LEVEL);
#define AUDIO_TASK_STACK_SIZE (2048)
#define AUDIO_MSG_THREAD_QUEUE_SIZE 10
K_THREAD_STACK_DEFINE(flare_audio_task_stack, AUDIO_TASK_STACK_SIZE);
K_MSGQ_DEFINE(audio_task_msgq, sizeof(enum audio_event_type), AUDIO_MSG_THREAD_QUEUE_SIZE, 4);
static struct k_thread flare_audio_task;
/* Function Prototypes */
bool init_tas2563(const struct device *const dev);
/* Callback Prototypes */
void process_temp_reading_cb();
static void audio_task(void *dummy0, void *dummy1, void *dummy2)
{
// Stuff to do once, when the thread initializes
LOG_INF("Starting %s ...", __FUNCTION__);
const struct device *const tas2563_dev = DEVICE_DT_GET(TAS2563_I2C_NODE);
if (!device_is_ready(tas2563_dev)) {
LOG_ERR("%s is not ready.\n", tas2563_dev->name);
return false;
}
if(!init_tas2563(tas2563_dev)) {
LOG_ERR("%s failed during I2C initialization.\n", tas2563_dev->name);
return false;
}
else {
LOG_INF("TAS2563 completed I2C initialization.\n");
}
while(1)
{
// Stuff to do every time the thread runs
LOG_INF("In %s ...", __FUNCTION__);
init_tas2563(tas2563_dev);
k_msleep(5000);
}
}
void flare_audio_task_start(void)
{
(void)k_thread_create(&flare_audio_task, flare_audio_task_stack,
K_THREAD_STACK_SIZEOF(flare_audio_task_stack), audio_task,
NULL, NULL, NULL, FLARE_AUDIO_TASK_PRIORITY, 0,
K_NO_WAIT);
k_thread_name_set(&flare_audio_task, "flare_audio_task");
}
void add_audio_event_to_queue(enum audio_event_type audio_event_to_add)
{
while (k_msgq_put(&audio_task_msgq, &audio_event_to_add, K_NO_WAIT)) {
LOG_WRN("The audio_task_msgq queue is full, purge old data");
k_msgq_purge(&audio_task_msgq);
}
}
bool init_tas2563(const struct device *const dev)
{
LOG_INF("Running init on %s.\n", dev->name);
uint8_t my_write_buff = 0x02; // I2C address to read
uint8_t my_read_buff = 0xA5; // data from I2C read should end up here, and overwrite 0xA5 with 0x0E
uint8_t cb_user_data = 0x00; // this is the data that is passed to the callback - I think we probably want to copy the read_buff here to use the read value in the callback?
struct i2c_msg * my_msgs;
i2c_callback_t my_callback = &process_temp_reading_cb;
int ret;
ret = i2c_write_read_cb(dev, my_msgs, 2, TAS2563_I2C_ADDR, &my_write_buff, sizeof(my_write_buff), &my_read_buff, sizeof(my_read_buff), my_callback, &cb_user_data);
if(ret == 0){
LOG_INF("i2c_write_read_cb returned success");
}
else{
LOG_INF("i2c_write_read_cb failed with %d", ret);
}
return true;
}
void process_temp_reading_cb(i2c_callback_t cb_data){
LOG_INF("in temp_reading_cb! cb_data = %d \n", cb_data);
}
#endif /* DT_ON_BUS(TAS2563_NODE, i2c) */