How to enable the SPI Receive DMA interrupt

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
MoNo_2793136
Level 2
Level 2

I am trying to enable the SPI Receive DMA interrupt on the 4343 combo chip.

I added this function to platform_spi.c file to enable the Rx DMA interrupt:

static platform_result_t spi_dma_rx( const platform_spi_t* spi, const platform_spi_message_segment_t* message )
{
    DMA_InitTypeDef dma_init;
    uint32_t loop_count;
    platform_result_t result = PLATFORM_SUCCESS;
    uint32_t pending_intr = 0;

    /* Error check buffers */
    if ((message->rx_buffer == NULL) && (message->tx_buffer == NULL))
        return PLATFORM_ERROR;

    /* Enable DMA peripheral clock */

    RCC->AHB1ENR |= RCC_AHB1Periph_DMA1; // DMA1 for Rx only


    dma_init.DMA_PeripheralBaseAddr = ( uint32_t )&spi->port->DR;
    dma_init.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;
    dma_init.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    dma_init.DMA_BufferSize         = message->length;
    dma_init.DMA_MemoryDataSize     = DMA_MemoryDataSize_Byte;
    dma_init.DMA_Mode               = DMA_Mode_Normal;
    dma_init.DMA_Priority           = DMA_Priority_High;
    dma_init.DMA_FIFOMode           = DMA_FIFOMode_Disable;
    dma_init.DMA_FIFOThreshold      = DMA_FIFOThreshold_1QuarterFull;
    dma_init.DMA_MemoryBurst        = DMA_MemoryBurst_Single;
    dma_init.DMA_PeripheralBurst    = DMA_PeripheralBurst_Single;

    wiced_assert( "for debug", message->rx_buffer == NULL ); // only for debugging by mn
    /* Setup RX first */
    DMA_ClearFlag( spi->rx_dma.stream, spi->rx_dma.complete_flags | spi->rx_dma.error_flags );

    DMA_DeInit( spi->rx_dma.stream );

    loop_count = 0;
    while (DMA_GetCmdStatus( spi->rx_dma.stream ) == ENABLE)
    {
        loop_count++;
          if ( loop_count >= (uint32_t) SPI_DMA_CTL_TIMEOUT_LOOPS )
            return PLATFORM_TIMEOUT;
    }

    dma_init.DMA_Channel            = spi->rx_dma.channel;
    dma_init.DMA_DIR                = DMA_DIR_PeripheralToMemory;
    if (message->rx_buffer != NULL)
    {
        dma_init.DMA_Memory0BaseAddr    = (uint32_t)message->rx_buffer;
        dma_init.DMA_MemoryInc          = DMA_MemoryInc_Enable;
    }

    /* Init and activate RX DMA channel */
    DMA_Init( spi->rx_dma.stream, &dma_init );

    DMA_Cmd( spi->rx_dma.stream, ENABLE );
    loop_count = 0;
    while (DMA_GetCmdStatus( spi->rx_dma.stream ) == DISABLE)
    {
        loop_count++;
        if ( loop_count >= (uint32_t) SPI_DMA_CTL_TIMEOUT_LOOPS )
        {
            return PLATFORM_TIMEOUT;
        }
    }

    SPI_I2S_DMACmd( spi->port, SPI_I2S_DMAReq_Rx, ENABLE );

    DMA_ITConfig(spi->rx_dma.stream, ( DMA_IT_TC | DMA_IT_TE | DMA_IT_DME | DMA_IT_FE ) , ENABLE);
    //DMA_ITConfig(spi->rx_dma.stream, DMA_IT_TC | DMA_IT_TE, ENABLE);
    NVIC_SetPriority(spi->rx_dma.irq_vector, 7);
    NVIC_EnableIRQ( spi->rx_dma.irq_vector );

   

    return result;
}

=====================================================================

The following is my interrupt service routine:

host_semaphore_type_t spi_rx_complete_sem;
void platform_spi2_rx_dma_irq( const platform_spi_t* driver )
{
    int rx_count;
    platform_spi_port_t* spi = (platform_spi_port_t*) driver->port;

  

    if ( (DMA1->LISR & DMA_LISR_TCIF3 ) != 0 ) // check the interrupt
    {
        // Clear the IRQ
        DMA1->LIFCR |= DMA_LISR_TCIF3;
        //driver->last_receive_result = PLATFORM_SUCCESS;
    }

    // Check for error
    if ( (  DMA1->LISR & (DMA_LISR_TEIF3 | DMA_LISR_FEIF3 | DMA_LISR_DMEIF3) ) != 0 )
    {
        // Clear the DMA interrupt's errors
        DMA1->LIFCR |= (DMA_LISR_TEIF3 | DMA_LISR_FEIF3 | DMA_LISR_DMEIF3);

        //driver->last_receive_result = PLATFORM_ERROR;
    }


}

=======================================================================

I added the following code snippet  to the file platform.c

WWD_RTOS_DEFINE_ISR( spi2_rx_dma_irq )

{

    platform_spi2_rx_dma_irq( &platform_spi_peripherals[WICED_SPI_2] );

}

WWD_RTOS_MAP_ISR( spi2_rx_dma_irq, DMA1_Stream3_irq )

=============================================================

The above steps should be sufficient to enable the invocation of the SPI DMA IRQ. But the IRQ is never invoke. However, the Rx DMA runs to completion since I can see that the stream->NDTR count drops to zero.

==========================================================

What is missing in the above step that prevents the invocation of the DMA ISR?

Thanks, Mohammad

0 Likes
1 Solution

workaround for the problem

   if ( !( driver->rx_dma.stream->NDTR  ) )

    {

        sem_result = host_rtos_set_semaphore( &spi_rx_complete_sem, WICED_TRUE );

    }

View solution in original post

0 Likes
2 Replies
VinayakS_26
Moderator
Moderator
Moderator
100 replies posted 50 replies posted 25 replies posted

Hi,

Let me check this code in my setup and try it out.

Regards

0 Likes

workaround for the problem

   if ( !( driver->rx_dma.stream->NDTR  ) )

    {

        sem_result = host_rtos_set_semaphore( &spi_rx_complete_sem, WICED_TRUE );

    }

0 Likes