STM32 SPI+DMA (HAL库)使用方法
阅读原文时间:2021年04月20日阅读:53
/*
* SPI硬件初始化,内存地址初始化
*/
static void Init(void)
{
    uint8_t i;
    /*失能SPI1*/
    HAL_SPI_DeInit(&hspi1);

    /*清空FpgaRevData内存*/
    for(i=0;i<REV_MAX_NUM;i++)
    {
        memset(FpgaRevData[i],0,FPGA_DATA_PAKET_LENGTH);
    }
    /*初始化内存指针*/
    gWritePtr=0;
    gReadPtr=0;
    /*使能SPI1*/
    HAL_SPI_Init(&hspi1);
    /*SPI DMA初始化,并开启一次数据接收*/    
    HAL_SPI_Receive_DMA_INIT(&hspi1,FpgaRevData[gWritePtr],FPGA_DATA_PAKET_LENGTH);
}

/*
* SPI DMA初始化,并开启一次数据接收,
* 关键是返回函数的初始化,DMA 源地址和目的地址的初始化,各标志位的清空与开启
* 该程序修改与HAL库的HAL_SPI_Receive_DMA函数
*/
void HAL_SPI_Receive_DMA_INIT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size)
{
  hspi->State       = HAL_SPI_STATE_BUSY_RX;
  hspi->RxXferSize  = Size;

  /*Init field not used in handle to zero */
  hspi->RxISR       = NULL;

  /* Set the SPI Rx DMA transfer complete callback */
  hspi->hdmarx->XferCpltCallback = SPI_DMAReceiveCplt;

  /* Enable the Rx DMA Stream */
  HAL_DMA_Start_IT(hspi->hdmarx, (uint32_t)&hspi->Instance->DR, (uint32_t)(uint8_t *)pData, Size);

  /* Check if the SPI is already enabled */
  if((hspi->Instance->CR1 &SPI_CR1_SPE) != SPI_CR1_SPE)
  {
    /* Enable SPI peripheral */
    __HAL_SPI_ENABLE(hspi);
  }

  /* Enable the SPI Error Interrupt Bit */
  SET_BIT(hspi->Instance->CR2, SPI_CR2_ERRIE);

  /* Enable Rx DMA Request */
  SET_BIT(hspi->Instance->CR2, SPI_CR2_RXDMAEN);
}


/*
* FPGA SPI1数据接收函数,一次接收6个字节数据包
* 该程序修改与HAL库的HAL_DMA_Start_IT函数和HAL_SPI_Receive_DMA函数
*/
__INLINE void FPGA_ReadBuffer(SPI_HandleTypeDef *hspi, uint8_t *DstAddress)
{
//  HAL_StatusTypeDef status = HAL_OK;

  /* calculate DMA base and stream number */
//  DMA_Base_Registers *regs = (DMA_Base_Registers *)(hspi->hdmarx)->StreamBaseAddress;

      /* Process locked */
//  __HAL_LOCK(hspi->hdmarx);
//  
//  if(HAL_DMA_STATE_READY == hspi->hdmarx->State)
//  {
    /* Change DMA peripheral state */
//    hspi->hdmarx->State = HAL_DMA_STATE_BUSY;

    /* Clear DBM bit */
    hspi->hdmarx->Instance->CR &= (uint32_t)(~DMA_SxCR_DBM);

    /* Configure DMA Stream destination address */
    hspi->hdmarx->Instance->M0AR = (uint32_t)(uint8_t *)DstAddress;

    /* Clear all interrupt flags at correct offset within the register */
//    regs->IFCR = 0x3FU << hspi->hdmarx->StreamIndex;

    /* Enable Common interrupts*/
    hspi->hdmarx->Instance->CR  |= DMA_IT_TC | DMA_IT_TE | DMA_IT_DME;
    hspi->hdmarx->Instance->FCR |= DMA_IT_FE;

    /* Enable the Peripheral */
    __HAL_DMA_ENABLE(hspi->hdmarx);
//  }
//  else
//  {
//    /* Process unlocked */
//    __HAL_UNLOCK(hspi->hdmarx);     
//    
//    /* Return error status */
//    status = HAL_BUSY;
//  }
      /* Check if the SPI is already enabled */
//  if((hspi->Instance->CR1 &SPI_CR1_SPE) != SPI_CR1_SPE)
//  {
//    /* Enable SPI peripheral */
//    __HAL_SPI_ENABLE(hspi);
//  }

  /* Enable the SPI Error Interrupt Bit */
  SET_BIT(hspi->Instance->CR2, SPI_CR2_ERRIE|SPI_CR2_RXDMAEN);

//  /* Enable Rx DMA Request */
//  SET_BIT(hspi->Instance->CR2, SPI_CR2_RXDMAEN);

//  return HAL_OK;
}



/*
*SPI 返回函数,打开SPI DMA开关,一次接收6个字节数据包
*/
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
    if(hspi==&hspi1)
    {           
        //HAL_SPI_DMAStop(hspi);//先关掉DMA
         /* Disable the SPI DMA Tx & Rx requests */
        CLEAR_BIT(hspi->Instance->CR2, SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN);//关掉DMA其实就是执行了这个操作
        if((gWritePtr + 1 == gReadPtr) || (gWritePtr == REV_MAX_NUM && gReadPtr == 0))//我的数据存储在一个二维数组中,这里判断满了
            return ;
        gWritePtr++;
        if (gWritePtr==REV_MAX_NUM) gWritePtr=0;        
        FPGA_ReadBuffer(hspi,FpgaRevData[gWritePtr]);       
    }
}

当SPI DMA硬件初始化(SPI DMA mode为DMA_NORMAL)后,就可以开始一次初始
化HAL_SPI_Receive_DMA_INIT,之后,当有数据到来,SPI接收完成返回函数会被调用,在返回函数中,首先关掉DMA,接收到数据后,提供下一次接收数据的地址,重新打开DMA。