Update version of EALib.

Dependencies:   FATFileSystem

Fork of EALib by IONX

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