A library with drivers for different peripherals on the LPC4088 QuickStart Board or related add-on boards.

Dependencies:   FATFileSystem

Fork of EALib by EmbeddedArtists AB

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers gpdma.cpp Source File

gpdma.cpp

00001 /*
00002  *  Copyright 2013 Embedded Artists AB
00003  *
00004  *  Licensed under the Apache License, Version 2.0 (the "License");
00005  *  you may not use this file except in compliance with the License.
00006  *  You may obtain a copy of the License at
00007  *
00008  *    http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  *  Unless required by applicable law or agreed to in writing, software
00011  *  distributed under the License is distributed on an "AS IS" BASIS,
00012  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  *  See the License for the specific language governing permissions and
00014  *  limitations under the License.
00015  */
00016 
00017 /******************************************************************************
00018  * Includes
00019  *****************************************************************************/
00020 
00021 #include "gpdma.h"
00022 
00023 /******************************************************************************
00024  * Defines and typedefs
00025  *****************************************************************************/
00026 
00027 #define NUM_GPDMA_CHANNELS  8
00028 
00029 #define GPDMACH(__x) ((LPC_GPDMACH_TypeDef*)(LPC_GPDMACH0_BASE + (0x20 * (__x))))
00030 
00031 #define CH_MASK(__ch)  (((1UL << (__ch)) & 0xFF))
00032 
00033 /**
00034  * @brief GPDMA request connections
00035  */
00036 #define GPDMA_CONN_MEMORY           ((0UL))
00037 #define GPDMA_CONN_SDC              ((1UL))      /*!< SD card */
00038 
00039 /**
00040  * @brief Macro defines for DMA channel control registers
00041  */
00042 #define GPDMA_DMACCxControl_TransferSize(n) (((n & 0xFFF) << 0))  /*!< Transfer size*/
00043 #define GPDMA_DMACCxControl_SBSize(n)       (((n & 0x07) << 12))  /*!< Source burst size*/
00044 #define GPDMA_DMACCxControl_DBSize(n)       (((n & 0x07) << 15))  /*!< Destination burst size*/
00045 #define GPDMA_DMACCxControl_SWidth(n)       (((n & 0x07) << 18))  /*!< Source transfer width*/
00046 #define GPDMA_DMACCxControl_DWidth(n)       (((n & 0x07) << 21))  /*!< Destination transfer width*/
00047 #define GPDMA_DMACCxControl_SI              ((1UL << 26))      /*!< Source increment*/
00048 #define GPDMA_DMACCxControl_DI              ((1UL << 27))      /*!< Destination increment*/
00049 #define GPDMA_DMACCxControl_SrcTransUseAHBMaster1   0
00050 #define GPDMA_DMACCxControl_DestTransUseAHBMaster1  0
00051 #define GPDMA_DMACCxControl_Prot1           ((1UL << 28))      /*!< Indicates that the access is in user mode or privileged mode*/
00052 #define GPDMA_DMACCxControl_Prot2           ((1UL << 29))      /*!< Indicates that the access is bufferable or not bufferable*/
00053 #define GPDMA_DMACCxControl_Prot3           ((1UL << 30))      /*!< Indicates that the access is cacheable or not cacheable*/
00054 #define GPDMA_DMACCxControl_I               ((1UL << 31))      /*!< Terminal count interrupt enable bit */
00055 
00056 /**
00057  * @brief GPDMA Burst size in Source and Destination definitions
00058  */
00059 #define GPDMA_BSIZE_1   ((0UL))  /*!< Burst size = 1 */
00060 #define GPDMA_BSIZE_4   ((1UL))  /*!< Burst size = 4 */
00061 #define GPDMA_BSIZE_8   ((2UL))  /*!< Burst size = 8 */
00062 #define GPDMA_BSIZE_16  ((3UL))  /*!< Burst size = 16 */
00063 #define GPDMA_BSIZE_32  ((4UL))  /*!< Burst size = 32 */
00064 #define GPDMA_BSIZE_64  ((5UL))  /*!< Burst size = 64 */
00065 #define GPDMA_BSIZE_128 ((6UL))  /*!< Burst size = 128 */
00066 #define GPDMA_BSIZE_256 ((7UL))  /*!< Burst size = 256 */
00067 
00068 /**
00069  * @brief Width in Source transfer width and Destination transfer width definitions
00070  */
00071 #define GPDMA_WIDTH_BYTE        ((0UL))  /*!< Width = 1 byte */
00072 #define GPDMA_WIDTH_HALFWORD    ((1UL))  /*!< Width = 2 bytes */
00073 #define GPDMA_WIDTH_WORD        ((2UL))  /*!< Width = 4 bytes */
00074 
00075 /**
00076  * @brief Macro defines for DMA Configuration register
00077  */
00078 #define GPDMA_DMACConfig_E              ((0x01))  /*!< DMA Controller enable*/
00079 #define GPDMA_DMACConfig_M              ((0x02))  /*!< AHB Master endianness configuration*/
00080 #define GPDMA_DMACConfig_BITMASK        ((0x03))
00081 
00082 /**
00083  * @brief Macro defines for DMA Channel Configuration registers
00084  */
00085 #define GPDMA_DMACCxConfig_E                    ((1UL << 0))      /*!< DMA control enable*/
00086 #define GPDMA_DMACCxConfig_SrcPeripheral(n)     (((n & 0x1F) << 1))    /*!< Source peripheral*/
00087 #define GPDMA_DMACCxConfig_DestPeripheral(n)    (((n & 0x1F) << 6))    /*!< Destination peripheral*/
00088 #define GPDMA_DMACCxConfig_TransferType(n)      (((n & 0x7) << 11))    /*!< This value indicates the type of transfer*/
00089 #define GPDMA_DMACCxConfig_IE                   ((1UL << 14))      /*!< Interrupt error mask*/
00090 #define GPDMA_DMACCxConfig_ITC                  ((1UL << 15))      /*!< Terminal count interrupt mask*/
00091 #define GPDMA_DMACCxConfig_L                    ((1UL << 16))      /*!< Lock*/
00092 #define GPDMA_DMACCxConfig_A                    ((1UL << 17))      /*!< Active*/
00093 #define GPDMA_DMACCxConfig_H                    ((1UL << 18))      /*!< Halt*/
00094 
00095 /**
00096  * @brief GPDMA structure using for DMA configuration
00097  */
00098 typedef struct {
00099   uint32_t ChannelNum;  /*!< DMA channel number, should be in
00100                *  range from 0 to 7.
00101                *  Note: DMA channel 0 has the highest priority
00102                *  and DMA channel 7 the lowest priority.
00103                */
00104   uint32_t TransferSize;  /*!< Length/Size of transfer */
00105   uint32_t TransferWidth;  /*!< Transfer width - used for TransferType is GPDMA_TRANSFERTYPE_M2M only */
00106   uint32_t SrcAddr;    /*!< Physical Source Address, used in case TransferType is chosen as
00107                *   GPDMA_TRANSFERTYPE_M2M or GPDMA_TRANSFERTYPE_M2P */
00108   uint32_t DstAddr;    /*!< Physical Destination Address, used in case TransferType is chosen as
00109                *   GPDMA_TRANSFERTYPE_M2M or GPDMA_TRANSFERTYPE_P2M */
00110   uint32_t TransferType;  /*!< Transfer Type, should be one of the following:
00111                * - GPDMA_TRANSFERTYPE_M2M: Memory to memory - DMA control
00112                * - GPDMA_TRANSFERTYPE_M2P: Memory to peripheral - DMA control
00113                * - GPDMA_TRANSFERTYPE_P2M: Peripheral to memory - DMA control
00114                * - GPDMA_TRANSFERTYPE_P2P: Source peripheral to destination peripheral - DMA control
00115                */
00116 } GPDMA_Channel_CFG_T;
00117 
00118 /******************************************************************************
00119  * External global variables
00120  *****************************************************************************/
00121 
00122 /******************************************************************************
00123  * Local variables
00124  *****************************************************************************/
00125 
00126 static bool used_channels[NUM_GPDMA_CHANNELS];
00127 
00128 /******************************************************************************
00129  * Local Functions
00130  *****************************************************************************/
00131 
00132 static void gpdma_transfer(GPDMA_Channel_CFG_T* cfg,
00133                            uint32_t CtrlWord,
00134                            uint32_t LinkListItem,
00135                            uint8_t SrcPeripheral,
00136                            uint8_t DstPeripheral)
00137 {
00138   /* Get Channel pointer */
00139   LPC_GPDMACH_TypeDef* pCh = GPDMACH(cfg->ChannelNum);
00140 
00141   /* Reset the Interrupt status */
00142   LPC_GPDMA->IntTCClear = CH_MASK(cfg->ChannelNum);
00143   LPC_GPDMA->IntErrClr = CH_MASK(cfg->ChannelNum);
00144 
00145   /* Assign Linker List Item value */
00146   pCh->CLLI = LinkListItem;
00147 
00148   /* Enable DMA channels, little endian */
00149   LPC_GPDMA->Config = GPDMA_DMACConfig_E;
00150   while (!(LPC_GPDMA->Config & GPDMA_DMACConfig_E)) {}
00151 
00152   pCh->CSrcAddr = cfg->SrcAddr;
00153   pCh->CDestAddr = cfg->DstAddr;
00154 
00155   /* Configure DMA Channel, enable Error Counter and Terminate counter */
00156   pCh->CConfig = GPDMA_DMACCxConfig_IE
00157            | GPDMA_DMACCxConfig_ITC
00158            | GPDMA_DMACCxConfig_TransferType((uint32_t) cfg->TransferType)
00159            | GPDMA_DMACCxConfig_SrcPeripheral(SrcPeripheral)
00160            | GPDMA_DMACCxConfig_DestPeripheral(DstPeripheral);
00161 
00162   pCh->CControl = CtrlWord;
00163 
00164   /* Start the Channel */
00165   pCh->CConfig |= GPDMA_DMACCxConfig_E;
00166 }
00167 
00168 /******************************************************************************
00169  * Public Functions
00170  *****************************************************************************/
00171 
00172 void gpdma_init()
00173 {
00174   uint8_t i;
00175 
00176   /* Enable GPDMA master clock */
00177   LPC_SC->PCONP |= (1<<29);
00178 
00179   /* Reset all channel configuration register */
00180   for (i = 0; i < NUM_GPDMA_CHANNELS; i++) {
00181     GPDMACH(i)->CConfig = 0;
00182   }
00183 
00184   /* Clear all DMA interrupt and error flag */
00185   LPC_GPDMA->IntTCClear = 0xFF;
00186   LPC_GPDMA->IntErrClr  = 0xFF;
00187 
00188   /* Reset all channels are free */
00189   for (int i = 0; i < NUM_GPDMA_CHANNELS; i++)
00190   {
00191     used_channels[i] = false;
00192   }
00193 }
00194 
00195 void gpdma_deinit()
00196 {
00197   /* Disable GPDMA master clock */
00198   LPC_SC->PCONP &= ~(1<<29);
00199 }
00200 
00201 void gpdma_stop(uint8_t ChannelNum)
00202 {
00203   if (ChannelNum >= NUM_GPDMA_CHANNELS) {
00204     return;
00205   }
00206 
00207   /* Disable channel */
00208   GPDMACH(ChannelNum)->CConfig &= ~GPDMA_DMACCxConfig_E;
00209 
00210   /* check terminal count interrupt request status for DMA */
00211   if (LPC_GPDMA->IntTCStat & CH_MASK(ChannelNum)) {
00212     /* Clear terminate counter Interrupt pending */
00213     LPC_GPDMA->IntTCClear = CH_MASK(ChannelNum);
00214   }
00215 
00216   /* check status of the error interrupt for DMA channels */
00217   if (LPC_GPDMA->IntErrStat & CH_MASK(ChannelNum)) {
00218     /* clear the error interrupt request */
00219     LPC_GPDMA->IntErrClr = CH_MASK(ChannelNum);
00220   }
00221 
00222   used_channels[ChannelNum] = false;
00223 }
00224 
00225 bool gpdma_interrupt(uint8_t ChannelNum)
00226 {
00227   /* check status of DMA channel interrupts */
00228   if (LPC_GPDMA->IntStat & CH_MASK(ChannelNum)) {
00229     /* Check counter terminal status */
00230     if (LPC_GPDMA->IntTCStat & CH_MASK(ChannelNum)) {
00231       /* Clear terminate counter Interrupt pending */
00232       LPC_GPDMA->IntTCClear = CH_MASK(ChannelNum);
00233       return true;
00234     }
00235     /* Check error terminal status */
00236     if (LPC_GPDMA->IntErrStat & CH_MASK(ChannelNum)) {
00237       /* Clear error counter Interrupt pending */
00238       LPC_GPDMA->IntErrClr = CH_MASK(ChannelNum);
00239       return false;
00240     }
00241   }
00242   return false;
00243 }
00244 
00245 bool gpdma_getFreeChannel(uint8_t* pCh)
00246 {
00247   for (int i = 0; i < NUM_GPDMA_CHANNELS; i++)
00248   {
00249     if ((!used_channels[i]) && ((LPC_GPDMA->EnbldChns & CH_MASK(i)) == 0))
00250     {
00251       used_channels[i] = true;
00252       *pCh = i;
00253       return true;
00254     }
00255   }
00256   return false;
00257 }
00258 
00259 bool gpdma_transfer_to_mci(uint8_t ChannelNum,
00260                            uint32_t src,
00261                            uint32_t Size)
00262 {
00263   GPDMA_Channel_CFG_T cfg;
00264   cfg.ChannelNum = ChannelNum;
00265   cfg.TransferType = GPDMA_TRANSFERTYPE_M2P_CONTROLLER_PERIPHERAL;
00266   cfg.TransferSize = Size;
00267   cfg.TransferWidth = 0;
00268   cfg.SrcAddr = src;
00269   cfg.DstAddr = (uint32_t) (&LPC_MCI->FIFO);
00270 
00271   uint32_t ctrl_word =
00272       GPDMA_DMACCxControl_TransferSize((uint32_t) cfg.TransferSize)
00273           | GPDMA_DMACCxControl_SBSize(GPDMA_BSIZE_8)
00274           | GPDMA_DMACCxControl_DBSize(GPDMA_BSIZE_8)
00275           | GPDMA_DMACCxControl_SWidth(GPDMA_WIDTH_WORD)
00276           | GPDMA_DMACCxControl_DWidth(GPDMA_WIDTH_WORD)
00277           | GPDMA_DMACCxControl_DestTransUseAHBMaster1
00278           | GPDMA_DMACCxControl_SI
00279           | GPDMA_DMACCxControl_I;
00280 
00281   if (LPC_GPDMA->EnbldChns & CH_MASK(ChannelNum)) {
00282     /* This channel is enabled, return ERROR, need to release this channel first */
00283     return false;
00284   }
00285 
00286   /* Select SD card interface in the DMA MUX*/
00287   LPC_SC->DMAREQSEL &= ~(1 << 1);
00288 
00289   gpdma_transfer(&cfg, ctrl_word, 0, GPDMA_CONN_MEMORY, GPDMA_CONN_SDC);
00290   return true;
00291 }
00292 
00293 bool gpdma_transfer_from_mci(uint8_t ChannelNum,
00294                              uint32_t dst,
00295                              uint32_t Size)
00296 {
00297   GPDMA_Channel_CFG_T cfg;
00298   cfg.ChannelNum = ChannelNum;
00299   cfg.TransferType = GPDMA_TRANSFERTYPE_P2M_CONTROLLER_PERIPHERAL;
00300   cfg.TransferSize = Size;
00301   cfg.TransferWidth = 0;
00302   cfg.SrcAddr = (uint32_t) (&LPC_MCI->FIFO);
00303   cfg.DstAddr = dst;
00304 
00305   uint32_t ctrl_word =
00306       GPDMA_DMACCxControl_TransferSize((uint32_t) cfg.TransferSize)
00307           | GPDMA_DMACCxControl_SBSize(GPDMA_BSIZE_8)
00308           | GPDMA_DMACCxControl_DBSize(GPDMA_BSIZE_8)
00309           | GPDMA_DMACCxControl_SWidth(GPDMA_WIDTH_WORD)
00310           | GPDMA_DMACCxControl_DWidth(GPDMA_WIDTH_WORD)
00311           | GPDMA_DMACCxControl_SrcTransUseAHBMaster1
00312           | GPDMA_DMACCxControl_DI
00313           | GPDMA_DMACCxControl_I;
00314 
00315   if (LPC_GPDMA->EnbldChns & CH_MASK(ChannelNum)) {
00316     /* This channel is enabled, return ERROR, need to release this channel first */
00317     return false;
00318   }
00319 
00320   /* Select SD card interface in the DMA MUX*/
00321   LPC_SC->DMAREQSEL &= ~(1 << 1);
00322 
00323   gpdma_transfer(&cfg, ctrl_word, 0, GPDMA_CONN_SDC, GPDMA_CONN_MEMORY);
00324   return true;
00325 }
00326 
00327