I2S/SPI DMA RX from audio chip not firing interrupts

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderators: barthess, RoccoMarco

chiVelle
Posts: 21
Joined: Sun Aug 25, 2013 4:16 pm

I2S/SPI DMA RX from audio chip not firing interrupts

Postby chiVelle » Thu Feb 13, 2014 5:44 pm

I have been struggling to achieve any sort of DMA RX callback success when working with a wolfson audio codec attached to SPI2 on the STM32F4 Discovery board. I have it all set up for I2S manually due to the I2S driver not ready yet. I am unable to find the bug. I have attached a logic analyzer to the Data, Clock, and Frame lines coming from the Wolfson dev kit and indeed I see audio data being transferred over the wires. The Wolfson is set up as slave, and the STM32 is the master. Both are configured for standard I2S mode at 8 KHz. The I2C Configuration to the Wolfson is all working fine. The I2S Configuration calculations are all ripped from the STM32 peripheral library for figuring out the dividers based on the frequency. Any ideas?

This is the DMA RX Callback:

Code: Select all

uint16_t wolfsonAudioBuffer0[BUFFER_SIZE];
uint16_t wolfsonAudioBuffer1[BUFFER_SIZE];

static void I2SDmaRxInterrupt(SPIDriver* spip, uint32_t flags)
{
    if(spip == &SPID2)
    {
       printConsole("INFO: INSIDE DMA RX ISR\n");
       
        if(flags & STM32_DMA_ISR_TCIF)
        {
            // TRANSFER COMPLETE
            palSetPad( DEV_BLUE_LED_PORT,  DEV_BLUE_LED_PIN);
        }
        else if(flags & STM32_DMA_ISR_FEIF)
        {
            // FIFO ERROR
            palSetPad( DEV_GREEN_LED_PORT,  DEV_GREEN_LED_PIN);
        }
        else if(flags & STM32_DMA_ISR_DMEIF)
        {
            // DIRECT MODE ERROR
            palSetPad( DEV_RED_LED_PORT,  DEV_RED_LED_PIN);
        }
        else if(flags & STM32_DMA_ISR_TEIF)
        {
            // TRANSFER ERROR
            palSetPad( DEV_ORANGE_LED_PORT,  DEV_ORANGE_LED_PIN);
        }
        else if(flags & STM32_DMA_ISR_HTIF)
        {
            // HALF TRANSFER COMPLETE
            palSetPad( DEV_BLUE_LED_PORT,  DEV_BLUE_LED_PIN);
        }
    }
}


This is the DMA Initialization:

Code: Select all

void I2SInit(void)
{
    // PROGRAM STREAM MODE SETTINGS
    // DEFAULTS IN SPI_LLD.C ARE : PERIPHERAL TO MEMORY, TCIE, DMEIE, TEIE
    // DOUBLE BUFFER MODE (STM32_DMA_CR_DBM)
    // MEMORY DATA SIZE HALF WORD (16-BIT) (STM32_DMA_CR_MSIZE_HWORD)
    // MEMORY INCREMENT MODE (STM32_DMA_CR_MINC)
    // PERIPHERAL DATA SIZE HALF WORD (16-bit) (STM32_DMA_CR_PSIZE_HWORD)
    // CIRCULAR MODE ENABLE (STM32_DMA_CR_CIRC)
    SPID2.rxdmamode |= ( STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD |
                         STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC |
                         STM32_DMA_CR_DBM );
                         
    // SINGLE FUNCTION ALLOCATES DMA STREAM, ENABLES DMA CLOCK, AND ASSOCIATES IRQ VECTOR
    bool streamStatus = dmaStreamAllocate(SPID2.dmarx,
                            STM32_SPI_SPI2_IRQ_PRIORITY,
                            (stm32_dmaisr_t)I2SDmaRxInterrupt,
                            &SPID2);
                            
   // FUNCTION ABOVE RETURNS FALSE ON NO ERROR, AND TRUE ON STREAM ALREADY TAKEN ERROR.                           
   if(streamStatus)
   {
      printConsole("ERROR: SPI2 DMA STREAM ALREADY TAKEN\n");
   }

    // ENABLE SPI2 PERIPHERAL CLOCK
    rccEnableSPI2(FALSE);
   
    // ASSOCIATE THE SPI2 DR REGISTER TO THE DMA STREAM
    dmaStreamSetPeripheral(SPID2.dmarx, &SPID2.spi->DR);
   
    // SPI SETUP AND ENABLE
    SPID2.spi->CR2 = SPI_CR2_RXDMAEN ;
   
    // PROGRAM STREAM FIFO SETTINGS
    // DIRECT MODE DISABLE
    // FIFO THRESHOLD 1/2 FULL
    dmaStreamSetFIFO(SPID2.dmarx, STM32_DMA_FCR_DMDIS | STM32_DMA_FCR_FTH_HALF );

    dmaStreamSetMemory0(SPID2.dmarx, wolfsonAudioBuffer0);
    dmaStreamSetMemory1(SPID2.dmarx, wolfsonAudioBuffer1);

    // SET THE NUMBER OF TRANSFERS TO BE PERFORMED
    // SEE PAGE 328 OF RM
    dmaStreamSetTransactionSize(SPID2.dmarx, BUFFER_SIZE / 2);
    dmaStreamSetMode(SPID2.dmarx, SPID2.rxdmamode );

    dmaStreamEnable(SPID2.dmarx);
}


This is the I2S Configuration Setup:

Code: Select all

void I2SSetup(uint32_t AudioFreq)
{
    uint16_t tmpreg = 0, i2sdiv = 2, i2sodd = 0;
    uint32_t pllm = 0, plln = 0, pllr = 0;
    uint32_t tmp = 0, i2sclk = 0;

    // SPI2 I2S CONFIGURATION
    SPID2.spi->I2SCFGR &= I2SCFGR_CLEAR_MASK;

    // SET I2S LINEAR PRESCALER TO 2
    // SEE PAGE 893 OF RM
    SPI2->I2SPR = 0x0002;

    // GET THE I2SCFGR REGISTER VALUE
    tmpreg = SPID2.spi->I2SCFGR;

    // SET PLLI2S AS I2S CLOCK SOURCE
    if ((RCC->CFGR & RCC_CFGR_I2SSRC) != 0)
    {
        // IF PLLI2S CLOCK IS NOT I2S CLOCK SOURCE, TURN IT ON
        RCC->CFGR &= ~(uint32_t)RCC_CFGR_I2SSRC;
    }

    // GET THE PLLI2SN VALUE
    plln = (RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SN) >> 6;

    // GET THE PLLI2SR VALUE
    pllr = (RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SR) >> 28;

    // GET THE PLLM VALUE
    pllm = (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM);

    // GET THE I2S SOURCE CLOCK VALUE
    i2sclk = (uint32_t)(((HSE_VALUE / pllm) * plln) / pllr);

    // COMPUTE THE REAL DIVIDER DEPENDING ON THE MCLK OUTPUT STATE WITH A FLOATING POINT
    tmp = (uint16_t)(((((i2sclk / 256) * 10) / AudioFreq)) + 5);

    // REMOVE FLOATING POINT
    tmp = tmp / 10;

    /* Check the parity of the divider */
    i2sodd = (uint16_t)(tmp & (uint16_t)0x0001);

    /* Compute the i2sdiv prescaler */
    i2sdiv = (uint16_t)((tmp - i2sodd) / 2);

    /* Get the Mask for the Odd bit (SPI_I2SPR[8]) register */
    i2sodd = (uint16_t) (i2sodd << 8);

    /* Test if the divider is 1 or 0 or greater than 0xFF */
    if ((i2sdiv < 2) || (i2sdiv > 0xFF))
    {
        /* Set the default values */
        i2sdiv = 2;
        i2sodd = 0;
    }

    /* Write to SPI2 I2SPR register the computed value */
    SPID2.spi->I2SPR = i2sdiv | i2sodd | I2S_MCLKOutput_Enable;

    // CONFIGURE I2S
    tmpreg |= SPI_I2SCFGR_I2SMOD | I2S_Mode_MasterRx | \
              I2S_Standard_Phillips | I2S_DataFormat_16b | \
              I2S_CPOL_Low | \
              SPI_I2SCFGR_I2SE;

    // WRITE CONFIGURATION TO SPI2 I2SCFGR REGISTER
    SPID2.spi->I2SCFGR = tmpreg;
}


The Pin Setup:

Code: Select all

void initI2S()
{
    palSetPadMode(I2S_CLK_PORT, I2S_CLK_PIN, PAL_MODE_OUTPUT_PUSHPULL | PAL_MODE_ALTERNATE(5) | PAL_STM32_OSPEED_HIGHEST);
    palSetPadMode(I2S_DATA_PORT, I2S_DATA_PIN, PAL_MODE_INPUT | PAL_MODE_ALTERNATE(5) | PAL_STM32_OSPEED_HIGHEST);
    palSetPadMode(I2S_WS_PORT, I2S_WS_PIN, PAL_MODE_OUTPUT_PUSHPULL | PAL_MODE_ALTERNATE(5) | PAL_STM32_OSPEED_HIGHEST);
}


The Caller Thread:

Code: Select all

  // INITIALIZE WOLFSON CODEC REGISTERS
    if( ! WM8974Init() )
    {
        printConsole("ERROR: Failure initializing Wolfson\n");
    }
    else
    {
        printConsole("INFO: Wolfson Initialized\n");
    }

    I2SSetup(8000);
    I2SInit();

User avatar
Giovanni
Site Admin
Posts: 12949
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 733 times
Been thanked: 609 times
Contact:

Re: I2S/SPI DMA RX from audio chip not firing interrupts

Postby Giovanni » Thu Feb 13, 2014 7:36 pm

Hi,

Not sure about the callbacks but I have a note: the HAL should already be able to setup the I2S clock, the output frequency is represented by the macro STM32_PLLI2SCLKOUT. See the files hal_lld.c and hal_lld.h for details.

I am not able to test all that code but I can confirm that he work on the I2S driver is going to resume, a couple of students are working on that.

Giovanni

Abhishek
Posts: 266
Joined: Wed May 23, 2012 3:15 pm
Location: India

Re: I2S/SPI DMA RX from audio chip not firing interrupts

Postby Abhishek » Sat Feb 15, 2014 4:45 am

I have observed a similar issue while attempting to read from the on board mic on the F4 Discovery [initially pass through to the on board audio DAC directly].

In my case, the clock starts being supplied as soon as I initialize I2S2 with the configuration, even before I actually enable the DMA stream. I am not sure why this is happening, but I know this as I can actually hear sound coming from the low-pass PDM stream being fed into the CS43L22 even before I enable DMA. The interrupts are not being triggered in my case too.

Regards
Abhishek

Abhishek
Posts: 266
Joined: Wed May 23, 2012 3:15 pm
Location: India

Re: I2S/SPI DMA RX from audio chip not firing interrupts

Postby Abhishek » Sat Feb 15, 2014 6:31 am

Hello chiVelle,

I fixed the issue for myself, and I believe you are facing the same issue as well.

If everything is configured properly, there is no question of not receiving an interrupt when the transfer completes.

Unless the DMA itself is not configured properly, or if, the DMA pointer refers to a null pointer. Even the Stream allocation returns true when the stm32_dma_stream_t* parameter is NULL, there is no way one notices this, unless the DMA registers are inspected.

Please add the following line to your DMA initialization code before the call to dmaStreamAllocate:

Code: Select all

SPID2.dmarx = STM32_DMA_STREAM(STM32_SPI_SPI2_RX_DMA_STREAM);


I believe this should resolve the issue.

Regards
Abhishek

P.S. Giovanni: Have changes been made to the I2S LLD format, or is it still the same? When is the I2S driver expected to be completed?

User avatar
Giovanni
Site Admin
Posts: 12949
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 733 times
Been thanked: 609 times
Contact:

Re: I2S/SPI DMA RX from audio chip not firing interrupts

Postby Giovanni » Sat Feb 15, 2014 9:24 am

In 3.0 the low level drivers organization is a bit different, I am thinking to add I2S to 3.0 and, eventually, backport it to 2.6.

I wish to give it a try during this weekend. I could try reading the microphone on the F4 Discovery but I never used an I2S device before, I may need help with testing.

Giovanni

Abhishek
Posts: 266
Joined: Wed May 23, 2012 3:15 pm
Location: India

Re: I2S/SPI DMA RX from audio chip not firing interrupts

Postby Abhishek » Sat Feb 15, 2014 11:18 am

IMO it would be easier to use I2S3/CS43L22 to play back for a test. Making sense of the microphone data requires use of a decimation filter on the received data. I am planning to make a demo including this PDM magic next week, after my exams end.

Regards
Abhishek

chiVelle
Posts: 21
Joined: Sun Aug 25, 2013 4:16 pm

Re: I2S/SPI DMA RX from audio chip not firing interrupts

Postby chiVelle » Sat Feb 15, 2014 6:20 pm

Abhishek,

Thank you for the support, I will give that a try later this weekend and report back any progress.

chiVelle
Posts: 21
Joined: Sun Aug 25, 2013 4:16 pm

Re: I2S/SPI DMA RX from audio chip not firing interrupts

Postby chiVelle » Sun Feb 16, 2014 1:56 am

I am still having issues with interrupts not being fired. Is it possible because I have my I2S Data port configured on the STM32F4 Discover as PC3 (I2S2_SD) which is muxed with SPI2_MOSI and because I am setting up the DMA for Receive Interrupts that it is expecting that data to come in on PC2 which is SPI2_MISO for master input? Is there a way for me to tell the DMA functions that I am using I2S2 and not SPI2 myself without waiting for an official driver? Thanks for the support.

Abhishek
Posts: 266
Joined: Wed May 23, 2012 3:15 pm
Location: India

Re: I2S/SPI DMA RX from audio chip not firing interrupts

Postby Abhishek » Sun Feb 16, 2014 8:42 am

There seems to be an error in GPIO initialization. PAL_MODE_OUTPUT_PUSHPULL conflicts with PAL_MODE_ALTERNATE(5).
Change this from:

Code: Select all

void initI2S()
{
    palSetPadMode(I2S_CLK_PORT, I2S_CLK_PIN, PAL_MODE_OUTPUT_PUSHPULL | PAL_MODE_ALTERNATE(5) | PAL_STM32_OSPEED_HIGHEST);
    palSetPadMode(I2S_DATA_PORT, I2S_DATA_PIN, PAL_MODE_INPUT | PAL_MODE_ALTERNATE(5) | PAL_STM32_OSPEED_HIGHEST);
    palSetPadMode(I2S_WS_PORT, I2S_WS_PIN, PAL_MODE_OUTPUT_PUSHPULL | PAL_MODE_ALTERNATE(5) | PAL_STM32_OSPEED_HIGHEST);
}
to:

Code: Select all

void initI2S()
{
    palSetPadMode(I2S_CLK_PORT, I2S_CLK_PIN, PAL_MODE_ALTERNATE(5) | PAL_STM32_OSPEED_HIGHEST);
    palSetPadMode(I2S_DATA_PORT, I2S_DATA_PIN, PAL_MODE_ALTERNATE(5) | PAL_STM32_OSPEED_HIGHEST);
    palSetPadMode(I2S_WS_PORT, I2S_WS_PIN,  PAL_MODE_ALTERNATE(5) | PAL_STM32_OSPEED_HIGHEST);
}


Also, if you are using PC3 and PB11 for I2S, you might also have a bus conflict with the on board mic of the F4D. It would be better to remap I2S2_SD onto PB15.

The I2S interface can use both MOSI and MISO inputs, but only in full-duplex mode. Normally when used in half-duplex mode the SPI2_MOSI (also I2S2_SD) serves both as input and output to the I2S bus. There is nothing wrong with that.

The DMA does not differentiate between I2S and SPI, it works in the same manner for both. This is also mentioned in the STM32F4 reference manual.

Regards
Abhishek

chiVelle
Posts: 21
Joined: Sun Aug 25, 2013 4:16 pm

Re: I2S/SPI DMA RX from audio chip not firing interrupts

Postby chiVelle » Sun Feb 16, 2014 11:19 pm

Thanks for all the help! Interrupts are now firing due to DMA Transfer Completion.


Return to “STM32 Support”

Who is online

Users browsing this forum: No registered users and 8 guests