mirror of
https://gitee.com/Lyon1998/pikapython.git
synced 2025-01-22 17:12:55 +08:00
482 lines
14 KiB
C
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));
|
|
}
|
|
}
|