MODDMA GPDMA Controller New features: transfer pins to memory buffer under periodic timer control and send double buffers to DAC

Dependents:   FirstTest WaveSim IO-dma-memmem DACDMAfuncgenlib ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MODDMA.cpp Source File

MODDMA.cpp

00001 /*
00002     Copyright (c) 2010 Andy Kirkham
00003  
00004     Permission is hereby granted, free of charge, to any person obtaining a copy
00005     of this software and associated documentation files (the "Software"), to deal
00006     in the Software without restriction, including without limitation the rights
00007     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00008     copies of the Software, and to permit persons to whom the Software is
00009     furnished to do so, subject to the following conditions:
00010  
00011     The above copyright notice and this permission notice shall be included in
00012     all copies or substantial portions of the Software.
00013  
00014     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00017     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00018     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00019     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00020     THE SOFTWARE.
00021 */
00022 #include "iomacros.h"
00023 #include "MODDMA.h"
00024 
00025 namespace AjK {
00026 
00027 // Create a "hook" for our ISR to make callbacks. Set by init()
00028 class MODDMA *moddma_p = (class MODDMA *)NULL;
00029 
00030 void
00031 MODDMA::Enable(CHANNELS ChannelNumber)
00032 {
00033     LPC_GPDMACH_TypeDef *pChannel = (LPC_GPDMACH_TypeDef *)Channel_p( ChannelNumber );
00034     pChannel->DMACCConfig |= _E ;
00035 }
00036 
00037 bool
00038 MODDMA::Enabled(CHANNELS ChannelNumber)
00039 {
00040     LPC_GPDMACH_TypeDef *pChannel = (LPC_GPDMACH_TypeDef *)Channel_p( ChannelNumber );    
00041     return (bool)(pChannel->DMACCConfig & _E );
00042 }
00043 
00044 void
00045 MODDMA::Disable(CHANNELS ChannelNumber)
00046 {
00047     LPC_GPDMACH_TypeDef *pChannel = (LPC_GPDMACH_TypeDef *)Channel_p( ChannelNumber );
00048     pChannel->DMACCConfig &= ~(_E );
00049 }
00050 
00051 bool
00052 MODDMA::isActive(CHANNELS ChannelNumber)
00053 {
00054     LPC_GPDMACH_TypeDef *pChannel = (LPC_GPDMACH_TypeDef *)Channel_p( ChannelNumber );
00055     return (bool)( pChannel->DMACCConfig & CxConfig_A() ) ;
00056 }
00057 
00058 void 
00059 MODDMA::haltChannel(CHANNELS ChannelNumber)
00060 {
00061     LPC_GPDMACH_TypeDef *pChannel = (LPC_GPDMACH_TypeDef *)Channel_p( ChannelNumber );
00062     pChannel->DMACCConfig |= CxConfig_H();
00063 }
00064 
00065 uint32_t 
00066 MODDMA::getControl(CHANNELS ChannelNumber)
00067 {
00068     LPC_GPDMACH_TypeDef *pChannel = (LPC_GPDMACH_TypeDef *)Channel_p( ChannelNumber );
00069     return pChannel->DMACCControl;
00070 }
00071 
00072 uint32_t oldDMAHandler = 0;
00073 typedef void (*MODDMA_FN)(void);
00074 
00075 extern "C" void MODDMA_IRQHandler(void) {
00076     uint32_t channel_mask;
00077         
00078     if (moddma_p == (class MODDMA *)NULL) {
00079         if (oldDMAHandler) {
00080             ((MODDMA_FN)oldDMAHandler)();
00081             return;
00082         }
00083         else {
00084             error("Interrupt without instance");
00085         }
00086     }
00087     
00088     for (int channel_number = 0; channel_number < 8; channel_number++) {
00089         channel_mask = (1UL << channel_number);
00090         if (LPC_GPDMA->DMACIntStat & channel_mask) {
00091             if (LPC_GPDMA->DMACIntTCStat & channel_mask) {
00092                 if (moddma_p->setups[channel_number] != (MODDMA_Config *)NULL) {
00093                     moddma_p->setIrqProcessingChannel((MODDMA::CHANNELS)channel_number);
00094                     moddma_p->setIrqType(MODDMA::TcIrq );
00095                     moddma_p->setups[channel_number]->isrIntTCStat->call();
00096                     moddma_p->isrIntTCStat.call();
00097                     // The user callback should clear the IRQ. But if they forget
00098                     // then the Mbed will lockup. So, check to see if the IRQ has
00099                     // been dismissed, if not, we will dismiss it here.
00100                     if (LPC_GPDMA->DMACIntTCStat & channel_mask) {
00101                         LPC_GPDMA->DMACIntTCClear = channel_mask;
00102                     }
00103                     // If the user has left the channel enabled, disable it.
00104                     // Note, we don't check Active here as it may block inside
00105                     // an ISR, we just shut it down immediately. If the user
00106                     // must wait for completion they should implement their
00107                     // own ISR. But only disable if the LLI linked list register
00108                     // is null otherwise we can crap out a series of transfers.
00109                     if (moddma_p->Enabled( (MODDMA::CHANNELS)channel_number )) {
00110                         if (moddma_p->lli( (MODDMA::CHANNELS)channel_number ) == 0 ) {
00111                             moddma_p->Disable( (MODDMA::CHANNELS)channel_number ); 
00112                         }
00113                     }
00114                 }            
00115             }
00116             
00117             if (LPC_GPDMA->DMACIntErrStat & channel_mask) {
00118                 if (moddma_p->setups[channel_number] != (MODDMA_Config *)NULL) {
00119                     moddma_p->setIrqProcessingChannel((MODDMA::CHANNELS)channel_number);
00120                     moddma_p->setIrqType(MODDMA::ErrIrq );
00121                     moddma_p->setups[channel_number]->isrIntErrStat->call();
00122                     moddma_p->isrIntErrStat.call();
00123                     // The user callback should clear the IRQ. But if they forget
00124                     // then the Mbed will lockup. So, check to see if the IRQ has
00125                     // been dismissed, if not, we will dismiss it here.
00126                     if (LPC_GPDMA->DMACIntErrStat & channel_mask) {
00127                         LPC_GPDMA->DMACIntErrClr = channel_mask;
00128                     }
00129                     // If the user has left the channel enabled, disable it.
00130                     // Not, we don't check Active here as it may block inside
00131                     // an ISR, we just shut it down immediately. If the user
00132                     // must wait for completion they should implement their
00133                     // own ISR. But only disable if the LLI linked list register
00134                     // is null otherwise we can crap out a series of transfers.
00135                     if (moddma_p->Enabled( (MODDMA::CHANNELS)channel_number )) {
00136                         if (moddma_p->lli( (MODDMA::CHANNELS)channel_number ) == 0 ) {
00137                             moddma_p->Disable( (MODDMA::CHANNELS)channel_number ); 
00138                         }
00139                     }
00140                 }            
00141             }
00142         }
00143     }
00144     
00145     /* IRQ should be handled by now, check to make sure. */
00146     if (LPC_GPDMA->DMACIntStat) {
00147         ((MODDMA_FN)oldDMAHandler)();
00148         LPC_GPDMA->DMACIntTCClear = (uint32_t)0xFF; /* If not, clear anyway! */
00149     }
00150     if (LPC_GPDMA->DMACIntErrStat) {
00151         ((MODDMA_FN)oldDMAHandler)();
00152         LPC_GPDMA->DMACIntErrClr = (uint32_t)0xFF; /* If not, clear anyway! */
00153     }
00154 }
00155 
00156 }; // namespace AjK ends
00157