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.