Changing master clock freq for i2s

Non-technical related questions should go here.
ptip83
Junior Member
Posts: 5
Joined: Fri Nov 15, 2019 6:02 pm

Changing master clock freq for i2s

Post by ptip83 »

Hello,
I had always used the cirrus logic CODECS referenced in the documentation, but due to part shortages have had to switch to a TI CODEC which needs a 12.288Mhz signal.
I know this is possible, via this documentation <https://www.xmos.ai/download/lib_i2s-[u ... .1rc1).pdf>, under section <I2S (2.0.1)1.1.2 I2S master speeds and performance>.
I know I will have to divide the clock line from the external oscillator to get my new mclk but I'm struggling where exactly to do that in the code? Not sure if it is during my clock configuration or i2s config or what. I can't find any examples.
I'm assuming this is simple so sorry for the hassle.
Thanks!
User avatar
CousinItt
Respected Member
Posts: 367
Joined: Wed May 31, 2017 6:55 pm

Post by CousinItt »

You can specify the mclk-to-bclk ratio in the i2s_config_t structure passed by the i2s.init() callback. I think it has to be a power of 2.

The mclk is usually generated by a low-jitter source, so the only software involvement would be where the clock source is configurable, like the CS2100 or Si5351.
ptip83
Junior Member
Posts: 5
Joined: Fri Nov 15, 2019 6:02 pm

Post by ptip83 »

Changing the mclk-blck ratio would not actually change the clocks though, right?
And are you saying I would not be able to change the mclk using a function such as "configure_clock_src_divide(mclk, p_mclk,1);"? Or just that the resulting clock timings just would'nt be ideal for the i2s signals?
User avatar
CousinItt
Respected Member
Posts: 367
Joined: Wed May 31, 2017 6:55 pm

Post by CousinItt »

I'm assuming we're talking about the i2s_master or i2s_frame_master. The mclk is supplied by an external oscillator, as an input to the xmos device and to external converters. The extent to which you can configure it depends on your hardware.

The mclk-to-bclk ratio sets the ratio between the mclk and bclk, so it will affect the clock speeds for the bclk and lrclk. Changing the clock divider internally would have no effect on the external mclk frequency.
User avatar
akp
XCore Expert
Posts: 580
Joined: Thu Nov 26, 2015 11:47 pm

Post by akp »

If you post a schematic of your clocking we might be able to help. If you've got a fixed oscillator replacing it with a 12.288 MHz one would do the trick.
ptip83
Junior Member
Posts: 5
Joined: Fri Nov 15, 2019 6:02 pm

Post by ptip83 »

Thanks for your replies. After looking into this further my main board already has the CS2100 chip on it ( I am currently working on an interface board to this using i2c/i2s). So while replacing my fixed oscillator would certainly work, it appears I should be able to use the CS2100 to change my mclk through firmware only, which would be preferred.
However my initialization of the registers for the CS2100 is not appearing to work, as I cannot see a signal on my CLK_OUT pin via a scope, and a read does not return a correct value.
I will attach that code,as well as the schematic. Any input is appreciated more than you know. If you need any more info or clarification please let me know.
I am using a 24Mhz input clock (was the only clock input into the CS2100 already) and dividing it down to get a 12.288Mhz output clock. Ratio of .512, using a 12.20 fixed point ratio.
Currently getting no bytes sent on the aborted write (not sure if I should or not) and a NACK on the read.
My firmware is selecting the CLK_OUT signal by using pll_select.output(1); to change the old 24.576Mhz to the new CLK_OUT.

Code: Select all

// Clk generator registers//           // For CS2100
#define CS2100_ADDR             0x9C
#define CS2100_ADDR_READ        0x9D
#define DEVICE_ID               0x01
#define DEVICE_CTRL             0x02
#define DEVICE_CFG              0x03
#define GLOBAL_CFG              0x05
#define RUD_RATIO1              0x06
#define RUD_RATIO2              0x07
#define RUD_RATIO3              0x08
#define RUD_RATIO4              0x09
#define FUNCT_CFG1              0x16
#define FUNCT_CFG2              0x17
#define FUNCT_CFG3              0x1E

void set_clk(client i2c_master_if i2c)
{
    i2c_res_t           data;
    uint8_t             bfr[1];
    size_t              num_bytes_sent;
    uint8_t             read_bfr[1];     //read buffer

    //Global Configuration  enable freeze
    i2c.write_reg(CS2100_ADDR, GLOBAL_CFG, 0b00001000);

    // Device Control
    i2c.write_reg(CS2100_ADDR, DEVICE_CTRL, 0b00000000);            // i2c.write_reg(CS2100_ADDR, register addy, data);

    //Global Configuration
    i2c.write_reg(CS2100_ADDR, GLOBAL_CFG, 0b00001001);

    //Device Configuration
    i2c.write_reg(CS2100_ADDR, DEVICE_CFG, 0b00000001);

    //Global Configuration  un-freeze
    i2c.write_reg(CS2100_ADDR, GLOBAL_CFG, 0b00000001);

    // Function Configuration 1
    i2c.write_reg(CS2100_ADDR, FUNCT_CFG1, 0b00001000);        //00001000

    // Function Configuration 2
    i2c.write_reg(CS2100_ADDR, FUNCT_CFG2, 0b00001000);       //00001000

    // User-defined ratio 1
    i2c.write_reg(CS2100_ADDR, RUD_RATIO1, 0b00000000);       //00000000

    // User-defined ratio 2
    i2c.write_reg(CS2100_ADDR, RUD_RATIO2, 0b00001000);       //00001000

    // User-defined ratio 3
    i2c.write_reg(CS2100_ADDR, RUD_RATIO3, 0b00110001);       //00110001

    // User-defined ratio 4
    i2c.write_reg(CS2100_ADDR, RUD_RATIO4, 0b00100111);       //00100111

    bfr[0] = FUNCT_CFG1;        //FUNCT_CFG1;

    //read a register to tell if writes worked
    data = i2c.write(CS2100_ADDR, bfr, 1, num_bytes_sent, 1 );  //aborted write

   data = i2c.read(CS2100_ADDR_READ, read_bfr, 1, 1);
   
    if (data == I2C_ACK)
        printf("i2c ack\n");
    if (data == I2C_NACK)
        printf("i2c Nack\n");

}


Image
User avatar
CousinItt
Respected Member
Posts: 367
Joined: Wed May 31, 2017 6:55 pm

Post by CousinItt »

The i2c library uses 7-bit address followed by the read/write bit, so the device address should be 0x4E.

i2c_write_reg() and i2c_read_reg() should work.
User avatar
akp
XCore Expert
Posts: 580
Joined: Thu Nov 26, 2015 11:47 pm

Post by akp »

Did you write a lot of new code? The device address should be 0x4E. All you need to do is take your old code and change the multiplier (registers 0x6 - 0x9) by a factor of 1/2.
ptip83
Junior Member
Posts: 5
Joined: Fri Nov 15, 2019 6:02 pm

Post by ptip83 »

Well certainly would help to use the right device address! I was modifying old code and copying in snippets and must have missed that.. Good news is read/write to the CS2100 now verified works.
However I still am not getting an output on the CLK_OUT port.
I have went over my register instructions pretty thoroughly, and just to test I can set AUX_OUT = REF_CLK and see the 24MHz signal on my scope.
Only thing I can think is that I can't get a signal on the PLL_SYNC pin . Only I have seen other posts on here saying that signal is not required for the CS2100 to work correctly?
User avatar
CousinItt
Respected Member
Posts: 367
Joined: Wed May 31, 2017 6:55 pm

Post by CousinItt »

You said the CS2100 only has a 24 MHz clock going into it. Does it have a crystal too? As I understand it the device needs both the low-jitter timing reference clock and a frequency reference clock to work. I tried clicking on the image link below your code but it didn't do anything.

In the default state the aux output should be echoing the timing reference clock. The device can produce an output on clk_out without lock, but only if ClkOutUnl is set in FunctionCfg2. It's a good idea to ensure things are stable before starting the I2s interface.