I2C in AudioRef Design

Sub forums for various specialist XMOS applications. e.g. USB audio, motor control and robotics.
AlexAdvice
XCore Addict
Posts: 146
Joined: Sun Feb 23, 2014 11:30 am

I2C in AudioRef Design

Post by AlexAdvice »

Hi friends.
I am using a reference design adapted for XU208. Everything works fine, but I want to add one feature and I have a problem.

I need to periodically (say every 100-200ms) read data from one I2C device, do some very simple math and send the result to a second I2C device.

So I wrote in customdefines.h:

Code: Select all

void myadd_task(void);
#define USER_MAIN_CORES    on tile[0]: myadd_task();
also in audiohw.xc I wrote:

Code: Select all

on tile [0] : struct r_i2c r_i2c = {PORT_I2C};  // port is defined in .xn file
...
void AudioHwInit(chanend ?c_codec) {
  timer t;
  unsigned time;
  int i;
  char ddt[3];
  
    /* Init the i2c module */
    i2c_shared_master_init(r_i2c);
    ddt[0]=0x4E;
    i2c_shared_master_write_reg(r_i2c, 0x18, 0, ddt, 1); // Init 1st I2C device
     ddt[0]=0x17;
    i2c_shared_master_write_reg(r_i2c, 0x20, 0, ddt, 1); // Init 2nd I2C device
    ...
 }
 ...
 void AudioHwConfig(unsigned samFreq, unsigned mClk, chanend ?c_codec,
unsigned dsdMode, unsigned samRes_DAC, unsigned samRes_ADC) {
char ddt[3];
 ...
   ddt[0]=dsdMode;
   i2c_shared_master_write_reg(r_i2c, 0x20, 1, ddt, 1); // Set  2nd I2C device Mode
...
}
 ....
 ....
void myadd_task(void){
   timer t;
   unsigned time;
   char ddt[3];
   
    while(1){
        t :> time;
        t when timerafter(time + (10000*2)) :> void;
        
         i2c_shared_master_read_reg(r_i2c, 0x18,  3, ddt, 2);  // <<<<<<<<<< Error
         // here will be calculations
         i2c_shared_master_write_reg(r_i2c, 0x20, 20, ddt, 2); // <<<<<<<<< Error

        }
    }
}

And I got an error:

Code: Select all

W:/wrk/snd/X200/module_usb_audio/main.xc:555:5: error: use of `r_i2c' violates parallel usage rules
    par
    ^~~
../src/extensions/audiohw.xc:280:40: note: object used here
            i2c_shared_master_read_reg(r_i2c, 0x18,  1, ddt, 2);
                                       ^~~~~
../src/extensions/audiohw.xc:205:28: note: object used here
    i2c_shared_master_init(r_i2c);
I understand that the problem is that I use i2c in AudioHwInit(), and in the AudioHwConfig() and also in the myadd_task(), but I don't know how to solve these.
Help me please!
User avatar
Ross
Verified
XCore Legend
Posts: 1070
Joined: Thu Dec 10, 2009 9:20 pm
Location: Bristol, UK

Post by Ross »

why not move all the init to myadd_task(void)?
Technical Director @ XMOS. Opinions expressed are my own
AlexAdvice
XCore Addict
Posts: 146
Joined: Sun Feb 23, 2014 11:30 am

Post by AlexAdvice »

As I understand, everything in myadd_task() before while(1) run once at start, so I think there is no problem to move init at this place.
But what to do with everything, running in AudioHwConfig?

I've already thought about it - to raise the flag in AudioHwConfiganf and to check it in myadd_task(). Is this a right way?
User avatar
Ross
Verified
XCore Legend
Posts: 1070
Joined: Thu Dec 10, 2009 9:20 pm
Location: Bristol, UK

Post by Ross »

AlexAdvice wrote: Wed Sep 04, 2024 4:12 pm As I understand, everything in myadd_task() before while(1) run once at start, so I think there is no problem to move init at this place.
Yep, it does. AudioHWInit() also only gets called once (at start)

AudioHwConfig() gets called on sample rate change. Looks like you might be wanting to do something on i2c when the device moves into DSD mode. So you might not be able to move everything to your task.

The ideal way to solve access from two places, If you really need that, is to run i2c in a thread and allow other thread to communicate to/from it via channel.
Technical Director @ XMOS. Opinions expressed are my own
AlexAdvice
XCore Addict
Posts: 146
Joined: Sun Feb 23, 2014 11:30 am

Post by AlexAdvice »

OK, I will try to do that.
Thank you, Ross.
AlexAdvice
XCore Addict
Posts: 146
Joined: Sun Feb 23, 2014 11:30 am

Post by AlexAdvice »

I think it could be done with 4-bit port like it possible to share the variables with GET_SHARED_GLOBAL/SET_SHARED_GLOBAL.
User avatar
Ross
Verified
XCore Legend
Posts: 1070
Joined: Thu Dec 10, 2009 9:20 pm
Location: Bristol, UK

Post by Ross »

If you use shared memory and access from two treads you will need to have some sort of system of arbitrating which thread can access the I2C resources to avoid a clash.

Note, those macros are historical, from when the tool chain didn't have a way of accessing shared memory variables (they use inline assembler). There are cleaner ways of doing this now (pointers in XC or C access functions, for example)
Technical Director @ XMOS. Opinions expressed are my own