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) */