USB audio i2c best practice

Discussions about USB Audio on XMOS devices
lmariotti
Active Member
Posts: 33
Joined: Mon Nov 21, 2022 5:38 pm

USB audio i2c best practice

Post by lmariotti »

Hi Everyone,

I'm working on a project that use sw_usb_audio 9.0.0.
I need to share the same i2c line with multiple tasks.
So far I've followed the preset route and I've something like:

Code: Select all

void Board_i2c_task(chanend c, client interface i2c_master_if i2c)
{
  while(1)
  {
    select
    {
      case c :> unsigned cmd:
        if(cmd == CMD_DAC_INIT)
        {
          unsafe
          {
		// Access i2c bus
          }
        }
        else if(cmd == CMD_READ_IO_EXPANDER)
        {
          unsafe
          {
		// Access i2c bus
          }
        }
        else if(cmd == CMD_WRITE_IO_EXPANDER)
        {
          unsafe
          {
		// Access i2c bus
          }
        }
        else if(...)
        	// And so on with multiple commands
The chanend is shared between:
  • A timed task (10Hz)
  • A GPIO event task
  • AudioHwConfig
Is that implementation correct or may cause trubles?
If not what's a best practice to access the same i2c bus from multiple tasks?

Thanks everyone
User avatar
andrewxcav
Verified
Experienced Member
Posts: 76
Joined: Wed Feb 17, 2016 5:10 pm

Post by andrewxcav »

If you aren't running out of chanends I would suggest making a dedicated task that can write to the I2C task and read a chanend from your other 3 tasks. This multiplexer task should probably have the form:

task(i2c_chan, task chans ... )
{
initialization code if any

while(1)
{
select{ // on each chanend and/or a 10Hz. timer if you wanted to pull that task into this one to save on cores or chanends...
...
}
}
}
User avatar
Ross
Verified
XCore Legend
Posts: 1183
Joined: Thu Dec 10, 2009 9:20 pm
Location: Bristol, UK

Post by Ross »

As andrewxcav suggests, you need a channel for each task you want to communicate with - since they all want to perform the same actions there is a short hand way of doing this called "replicated cases"

Here's a small working example

Code: Select all

#include <stdio.h>

void server0(chanend c[2])
{
    int cmd;
    while(1)
    {
        select
        {
            case c[int x] :> cmd:
                printf("command %d from client %d\n", x, cmd);
                break;
        }
    }
}

void client0(chanend c)
{
    c <: 0;
}

void client1(chanend c)
{
    c <: 1;
}

int main()
{
    chan c[2];
    par
    {
        server0(c);
        client0(c[0]);
        client1(c[1]);
    }
    return 0;
}

Code: Select all

$ xcc -target=XK-EVK-XU316 test.xc 

$ xsim ./a.xe 
command 1 from client 1
command 0 from client 0
Technical Director @ XMOS. Opinions expressed are my own