简体   繁体   中英

STM32: Receiving SPI data with DMA - always wrong number of bytes in Rx buffer

With an STM32F764 I want to receive 33 bytes from 11 daisy-chained 24 bit ADCs via SPI in read-only mode. The received data looks okay but there are 37 to 39 bytes in the buffer. Also with other byte numbers I receive 4 to 6 bytes more than expected.

Does anyone have an idea why that happens?

HAL_SPI_Receive_DMA is called by a GPIO interrupt from an external ADC when the 33 bytes are ready. After finishing the DMA the buffer content is processed in Sampling().

Is the external GPIO interrupt handler the correct place for calling HAL_SPI_Receive_DMA?

/*SPI init for external ADCs (only Rx)*/
uint8_t SPI3_Init_ADC(void)
{
    hspi3.Instance = SPI3;
    hspi3.Init.Mode = SPI_MODE_MASTER;
    hspi3.Init.Direction = SPI_DIRECTION_2LINES_RXONLY;
    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_4; /*SPI3_CLK = 12.5 MHz*/
    hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;
    hspi3.Init.TIMode = SPI_TIMODE_DISABLE;
    hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    hspi3.Init.CRCPolynomial = 7;
    hspi3.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
    hspi3.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
    if (HAL_SPI_Init(&hspi3) != HAL_OK)
        return ERR;
    return OK;
}
    /*SPI MSP and DMA Initialization*/
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    /*SPI3: ADCs*/
    if(hspi->Instance==SPI3)
    {
        __HAL_RCC_SPI3_CLK_ENABLE(); /* Peripheral clock enable */
        __HAL_RCC_GPIOB_CLK_ENABLE();
        /*PB3 --> SPI3_SCK*/
        /*PB4 --> SPI3_MISO*/
        GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_4;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
        /*DMA 1 / channel 0 / stream 0 transfers data from external ADC to sample registers*/
        __HAL_RCC_DMA1_CLK_ENABLE(); /*DMA clock*/
        hdma_spi3_rx.Init.Channel = DMA_CHANNEL_0;
        hdma_spi3_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; /*from SPI to memory*/
        hdma_spi3_rx.Init.PeriphInc = DMA_PINC_DISABLE; /*no increment on SPI side*/
        hdma_spi3_rx.Init.MemInc = DMA_MINC_ENABLE; /*increment sample memory address*/
        hdma_spi3_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        hdma_spi3_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        hdma_spi3_rx.Init.Mode = DMA_NORMAL;
        hdma_spi3_rx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
        hdma_spi3_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
        hdma_spi3_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
        hdma_spi3_rx.Init.MemBurst = DMA_PBURST_SINGLE;
        hdma_spi3_rx.Init.PeriphBurst = DMA_PBURST_SINGLE;
        hdma_spi3_rx.Instance = DMA1_Stream0;
        HAL_DMA_Init(&hdma_spi3_rx);
        HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 0); /*highest priority for DMA interrupt*/
        HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn); /*enable DMA interrupt*/
        __HAL_LINKDMA(hspi, hdmarx, hdma_spi3_rx); /*link DMA1 to SPI3*/
    }

/*INTERRUPT HANDLERS*/

/*Data ready interrupt (/ADC_/DRDY) of external ADCs*/
void EXTI9_5_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_7); /*clear interrupt*/
    HAL_SPI_Receive_DMA(&hspi3, SplRxBuff, 33); /*get 33 bytes ADC data*/
}

/*DMA1 stream0 global interrupt (Rx of external ADCs complete)*/
void SPI_DMA_Rx_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&hdma_spi3_rx);
    Sampling();
}

Screenshot:

The red part is excess data. The ADC delivers actual data here from its unused 12th channel.

I bet as you do not protect the start transmition function call with any synchronisation mechanism (flag, semaphore etc) your interrupt is triggered before other transmit is done. Also the mystery function sampling in the DMA handler may does something strange.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM