A board support package for the LPC4088 Display Module.

Dependencies:   DM_HttpServer DM_USBHost

Dependents:   lpc4088_displaymodule_emwin lpc4088_displaymodule_demo_sphere sampleGUI sampleEmptyGUI ... more

Fork of DMSupport by EmbeddedArtists AB

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers <title>GPDMA.cpp Source File</title>

GPDMA.cpp

00001 /*
00002  *  Copyright 2015 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 #include "mbed.h"
00018 #include "DMBoard.h"
00019 #include "GPDMA.h"
00020 
00021 
00022 /******************************************************************************
00023  * Defines and typedefs
00024  *****************************************************************************/
00025 
00026 #define GPDMACH(__x) ((LPC_GPDMACH_TypeDef*)(LPC_GPDMACH0_BASE + (0x20 * (__x))))
00027 
00028 #define CH_MASK(__ch)  (((1UL << (__ch)) & 0xFF))
00029 
00030 #define GPDMA_ALL_CH_MASK  (0xff)
00031 
00032 /******************************************************************************
00033  * Local variables
00034  *****************************************************************************/
00035 
00036 /******************************************************************************
00037  * Private Class
00038  *****************************************************************************/
00039 
00040 /******************************************************************************
00041  * DMA Interrupt Functon
00042  *****************************************************************************/
00043 
00044 static void mydmairq()
00045 {
00046   GPDMA::instance().processInterrupt();
00047 }
00048 
00049 /******************************************************************************
00050  * Private Functions
00051  *****************************************************************************/
00052 
00053 /******************************************************************************
00054  * Public Functions
00055  *****************************************************************************/
00056 
00057 GPDMA::GPDMA() : _usedChannels(0), _initialized(false)
00058 {
00059   for (int i = 0; i < NumDMAChannels; i++) {
00060     _chData[i].inUse = false;
00061     _chData[i].func = NULL;
00062   }
00063 
00064   /* Redirect all DMA IRQs to the local mydmairq() function */
00065   NVIC_SetVector(DMA_IRQn, (uint32_t) mydmairq);
00066 }
00067 
00068 GPDMA::~GPDMA()
00069 {
00070 }
00071 
00072 void GPDMA::init()
00073 {
00074   _mutex.lock();
00075   if (!_initialized) {
00076     /* Enable GPDMA master clock */
00077     LPC_SC->PCONP |= (1<<29);
00078 
00079     /* Reset all channel configuration register */
00080     for (int i = 0; i < NumDMAChannels; i++) {
00081       GPDMACH(i)->CConfig = 0;
00082     }
00083 
00084     /* Clear all DMA interrupt and error flag */
00085     LPC_GPDMA->IntTCClear = 0xFF;
00086     LPC_GPDMA->IntErrClr  = 0xFF;
00087 
00088     /* Reset all channel datas */
00089     for (int i = 0; i < NumDMAChannels; i++) {
00090       _chData[i].inUse = false;
00091       _chData[i].func = NULL;
00092     }
00093 
00094     _initialized = true;
00095   }
00096   _mutex.unlock();
00097 }
00098 
00099 void GPDMA::deinit()
00100 {
00101   _mutex.lock();
00102   if (_usedChannels == 0) {
00103     /* Disable the real interrupt */
00104     NVIC_DisableIRQ(DMA_IRQn);
00105 
00106     /* Clear all DMA interrupt and error flag */
00107     LPC_GPDMA->IntTCClear = 0xFF;
00108     LPC_GPDMA->IntErrClr  = 0xFF;
00109 
00110     /* Disable GPDMA master clock */
00111     LPC_SC->PCONP &= ~(1<<29);
00112 
00113     _initialized = false;
00114   }
00115   _mutex.unlock();
00116 }
00117 
00118 GPDMA::DMAChannels GPDMA::acquireChannel(void (*irqfunc)(void), DMAChannels suggested)
00119 {
00120   DMAChannels result = DMACh_Unavailable;
00121   _mutex.lock();
00122   if (!_initialized) {
00123     init();
00124   }
00125   for (int i = suggested; i < NumDMAChannels; i++) {
00126     if ((!_chData[i].inUse) && ((LPC_GPDMA->EnbldChns & CH_MASK(i)) == 0)) {
00127       _chData[i].inUse = true;
00128       _chData[i].func = irqfunc;
00129       result = (DMAChannels)i;
00130       _usedChannels++;
00131       break;
00132     }
00133   }
00134 
00135   _mutex.unlock();
00136   return result;
00137 }
00138 
00139 void GPDMA::releaseChannel(DMAChannels ch)
00140 {
00141   _mutex.lock();
00142   if (ch < NumDMAChannels) {
00143     stopTransfer(ch);
00144     if (_chData[ch].inUse) {
00145       _usedChannels--;
00146     }
00147     _chData[ch].inUse = false;
00148     _chData[ch].func = NULL;
00149   }
00150   _mutex.unlock();
00151 }
00152 
00153 LPC_GPDMACH_TypeDef* GPDMA::getDirectRegisters(DMAChannels ch)
00154 {
00155   if (ch < NumDMAChannels) {
00156     return GPDMACH(ch);
00157   } else {
00158     return NULL;
00159   }
00160 }
00161 
00162 void GPDMA::processInterrupt()
00163 {
00164   /* check status of DMA channel interrupts */
00165   uint32_t intstat = LPC_GPDMA->IntStat;
00166 
00167   for (int i = 0; i < NumDMAChannels; i++) {
00168     uint32_t mask = CH_MASK(i);
00169     if (intstat & mask) {
00170       if (_chData[i].func != NULL) {
00171         /* Notify registered subscriber */
00172         _chData[i].func();//GPDMACH(i), (tcstat&mask)!=0, (errstat&mask)!=0);
00173       }
00174     }
00175   }
00176 
00177   if ((LPC_GPDMA->EnbldChns & GPDMA_ALL_CH_MASK) == 0) {
00178     /* No more enabled DMA channels, so turn of DMA IRQ */
00179     //NVIC_DisableIRQ(DMA_IRQn);
00180   }
00181 }
00182 
00183 bool GPDMA::transfer(GPDMA_Channel_CFG_T* cfg, uint32_t CtrlWord,
00184                      uint32_t LinkListItem, uint8_t SrcPeripheral,
00185                      uint8_t DstPeripheral)
00186 {
00187   if (LPC_GPDMA->EnbldChns & CH_MASK(cfg->ChannelNum)) {
00188     /* This channel is enabled, return ERROR, need to release this channel first */
00189     return false;
00190   }
00191 
00192   /* Get Channel pointer */
00193   LPC_GPDMACH_TypeDef* pCh = GPDMACH(cfg->ChannelNum);
00194 
00195   /* Reset the Interrupt status */
00196   LPC_GPDMA->IntTCClear = CH_MASK(cfg->ChannelNum);
00197   LPC_GPDMA->IntErrClr = CH_MASK(cfg->ChannelNum);
00198 
00199   /* Clear configuration */
00200   pCh->CControl = 0x00;
00201   pCh->CConfig = 0x00;
00202 
00203   /* Assign Linker List Item value */
00204   pCh->CLLI = LinkListItem;
00205 
00206   pCh->CSrcAddr = cfg->SrcAddr;
00207   pCh->CDestAddr = cfg->DstAddr;
00208   pCh->CControl = CtrlWord;
00209 
00210   /* Enable DMA channels, little endian */
00211   LPC_GPDMA->Config = GPDMA_DMACConfig_E;
00212   while (!(LPC_GPDMA->Config & GPDMA_DMACConfig_E)) {}
00213 
00214   /* Configure DMA Channel, enable Error Counter and Terminate counter */
00215   pCh->CConfig = GPDMA_DMACCxConfig_IE
00216                | GPDMA_DMACCxConfig_ITC
00217                | GPDMA_DMACCxConfig_TransferType((uint32_t) cfg->TransferType)
00218                | GPDMA_DMACCxConfig_SrcPeripheral(SrcPeripheral)
00219                | GPDMA_DMACCxConfig_DestPeripheral(DstPeripheral);
00220 
00221   /* Enable the interrupts */
00222   NVIC_EnableIRQ(DMA_IRQn);
00223 
00224   /* Start the Channel */
00225   pCh->CConfig |= GPDMA_DMACCxConfig_E;
00226 
00227   return true;
00228 }
00229 
00230 void GPDMA::stopTransfer(DMAChannels ch)
00231 {
00232   /* Disable channel */
00233   GPDMACH(ch)->CConfig &= ~GPDMA_DMACCxConfig_E;
00234 
00235   /* Clear pending interrupts */
00236   LPC_GPDMA->IntTCClear = CH_MASK(ch);
00237   LPC_GPDMA->IntErrClr = CH_MASK(ch);
00238 }