AnsweredAssumed Answered

Using SPI in slave mode with tx only DMA

Question asked by mex1 on Dec 16, 2013
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.

Outcomes