SPI+DMA Slave Receiver of stm32 Single Chip Microcomputer

    hspi1.Instance = SPI1;
    hspi1.Init.Mode = SPI_MODE_SLAVE;
    hspi1.Init.Direction = SPI_DIRECTION_2LINES;
    hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
    hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH;
    hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;
    hspi1.Init.NSS = SPI_NSS_SOFT;//SPI_NSS_HARD_OUTPUT;
//    hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
    hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
    hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
    hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    hspi1.Init.CRCPolynomial = 7;
    hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
    hspi1.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;

    if(HAL_SPI_Init(&hspi1) != HAL_OK) {
        _Error_Handler(__FILE__, __LINE__);
    }
		

	HAL_SPI_Receive_DMA(&hspi1, receive_data, 162);

The above is the initialization code of SPI.

A small module in the project needs to be used, so there is no specific understanding of the SPI protocol. SPI slave receives design bit SLAVE, shielding clock design (clock follows host, slave does not need configuration).

SPI has four working modes. Since CPHA and CPOL are both 1 on the host side, my design here is as follows:

hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH;
hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;

Call the SPI receiving function of the HAL library once at the initialization clock.

The following is the initialization settings for DMA.

	__HAL_LINKDMA(hspi,hdmarx,hdma_spi1_rx);
		
    hdma_spi1_rx.Instance = DMA2_Stream0;                    //Data channels need to be self-configurable
    hdma_spi1_rx.Init.Channel = DMA_CHANNEL_3;
    hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;       //Receive and select peripherals to memory
    hdma_spi1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi1_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_spi1_rx.Init.Mode = DMA_NORMAL;
    hdma_spi1_rx.Init.Priority = DMA_PRIORITY_HIGH;
    hdma_spi1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_spi1_rx) != HAL_OK)
    {
      _Error_Handler(__FILE__, __LINE__);
    }

There's not much to notice about the initialization of DMA, but we still need to pay attention to the mode in the initialization.

At first, I configure the DMA_CIRCULAR Receiver (the DMA Receiver function only needs to be used once), because the data is sent too fast, there will be packet loss. So use DMA_NORMAL instead (the DMA receiving function needs to be called again in the middle end of the receiving completion).

The acceptance completion function of SPIdeDMA is difficult to find. The author has spent some effort to record the following. SPI_DMAReceive Cplt();

HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 3, 2);
HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);

The interrupt of DMA also remembers to initialize. Here's a supplement.

Posted by Graphi on Wed, 02 Oct 2019 06:26:17 -0700