Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: DM_HttpServer DM_USBHost
Dependents: lpc4088_displaymodule_emwin lpc4088_displaymodule_demo_sphere sampleGUI sampleEmptyGUI ... more
Fork of DMSupport by
FileSystems/gpdma.cpp
- Committer:
- embeddedartists
- Date:
- 2014-12-11
- Revision:
- 9:a33326afd686
- Parent:
- 0:6b68dac0d986
File content as of revision 9:a33326afd686:
/*
* Copyright 2014 Embedded Artists AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/******************************************************************************
* Includes
*****************************************************************************/
#include "gpdma.h"
/******************************************************************************
* Defines and typedefs
*****************************************************************************/
#define NUM_GPDMA_CHANNELS 8
#define GPDMACH(__x) ((LPC_GPDMACH_TypeDef*)(LPC_GPDMACH0_BASE + (0x20 * (__x))))
#define CH_MASK(__ch) (((1UL << (__ch)) & 0xFF))
/**
* @brief GPDMA request connections
*/
#define GPDMA_CONN_MEMORY ((0UL))
#define GPDMA_CONN_SDC ((1UL)) /*!< SD card */
/**
* @brief Macro defines for DMA channel control registers
*/
#define GPDMA_DMACCxControl_TransferSize(n) (((n & 0xFFF) << 0)) /*!< Transfer size*/
#define GPDMA_DMACCxControl_SBSize(n) (((n & 0x07) << 12)) /*!< Source burst size*/
#define GPDMA_DMACCxControl_DBSize(n) (((n & 0x07) << 15)) /*!< Destination burst size*/
#define GPDMA_DMACCxControl_SWidth(n) (((n & 0x07) << 18)) /*!< Source transfer width*/
#define GPDMA_DMACCxControl_DWidth(n) (((n & 0x07) << 21)) /*!< Destination transfer width*/
#define GPDMA_DMACCxControl_SI ((1UL << 26)) /*!< Source increment*/
#define GPDMA_DMACCxControl_DI ((1UL << 27)) /*!< Destination increment*/
#define GPDMA_DMACCxControl_SrcTransUseAHBMaster1 0
#define GPDMA_DMACCxControl_DestTransUseAHBMaster1 0
#define GPDMA_DMACCxControl_Prot1 ((1UL << 28)) /*!< Indicates that the access is in user mode or privileged mode*/
#define GPDMA_DMACCxControl_Prot2 ((1UL << 29)) /*!< Indicates that the access is bufferable or not bufferable*/
#define GPDMA_DMACCxControl_Prot3 ((1UL << 30)) /*!< Indicates that the access is cacheable or not cacheable*/
#define GPDMA_DMACCxControl_I ((1UL << 31)) /*!< Terminal count interrupt enable bit */
/**
* @brief GPDMA Burst size in Source and Destination definitions
*/
#define GPDMA_BSIZE_1 ((0UL)) /*!< Burst size = 1 */
#define GPDMA_BSIZE_4 ((1UL)) /*!< Burst size = 4 */
#define GPDMA_BSIZE_8 ((2UL)) /*!< Burst size = 8 */
#define GPDMA_BSIZE_16 ((3UL)) /*!< Burst size = 16 */
#define GPDMA_BSIZE_32 ((4UL)) /*!< Burst size = 32 */
#define GPDMA_BSIZE_64 ((5UL)) /*!< Burst size = 64 */
#define GPDMA_BSIZE_128 ((6UL)) /*!< Burst size = 128 */
#define GPDMA_BSIZE_256 ((7UL)) /*!< Burst size = 256 */
/**
* @brief Width in Source transfer width and Destination transfer width definitions
*/
#define GPDMA_WIDTH_BYTE ((0UL)) /*!< Width = 1 byte */
#define GPDMA_WIDTH_HALFWORD ((1UL)) /*!< Width = 2 bytes */
#define GPDMA_WIDTH_WORD ((2UL)) /*!< Width = 4 bytes */
/**
* @brief Macro defines for DMA Configuration register
*/
#define GPDMA_DMACConfig_E ((0x01)) /*!< DMA Controller enable*/
#define GPDMA_DMACConfig_M ((0x02)) /*!< AHB Master endianness configuration*/
#define GPDMA_DMACConfig_BITMASK ((0x03))
/**
* @brief Macro defines for DMA Channel Configuration registers
*/
#define GPDMA_DMACCxConfig_E ((1UL << 0)) /*!< DMA control enable*/
#define GPDMA_DMACCxConfig_SrcPeripheral(n) (((n & 0x1F) << 1)) /*!< Source peripheral*/
#define GPDMA_DMACCxConfig_DestPeripheral(n) (((n & 0x1F) << 6)) /*!< Destination peripheral*/
#define GPDMA_DMACCxConfig_TransferType(n) (((n & 0x7) << 11)) /*!< This value indicates the type of transfer*/
#define GPDMA_DMACCxConfig_IE ((1UL << 14)) /*!< Interrupt error mask*/
#define GPDMA_DMACCxConfig_ITC ((1UL << 15)) /*!< Terminal count interrupt mask*/
#define GPDMA_DMACCxConfig_L ((1UL << 16)) /*!< Lock*/
#define GPDMA_DMACCxConfig_A ((1UL << 17)) /*!< Active*/
#define GPDMA_DMACCxConfig_H ((1UL << 18)) /*!< Halt*/
/**
* @brief GPDMA structure using for DMA configuration
*/
typedef struct {
uint32_t ChannelNum; /*!< DMA channel number, should be in
* range from 0 to 7.
* Note: DMA channel 0 has the highest priority
* and DMA channel 7 the lowest priority.
*/
uint32_t TransferSize; /*!< Length/Size of transfer */
uint32_t TransferWidth; /*!< Transfer width - used for TransferType is GPDMA_TRANSFERTYPE_M2M only */
uint32_t SrcAddr; /*!< Physical Source Address, used in case TransferType is chosen as
* GPDMA_TRANSFERTYPE_M2M or GPDMA_TRANSFERTYPE_M2P */
uint32_t DstAddr; /*!< Physical Destination Address, used in case TransferType is chosen as
* GPDMA_TRANSFERTYPE_M2M or GPDMA_TRANSFERTYPE_P2M */
uint32_t TransferType; /*!< Transfer Type, should be one of the following:
* - GPDMA_TRANSFERTYPE_M2M: Memory to memory - DMA control
* - GPDMA_TRANSFERTYPE_M2P: Memory to peripheral - DMA control
* - GPDMA_TRANSFERTYPE_P2M: Peripheral to memory - DMA control
* - GPDMA_TRANSFERTYPE_P2P: Source peripheral to destination peripheral - DMA control
*/
} GPDMA_Channel_CFG_T;
/******************************************************************************
* External global variables
*****************************************************************************/
/******************************************************************************
* Local variables
*****************************************************************************/
static bool used_channels[NUM_GPDMA_CHANNELS];
/******************************************************************************
* Local Functions
*****************************************************************************/
static void gpdma_transfer(GPDMA_Channel_CFG_T* cfg,
uint32_t CtrlWord,
uint32_t LinkListItem,
uint8_t SrcPeripheral,
uint8_t DstPeripheral)
{
/* Get Channel pointer */
LPC_GPDMACH_TypeDef* pCh = GPDMACH(cfg->ChannelNum);
/* Reset the Interrupt status */
LPC_GPDMA->IntTCClear = CH_MASK(cfg->ChannelNum);
LPC_GPDMA->IntErrClr = CH_MASK(cfg->ChannelNum);
/* Assign Linker List Item value */
pCh->CLLI = LinkListItem;
/* Enable DMA channels, little endian */
LPC_GPDMA->Config = GPDMA_DMACConfig_E;
while (!(LPC_GPDMA->Config & GPDMA_DMACConfig_E)) {}
pCh->CSrcAddr = cfg->SrcAddr;
pCh->CDestAddr = cfg->DstAddr;
/* Configure DMA Channel, enable Error Counter and Terminate counter */
pCh->CConfig = GPDMA_DMACCxConfig_IE
| GPDMA_DMACCxConfig_ITC
| GPDMA_DMACCxConfig_TransferType((uint32_t) cfg->TransferType)
| GPDMA_DMACCxConfig_SrcPeripheral(SrcPeripheral)
| GPDMA_DMACCxConfig_DestPeripheral(DstPeripheral);
pCh->CControl = CtrlWord;
/* Start the Channel */
pCh->CConfig |= GPDMA_DMACCxConfig_E;
}
/******************************************************************************
* Public Functions
*****************************************************************************/
void gpdma_init()
{
uint8_t i;
/* Enable GPDMA master clock */
LPC_SC->PCONP |= (1<<29);
/* Reset all channel configuration register */
for (i = 0; i < NUM_GPDMA_CHANNELS; i++) {
GPDMACH(i)->CConfig = 0;
}
/* Clear all DMA interrupt and error flag */
LPC_GPDMA->IntTCClear = 0xFF;
LPC_GPDMA->IntErrClr = 0xFF;
/* Reset all channels are free */
for (int i = 0; i < NUM_GPDMA_CHANNELS; i++)
{
used_channels[i] = false;
}
}
void gpdma_deinit()
{
/* Disable GPDMA master clock */
LPC_SC->PCONP &= ~(1<<29);
}
void gpdma_stop(uint8_t ChannelNum)
{
if (ChannelNum >= NUM_GPDMA_CHANNELS) {
return;
}
/* Disable channel */
GPDMACH(ChannelNum)->CConfig &= ~GPDMA_DMACCxConfig_E;
/* check terminal count interrupt request status for DMA */
if (LPC_GPDMA->IntTCStat & CH_MASK(ChannelNum)) {
/* Clear terminate counter Interrupt pending */
LPC_GPDMA->IntTCClear = CH_MASK(ChannelNum);
}
/* check status of the error interrupt for DMA channels */
if (LPC_GPDMA->IntErrStat & CH_MASK(ChannelNum)) {
/* clear the error interrupt request */
LPC_GPDMA->IntErrClr = CH_MASK(ChannelNum);
}
used_channels[ChannelNum] = false;
}
bool gpdma_interrupt(uint8_t ChannelNum)
{
/* check status of DMA channel interrupts */
if (LPC_GPDMA->IntStat & CH_MASK(ChannelNum)) {
/* Check counter terminal status */
if (LPC_GPDMA->IntTCStat & CH_MASK(ChannelNum)) {
/* Clear terminate counter Interrupt pending */
LPC_GPDMA->IntTCClear = CH_MASK(ChannelNum);
return true;
}
/* Check error terminal status */
if (LPC_GPDMA->IntErrStat & CH_MASK(ChannelNum)) {
/* Clear error counter Interrupt pending */
LPC_GPDMA->IntErrClr = CH_MASK(ChannelNum);
return false;
}
}
return false;
}
bool gpdma_getFreeChannel(uint8_t* pCh)
{
for (int i = 0; i < NUM_GPDMA_CHANNELS; i++)
{
if ((!used_channels[i]) && ((LPC_GPDMA->EnbldChns & CH_MASK(i)) == 0))
{
used_channels[i] = true;
*pCh = i;
return true;
}
}
return false;
}
bool gpdma_transfer_to_mci(uint8_t ChannelNum,
uint32_t src,
uint32_t Size)
{
GPDMA_Channel_CFG_T cfg;
cfg.ChannelNum = ChannelNum;
cfg.TransferType = GPDMA_TRANSFERTYPE_M2P_CONTROLLER_PERIPHERAL;
cfg.TransferSize = Size;
cfg.TransferWidth = 0;
cfg.SrcAddr = src;
cfg.DstAddr = (uint32_t) (&LPC_MCI->FIFO);
uint32_t ctrl_word =
GPDMA_DMACCxControl_TransferSize((uint32_t) cfg.TransferSize)
| GPDMA_DMACCxControl_SBSize(GPDMA_BSIZE_8)
| GPDMA_DMACCxControl_DBSize(GPDMA_BSIZE_8)
| GPDMA_DMACCxControl_SWidth(GPDMA_WIDTH_WORD)
| GPDMA_DMACCxControl_DWidth(GPDMA_WIDTH_WORD)
| GPDMA_DMACCxControl_DestTransUseAHBMaster1
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_I;
if (LPC_GPDMA->EnbldChns & CH_MASK(ChannelNum)) {
/* This channel is enabled, return ERROR, need to release this channel first */
return false;
}
/* Select SD card interface in the DMA MUX*/
LPC_SC->DMAREQSEL &= ~(1 << 1);
gpdma_transfer(&cfg, ctrl_word, 0, GPDMA_CONN_MEMORY, GPDMA_CONN_SDC);
return true;
}
bool gpdma_transfer_from_mci(uint8_t ChannelNum,
uint32_t dst,
uint32_t Size)
{
GPDMA_Channel_CFG_T cfg;
cfg.ChannelNum = ChannelNum;
cfg.TransferType = GPDMA_TRANSFERTYPE_P2M_CONTROLLER_PERIPHERAL;
cfg.TransferSize = Size;
cfg.TransferWidth = 0;
cfg.SrcAddr = (uint32_t) (&LPC_MCI->FIFO);
cfg.DstAddr = dst;
uint32_t ctrl_word =
GPDMA_DMACCxControl_TransferSize((uint32_t) cfg.TransferSize)
| GPDMA_DMACCxControl_SBSize(GPDMA_BSIZE_8)
| GPDMA_DMACCxControl_DBSize(GPDMA_BSIZE_8)
| GPDMA_DMACCxControl_SWidth(GPDMA_WIDTH_WORD)
| GPDMA_DMACCxControl_DWidth(GPDMA_WIDTH_WORD)
| GPDMA_DMACCxControl_SrcTransUseAHBMaster1
| GPDMA_DMACCxControl_DI
| GPDMA_DMACCxControl_I;
if (LPC_GPDMA->EnbldChns & CH_MASK(ChannelNum)) {
/* This channel is enabled, return ERROR, need to release this channel first */
return false;
}
/* Select SD card interface in the DMA MUX*/
LPC_SC->DMAREQSEL &= ~(1 << 1);
gpdma_transfer(&cfg, ctrl_word, 0, GPDMA_CONN_SDC, GPDMA_CONN_MEMORY);
return true;
}
