HAL_StatusTypeDef HAL_SPI_TransmitReceive_DMA()

in Drivers/STM32U5xx_HAL/Src/stm32u5xx_hal_spi.c [2300:2585]


HAL_StatusTypeDef HAL_SPI_TransmitReceive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData,
                                              uint16_t Size)
{
  HAL_SPI_StateTypeDef tmp_state;
  HAL_StatusTypeDef errorcode;

  uint32_t             tmp_mode;

  /* Check Direction parameter */
  assert_param(IS_SPI_DIRECTION_2LINES(hspi->Init.Direction));

  /* Lock the process */
  __HAL_LOCK(hspi);

  /* Init temporary variables */
  tmp_state   = hspi->State;
  tmp_mode    = hspi->Init.Mode;

  if (!((tmp_state == HAL_SPI_STATE_READY) || \
        ((tmp_mode == SPI_MODE_MASTER) && \
         (hspi->Init.Direction == SPI_DIRECTION_2LINES) && \
         (tmp_state == HAL_SPI_STATE_BUSY_RX))))
  {
    errorcode = HAL_BUSY;
    __HAL_UNLOCK(hspi);
    return errorcode;
  }

  if ((pTxData == NULL) || (pRxData == NULL) || (Size == 0UL))
  {
    errorcode = HAL_ERROR;
    __HAL_UNLOCK(hspi);
    return errorcode;
  }

  /* Don't overwrite in case of HAL_SPI_STATE_BUSY_RX */
  if (hspi->State != HAL_SPI_STATE_BUSY_RX)
  {
    hspi->State = HAL_SPI_STATE_BUSY_TX_RX;
  }

  /* Set the transaction information */
  hspi->ErrorCode   = HAL_SPI_ERROR_NONE;
  hspi->pTxBuffPtr  = (uint8_t *)pTxData;
  hspi->TxXferSize  = Size;
  hspi->TxXferCount = Size;
  hspi->pRxBuffPtr  = (uint8_t *)pRxData;
  hspi->RxXferSize  = Size;
  hspi->RxXferCount = Size;

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

  /* Reset the Tx/Rx DMA bits */
  CLEAR_BIT(hspi->Instance->CFG1, SPI_CFG1_TXDMAEN | SPI_CFG1_RXDMAEN);

  /* Packing mode management is enabled by the DMA settings */
  if (((hspi->Init.DataSize > SPI_DATASIZE_16BIT) && (hspi->hdmarx->Init.DestDataWidth != DMA_DEST_DATAWIDTH_WORD) && \
       (IS_SPI_FULL_INSTANCE(hspi->Instance))) || \
      ((hspi->Init.DataSize > SPI_DATASIZE_8BIT)  && (hspi->hdmarx->Init.DestDataWidth == DMA_DEST_DATAWIDTH_BYTE)))
  {
    /* Restriction the DMA data received is not allowed in this mode */
    errorcode = HAL_ERROR;
    /* Unlock the process */
    __HAL_UNLOCK(hspi);
    return errorcode;
  }

  /* Adjust XferCount according to DMA alignment / Data size */
  if (hspi->Init.DataSize <= SPI_DATASIZE_8BIT)
  {
    if (hspi->hdmatx->Init.SrcDataWidth == DMA_SRC_DATAWIDTH_HALFWORD)
    {
      hspi->TxXferCount = (hspi->TxXferCount + (uint16_t) 1UL) >> 1UL;
    }
    if (hspi->hdmatx->Init.SrcDataWidth == DMA_SRC_DATAWIDTH_WORD)
    {
      hspi->TxXferCount = (hspi->TxXferCount + (uint16_t) 3UL) >> 2UL;
    }
    if (hspi->hdmarx->Init.DestDataWidth == DMA_DEST_DATAWIDTH_HALFWORD)
    {
      hspi->RxXferCount = (hspi->RxXferCount + (uint16_t) 1UL) >> 1UL;
    }
    if (hspi->hdmarx->Init.DestDataWidth == DMA_DEST_DATAWIDTH_WORD)
    {
      hspi->RxXferCount = (hspi->RxXferCount + (uint16_t) 3UL) >> 2UL;
    }
  }
  else if (hspi->Init.DataSize <= SPI_DATASIZE_16BIT)
  {
    if (hspi->hdmatx->Init.SrcDataWidth == DMA_SRC_DATAWIDTH_WORD)
    {
      hspi->TxXferCount = (hspi->TxXferCount + (uint16_t) 1UL) >> 1UL;
    }
    if (hspi->hdmarx->Init.DestDataWidth == DMA_DEST_DATAWIDTH_WORD)
    {
      hspi->RxXferCount = (hspi->RxXferCount + (uint16_t) 1UL) >> 1UL;
    }
  }
  else
  {
    /* Adjustment done */
  }

  /* Check if we are in Rx only or in Rx/Tx Mode and configure the DMA transfer complete callback */
  if (hspi->State == HAL_SPI_STATE_BUSY_RX)
  {
    /* Set the SPI Rx DMA Half transfer complete callback */
    hspi->hdmarx->XferHalfCpltCallback = SPI_DMAHalfReceiveCplt;
    hspi->hdmarx->XferCpltCallback     = SPI_DMAReceiveCplt;
  }
  else
  {
    /* Set the SPI Tx/Rx DMA Half transfer complete callback */
    hspi->hdmarx->XferHalfCpltCallback = SPI_DMAHalfTransmitReceiveCplt;
    hspi->hdmarx->XferCpltCallback     = SPI_DMATransmitReceiveCplt;
  }

  /* Set the DMA error callback */
  hspi->hdmarx->XferErrorCallback = SPI_DMAError;

  /* Set the DMA AbortCallback */
  hspi->hdmarx->XferAbortCallback = NULL;

  if (hspi->Init.DataSize <= SPI_DATASIZE_8BIT)
  {
    hspi->RxXferCount = Size;
  }
  else if (hspi->Init.DataSize <= SPI_DATASIZE_16BIT)
  {
    hspi->RxXferCount = Size * 2U;
  }
  else
  {
    hspi->RxXferCount = Size * 4U;
  }
  /* Enable the Rx DMA Stream/Channel  */
  if ((hspi->hdmarx->Mode & DMA_LINKEDLIST) == DMA_LINKEDLIST)
  {
    if (hspi->hdmarx->LinkedListQueue != NULL)
    {
      /* Set DMA data size */
      hspi->hdmarx->LinkedListQueue->Head->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] = hspi->RxXferCount;

      /* Set DMA source address */
      hspi->hdmarx->LinkedListQueue->Head->LinkRegisters[NODE_CSAR_DEFAULT_OFFSET] = (uint32_t)&hspi->Instance->RXDR;

      /* Set DMA destination address */
      hspi->hdmarx->LinkedListQueue->Head->LinkRegisters[NODE_CDAR_DEFAULT_OFFSET] = (uint32_t)hspi->pRxBuffPtr;

      errorcode = HAL_DMAEx_List_Start_IT(hspi->hdmarx);
    }
    else
    {
      /* Update SPI error code */
      SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_DMA);

      /* Unlock the process */
      __HAL_UNLOCK(hspi);

      hspi->State = HAL_SPI_STATE_READY;
      errorcode = HAL_ERROR;
      return errorcode;
    }
  }
  else
  {
    errorcode = HAL_DMA_Start_IT(hspi->hdmarx, (uint32_t)&hspi->Instance->RXDR, (uint32_t)hspi->pRxBuffPtr,
                                 hspi->RxXferCount);
  }

  /* Check status */
  if (errorcode != HAL_OK)
  {
    /* Update SPI error code */
    SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_DMA);

    /* Unlock the process */
    __HAL_UNLOCK(hspi);

    hspi->State = HAL_SPI_STATE_READY;
    errorcode = HAL_ERROR;
    return errorcode;
  }

  /* Enable Rx DMA Request */
  SET_BIT(hspi->Instance->CFG1, SPI_CFG1_RXDMAEN);

  /* Set the SPI Tx DMA transfer complete callback as NULL because the communication closing
  is performed in DMA reception complete callback  */
  hspi->hdmatx->XferHalfCpltCallback = NULL;
  hspi->hdmatx->XferCpltCallback     = NULL;
  hspi->hdmatx->XferErrorCallback    = NULL;
  hspi->hdmatx->XferAbortCallback    = NULL;

  if (hspi->Init.DataSize <= SPI_DATASIZE_8BIT)
  {
    hspi->TxXferCount = Size;
  }
  else if (hspi->Init.DataSize <= SPI_DATASIZE_16BIT)
  {
    hspi->TxXferCount = Size * 2U;
  }
  else
  {
    hspi->TxXferCount = Size * 4U;
  }

  /* Enable the Tx DMA Stream/Channel  */
  if ((hspi->hdmatx->Mode & DMA_LINKEDLIST) == DMA_LINKEDLIST)
  {
    if (hspi->hdmatx->LinkedListQueue != NULL)
    {
      /* Set DMA data size */
      hspi->hdmatx->LinkedListQueue->Head->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] = hspi->TxXferCount;

      /* Set DMA source address */
      hspi->hdmatx->LinkedListQueue->Head->LinkRegisters[NODE_CSAR_DEFAULT_OFFSET] = (uint32_t)hspi->pTxBuffPtr;

      /* Set DMA destination address */
      hspi->hdmatx->LinkedListQueue->Head->LinkRegisters[NODE_CDAR_DEFAULT_OFFSET] = (uint32_t)&hspi->Instance->TXDR;

      errorcode = HAL_DMAEx_List_Start_IT(hspi->hdmatx);
    }
    else
    {
      /* Update SPI error code */
      SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_DMA);

      /* Unlock the process */
      __HAL_UNLOCK(hspi);

      hspi->State = HAL_SPI_STATE_READY;
      errorcode = HAL_ERROR;
      return errorcode;
    }
  }
  else
  {
    errorcode = HAL_DMA_Start_IT(hspi->hdmatx, (uint32_t)hspi->pTxBuffPtr, (uint32_t)&hspi->Instance->TXDR,
                                 hspi->TxXferCount);
  }

  /* Check status */
  if (errorcode != HAL_OK)
  {
    /* Update SPI error code */
    SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_DMA);

    /* Unlock the process */
    __HAL_UNLOCK(hspi);

    hspi->State = HAL_SPI_STATE_READY;
    errorcode = HAL_ERROR;
    return errorcode;
  }

  if ((hspi->hdmarx->Mode == DMA_LINKEDLIST_CIRCULAR) && (hspi->hdmatx->Mode == DMA_LINKEDLIST_CIRCULAR))
  {
    MODIFY_REG(hspi->Instance->CR2, SPI_CR2_TSIZE, 0UL);
  }
  else
  {
    MODIFY_REG(hspi->Instance->CR2, SPI_CR2_TSIZE, Size);
  }

  /* Enable Tx DMA Request */
  SET_BIT(hspi->Instance->CFG1, SPI_CFG1_TXDMAEN);

  /* Enable the SPI Error Interrupt Bit */
  __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_OVR | SPI_IT_UDR | SPI_IT_FRE | SPI_IT_MODF));

  /* Enable SPI peripheral */
  __HAL_SPI_ENABLE(hspi);

  if (((hspi->Instance->AUTOCR & SPI_AUTOCR_TRIGEN) == 0U) && (hspi->Init.Mode == SPI_MODE_MASTER))
  {
    /* Master transfer start */
    SET_BIT(hspi->Instance->CR1, SPI_CR1_CSTART);
  }

  /* Unlock the process */
  __HAL_UNLOCK(hspi);
  return errorcode;
}