2022-02-18 11:27:58 +08:00

482 lines
14 KiB
C

#include "wm_dma.h"
#include "wm_cpu.h"
static void DMA_SetConfig(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint16_t DataLength);
/**
* @breief Initialize the DMA according to the specified
* parameters in the DMA_InitTypeDef and initialize the associated handle.
* @param hdma: Pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DMA_Init(DMA_HandleTypeDef *hdma)
{
uint32_t temp = 0;
DMA_LinkDescriptor *desc;
if (hdma == NULL)
{
return HAL_ERROR;
}
assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance));
assert_param(IS_DMA_DIRECTION(hdma->Init.Direction));
assert_param(IS_DMA_DEST_INC_STATE(hdma->Init.DestInc));
assert_param(IS_DMA_SRC_INC_STATE(hdma->Init.SrcInc));
assert_param(IS_DMA_DATA_SIZE(hdma->Init.DataAlignment));
assert_param(IS_DMA_MODE(hdma->Init.Mode));
hdma->DmaBaseAddress = DMA;
hdma->ChannelIndex = (((uint32_t)hdma->Instance - (uint32_t)DMA_Channel0) / ((uint32_t)DMA_Channel1 - (uint32_t)DMA_Channel0));
hdma->State = HAL_DMA_STATE_BUSY;
CLEAR_REG(hdma->Instance->CR2);
CLEAR_REG(hdma->Instance->MODE);
WRITE_REG(hdma->Instance->MODE, hdma->Init.Direction);
if ((hdma->Init.Direction == DMA_PERIPH_TO_MEMORY) || (hdma->Init.Direction == DMA_MEMORY_TO_PERIPH))
{
assert_param(IS_DMA_REQUEST_SOURCE(hdma->Init.RequestSourceSel));
MODIFY_REG(hdma->Instance->MODE, DMA_MODE_CH, hdma->Init.RequestSourceSel);
if ((hdma->Init.RequestSourceSel == DMA_REQUEST_SOURCE_UART_RX) || (hdma->Init.RequestSourceSel == DMA_REQUEST_SOURCE_UART_TX))
{
assert_param(IS_DMA_UART_CHANNEL(hdma->Init.RequestUartSel));
MODIFY_REG(hdma->DmaBaseAddress->REQCH, DMA_REQCH_UART, hdma->Init.RequestUartSel);
}
}
if ((hdma->Init.Mode == DMA_MODE_NORMAL_SINGLE) || (hdma->Init.Mode == DMA_MODE_NORMAL_CIRCULAR))
{
WRITE_REG(hdma->Instance->CR2, (hdma->Init.DataAlignment | hdma->Init.DestInc | hdma->Init.SrcInc));
if (hdma->Init.Mode == DMA_MODE_NORMAL_CIRCULAR)
{
SET_BIT(hdma->Instance->CR2, DMA_CR2_AUTORELOAD);
}
}
else if ((hdma->Init.Mode == DMA_MODE_LINK_SINGLE) || (hdma->Init.Mode == DMA_MODE_LINK_CIRCULAR))
{
SET_BIT(hdma->Instance->MODE, (DMA_MODE_LNM | DMA_MODE_LINK));
desc = hdma->LinkDesc;
temp = (hdma->Init.DataAlignment | hdma->Init.DestInc | hdma->Init.SrcInc) >> 1;
desc[0].Valid = 0;
desc[0].Control = temp;
desc[0].Next = (DMA_LinkDescriptor *)&desc[1];
desc[1].Valid = 0;
desc[1].Control = temp;
if (hdma->Init.Mode == DMA_MODE_LINK_CIRCULAR)
{
desc[1].Next = (DMA_LinkDescriptor *)&desc[0];
}
else if(hdma->Init.Mode == DMA_MODE_LINK_SINGLE)
{
desc[1].Next = NULL;
}
}
hdma->ErrorCode = HAL_DMA_ERROR_NONE;
hdma->State = HAL_DMA_STATE_READY;
hdma->Lock = HAL_UNLOCKED;
return HAL_OK;
}
/**
* @brief DeInitialize the DMA peripheral.
* @param hdma: pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DMA_DeInit (DMA_HandleTypeDef *hdma)
{
if (hdma == NULL)
{
return HAL_ERROR;
}
assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance));
__HAL_DMA_DISABLE(hdma);
hdma->Instance->SA = 0U;
hdma->Instance->DA = 0U;
hdma->Instance->SWA = 0U;
hdma->Instance->DWA = 0U;
hdma->Instance->LA = 0U;
hdma->Instance->CR1 = 0U;
hdma->Instance->MODE = 0U;
hdma->Instance->CR2 = 0U;
hdma->DmaBaseAddress->IF = ((DMA_IF_TRANSFER_DONE | DMA_IF_BURST_DONE) << (hdma->ChannelIndex * 2));
hdma->ErrorCode = HAL_DMA_ERROR_NONE;
hdma->State = HAL_DMA_STATE_RESET;
__HAL_UNLOCK(hdma);
return HAL_OK;
}
/**
* @brief Start the DMA Transfer.
* @param hdma: pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @param SrcAddress: The source memory Buffer address
* @param DstAddress: The destination memory Buffer address
* @param DataLength: The length of data to be transferred from source to destination. Unit: Byte
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DMA_Start(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint16_t DataLength)
{
HAL_StatusTypeDef status = HAL_OK;
assert_param(IS_DMA_BUFFER_SIZE(DataLength));
__HAL_LOCK(hdma);
if (HAL_DMA_STATE_READY == hdma->State)
{
hdma->State = HAL_DMA_STATE_BUSY;
hdma->ErrorCode = HAL_DMA_ERROR_NONE;
__HAL_DMA_DISABLE(hdma);
DMA_SetConfig(hdma, SrcAddress, DstAddress, DataLength);
__HAL_DMA_ENABLE(hdma);
}
else
{
__HAL_UNLOCK(hdma);
status = HAL_BUSY;
}
return status;
}
/**
* @brief Start the DMA Transfer with interrupt enabled.
* @param hdma: pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @param SrcAddress: The source memory Buffer address
* @param DstAddress: The destination memory Buffer address
* @param DataLength: The length of data to be transferred from source to destination. Unit: Byte
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint16_t DataLength)
{
HAL_StatusTypeDef status = HAL_OK;
assert_param(IS_DMA_BUFFER_SIZE(DataLength));
__HAL_LOCK(hdma);
if (HAL_DMA_STATE_READY == hdma->State)
{
hdma->State = HAL_DMA_STATE_BUSY;
hdma->ErrorCode = HAL_DMA_ERROR_NONE;
__HAL_DMA_DISABLE(hdma);
DMA_SetConfig(hdma, SrcAddress, DstAddress, DataLength);
__HAL_DMA_ENABLE_IT(hdma, (DMA_FLAG_TF_DONE << (hdma->ChannelIndex * 2)));
__HAL_DMA_ENABLE(hdma);
}
else
{
__HAL_UNLOCK(hdma);
status = HAL_BUSY;
}
return status;
}
/**
* @brief Abort the DMA Transfer.
* @param hdma: pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DMA_Abort(DMA_HandleTypeDef *hdma)
{
HAL_StatusTypeDef status = HAL_OK;
if (hdma->State != HAL_DMA_STATE_BUSY)
{
hdma->ErrorCode = HAL_DMA_ERROR_NO_XFER;
__HAL_UNLOCK(hdma);
return HAL_ERROR;
}
else
{
__HAL_DMA_DISABLE_IT(hdma, ((DMA_IF_TRANSFER_DONE | DMA_IF_BURST_DONE) << (hdma->ChannelIndex * 2)));
__HAL_DMA_DISABLE(hdma);
__HAL_DMA_CLEAR_FLAG(hdma, ((DMA_IF_TRANSFER_DONE | DMA_IF_BURST_DONE) << (hdma->ChannelIndex * 2)));
}
hdma->State = HAL_DMA_STATE_READY;
__HAL_UNLOCK(hdma);
return status;
}
/**
* @brief Aborts the DMA Transfer in Interrupt mode.
* @param hdma : pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DMA_Abort_IT(DMA_HandleTypeDef *hdma)
{
HAL_StatusTypeDef status = HAL_OK;
if (hdma->State != HAL_DMA_STATE_BUSY)
{
hdma->ErrorCode = HAL_DMA_ERROR_NO_XFER;
status = HAL_ERROR;
}
else
{
__HAL_DMA_DISABLE_IT(hdma, ((DMA_IF_TRANSFER_DONE | DMA_IF_BURST_DONE) << (hdma->ChannelIndex * 2)));
__HAL_DMA_DISABLE(hdma);
__HAL_DMA_CLEAR_FLAG(hdma, ((DMA_IF_TRANSFER_DONE | DMA_IF_BURST_DONE) << (hdma->ChannelIndex * 2)));
hdma->State = HAL_DMA_STATE_READY;
__HAL_UNLOCK(hdma);
if (hdma->XferAbortCallback != NULL)
{
hdma->XferAbortCallback(hdma);
}
}
return status;
}
/**
* @brief Polling for transfer complete.
* @param hdma: pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @param CompleteLevel: Specifies the DMA level complete.
* @param Timeout: Timeout duration.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DMA_PollForTransfer(DMA_HandleTypeDef *hdma, HAL_DMA_LevelCompleteTypeDef CompleteLevel, uint32_t Timeout)
{
uint32_t tickstart = 0U;
uint32_t temp;
if (HAL_DMA_STATE_BUSY != hdma->State)
{
hdma->ErrorCode = HAL_DMA_ERROR_NO_XFER;
__HAL_UNLOCK(hdma);
return HAL_ERROR;
}
if ((hdma->Init.Mode == DMA_MODE_NORMAL_CIRCULAR) || (hdma->Init.Mode == DMA_MODE_LINK_CIRCULAR))
{
hdma->ErrorCode = HAL_DMA_ERROR_NOT_SUPPORTED;
return HAL_ERROR;
}
assert_param(IS_DMA_COMPLETELEVEL(CompleteLevel));
if ((CompleteLevel == HAL_DMA_HALF_TRANSFER) && (hdma->Init.Mode == DMA_MODE_NORMAL_SINGLE))
{
hdma->ErrorCode = HAL_DMA_ERROR_NOT_SUPPORTED;
return HAL_ERROR;
}
temp = DMA_FLAG_TF_DONE << (hdma->ChannelIndex * 2);
tickstart = HAL_GetTick();
while (1)
{
if (hdma->Init.Mode == DMA_MODE_NORMAL_SINGLE)
{
if (__HAL_DMA_GET_FLAG(hdma, temp) != RESET)
{
break;
}
}
else
{
if ((hdma->LinkDesc[CompleteLevel]).Valid == RESET)
{
break;
}
}
if (Timeout != HAL_MAX_DELAY)
{
if ((Timeout == 0U) || ((HAL_GetTick() - tickstart) > Timeout))
{
hdma->ErrorCode = HAL_DMA_ERROR_TIMEOUT;
hdma->State = HAL_DMA_STATE_READY;
__HAL_UNLOCK(hdma);
return HAL_ERROR;
}
}
}
__HAL_DMA_CLEAR_FLAG(hdma, temp);
hdma->State = HAL_DMA_STATE_READY;
__HAL_UNLOCK(hdma);
return HAL_OK;
}
/**
* @brief Handles DMA interrupt request.
* @param hdma: pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @retval None
*/
void HAL_DMA_IRQHandler(DMA_HandleTypeDef *hdma)
{
uint32_t source_it = hdma->DmaBaseAddress->IM;
uint32_t flag = DMA_FLAG_TF_DONE << (hdma->ChannelIndex * 2);
if ((__HAL_DMA_GET_FLAG(hdma, flag) != RESET) && ((source_it & flag) == RESET))
{
if (hdma->Init.Mode == DMA_MODE_NORMAL_SINGLE)
{
__HAL_DMA_DISABLE_IT(hdma, flag);
hdma->State = HAL_DMA_STATE_READY;
__HAL_UNLOCK(hdma);
if (hdma->XferCpltCallback != NULL)
{
hdma->XferCpltCallback(hdma);
}
}
else if (hdma->Init.Mode == DMA_MODE_NORMAL_CIRCULAR)
{
uint32_t cur_len = (hdma->Instance->CR2 & DMA_CR2_LEN_Msk) >> DMA_CR2_LEN_Pos;
if ((cur_len + hdma->offset) > 0xFFFF)
{
cur_len = 0;
__HAL_DMA_DISABLE(hdma);
__HAL_DMA_ENABLE(hdma);
}
MODIFY_REG(hdma->Instance->CR2, (uint32_t)(DMA_CR2_LEN_Msk),
(uint32_t)((cur_len + hdma->offset) << DMA_CR2_LEN_Pos));
if (hdma->XferCpltCallback != NULL)
{
hdma->XferCpltCallback(hdma);
}
}
else if ((hdma->Init.Mode == DMA_MODE_LINK_SINGLE) || (hdma->Init.Mode == DMA_MODE_LINK_CIRCULAR))
{
if (hdma->LinkDesc[0].Valid == 0)
{
hdma->LinkDesc[0].Valid = (1 << 31);
if (hdma->XferHalfCpltCallback != NULL)
{
hdma->XferHalfCpltCallback(hdma);
}
}
else if (hdma->LinkDesc[1].Valid == 0)
{
if (hdma->Init.Mode == DMA_MODE_LINK_SINGLE)
{
__HAL_DMA_DISABLE_IT(hdma, flag);
hdma->State = HAL_DMA_STATE_READY;
}
hdma->LinkDesc[1].Valid = (1 << 31);
__HAL_UNLOCK(hdma);
if (hdma->XferCpltCallback != NULL)
{
hdma->XferCpltCallback(hdma);
}
}
}
}
__HAL_DMA_CLEAR_FLAG(hdma, flag);
}
/**
* @brief Return the DMA hande state.
* @param hdma: pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @retval HAL state
*/
HAL_DMA_StateTypeDef HAL_DMA_GetState(DMA_HandleTypeDef *hdma)
{
return hdma->State;
}
/**
* @brief Return the DMA error code.
* @param hdma : pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @retval DMA Error Code
*/
uint32_t HAL_DMA_GetError(DMA_HandleTypeDef *hdma)
{
return hdma->ErrorCode;
}
/**
* @brief Sets the DMA Transfer parameter.
* @param hdma: pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @param SrcAddress: The source memory Buffer address
* @param DstAddress: The destination memory Buffer address
* @param DataLength: The length of data to be transferred from source to destination. Unit: Byte
* @retval HAL status
*/
static void DMA_SetConfig(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint16_t DataLength)
{
assert_param(IS_DMA_SRC_ADDR(SrcAddress));
assert_param(IS_DMA_DEST_ADDR(DstAddress));
assert_param(IS_DMA_LENGTH(hdma->Init.DataAlignment, DataLength));
hdma->DmaBaseAddress->IF = ((DMA_IF_TRANSFER_DONE | DMA_IF_BURST_DONE) << (hdma->ChannelIndex * 2));
if (hdma->Init.Mode == DMA_MODE_NORMAL_SINGLE)
{
hdma->Instance->SA = SrcAddress;
hdma->Instance->DA = DstAddress;
MODIFY_REG(hdma->Instance->CR2, DMA_CR2_LEN, (DataLength << DMA_CR2_LEN_Pos));
}
else if (hdma->Init.Mode == DMA_MODE_NORMAL_CIRCULAR)
{
hdma->Instance->SA = SrcAddress;
hdma->Instance->DA = DstAddress;
hdma->Instance->SWA = SrcAddress;
hdma->Instance->DWA = DstAddress;
hdma->Instance->WLEN = 0;
if (hdma->Init.SrcInc == DMA_SINC_CIRCULAR)
{
MODIFY_REG(hdma->Instance->WLEN, DMA_WLEN_S_Msk, (DataLength << DMA_WLEN_S_Pos));
}
if (hdma->Init.DestInc == DMA_DINC_CIRCULAR)
{
MODIFY_REG(hdma->Instance->WLEN, DMA_WLEN_D_Msk, (DataLength << DMA_WLEN_D_Pos));
}
hdma->offset = DataLength;
MODIFY_REG(hdma->Instance->CR2, DMA_CR2_LEN, (DataLength << DMA_CR2_LEN_Pos));
}
else
{
assert_param(IS_DMA_LINK_LENGTH(DataLength));
hdma->LinkDesc[0].Control |= ((DataLength / 2) << 7);
hdma->LinkDesc[0].Valid = (1 << 31);
hdma->LinkDesc[0].SrcAddr = SrcAddress;
hdma->LinkDesc[0].DestAddr = DstAddress;
hdma->LinkDesc[1].Control |= ((DataLength - (DataLength / 2)) << 7);
hdma->LinkDesc[1].Valid = (1 << 31);
if (hdma->Init.SrcInc == DMA_SINC_ENABLE)
{
hdma->LinkDesc[1].SrcAddr = SrcAddress + (DataLength / 2);
}
else
{
hdma->LinkDesc[1].SrcAddr = SrcAddress;
}
if (hdma->Init.DestInc == DMA_DINC_ENABLE)
{
hdma->LinkDesc[1].DestAddr = DstAddress + (DataLength / 2);
}
else
{
hdma->LinkDesc[1].DestAddr = DstAddress;
}
WRITE_REG(hdma->Instance->LA, (uint32_t)(hdma->LinkDesc));
}
}