Changing master clock freq for i2s

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

Changing master clock freq for i2s

Post by ptip83 »

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 <[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.

User avatar
Respected Member
Posts: 286
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.
Junior Member
Posts: 4
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
Respected Member
Posts: 286
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
XCore Expert
Posts: 547
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.
Junior Member
Posts: 4
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 =, read_bfr, 1, 1);
    if (data == I2C_ACK)
        printf("i2c ack\n");
    if (data == I2C_NACK)
        printf("i2c Nack\n");