STM32 SPI+DMA (HAL庫)使用方法

/*
* 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。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章