AnsweredAssumed Answered

[SOLVED] STM32F301K8Ux SPI DMA Transfer works only once

Question asked by kuczek.krzysztof.001 on Nov 29, 2014
Latest reply on Mar 1, 2018 by Manish Sharma
Hi,
I have strange problem with making SPI DMA transfers working.
It works only one time, the second dma transfer is not performed.
I use similar coding for USART and it works perfect, but SPI doesn't.
So the issue is to send one byte and receive many bytes.
The SPI initialization (using MX lib) looks like following
void MX_SPI3_Init(void)
{
 
  hspi3.Instance = SPI3;
  hspi3.Init.Mode = SPI_MODE_MASTER;
  hspi3.Init.Direction = SPI_DIRECTION_2LINES;
  hspi3.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi3.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi3.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi3.Init.NSS = SPI_NSS_SOFT;
  hspi3.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
  hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi3.Init.TIMode = SPI_TIMODE_DISABLED;
  hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;
  hspi3.Init.NSSPMode = SPI_NSS_PULSE_DISABLED;
  HAL_SPI_Init(&hspi3);
 
}

The chip select pin is software driven, so two irq are in use
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
    if (hspi->Instance == hspi3.Instance)
    {
        mpu9250_read_regs_dma_tc();
    }
}
 
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
    if (hspi->Instance == hspi3.Instance)
    {
        mpu9250_read_regs_dma_tc();
    }
}
 
void mpu9250_read_regs_dma_tc(void)
{
    mpu9250_set_cs_state(GPIO_PIN_SET);
    dma_regs_read_flag = 0;
}

The routine which is responsible for reading all the registers is like that
void mpu9250_read_regs_dma(uint8_t start_reg_no, uint8_t no_of_bytes, uint8_t * buff)
{
 
    if ( dma_regs_read_flag == 0 ) //it's not perfect but it should not be called more frequently then DMA transfer makes possible
    {
        dma_regs_read_flag = 1;
        mpu9250_set_cs_state(GPIO_PIN_RESET);
        memset(spi_tx_buff_dma, 0, no_of_bytes+1);
        memset(spi_rx_buff_dma, 0, no_of_bytes+1);
        spi_tx_buff_dma[0] = start_reg_no | 0x80;  // need to set 0x80 bit for reading operation
 
        // it working but only one time
        //HAL_SPI_TransmitReceive_DMA(&hspi3, spi_tx_buff_dma, spi_rx_buff_dma,no_of_bytes+1);
 
        // it does not work either :(
        HAL_SPI_Transmit(&hspi3, spi_tx_buff_dma, 1 , MPU9250_TIMEOUT);
        HAL_SPI_Receive_DMA(&hspi3, spi_rx_buff_dma,no_of_bytes);
 
    }
 
}
I have tried two approach, first (commented) where sending and reciving are made by DMA, and second, where DMA is utilized only for receiving data.

Both works, but only for first call. Please take a look attached files. You can see that first transfer is ok, but second only sending one byte is ok, but DMA reciving does not work at all (even MISO is going high, I don't know why). The transfer complete interrupt is not called either.

I know, that CubeMX is not the best lib, but it's function for starting DMA transfer HAL_DMA_Start_IT (which is in use) looks ok. It disables DMA using CCR register, makes configuration and start DMA again.

Any idea?





Outcomes