cancel
Showing results for 
Search instead for 
Did you mean: 

Using SPI in slave mode with tx only DMA

kevinhuang
Associate II
Posted on December 16, 2013 at 18:44

Hello, I've been having issue with getting DMA to work properly with with SPI. My goal is to have the stm32f3 configured in slave mode and wait for a specific byte code, then when it receives the expected code send a DMA request to read an array of data to be transmitted back. The code I have so far is below:

void init(void)

{

    SPI_InitTypeDef spi_init_struct; 

    NVIC_InitTypeDef nvic_init_struct;

    DMA_InitTypeDef dma_init_struct;

    /* Enable peripheral clock */

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    /* Initialize SPI Struct */

    SPI_I2S_DeInit(SPI1);

    SPI_StructInit(&spi_init_struct);

    spi_init_struct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;

    spi_init_struct.SPI_Mode = SPI_Mode_Slave;

    spi_init_struct.SPI_DataSize = SPI_DataSize_8b;

    spi_init_struct.SPI_CPOL = SPI_CPOL_Low;

    spi_init_struct.SPI_CPHA = SPI_CPHA_2Edge;

    spi_init_struct.SPI_NSS = SPI_NSS_Hard;

    spi_init_struct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;

    spi_init_struct.SPI_FirstBit = SPI_FirstBit_MSB;

    spi_init_struct.SPI_CRCPolynomial = 7;

    SPI_Init(SPI1, &spi_init_struct);

    /* Configure the Priority Group to 1 bit */

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    /* Initialize SPI FIFO Threshold */

    SPI_RxFIFOThresholdConfig(SPI1, SPI_RxFIFOThreshold_QF);

    /* Initialize NVIC Struct for SPI*/

    nvic_init_struct.NVIC_IRQChannel = SPI1_IRQn;

    nvic_init_struct.NVIC_IRQChannelPreemptionPriority = 1;

    nvic_init_struct.NVIC_IRQChannelSubPriority = 0;

    nvic_init_struct.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&nvic_init_struct);

    

    /* Initialize DMA Struct */

    DMA_DeInit(DMA1_Channel3);

    DMA_StructInit(&dma_init_struct);

    dma_init_struct.DMA_PeripheralBaseAddr = (uint32_t) & SPI1->DR;

    dma_init_struct.DMA_MemoryBaseAddr = (uint32_t) table; /* This is an array */

    dma_init_struct.DMA_DIR = DMA_DIR_PeripheralDST;

    dma_init_struct.DMA_BufferSize = 0; /* Start at 0, because no data to send yet */ 

    dma_init_struct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

    dma_init_struct.DMA_MemoryInc = DMA_PeripheralInc_Enable;

    dma_init_struct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

    dma_init_struct.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;

    dma_init_struct.DMA_Mode = DMA_Mode_Normal;

    dma_init_struct.DMA_Priority = DMA_Priority_VeryHigh;

    dma_init_struct.DMA_M2M = DMA_M2M_Disable;

    DMA_Init(DMA1_Channel3, &dma_init_struct);

    /* Initialize NVIC Struct for DMA */

    nvic_init_struct.NVIC_IRQChannel = DMA1_Channel3_IRQn;

    nvic_init_struct.NVIC_IRQChannelPreemptionPriority = 1;

    nvic_init_struct.NVIC_IRQChannelSubPriority = 0;

    nvic_init_struct.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&nvic_init_struct);

    /* Enable SPI Error Interrupt */

    SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_ERR, ENABLE);

    /* Enable SPI RXNE Interrupt */

    SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_RXNE, ENABLE);

    /* Enable SPI */

    SPI_Cmd(SPI1, ENABLE);

    /* Enable DMA */

    DMA_Cmd(DMA1_Channel3, ENABLE);

    /* Enable DMA Error Interrupt */

    DMA_ITConfig(DMA1_Channel3, DMA_IT_TE, ENABLE);

    /* Enable DMA Error Interrupt */

    DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, ENABLE);

}

Elsewhere is an interrupt service routine:

void spi_rx_isr(void)

{

    RxIdx = 0;

    RxBuffer[RxIdx] = SPI_ReceiveData8(SPI1);

    printf(''Byte received: %x\n\r'', RxBuffer[RxIdx]);

    if (RxBuffer[RxIdx] == RX_READ)

    {

        active_table_status status = valves_toggle_active_table();

        DMA_Cmd(DMA1_Channel3, DISABLE);

        /* Set number of data to send */

        DMA1_Channel3->CNDTR = (uint16_t) sizeof(table_row) * TABLE_SIZE;

        DMA_Cmd(DMA1_Channel3, ENABLE);

        /* Send request */

        SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);

    }

    RxIdx++;

}

Before you ask, I have the gpio pins configured elsewhere and I can confirm that spi mode works when not attempting to use DMA. I've looked at the output with a logic analyzer, and it's clear that the MOSI, Clock, and SS lines are performing as expected, but the output from MISO is completely flat. I also originally had SPI configured to catch overrun interrupts, but I read that because I was using DMA in tx only mode, the OVR bit was inevitable because I wasn't reading the received bytes. 

I've run out of ideas... Any help would be appreciated.

#dma #spi
0 REPLIES 0