A library with drivers for different peripherals on the LPC4088 QuickStart Board or related add-on boards.
Dependencies: FATFileSystem
Fork of EALib by
Diff: gpdma.cpp
- Revision:
- 0:0fdadbc3d852
- Child:
- 12:15597e45eea0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gpdma.cpp Thu Sep 26 06:37:02 2013 +0000 @@ -0,0 +1,312 @@ + +/****************************************************************************** + * 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; +} + +