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/TM4C123GH6PM: Two SSI-modules with uDMA in Ping-Pong-Mode

Part Number: TM4C123GH6PM

Tool/software: Code Composer Studio

Hi all,

because I´m emulating an I2S-interface described in document spma042b.pdf I want two use two SSI-modules (SSI0 and SSI3) with µDMA in Ping-Pong-Mode. SSI0 ist the left and SSI3 ist the right channel. But SSI0 only is transferring data and SSI3 don´t get into the interrupt. Have you some tipps for me?

// Buffer definitions outside main.c
#pragma DATA_SECTION(inbuffera1, ".data")
static uint16_t inbuffera1[BUFF_SIZE];
#pragma DATA_SECTION(inbuffera2, ".data")
static uint16_t inbuffera2[BUFF_SIZE];
#pragma DATA_SECTION(outbuffera1, ".data")
static uint16_t outbuffera1[BUFF_SIZE];
#pragma DATA_SECTION(outbuffera2, ".data")
static uint16_t outbuffera2[BUFF_SIZE];

#pragma DATA_SECTION(inbufferb1, ".data")
static uint16_t inbufferb1[BUFF_SIZE];
#pragma DATA_SECTION(inbufferb2, ".data")
static uint16_t inbufferb2[BUFF_SIZE];
#pragma DATA_SECTION(outbufferb1, ".data")
static uint16_t outbufferb1[BUFF_SIZE];
#pragma DATA_SECTION(outbufferb2, ".data")
static uint16_t outbufferb2[BUFF_SIZE];

// uDMA control table aligned to 1024-byte boundary outside main.c
#pragma DATA_ALIGN(ucControlTable, 1024)
uint16_t ucControlTable[1024];

// Functions called inside main.c
void hwi_SSI0_ISR(void)
{
    uint32_t ui32Status;
    uint32_t ui32Mode;

    ui32Status = SSIIntStatus(SSI0_BASE, 1);

    SSIIntClear(SSI0_BASE, ui32Status);

    ui32Mode = uDMAChannelModeGet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT);
    if(ui32Mode == UDMA_MODE_STOP)
    {
    	//wssus(inbuffera1, outbuffera1);
        g_ui32SSIRxPingCount++;
        uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG,(void *)(SSI0_BASE + SSI_O_DR), inbuffera1, sizeof(inbuffera1));
    }

    ui32Mode = uDMAChannelModeGet(UDMA_CHANNEL_SSI0RX | UDMA_ALT_SELECT);
    if(ui32Mode == UDMA_MODE_STOP)
    {
    	//wssus(inbuffera2, outbuffera2);
        g_ui32SSIRxPongCount++;
        uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void *)(SSI0_BASE + SSI_O_DR), inbuffera2, sizeof(inbuffera2));
    }

	ui32Mode = uDMAChannelModeGet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT);
	if(ui32Mode == UDMA_MODE_STOP)
	{
		g_ui32SSITxPingCount++;
		uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, outbuffera1, (void *)(SSI0_BASE + SSI_O_DR), sizeof(outbuffera1));
	}

	ui32Mode = uDMAChannelModeGet(UDMA_CHANNEL_SSI0TX | UDMA_ALT_SELECT);
	if(ui32Mode == UDMA_MODE_STOP)
	{
		g_ui32SSITxPongCount++;
		uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, outbuffera2, (void *)(SSI0_BASE + SSI_O_DR), sizeof(outbuffera2));
	}
}

void hwi_SSI3_ISR(void)
{
    uint32_t ui32Status;
    uint32_t ui32Mode;

    ui32Status = SSIIntStatus(SSI3_BASE, 1);

    SSIIntClear(SSI3_BASE, ui32Status);

    ui32Mode = uDMAChannelModeGet(UDMA_CH14_SSI3RX | UDMA_PRI_SELECT);
    if(ui32Mode == UDMA_MODE_STOP)
    {
    	//wssus(inbufferb1, outbufferb1);
        g_ui32SSIRxPingCount++;
        uDMAChannelTransferSet(UDMA_CH14_SSI3RX | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG,(void *)(SSI3_BASE + SSI_O_DR), inbufferb1, sizeof(inbufferb1));
    }

    ui32Mode = uDMAChannelModeGet(UDMA_CH14_SSI3RX | UDMA_ALT_SELECT);
    if(ui32Mode == UDMA_MODE_STOP)
    {
    	//wssus(inbufferb2, outbufferb2);
        g_ui32SSIRxPongCount++;
        uDMAChannelTransferSet(UDMA_CH14_SSI3RX | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void *)(SSI3_BASE + SSI_O_DR), inbufferb2, sizeof(inbufferb2));
    }

	ui32Mode = uDMAChannelModeGet(UDMA_CH15_SSI3TX | UDMA_PRI_SELECT);
	if(ui32Mode == UDMA_MODE_STOP)
	{
		g_ui32SSITxPingCount++;
		uDMAChannelTransferSet(UDMA_CH15_SSI3TX | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, outbufferb1, (void *)(SSI3_BASE + SSI_O_DR), sizeof(outbufferb1));
	}

	ui32Mode = uDMAChannelModeGet(UDMA_CH15_SSI3TX | UDMA_ALT_SELECT);
	if(ui32Mode == UDMA_MODE_STOP)
	{
		g_ui32SSITxPongCount++;
		uDMAChannelTransferSet(UDMA_CH15_SSI3TX | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, outbufferb2, (void *)(SSI3_BASE + SSI_O_DR), sizeof(outbufferb2));
	}
}

// Initialize SSI uDMA transfer
void Init_SSI0_uDMA_Transfer(void)
{
    // Enable uDMA
	SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
	SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UDMA);
	while(!SysCtlPeripheralReady(SYSCTL_PERIPH_UDMA));		// wait until uDMA is ready
	IntEnable(INT_UDMAERR);
	uDMAEnable();
	uDMAControlBaseSet(ucControlTable);

    SSIDMAEnable(SSI0_BASE, SSI_DMA_RX | SSI_DMA_TX);		// Enable TX and RX channels.

    //HWREG(SSI0_BASE + SSI_O_CR1) |= SSI_CR1_LBM;		// Loopback-mode (data sent to TX (output) to RX (input) )


    uDMAChannelAttributeDisable(UDMA_CHANNEL_SSI0RX, UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT | (UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK));		// assure starting point for RX-channel
    //****************************************************************************
    //uDMA SSI0 RX Ping
    //****************************************************************************
    uDMAChannelControlSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_16);		// transfer element size RX Ping
    uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, (void *)(SSI0_BASE + SSI_O_DR), inbuffera1, sizeof(inbuffera1));		// source and destination for RX Ping

    //****************************************************************************
    //uDMA SSI0 RX Pong
    //****************************************************************************
    uDMAChannelControlSet(UDMA_CHANNEL_SSI0RX | UDMA_ALT_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_16);		// transfer element size RX Pong
    uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void *)(SSI0_BASE + SSI_O_DR), inbuffera2, sizeof(inbuffera2));		// source and destination for RX Pong


    uDMAChannelAttributeDisable(UDMA_CHANNEL_SSI0TX, UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);		// put attributes in known state
    uDMAChannelAttributeEnable(UDMA_CHANNEL_SSI0TX, UDMA_ATTR_USEBURST);		// use burst mode (transfer, when 4 or more items are in RX FIFO)
    //****************************************************************************
    //uDMA SSI0 TX Ping
    //****************************************************************************
    uDMAChannelControlSet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_16 | UDMA_DST_INC_NONE | UDMA_ARB_16);		// transfer element size
    uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, outbuffera1, (void *)(SSI0_BASE + SSI_O_DR), sizeof(outbuffera1));

    //****************************************************************************
    //uDMA SSI0 TX Pong
    //****************************************************************************
    uDMAChannelControlSet(UDMA_CHANNEL_SSI0TX | UDMA_ALT_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_16 | UDMA_DST_INC_NONE | UDMA_ARB_16);
    uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, outbuffera2, (void *)(SSI0_BASE + SSI_O_DR), sizeof(outbuffera2));


    uDMAChannelEnable(UDMA_CHANNEL_SSI0RX);
    uDMAChannelEnable(UDMA_CHANNEL_SSI0TX);

    SSIIntEnable(SSI0_BASE, SSI_DMATX | SSI_DMARX);		// Enable the SSI0 DMA TX/RX interrupts.
    IntEnable(INT_SSI0);		// Enable the SSI0 peripheral interrupts.

}

void Init_SSI3_uDMA_Transfer(void)
{
	//uDMAChannelSelectSecondary();

	SSIDMAEnable(SSI3_BASE, SSI_DMA_RX | SSI_DMA_TX);		// Enable TX and RX channels.

	uDMAChannelAttributeDisable(UDMA_CH14_SSI3RX, UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT | (UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK));		// assure starting point for RX-channel
	//****************************************************************************
	//uDMA SSI3 RX Ping
	//****************************************************************************
	uDMAChannelControlSet(UDMA_CH14_SSI3RX | UDMA_PRI_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_16);		// transfer element size RX Ping
	uDMAChannelTransferSet(UDMA_CH14_SSI3RX | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, (void *)(SSI3_BASE + SSI_O_DR), inbufferb1, sizeof(inbufferb1));		// source and destination for RX Ping

	//****************************************************************************
	//uDMA SSI3 RX Pong
	//****************************************************************************
	uDMAChannelControlSet(UDMA_CH14_SSI3RX | UDMA_ALT_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_16);		// transfer element size RX Pong
	uDMAChannelTransferSet(UDMA_CH14_SSI3RX | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void *)(SSI3_BASE + SSI_O_DR), inbufferb2, sizeof(inbufferb2));		// source and destination for RX Pong


	uDMAChannelAttributeDisable(UDMA_CH15_SSI3TX, UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);		// put attributes in known state
	uDMAChannelAttributeEnable(UDMA_CH15_SSI3TX, UDMA_ATTR_USEBURST);		// use burst mode (transfer, when 4 or more items are in RX FIFO)
	//****************************************************************************
	//uDMA SSI3 TX Ping
	//****************************************************************************
	uDMAChannelControlSet(UDMA_CH15_SSI3TX | UDMA_PRI_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_16 | UDMA_DST_INC_NONE | UDMA_ARB_16);		// transfer element size
	uDMAChannelTransferSet(UDMA_CH15_SSI3TX | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, outbufferb1, (void *)(SSI3_BASE + SSI_O_DR), sizeof(outbufferb1));

	//****************************************************************************
	//uDMA SSI3 TX Pong
	//****************************************************************************
	uDMAChannelControlSet(UDMA_CH15_SSI3TX | UDMA_ALT_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_16 | UDMA_DST_INC_NONE | UDMA_ARB_16);
	uDMAChannelTransferSet(UDMA_CH15_SSI3TX | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, outbufferb2, (void *)(SSI3_BASE + SSI_O_DR), sizeof(outbufferb2));


	uDMAChannelEnable(UDMA_CH14_SSI3RX);
	uDMAChannelEnable(UDMA_CH15_SSI3TX);

	SSIIntEnable(SSI3_BASE, SSI_DMATX | SSI_DMARX);		// Enable the SSI3 DMA TX/RX interrupts.
	IntEnable(INT_SSI3);		// Enable the SSI0 peripheral interrupts.
}

void Init_SSI(void)
{
    // GPIO setup for SSI0
    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_SSI0);
    GPIOPinConfigure(GPIO_PA2_SSI0CLK);
    GPIOPinConfigure(GPIO_PA3_SSI0FSS);
    GPIOPinConfigure(GPIO_PA4_SSI0RX);
    GPIOPinConfigure(GPIO_PA5_SSI0TX);
    GPIOPinTypeSSI(GPIO_PORTA_BASE,GPIO_PIN_5|GPIO_PIN_4|GPIO_PIN_3|GPIO_PIN_2);
    SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_SLAVE, 10000, 16);
    SSIEnable(SSI0_BASE);


    // GPIO setup for SSI3
	SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI3);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
	SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_SSI3);
	GPIOPinConfigure(GPIO_PD0_SSI3CLK);
	GPIOPinConfigure(GPIO_PD1_SSI3FSS);
	GPIOPinConfigure(GPIO_PD2_SSI3RX);
	GPIOPinConfigure(GPIO_PD3_SSI3TX);
	GPIOPinTypeSSI(GPIO_PORTD_BASE,GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
	SSIConfigSetExpClk(SSI3_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_SLAVE, 10000, 16);
	SSIEnable(SSI3_BASE);
}

// called inside main.c
    FPULazyStackingEnable();
    //Set CPU Clock to 80MHz. 400MHz PLL/2 = 200 DIV 2.5 = 80MHz
    SysCtlClockSet(SYSCTL_SYSDIV_2_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);
    SysCtlPeripheralClockGating(true);

    Init_AIC3104();
    Init_SSI();
    Init_SSI0_uDMA_Transfer();
    Init_SSI3_uDMA_Transfer();

    BIOS_start();

  • Sadullah Zeyrek said:
    I´m emulating an I2S-interface

    Perhaps - in light of your clear effort (the great mass of code presented) it proves useful to ask:

    • how much will "emulation" degrade your effort
    • same for the RTOS

    You should know that (even) Cortex M0 class MCUs contain a (proper) I2S interface - can the "lesser (emulation) performance" - and extra work - demanded when "bending/beating a (function deprived) device into (some) compliance" make full/proper sense?     Should you not first seek (some) "specification" of your, "minimum functional requirements" - to justify such effort?     

    It is noted that you reference a "tech-doc" - it is hoped that (some) listing of "expected performance figures" are contained therein.   (if not - is that not "telling?")

    You may be able to "glean" minimal performance, I2S specs, via use of an MCU which includes "native I2S" - and then (deliberately) down-grading its performance - to discover the "spec level your application" may require...

    Emulation (any emulation) most always cannot approach the "original" for "Speed, functional completeness, clarity of usage, and robustness" - thus "analysis should be performed" prior to, "Launching such effort."    (especially so when the "candidate function to be emulated is, "ALIVE & WELL in Native Form!")

  • Hi cb1_mobile,

    I am using a TM4C123GH6PM with the AIC3104 Audio-Codec. Because this Microcontroller don´t have a I2S-Interface, I need to emulate I2S with tow SPI-Modules.

    I have the solution already.

    uDMAChannelAssign(UDMA_CH14_SSI3RX);
    uDMAChannelAssign(UDMA_CH15_SSI3TX);

    With this function it works!