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.

TMS320C5517: Cannot get I2S0 interrupts to fire in simple code

Part Number: TMS320C5517


I am trying to configure the I2S0 module on the C5517 as a master transmitter, but I am unable to get the interrupts to fire. To confirm this I've tried both having an infinite loop in the ISR (so that when I break in CCS I can see that it's in the ISR) and have a GPIO pin toggle when the ISR fires (with an oscilloscope checking the level). Neither show that the ISR is ever entered.

I have some code below, but I'll summarise the main points:

  • I can use similar code to get UART interrupts working, so I know my vector table is being used and IPVD etc. are being set.
  • I'm setting the appropriate flags in both the IER0 and I2S0INTMASK registers.
  • I'm reading the interrupt registers to clear them when I start.
  • I've even tried writing 1 to the IFR0 PROG0 field to manually trigger the interrupt.

As far as I can tell I haven't missed anything from the manual. But I cannot see that the ISR is ever being entered.

Here's the code:

main.c

#include <stdint.h>
#include "csl/inc/soc.h"

/* This is measured to give a little over 4ms delay. See notes in PLL section of
 * c5517_setup().
 */
#define PLL_LOCK_DELAY (4000U)

/* This (shifted left by 8) must match the value of VECS in the linker command
 * file.
 */
#define INTERRUPT_BASE (0x00FF)

__interrupt void i2s0_tx_isr(void)
{
    const uint_fast16_t i2sintfl = CSL_I2S0_REGS->I2SINTFL;
    const uint_fast16_t transmitted = CSL_FEXT(i2sintfl, I2S_I2SINTFL_XMITSTFL);

    CSL_FINST(CSL_GPIO_REGS->IODATAOUT1, GPIO_IODATAOUT1_OUT15, CLEAR);

    if (transmitted)
    {
        CSL_I2S0_REGS->I2STXLTL = 0x5555U;
        CSL_I2S0_REGS->I2STXLTU = 0x5555U;
        CSL_I2S0_REGS->I2STXRTL = 0x5555U;
        CSL_I2S0_REGS->I2STXRTU = 0x5555U;
    }
}

/* EBSR (external bus select register) settings. The EBSR is used to change
 * which peripherals are exposed on certain pins. See S1.7.3.1 of the
 * TMS320C5517 Technical Reference Manual.
 */
static void c5517_ebsr_configure(void)
{
    /* Do clock handshakes before gating peripheral clocks. These have to be
     * busy waits because we can't idle until this is all done.
     */
    CSL_FINST(CSL_SYSCTRL_REGS->CLKSTOP1, SYS_CLKSTOP1_USBCLKSTPREQ, REQ);
    while(!CSL_FEXT(CSL_SYSCTRL_REGS->CLKSTOP1, SYS_CLKSTOP1_USBCLKSTPACK));

    CSL_FINST(CSL_SYSCTRL_REGS->CLKSTOP1, SYS_CLKSTOP1_URTCLKSTPREQ, REQ);
    while(!CSL_FEXT(CSL_SYSCTRL_REGS->CLKSTOP1, SYS_CLKSTOP1_URTCLKSTPACK));

    CSL_FINST(CSL_SYSCTRL_REGS->CLKSTOP1, SYS_CLKSTOP1_EMIFCLKSTPREQ, REQ);
    while(!CSL_FEXT(CSL_SYSCTRL_REGS->CLKSTOP1, SYS_CLKSTOP1_EMIFCLKSTPACK));

    CSL_FINST(CSL_SYSCTRL_REGS->CLKSTOP1, SYS_CLKSTOP1_UHPICLKSTPREQ, REQ);
    while(!CSL_FEXT(CSL_SYSCTRL_REGS->CLKSTOP1, SYS_CLKSTOP1_UHPICLKSTPACK));

    CSL_FINST(CSL_SYSCTRL_REGS->CLKSTOP1, SYS_CLKSTOP1_MBPCLKSTPREQ, REQ);
    while(!CSL_FEXT(CSL_SYSCTRL_REGS->CLKSTOP1, SYS_CLKSTOP1_MBPCLKSTPACK));

    CSL_FINST(CSL_SYSCTRL_REGS->CLKSTOP1, SYS_CLKSTOP1_URTCLKSTPREQ, REQ);
    while(!CSL_FEXT(CSL_SYSCTRL_REGS->CLKSTOP1, SYS_CLKSTOP1_URTCLKSTPACK));

    CSL_FINST(CSL_SYSCTRL_REGS->CLKSTOP2, SYS_CLKSTOP2_MSPBRIDGECLKSTPREQ, REQ);
    while(!CSL_FEXT(CSL_SYSCTRL_REGS->CLKSTOP2, SYS_CLKSTOP2_MSPBRIDGECLKSTPACK));

    CSL_FINST(CSL_SYSCTRL_REGS->CLKSTOP2, SYS_CLKSTOP2_MSPCLKSTPREQ, REQ);
    while(!CSL_FEXT(CSL_SYSCTRL_REGS->CLKSTOP2, SYS_CLKSTOP2_MSPCLKSTPACK));

    /* Clock gate peripherals before changing external bus select mode. */
    CSL_SYSCTRL_REGS->PCGCR1 = (~CSL_SYS_PCGCR1_SYSCLKDIS_MASK) & 0xFFFFU;
    CSL_SYSCTRL_REGS->PCGCR2 = 0xFFFFU;

    /* Change SP0 external bus select to mode 1 to include I2S0. */
    CSL_FINST(CSL_SYSCTRL_REGS->EBSR, SYS_EBSR_SP0MODE, MODE1);

    /* Turn on peripheral clocks again. */
    CSL_SYSCTRL_REGS->PCGCR1 = 0x0000U;
    CSL_SYSCTRL_REGS->PCGCR2 = 0x0000U;
}

/* Disable the USB clock domain. The USB clock domain must be disabled to put
 * the CPU to sleep in the IDLE2 state. But it can't be done repeatedly,
 * otherwise the system will lock up. So it's done here and not in the sleep
 * function. See S1.5.3.4.1 of the TMS320C5515 DSP System User's Guide.
 */
static void c5517_usb_clock_disable(void)
{
    CSL_FINS(CSL_USB_REGS->FADDR_POWER, USB_FADDR_POWER_SUSPENDM, 1);
    CSL_FINST(CSL_SYSCTRL_REGS->CLKSTOP1, SYS_CLKSTOP1_USBCLKSTPREQ, REQ);
    /* No way around this busy-wait since we can't idle until this is done. */
    while(!CSL_FEXT(CSL_SYSCTRL_REGS->CLKSTOP1, SYS_CLKSTOP1_USBCLKSTPACK)) ;

    CSL_FINST(CSL_SYSCTRL_REGS->PCGCR2, SYS_PCGCR2_USBCG, DISABLED);
    CSL_FINST(CSL_SYSCTRL_REGS->USBSCR, SYS_USBSCR_USBOSCDIS, DISABLED);
    CSL_FINST(CSL_SYSCTRL_REGS->USBSCR, SYS_USBSCR_USBPWDN, PWRDN);
}

/* Debugging outputs. Currently system clock on CLKOUT, and GPIO15 for
 * miscellaneous timing measurements or state changes.
 */
static void c5517_debug_misc(void)
{
    /* Timing debug. */
    CSL_FINST(CSL_CPU_REGS->ST3_55, CPU_ST3_55_CLKOFF, ENABLE);
    CSL_FINST(CSL_SYSCTRL_REGS->CLKOUTCR, SYS_CLKOUTCR_CLKOUT_GZ, COEN);
    CSL_FINST(CSL_SYSCTRL_REGS->CLKOUTCR, SYS_CLKOUTCR_SRC, MODE11);

    /* This GPIO pin is mainly used for debugging eg. entering and exit a
     * particular state, like sleeping, or tuning the PLL lock delay below.
     */
    CSL_FINST(CSL_GPIO_REGS->IODIR1, GPIO_IODIR1_DIR15, SET);
    /* CSL_FINST(CSL_SYSCTRL_REGS->PDINHIBR1, SYS_PDINHIBR1_S4PD, ENABLE); */
    CSL_FINST(CSL_GPIO_REGS->IODATAOUT1, GPIO_IODATAOUT1_OUT15, CLEAR);
}

/* Timing: we currently use the 12 MHz clock on the EVM5517 board. This
 * requires the CLK_SEL pin to be driven high at poweron. This is set by the
 * jumper JP10 (should be connected). We set the PLL to provide 131MHz.
 */
static void c5517_timing_configure(void)
{
    volatile unsigned int pll_delay_counter = PLL_LOCK_DELAY;

    /* Put the chip in bypass mode. */
    CSL_FINST(CSL_SYSCTRL_REGS->CCR2, SYS_CCR2_SYSCLKSEL, BYPASS);

    /* Wait 4 cycles. */
    __asm("\tnop");
    __asm("\tnop");
    __asm("\tnop");
    __asm("\tnop");

    /* Put PLL in reset. */
    CSL_FINST(CSL_SYSCTRL_REGS->PCR, SYS_PCR_PLLRST, RST);
    /* Power it on. */
    CSL_FINST(CSL_SYSCTRL_REGS->PCR, SYS_PCR_PLLPWRDN, PWRD);

    /* Program PLLM and dividers. */
    CSL_FINS(CSL_SYSCTRL_REGS->PMR, SYS_PMR_PLLM15_0, 0x15A0U);
    CSL_FINS(CSL_SYSCTRL_REGS->PICR, SYS_PICR_PLLM16, 0x0000U);
    CSL_FINS(CSL_SYSCTRL_REGS->PICR, SYS_PICR_RD, 0x0001U);

    CSL_FINS(CSL_SYSCTRL_REGS->PODCR, SYS_PODCR_OD, 0x0000U);
    CSL_FINS(CSL_SYSCTRL_REGS->PODCR, SYS_PODCR_OD2, 0x0000U);
    CSL_FINST(CSL_SYSCTRL_REGS->PODCR, SYS_PODCR_OUTDIV2BY, OD2BYP);

    /* 4ms delay while the PLL locks. */

    CSL_FINST(CSL_SYSCTRL_REGS->PCR, SYS_PCR_PLLRST, NRST);

    for (
        pll_delay_counter = PLL_LOCK_DELAY;
        pll_delay_counter != 0;
        pll_delay_counter--
    );

    CSL_FINST(CSL_SYSCTRL_REGS->CCR2, SYS_CCR2_SYSCLKSEL, LOCK);
}

/* CPU and peripheral interrupt settings. */
static void c5517_interrupt_configure(void)
{
    /* Set the interrupt vector table locations. */
    CSL_CPU_REGS->IVPD = INTERRUPT_BASE;
    CSL_CPU_REGS->IVPH = INTERRUPT_BASE;

    /* Clear interrupt flags. */
    CSL_CPU_REGS->IFR0 = (~0x0001U) & 0xFFFFU;
    CSL_CPU_REGS->IFR1 = (~0xF800U) & 0xFFFFU;
}

/* I2S specific interrupt settings. */
static void c5517_i2s_interrupt_configure(void)
{
    /* There are two levels of I2S interrupts - the interrupts generated in the
     * I2S module itself, and the CPU interrupts. Here we enable the I2S
     * interrupt in the CPU.
     */
    CSL_FINST(CSL_CPU_REGS->IER0, CPU_IER0_PROG0, ENABLE);
}

static void c5517_i2s_configure(void)
{
    // CSL_FINST(CSL_SYSCTRL_REGS->PCGCR1, SYS_PCGCR1_I2S0CG, ACTIVE);
    // CSL_FINST(CSL_SYSCTRL_REGS->PCGCR1, SYS_PCGCR1_I2S2CG, ACTIVE);

    while(CSL_FEXT(CSL_SYSCTRL_REGS->PRCR, SYS_PRCR_PG3_RST));

    CSL_FINST(CSL_SYSCTRL_REGS->PCGCR1, SYS_PCGCR1_I2S0CG, ACTIVE);

    CSL_FINST(CSL_I2S0_REGS->I2SSRATE, I2S_I2SSRATE_FSDIV, DIV64);
    CSL_FINST(CSL_I2S0_REGS->I2SSRATE, I2S_I2SSRATE_CLKDIV, DIV64);

    CSL_FINST(CSL_I2S2_REGS->I2SSRATE, I2S_I2SSRATE_FSDIV, DIV64);
    CSL_FINST(CSL_I2S2_REGS->I2SSRATE, I2S_I2SSRATE_CLKDIV, DIV64);

    /* 0x8 is 32-bit word length. */
    CSL_FINS(CSL_I2S0_REGS->I2SSCTRL, I2S_I2SSCTRL_WDLNGTH, 0x0008U);
    CSL_FINS(CSL_I2S0_REGS->I2SSCTRL, I2S_I2SSCTRL_WDLNGTH, 0x0008U);

    CSL_FINST(CSL_I2S0_REGS->I2SSCTRL, I2S_I2SSCTRL_ENABLE, SET);
    CSL_FINST(CSL_I2S0_REGS->I2SSCTRL, I2S_I2SSCTRL_ENABLE, SET);
}

void c5517_i2s_setup(void)
{
    _disable_interrupts();

    c5517_ebsr_configure();
    c5517_usb_clock_disable();
    c5517_debug_misc();
    c5517_timing_configure();

    CSL_FINST(CSL_GPIO_REGS->IODATAOUT1, GPIO_IODATAOUT1_OUT15, SET);

    CSL_FINS(CSL_SYSCTRL_REGS->PSRCR, SYS_PSRCR_COUNT, 0x0020U);
    CSL_FINST(CSL_SYSCTRL_REGS->PRCR, SYS_PRCR_PG3_RST, RST);

    c5517_i2s_configure();
    c5517_interrupt_configure();
    c5517_i2s_interrupt_configure();

    /* Enable maskable interrupts. */
    _enable_interrupts();

    CSL_FINST(CSL_I2S0_REGS->I2SINTMASK, I2S_I2SINTMASK_XMITST, ENABLE);
    CSL_FINST(CSL_I2S0_REGS->I2SINTMASK, I2S_I2SINTMASK_OUERR, DISABLE);
    CSL_FINST(CSL_I2S0_REGS->I2SINTMASK, I2S_I2SINTMASK_FERR, DISABLE);

    (void) CSL_I2S0_REGS->I2SINTFL;

    CSL_I2S0_REGS->I2STXLTU = 0xEEEEU;
    CSL_I2S0_REGS->I2STXLTL = 0xEEEEU;
    CSL_I2S0_REGS->I2STXRTU = 0xEEEEU;
    CSL_I2S0_REGS->I2STXRTL = 0xEEEEU;
}

int main(void)
{
    c5517_i2s_setup();
    for(;;);
    return 0;
}

interrupts.asm:

; Interrupt vector table.
    .ref _uart_isr
    .ref _i2s0_tx_isr
    .ref _c_int00
    .sect "vectors"
    .align 256

    .def    _Reset

    .if __TMS320C55X_PLUS_BYTE__
_Reset: .ivec _c_int00, STK_LINEAR | RET_FAST | DATA_PTR_BYTE
    .else
_Reset: .ivec _c_int00, USE_RETA
    .endif

; RST:        .ivec    _c_int00, USE_RETA   ; Reset / Software Interrupt #0
NMI:        .ivec    no_isr               ; Nonmaskable Interrupt
INT0:       .ivec    no_isr               ; External User Interrupt #0
INT1:       .ivec    no_isr               ; External User Interrupt #1
TINT:       .ivec    no_isr               ; Timer #0 / Software Interrupt #4
PROG0:      .ivec    _i2s0_tx_isr         ; Programmable 0 Interrupt
UART:       .ivec    no_isr               ; IIS #1 Receive Interrupt
PROG1:      .ivec    no_isr               ; Programmable 1 Interrupt
DMA:        .ivec    no_isr               ; DMA Interrupt
PROG2:      .ivec    no_isr               ; Programmable 2 Interrupt
COPROCFFT:  .ivec    no_isr               ; Coprocessor FFT Module Interrupt
PROG3:      .ivec    no_isr               ; Programmable 3 Interrupt
LCD:        .ivec    no_isr               ; LCD Interrupt
SARADC:     .ivec    no_isr               ; SAR ADC Interrupt
XMT2:       .ivec    no_isr               ; I2S2 Tx Interrupt
RCV2:       .ivec    no_isr               ; I2S2 Rx Interrupt
XMT3:       .ivec    no_isr               ; I2S3 Tx Interrupt
RCV3:       .ivec    no_isr               ; I2S3 Rx Interrupt
RTC:        .ivec    no_isr               ; RTC interrupt
SPI:        .ivec    no_isr               ; SPI Receive Interrupt
USB:        .ivec    no_isr               ; USB Transmit Interrupt
GPIO:       .ivec    no_isr               ; GPIO Interrupt
EMIF:       .ivec    no_isr               ; EMIF Error Interrupt
I2C:        .ivec    no_isr               ; IIC interrupt
BERR:       .ivec    no_isr               ; Bus Error Interrupt
DLOG:       .ivec    no_isr               ; Emulation Interrupt - DLOG
RTOS:       .ivec    no_isr               ; Emulation Interrupt - RTOS
RTDXRCV:    .ivec    no_isr               ; Emulation Interrupt - RTDX receive
RTDXXMT:    .ivec    no_isr               ; Emulation Interrupt - RTDX transmit
EMUINT:     .ivec    no_isr               ; Emulation monitor mode interrupt
SINT30:     .ivec    no_isr               ; Software Interrupt #30
SINT31:     .ivec    no_isr               ; Software Interrupt #31

      .text
no_isr: b no_isr

Linker script:

MEMORY
{
    MMR:     o = 0x000000  l = 0x0000c0  /* 192B Memory Mapped Registers */
    DARAM:   o = 0x0000C0  l = 0x00F740  /* Dual Access RAM */
    FFT_RAM: o = 0x00F800  l = 0x000700  /* Dual Access RAM - FFT data */
    VECS:    o = 0x00FF00  l = 0x000100  /* Interrupt vector table */

    SARAM_S: o = 0x010000  l = 0x00D000  /* Single Access RAM - stack */
    SARAM:   o = 0x01D000  l = 0x033000  /* Single Access RAM */

    CS0:     o = 0x050000  l = 0x7B0000  /* 8MB CS0 external memory space */
    CS2:     o = 0x800000  l = 0x400000  /* 4MB CS2 external memory space */
    CS3:     o = 0xC00000  l = 0x200000  /* 2MB CS3 external memory space */
    CS4:     o = 0xE00000  l = 0x100000  /* 1MB CS4 external memory space */
    CS5:     o = 0xF00000  l = 0x0E0000  /* 1MB CS5 external memory space */
    ROM:     o = 0xFE0000  l = 0x01FF00  /* 128kB ROM (MPNMC=0) or CS5 (MPNMC=1) */
}

SECTIONS
{
    vectors        >  VECS   ALIGN = 256
    fft_data       >  FFT_RAM
    .stack         >  SARAM_S
    .sysstack      >  SARAM_S
    .text          >  SARAM
    .cinit         >  DARAM
    .sysmem        >  DARAM
    .data          >  DARAM
    .cio           >  DARAM
    .bss           >  DARAM
    .const         >  DARAM
}

Thanks for any help.