This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CCS/CC1350: i2s

Part Number: CC1350

Tool/software: Code Composer Studio

Is there any CLEAR documentation on how i2s is working on CC1350. 

The information cited in paragraph 22 of CC13x0, CC26x0 SimpleLink™ Wireless MCU Technical Reference Manual is not enough.

Very unclear how DMA, samplestamp generator, triggers and interrupts are working together to transfer I2S data. 

I cannot find any additional documentation on that issue. Does I2S really work  on cc1350????

Can anybody help me with that?

Boris Shkarban

  • Please look at the pdmstream example, where the CC1350 I2S interface is used to compress Audio data using ADPCM. It runs on a CC1350STK.

    You can find the example in the 1_60 SDK (http://www.ti.com/tool/download/SIMPLELINK-CC13X0-SDK )

    <INSTALL_DIR>:\ti\simplelink_cc13x0_sdk_1_60_00_21\examples\rtos\CC1350STK\drivers

    Siri

  • Hi, Siri,

    I am currently working in CCS and Simplelink SDK -2.10.00.36. I do not fully understand how can I install there cc1350STK.
    Will it work on CC1350 LAUNCHPAD? iF yes, please advice how can I install it into Code Composer studio version 8.0

    Another question, I am still trying to configure I2S by my own, in doing that I am trying to register an interrupt,

    I2SIntRegister(I2S0_BASE,Handler_i2s);

    where callback function Handler_i2s will be used to set a new block of data to the output register. Still, something wrong is with that I2SIntRegister function. When linking, I am getting messsage:
    "warning #10247-D: creating output section ".vtable_ram" without a SECTIONS specification"
    After downloading, program does not work at all.
    Can you help me with correcting the way interrupt callback function on IRQFLAGS.AIF_DMA_OUT flag would be set.

    Boris Shkarban
  • As I wrote, you need to use the 1.60 sdk and not the 2.10 sdk (the example was wrongly removed when going from 1_xx to 2_xx, but will be put back into the SDK).

    You then find the example under the sensortag:

    The code will not run out-of-the-box since you are using a LP and this is for a sensorTag. I simply reffered to it as this is the only example we have using I2S.

    I am not an I2S expert so I cannot answer your question regarding the issues you are having with your code, but please look at the pdmstream example and how that implements I2S, and maybe it solves your problem.

    Siri

  • Thanks Siri, for your suuport. At least I am now able to work with pdmstream example. Will start digging in it. Please be on support line for a while, some your hints might be very time saving for me.

    By the way, after 3 weeks of hard work I2s data exchange has started working on my launchpad board with some defects still. When I will clean ithem out, I can send you a code to make life easier for other poor people struggling with i2s configuration.

  • Hi Boris

    It is great if you have code to share that other people might benefit from. I think we have started working on an I2s driver, but I am not sure when it is supposed to be released.

    Siri
  • Siri, in the bottom is my I2S configuration code with comments as promised. It works well, the only issue left is setting callback function for I2s interrupt handling.
    The interrupt flag I2S_INT_DMA_OUT is being set when the buffer pointed by I2S:AIFOUTPTR is emptied. We need to process that interrupt by setting pointer I2S:AIFOUTPTRNEXT on the next portion of data. This we can do within a callback function, which is processing that interrupt.

    BUT

    When I am using
    IntRegister(INT_I2S_IRQ, I2SHandler);//// (I2SHandler - is that callback function)
    during program linking I am getting message
    "warning #10247-D: creating output section ".vtable_ram" without a SECTIONS specification"
    and nothing is working, even clocks.

    In order to avoid this message I substitute IntRegister function by its content from the library:

    if(HWREG(NVIC_VTABLE) != (uint32_t)g_pfnRAMVectors)
    {
    //
    // Copy the vector table from the beginning of FLASH to the RAM vector
    // table.
    //
    ui32Value = HWREG(NVIC_VTABLE);
    for(ui32Idx = 0; ui32Idx < NUM_INTERRUPTS; ui32Idx++)
    {
    g_pfnRAMVectors[ui32Idx] = (void (*)(void))HWREG((ui32Idx * 4) + ui32Value);
    }
    //
    // Point NVIC at the RAM vector table.
    //
    HWREG(NVIC_VTABLE) = (uint32_t)g_pfnRAMVectors;
    }
    // Save the interrupt handler.
    //
    g_pfnRAMVectors[INT_I2S_IRQ] = I2SHandler;
    }

    Now the linker shows everything okey, program is being downloaded to the target, everything is working, but still callback function I2SHandler does not work.

    What is wrong with setting I2S interrupt callback function? Please advice if possible.

    Boris

    ////////////////////////the i2s_init code/////////////////////////////
    void i2s_init(void)
    {

    // 1. Set up and configure required ADx and clock pins (set externally in the IOC module) IOC registers are written under 40081018 and 4008101c addresses as 0000 6027 (nopull(6),WCLK) AND 0000 6028 (nopull(6),BCLK)
    IOCPortConfigureSet(IOID_7, IOC_PORT_MCU_I2S_BCLK,IOC_STD_OUTPUT);
    IOCPortConfigureSet(IOID_6, IOC_PORT_MCU_I2S_WCLK,IOC_STD_OUTPUT);
    ///// назначаем MCU I2S Data Pin 0 это и есть ADX - пины данных, о которых говорится в тех. описании
    IOCPortConfigureSet(IOID_20, IOC_PORT_MCU_I2S_AD0, IOC_STD_OUTPUT);

    // 2. Enable I2S peripheral and configure WCLK and MCLK audio clocks (set externally in the PRCM module).

    PRCMAudioClockDisable();//disable the audio clock generation setting PRCMCLKCTL (40082000 TO 0X0000)
    PRCMPeripheralRunEnable(PRCM_PERIPH_I2S); // Set up I2S clocks, register I2SCLKGDS (40082084), К НЕМУ ДОБАВЛЯЕТСЯ 0x00000001
    PRCMLoadSet();///PRCM:CLKLOADCTL (40082028) 1: Load settings to CLKCTRL. Bit is HW cleared
    PRCMPeripheralSleepDisable(PRCM_PERIPH_I2S); //disable I2S Clock Gate For Sleep Mode (40082088)
    PRCMLoadSet();
    PRCMPeripheralDeepSleepDisable(PRCM_PERIPH_I2S);//disable I2S Clock Gate For Deep Sleep Mode (4008208c)
    PRCMLoadSet();
    // Sample at 16 KHz for now
    ///I2SCLKCTL (400820d0) is set to 0x00000002 according to the value of PRCM_WCLK_DUAL_PHASE| PRCM_WCLK_POS_EDGE=2,
    ///dividers I2SMCLKDIV (400820D4), I2SBCLKDIV (400820D8),I2SWCLKDIV (400820DC), equal respectively 0x00000006, 0x0000003c, 0x00000019 based on the value of I2S_SAMPLE_RATE_16K
    PRCMAudioClockConfigSet( PRCM_WCLK_DUAL_PHASE| PRCM_WCLK_POS_EDGE,I2S_SAMPLE_RATE_16K);
    PRCMLoadSet();

    // 3. Configure the serial audio interface format and the memory interface controller:
    // • Set the following registers:
    // I2S:AIFWCLKSRC,I2S:AIFFMTCFG,I2S:AIFDIRCFG
    // I2S:AIFWMSK0, I2S:AIFWMSK1, I2S:AIFWMSK2.
    // BCLK must not be running when changing the I2S:AIFWCLKSRC register.

    I2SControlTable g_controlTable; // Define global
    g_pControlTable = &g_controlTable; // Assign pointer

    PRCMAudioClockDisable();//disable the audio clock generation setting PRCMCLKCTL (40082000 TO 0x00000000)
    ///set AIFWCLKSRC register (40021000) = 6, which is I2S_INT_WCLK | I2S_INVERT_WCLK
    I2SClockConfigure(I2S0_BASE/*base address of I2S module*/,I2S_INT_WCLK |/* Clock source (internal)=2*/I2S_NORMAL_WCLK/* Clock polarity (inverted)=4*/);

    ///set AIFFMTCFG register (4002100C) =0x00000170 to the same value, which is dictated by I2S_MEM_LENGTH_16|I2S_POS_EDGE| I2S_DUAL_PHASE_FMT| I2S_WORD_LENGTH_16 = 70, the 1 - is data delay (i2s - 1 bit)- bits 15:8 in FMTCFG register
    I2SAudioFormatConfigure(I2S0_BASE,/*I2S registers*/I2S_MEM_LENGTH_16 /*16-bits packed in mem=0x0*/| I2S_POS_EDGE/*Sampled on pos edge=0x40*/| I2S_DUAL_PHASE_FMT /*2 phases in I2S=0x20*/| I2S_WORD_LENGTH_16, /* 16-bit samples=0x02*/1 /* 1 bit delay*/);

    ///set AIFDIRCFG register (40021008) TO 0x00000002 according to value I2S_LINE_OUTPUT, :AIFWMSK0, I2S:AIFWMSK1 is set according to I2S_MONO_MODE,I2S:AIFWMSK1, I2S:AIFWMSK2 are not used
    I2SChannelConfigure(I2S0_BASE, I2S_LINE_OUTPUT/* Chan 0: I2S - Mono=2*/ | I2S_MONO_MODE/*=100*/, I2S_LINE_UNUSED /* Chan 2: unused*/);

    I2SBufferConfig(I2S0_BASE/*base address of I2S module*/, NULL, /*(uint32_t) &inBuf, is the address of the input buffer.*/ (uint32_t) &outBuf, /* is the address of the output buffer*/ I2S_DMA_BUF_SIZE_256, /* is the size of the DMA buffers. Must be > 0!*/I2S_BUFF_SIZE); // is the size of the channel buffers.

    // 4. Enable BCLK (set externally in the PRCM module).
    HWREG(PRCM_BASE + PRCM_O_I2SBCLKSEL) = 1; // use internally generated clock
    PRCMLoadSet();
    PRCMAudioClockEnable();
    PRCMLoadSet();

    // 5. Configure and prepare the samplestamp generator:
    // • Set the I2S:STMPWPER register. This number corresponds to the total size of the sample ring buffer used by the system.
    // • Set the two registers I2S:STMPINTRIG and I2S:STMPOUTTRIG > I2S:STMPWPER to avoid false triggers before the samplestamp generator is started.
    /////setting STMPWPER - WCLK Counter Period Value (40021004) to 256, This number must correspond to the size of the sample buffer used by the system
    //// used to define after which number of WCLK STMPWCNT counter is to be reset to 0
    HWREG(I2S0_BASE + I2S_O_STMPWPER) = I2S_BUFF_SIZE;
    /////WCLK Counter Trigger Value for Output Pins
    /////Compare value used to start the outgoing audio streams.
    /////This bit field must equal the WCLK counter value during the WCLK period in which the first output word(s) read from memory are clocked out (that is the sample at the start of the very first DMA output buffer).
    HWREG(I2S0_BASE + I2S_O_STMPOUTTRIG) = I2S_BUFF_SIZE+1;

    // 6.Enable the samplestamp generator:
    // • Set I2S:STMPCTRL.STMP_EN = 1
    HWREG(I2S0_BASE + I2S_O_STMPCTL) = I2S_STMPCTL_STMP_EN;

    // 7. Enable the serial audio interface:
    // • Set the I2S:AIFOUTPTRNEXT register for first memory interface
    // buffers.
    // • Set the I2S:AIFDMACFG register; This number corresponds to the length of each block in the
    // sample ring buffer used by the system.

    ////i2s interrupt DMA_OUT////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////////////////////////////
    I2SIntEnable(I2S0_BASE,I2S_INT_DMA_OUT);
    IntRegister(INT_I2S_IRQ, I2SHandler);

    // the content of IntRegister(INT_I2S_IRQ, I2SHandler);/// registering callback function for i2s interrupt///////////
    /* if(HWREG(NVIC_VTABLE) != (uint32_t)g_pfnRAMVectors)
    {
    //
    // Copy the vector table from the beginning of FLASH to the RAM vector
    // table.
    //
    ui32Value = HWREG(NVIC_VTABLE);
    for(ui32Idx = 0; ui32Idx < NUM_INTERRUPTS; ui32Idx++)
    {
    g_pfnRAMVectors[ui32Idx] = (void (*)(void))HWREG((ui32Idx * 4) + ui32Value);
    }
    //
    // Point NVIC at the RAM vector table.
    //
    HWREG(NVIC_VTABLE) = (uint32_t)g_pfnRAMVectors;
    }
    // Save the interrupt handler.
    //
    g_pfnRAMVectors[INT_I2S_IRQ] = I2SHandler;
    */
    /////////////////enable interrupt i2s//////////////
    IntEnable(INT_I2S_IRQ);

    //////////////////////////END i2s interrupt DMA_OUT SECTION///////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////

    HWREG(I2S0_BASE + I2S_O_AIFOUTPTRNEXT)=(uint32_t)((uint16_t *)&(outBuf[0]));


    // DMA Buffer Size Configuration (40021004)
    HWREG(I2S0_BASE + I2S_O_AIFDMACFG) = I2S_BUFF_SIZE-1;

    // HWREG(I2S0_BASE + I2S_O_AIFOUTPTRNEXT)=(uint32_t)((uint16_t *)&(outBuf[0]));

    // 8. Start input and output audio streaming:
    // Set the I2S:STMPINTRIG and the I2S:STMPOUTTRIG registers so they correctly match the I2S:AIFINPTR and the I2S:AIFOUTPTR //registers.
    I2SSampleStampConfigure(I2S0_BASE, false, true);
  • Hi Boris,

    As you seem to be running TI-RTOS, have you tried to register the interrupt using the Hwi module from the kernel to see if that solves your issue? 

    If you look inside the PDMCC26XX_util.c file that is used by the PDM driver, you can find how the I2S hardware is setup in terms of power and interrupts.

    Typically, if you are working with TI-RTOS you should try to use the Power driver to enable power domains and hardware instead of the PRCM driver lib. You should also try to use the Hwi module to register interrupts so that these are serviced as part of the TI-RTOS.