395 lines
12 KiB
C
395 lines
12 KiB
C
/*
|
|
******************************************************************************
|
|
* @file driver_dma.c
|
|
* @author FreqChip Firmware Team
|
|
* @version V1.0.0
|
|
* @date 2021
|
|
* @brief DMA module driver.
|
|
* This file provides firmware functions to manage the
|
|
* Direct Memory Access (DMA) peripheral
|
|
******************************************************************************
|
|
* @attention
|
|
*
|
|
* Copyright (c) 2021 FreqChip.
|
|
* All rights reserved.
|
|
******************************************************************************
|
|
*/
|
|
#include "fr30xx.h"
|
|
|
|
/*********************************************************************
|
|
* @fn dma_init
|
|
*
|
|
* @brief Initialize the DMA according to the specified parameters
|
|
* in the dma_InitParameter_t
|
|
*
|
|
* @param hdma : pointer to a DMA_HandleTypeDef structure that contains
|
|
* the configuration information for DMA module
|
|
*
|
|
* @return None.
|
|
*/
|
|
void dma_init(DMA_HandleTypeDef *hdma)
|
|
{
|
|
struct_DMA_t *DMA = hdma->DMAx;
|
|
|
|
/* FIFO_MODE_1 */
|
|
DMA->Channels[hdma->Channel].CFG2.FIFO_MODE = 1;
|
|
|
|
/* Clear Linked List Pointer Register */
|
|
DMA->Channels[hdma->Channel].LLP.LOC = 0;
|
|
DMA->Channels[hdma->Channel].LLP.LMS = 0;
|
|
|
|
/* Interrupt Enable */
|
|
DMA->Channels[hdma->Channel].CTL1.INT_EN = 1;
|
|
|
|
/* Bus Master Selection */
|
|
DMA->Channels[hdma->Channel].CTL1.SMS = hdma->Init.Source_Master_Sel;
|
|
DMA->Channels[hdma->Channel].CTL1.DMS = hdma->Init.Desination_Master_Sel;
|
|
|
|
/* Transfer Width */
|
|
DMA->Channels[hdma->Channel].CTL1.SRC_TR_WIDTH = hdma->Init.Source_Width;
|
|
DMA->Channels[hdma->Channel].CTL1.DST_TR_WIDTH = hdma->Init.Desination_Width;
|
|
|
|
/* Burst Length */
|
|
DMA->Channels[hdma->Channel].CTL1.DEST_MSIZE = hdma->Init.Desination_Burst_Len;
|
|
DMA->Channels[hdma->Channel].CTL1.SRC_MSIZE = hdma->Init.Source_Burst_Len;
|
|
|
|
/* Address Increment */
|
|
DMA->Channels[hdma->Channel].CTL1.SINC = hdma->Init.Source_Inc;
|
|
DMA->Channels[hdma->Channel].CTL1.DINC = hdma->Init.Desination_Inc;
|
|
|
|
/* DMA Data Flow */
|
|
DMA->Channels[hdma->Channel].CTL1.TT_FC = hdma->Init.Data_Flow;
|
|
|
|
/* Set Peripheral Request ID */
|
|
if (hdma->Init.Data_Flow == DMA_M2P_DMAC)
|
|
{
|
|
DMA->Channels[hdma->Channel].CFG2.DEST_PER = hdma->Init.Request_ID;
|
|
}
|
|
else if (hdma->Init.Data_Flow == DMA_P2M_DMAC)
|
|
{
|
|
DMA->Channels[hdma->Channel].CFG2.SRC_PER = hdma->Init.Request_ID;
|
|
}
|
|
|
|
/* Hardware handshaking interface */
|
|
DMA->Channels[hdma->Channel].CFG1.HS_SEL_SRC = 0;
|
|
DMA->Channels[hdma->Channel].CFG1.HS_SEL_DST = 0;
|
|
|
|
/* AHB dmac Enabled */
|
|
DMA->Misc_Reg.DmaCfgReg.DMA_EN = 1;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn dma_start
|
|
*
|
|
* @brief DMA transfer start.
|
|
*
|
|
* @param hdma : pointer to a DMA_HandleTypeDef structure that contains
|
|
* the configuration information for DMA module
|
|
* SrcAddr: source address
|
|
* DstAddr: desination address
|
|
* Size: transfer size (This parameter can be a 12-bit Size)
|
|
* @return None.
|
|
*/
|
|
void dma_start(DMA_HandleTypeDef *hdma, uint32_t SrcAddr, uint32_t DstAddr, uint32_t Size)
|
|
{
|
|
struct_DMA_t *DMA = hdma->DMAx;
|
|
|
|
/* Set source address and desination address */
|
|
DMA->Channels[hdma->Channel].SAR = SrcAddr;
|
|
DMA->Channels[hdma->Channel].DAR = DstAddr;
|
|
|
|
/* Set Transfer Size */
|
|
DMA->Channels[hdma->Channel].CTL2.BLOCK_TS = Size;
|
|
|
|
/* Enable the channel */
|
|
DMA->Misc_Reg.ChEnReg |= (1 << hdma->Channel | (1 << (hdma->Channel + 8)));
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn dma_start_IT
|
|
*
|
|
* @brief DMA transfer start and enable interrupt
|
|
*
|
|
* @param hdma : pointer to a DMA_HandleTypeDef structure that contains
|
|
* the configuration information for DMA module
|
|
* SrcAddr: source address
|
|
* DstAddr: desination address
|
|
* Size: transfer size (This parameter can be a 12-bit Size)
|
|
* @return None.
|
|
*/
|
|
void dma_start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddr, uint32_t DstAddr, uint32_t Size)
|
|
{
|
|
struct_DMA_t *DMA = hdma->DMAx;
|
|
|
|
/* Set source address and desination address */
|
|
DMA->Channels[hdma->Channel].SAR = SrcAddr;
|
|
DMA->Channels[hdma->Channel].DAR = DstAddr;
|
|
|
|
/* Set Transfer Size */
|
|
DMA->Channels[hdma->Channel].CTL2.BLOCK_TS = Size;
|
|
|
|
/* Clear Transfer complete status */
|
|
dma_clear_tfr_Status(hdma);
|
|
/* channel Transfer complete interrupt enable */
|
|
dma_tfr_interrupt_enable(hdma);
|
|
|
|
/* Enable the channel */
|
|
DMA->Misc_Reg.ChEnReg |= (1 << hdma->Channel | (1 << (hdma->Channel + 8)));
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn dma_linked_list_init
|
|
*
|
|
* @brief Initialize the linked list parameters
|
|
*
|
|
* @param link : The list structure that needs to be initialized
|
|
* param: Initialization parameter
|
|
* @return None
|
|
*/
|
|
void dma_linked_list_init(DMA_LLI_InitTypeDef *link, dma_LinkParameter_t *param)
|
|
{
|
|
link->SrcAddr = param->SrcAddr;
|
|
link->DstAddr = param->DstAddr;
|
|
link->Next = (DMA_LLI_InitTypeDef *)param->NextLink;
|
|
|
|
link->CTL1.INT_EN = 1;
|
|
link->CTL1.SRC_TR_WIDTH = param->Source_Width;
|
|
link->CTL1.DST_TR_WIDTH = param->Desination_Width;
|
|
link->CTL1.SMS = param->Source_Master_Sel;
|
|
link->CTL1.DMS = param->Desination_Master_Sel;
|
|
link->CTL1.SINC = param->Source_Inc;
|
|
link->CTL1.DINC = param->Desination_Inc;
|
|
link->CTL1.TT_FC = param->Data_Flow;
|
|
link->CTL1.DEST_MSIZE = param->Desination_Burst_Len;
|
|
link->CTL1.SRC_MSIZE = param->Source_Burst_Len;
|
|
link->CTL1.SRC_GATHER_EN = param->gather_enable;
|
|
link->CTL1.DST_SCATTER_EN = param->scatter_enable;
|
|
link->CTL2.BLOCK_TS = param->Size;
|
|
|
|
/* Block chaining using Linked List is enabled on the Source side */
|
|
/* Block chaining using Linked List is enabled on the Destination side */
|
|
link->CTL1.LLP_DST_EN = 1;
|
|
link->CTL1.LLP_SRC_EN = 1;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn dma_linked_list_start.
|
|
*
|
|
* @brief DMA linked list transfer start.
|
|
*
|
|
* @param link : The first address of the linked list
|
|
* param : Initialization parameter
|
|
* hdma : DMA handle
|
|
*
|
|
* @return None
|
|
*/
|
|
void dma_linked_list_start(DMA_HandleTypeDef *hdma, DMA_LLI_InitTypeDef *link, dma_LinkParameter_t *param)
|
|
{
|
|
struct_DMA_t *DMA = hdma->DMAx;
|
|
uint32_t Channel = hdma->Channel;
|
|
|
|
/* Set Peripheral Request ID */
|
|
if (link->CTL1.TT_FC == DMA_M2P_DMAC)
|
|
{
|
|
DMA->Channels[Channel].CFG2.DEST_PER = param->Request_ID;
|
|
}
|
|
else if (link->CTL1.TT_FC == DMA_P2M_DMAC)
|
|
{
|
|
DMA->Channels[Channel].CFG2.SRC_PER = param->Request_ID;
|
|
}
|
|
|
|
/* Hardware handshaking interface */
|
|
DMA->Channels[Channel].CFG1.HS_SEL_SRC = 0;
|
|
DMA->Channels[Channel].CFG1.HS_SEL_DST = 0;
|
|
|
|
/* Block chaining using Linked List is enabled on the Source side */
|
|
/* Block chaining using Linked List is enabled on the Destination side */
|
|
DMA->Channels[Channel].CTL1.LLP_DST_EN = link->CTL1.LLP_DST_EN;
|
|
DMA->Channels[Channel].CTL1.LLP_SRC_EN = link->CTL1.LLP_SRC_EN;
|
|
|
|
DMA->Channels[Channel].LLP.LOC = ((uint32_t)link) >> 2;
|
|
|
|
/* AHB dmac Enabled */
|
|
DMA->Misc_Reg.DmaCfgReg.DMA_EN = 1;
|
|
|
|
DMA->Misc_Reg.ChEnReg |= (1 << Channel | (1 << (Channel + 8)));
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn dma_linked_list_start_IT
|
|
*
|
|
* @brief DMA linked list transfer start and enable interrupt
|
|
*
|
|
* @param link : The first address of the linked list
|
|
* param : Initialization parameter
|
|
* hdma : DMA handle
|
|
*
|
|
* @return None
|
|
*/
|
|
void dma_linked_list_start_IT(DMA_HandleTypeDef *hdma, DMA_LLI_InitTypeDef *link, dma_LinkParameter_t *param)
|
|
{
|
|
struct_DMA_t *DMA = hdma->DMAx;
|
|
uint32_t Channel = hdma->Channel;
|
|
|
|
/* Set Peripheral Request ID */
|
|
if (link->CTL1.TT_FC == DMA_M2P_DMAC)
|
|
{
|
|
DMA->Channels[Channel].CFG2.DEST_PER = param->Request_ID;
|
|
}
|
|
else if (link->CTL1.TT_FC == DMA_P2M_DMAC)
|
|
{
|
|
DMA->Channels[Channel].CFG2.SRC_PER = param->Request_ID;
|
|
}
|
|
|
|
/* Hardware handshaking interface */
|
|
DMA->Channels[Channel].CFG1.HS_SEL_SRC = 0;
|
|
DMA->Channels[Channel].CFG1.HS_SEL_DST = 0;
|
|
|
|
DMA->Channels[Channel].CTL1.LLP_DST_EN = link->CTL1.LLP_DST_EN;
|
|
DMA->Channels[Channel].CTL1.LLP_SRC_EN = link->CTL1.LLP_SRC_EN;
|
|
|
|
DMA->Channels[Channel].LLP.LOC = ((uint32_t)link) >> 2;
|
|
|
|
/* Clear Transfer complete status */
|
|
dma_clear_tfr_Status(hdma);
|
|
/* channel Transfer complete interrupt enable */
|
|
dma_tfr_interrupt_enable(hdma);
|
|
|
|
/* AHB dmac Enabled */
|
|
DMA->Misc_Reg.DmaCfgReg.DMA_EN = 1;
|
|
|
|
DMA->Misc_Reg.ChEnReg |= (1 << Channel | (1 << (Channel + 8)));
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn dma_tfr_interrupt_enable
|
|
*
|
|
* @brief channel transfer complete interrupt enable
|
|
*
|
|
* @param hdma : DMA handle
|
|
*
|
|
* @return None
|
|
*/
|
|
void dma_tfr_interrupt_enable(DMA_HandleTypeDef *hdma)
|
|
{
|
|
hdma->DMAx->Int_Reg.MaskTfr = (1 << (hdma->Channel)) | (1 << ((hdma->Channel) + 8));
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn dma_tfr_interrupt_disable
|
|
*
|
|
* @brief channel transfer complete interrupt disable
|
|
*
|
|
* @param hdma : DMA handle
|
|
*
|
|
* @return None
|
|
*/
|
|
void dma_tfr_interrupt_disable(DMA_HandleTypeDef *hdma)
|
|
{
|
|
hdma->DMAx->Int_Reg.MaskTfr = (1 << ((hdma->Channel) + 8));
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn dma_get_tfr_Status
|
|
*
|
|
* @brief Get channel transfer complete status
|
|
*
|
|
* @param hdma : DMA handle
|
|
*
|
|
* @return true: channel Transfer complete
|
|
* false: Not
|
|
*/
|
|
bool dma_get_tfr_Status(DMA_HandleTypeDef *hdma)
|
|
{
|
|
/* Check channel Transfer complete */
|
|
if (hdma->DMAx->Int_Reg.RawTfr & (1 << (hdma->Channel)))
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn dma_clear_tfr_Status
|
|
*
|
|
* @brief clear channel transfer complete status
|
|
*
|
|
* @param hdma : DMA handle
|
|
*
|
|
* @return None
|
|
*/
|
|
void dma_clear_tfr_Status(DMA_HandleTypeDef *hdma)
|
|
{
|
|
/* Clear channel Transfer complete Status */
|
|
hdma->DMAx->Int_Reg.ClearTfr = 1 << (hdma->Channel);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn dma_tfr_interrupt_enable
|
|
*
|
|
* @brief channel transfer complete interrupt enable
|
|
*
|
|
* @param hdma : DMA handle
|
|
*
|
|
* @return None
|
|
*/
|
|
void dma_error_interrupt_enable(DMA_HandleTypeDef *hdma)
|
|
{
|
|
hdma->DMAx->Int_Reg.MaskErr = (1 << (hdma->Channel)) | (1 << ((hdma->Channel) + 8));
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn dma_tfr_interrupt_disable
|
|
*
|
|
* @brief channel transfer complete interrupt disable
|
|
*
|
|
* @param hdma : DMA handle
|
|
*
|
|
* @return None
|
|
*/
|
|
void dma_error_interrupt_disable(DMA_HandleTypeDef *hdma)
|
|
{
|
|
hdma->DMAx->Int_Reg.MaskErr = (1 << ((hdma->Channel) + 8));
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn dma_get_tfr_Status
|
|
*
|
|
* @brief Get channel transfer complete status
|
|
*
|
|
* @param hdma : DMA handle
|
|
*
|
|
* @return true: channel Transfer complete
|
|
* false: Not
|
|
*/
|
|
bool dma_get_error_Status(DMA_HandleTypeDef *hdma)
|
|
{
|
|
/* Check channel Transfer complete */
|
|
if (hdma->DMAx->Int_Reg.RawErr & (1 << (hdma->Channel)))
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn dma_clear_tfr_Status
|
|
*
|
|
* @brief clear channel transfer complete status
|
|
*
|
|
* @param hdma : DMA handle
|
|
*
|
|
* @return None
|
|
*/
|
|
void dma_clear_error_Status(DMA_HandleTypeDef *hdma)
|
|
{
|
|
/* Clear channel Transfer complete Status */
|
|
hdma->DMAx->Int_Reg.ClearErr = 1 << (hdma->Channel);
|
|
}
|