Problem with I2C Volume Control Topic is solved

Technical questions regarding the XTC tools and programming with XMOS.
User avatar
masaikemlol
Member
Posts: 12
Joined: Thu Jul 18, 2024 4:10 am

Problem with I2C Volume Control

Post by masaikemlol »

Hello everyone,

Recently, I've been trying to implement hardware I2C volume control using the sw_usb_audio_8.1.0 reference design on the XMOS xcore.ai XU316 platform.

I referenced the suggestions from MaximLiadov and infiniteimprobability to enable I2C volume adjustment at sw_usb_audio_8.1.0\lib_xua\lib_xua\src\core\endpoint0\xua_ep0_uacreqs.xc. (or audiorequests.xc)
However, the specific problem I'm facing is that when I insert the I2C code after the updateVol point, the XU316 chip gets stuck and sometimes fails to enumerate properly.

(By the way, my Audio runs on tile 0, the I2C port is on tile 0, and the USB runs on tile 1.)

Here are the I2C definitions in my user_main.h:

Code: Select all

extern unsafe client interface i2c_master_if i_i2c_client;
extern void interface_saver(client interface i2c_master_if i);
extern void board_setup();

/* I2C interface ports */
extern port p_i2c;                  //on tile0 <Port Location="XS1_PORT_4E" Name="PORT_I2C"/>

#define USER_MAIN_DECLARATIONS \
    interface i2c_master_if i2c[1];

#define USER_MAIN_CORES on tile[0]: {\
                                        board_setup();\
                                        i2c_master_single_port(i2c, 1, p_i2c, 80, 2, 3, 0);\
                                    }\
                        on tile[1]: {\
                                        unsafe\
                                        {\
                                            i_i2c_client = i2c[0];\
                                        }\
                                    }

I referenced app_usb_aud_xk_316_mc and inserted the following I2C code in xua_ep0_uacreqs.xc:

Code: Select all

#include "user_main.h"
#include "xassert.h"
#include "i2c.h"
unsafe client interface i2c_master_if i_i2c_client;
i2c_regop_res_t i2c_reg_write(uint8_t device_addr, uint8_t reg, uint8_t data)
{
    uint8_t a_data[2] = {reg, data};
    size_t n;

    unsafe
    {
        i_i2c_client.write(device_addr, a_data, 2, n, 1);
    }

    if (n == 0)
    {
        return I2C_REGOP_DEVICE_NACK;
    }
    if (n < 2)
    {
        return I2C_REGOP_INCOMPLETE;
    }

    return I2C_REGOP_SUCCESS;
}

void WriteRegs(int deviceAddr, int regAddr, int regData)
{
    i2c_regop_res_t result;
    unsafe
    {
        result = i2c_reg_write(deviceAddr, regAddr, regData);
    }
    assert(result == I2C_REGOP_SUCCESS && msg("I2C write reg failed"));
}

In int AudioClassRequests_2 at FU_USBOUT, I disabled the updateVol and inserted the I2C code (in xua_ep0_uacreqs.xc):

Code: Select all

/*at line 573*/
if(unitID == FU_USBOUT) {
    if ((sp.wValue & 0xff) <= NUM_USB_CHAN_OUT) {
        volsOut[sp.wValue & 0xff] = (buffer, unsigned char[])[0] | (((int)(signed char)(buffer, unsigned char[])[1]) << 8);
        // updateVol(unitID, (sp.wValue & 0xff), c_mix_ctl);
        
        /* I2C test here */
        WriteRegs(0x20, 125, 0x00);  
        return XUD_DoSetRequestStatus(ep0_in);
    }
}
The firmware can compile successfully.
What could be the problem? I would greatly appreciate any suggestions you might have!

Here is the reference link:
https://www.xcore.com/viewtopic.php?t=7181&start=12
https://www.xcore.com/viewtopic.php?t=5761&start=10
https://www.xcore.com/viewtopic.php?p=2 ... OUT#p25929
Last edited by masaikemlol on Wed Oct 23, 2024 8:29 am, edited 2 times in total.
View Solution
User avatar
masaikemlol
Member
Posts: 12
Joined: Thu Jul 18, 2024 4:10 am

Post by masaikemlol »

Additionally, I am unsure how to use the same I2C port defined on tile0 in different functions on both tile0 and tile1, or how to use the I2C service defined in user_main.h simultaneously on both tiles.

For example, I would like to use the same I2C port on tile0 in both the [on AUDIO tile] AudioHwInit()(for Init) and [on USB tile] AudioClassRequests_2()(for VolCtl) functions.

I have tried various methods, but they all resulted in errors.
Directly defining a new I2C in the AudioHwInit function leads to the error: "error: use of 'p_i2c' violates parallel usage rules."

Code: Select all

void AudioHwInit() {
    /* samFreqInit */
    set_gpio(MCLK_441_ENABLE, 1);
    
    /* DAC_Boot_Reset */
    DAC_REST <: peek(DAC_REST) & (~0x10);
    delay_milliseconds(10); /* 8D4_DAC_REST */
    DAC_REST <: peek(DAC_REST) | 0x10;

    /* I2C_Init */
    delay_milliseconds(10);

    // i2c_master_if ii_i2c[1];
    // par {
    //     i2c_master_single_port(ii_i2c, 1, p_i2c, 80, 2, 3, 0x03);
    //     {
    //         delay_milliseconds(10);
    //         DAC_Init(ii_i2c[0]);
    //         ii_i2c[0].shutdown();
    //     }
    // }
}
User avatar
Ross
Verified
XCore Legend
Posts: 1163
Joined: Thu Dec 10, 2009 9:20 pm
Location: Bristol, UK

Post by Ross »

You code and approach look reasonable to me, can you add some more detail regarding "device gets stuck"?

On the second problem you should add a task to arbitrate access to the I2C.
Technical Director @ XMOS. Opinions expressed are my own
User avatar
masaikemlol
Member
Posts: 12
Joined: Thu Jul 18, 2024 4:10 am

Post by masaikemlol »

Ross wrote: Wed Oct 23, 2024 11:15 pm You code and approach look reasonable to me, can you add some more detail regarding "device gets stuck"?

On the second problem you should add a task to arbitrate access to the I2C.
Thank you for your response, Ross.
I have successfully resolved the problem of calling I2C in AudioClassRequests_2. I had overlooked the specificity of unsafe, and the failure to wait for the initialization of the I2C client within the unsafe block was causing the I2C call to fail.

Now, the I2C is working smoothly within AudioClassRequests_2.

Regarding running the same I2C port across multiple tiles simultaneously, you mentioned an arbitrating access task to the I2C. Could you kindly provide any reference materials on this topic?
Once again, I appreciate your assistance.
User avatar
Ross
Verified
XCore Legend
Posts: 1163
Joined: Thu Dec 10, 2009 9:20 pm
Location: Bristol, UK

Post by Ross »

Ah, classic race condition!

I would author an I²C "server" task, this would "own" and access the I²C interface. It would take two chanend parameters to receive simple commands from your two client tasks.
Technical Director @ XMOS. Opinions expressed are my own
User avatar
masaikemlol
Member
Posts: 12
Joined: Thu Jul 18, 2024 4:10 am

Post by masaikemlol »

Ross wrote: Thu Oct 24, 2024 12:37 pm Ah, classic race condition!

I would author an I²C "server" task, this would "own" and access the I²C interface. It would take two chanend parameters to receive simple commands from your two client tasks.
Thank you for your help, Ross. You've made everything so much easier!
I'm currently reviewing XMOS coding guidelines, hoping to gradually get more familiar with XMOS features.
User avatar
Ross
Verified
XCore Legend
Posts: 1163
Joined: Thu Dec 10, 2009 9:20 pm
Location: Bristol, UK

Post by Ross »

Image
Technical Director @ XMOS. Opinions expressed are my own