Zoltan Hudak / MODDMA
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                     if (moddma_p->setups[channel_number]->isrIntTCStat != NULL)
00096                         moddma_p->setups[channel_number]->isrIntTCStat.call();
00097                     if (moddma_p->isrIntTCStat != NULL)
00098                         moddma_p->isrIntTCStat.call();
00099                     // The user callback should clear the IRQ. But if they forget
00100                     // then the Mbed will lockup. So, check to see if the IRQ has
00101                     // been dismissed, if not, we will dismiss it here.
00102                     if (LPC_GPDMA->DMACIntTCStat & channel_mask) {
00103                         LPC_GPDMA->DMACIntTCClear = channel_mask;
00104                     }
00105                     // If the user has left the channel enabled, disable it.
00106                     // Note, we don't check Active here as it may block inside
00107                     // an ISR, we just shut it down immediately. If the user
00108                     // must wait for completion they should implement their
00109                     // own ISR. But only disable if the LLI linked list register
00110                     // is null otherwise we can crap out a series of transfers.
00111                     if (moddma_p->Enabled( (MODDMA::CHANNELS)channel_number )) {
00112                         if (moddma_p->lli( (MODDMA::CHANNELS)channel_number ) == 0 ) {
00113                             moddma_p->Disable( (MODDMA::CHANNELS)channel_number );
00114                         }
00115                     }
00116                 }
00117             }
00118 
00119             if (LPC_GPDMA->DMACIntErrStat & channel_mask) {
00120                 if (moddma_p->setups[channel_number] != (MODDMA_Config *)NULL) {
00121                     moddma_p->setIrqProcessingChannel((MODDMA::CHANNELS)channel_number);
00122                     moddma_p->setIrqType(MODDMA::ErrIrq );
00123                     if (moddma_p->setups[channel_number]->isrIntErrStat != NULL)
00124                         moddma_p->setups[channel_number]->isrIntErrStat.call();
00125                     if (moddma_p->isrIntErrStat != NULL)
00126                         moddma_p->isrIntErrStat.call();
00127                     // The user callback should clear the IRQ. But if they forget
00128                     // then the Mbed will lockup. So, check to see if the IRQ has
00129                     // been dismissed, if not, we will dismiss it here.
00130                     if (LPC_GPDMA->DMACIntErrStat & channel_mask) {
00131                         LPC_GPDMA->DMACIntErrClr = channel_mask;
00132                     }
00133                     // If the user has left the channel enabled, disable it.
00134                     // Not, we don't check Active here as it may block inside
00135                     // an ISR, we just shut it down immediately. If the user
00136                     // must wait for completion they should implement their
00137                     // own ISR. But only disable if the LLI linked list register
00138                     // is null otherwise we can crap out a series of transfers.
00139                     if (moddma_p->Enabled( (MODDMA::CHANNELS)channel_number )) {
00140                         if (moddma_p->lli( (MODDMA::CHANNELS)channel_number ) == 0 ) {
00141                             moddma_p->Disable( (MODDMA::CHANNELS)channel_number );
00142                         }
00143                     }
00144                 }
00145             }
00146         }
00147     }
00148 
00149     /* IRQ should be handled by now, check to make sure. */
00150     if (LPC_GPDMA->DMACIntStat) {
00151         ((MODDMA_FN)oldDMAHandler)();
00152         LPC_GPDMA->DMACIntTCClear = (uint32_t)0xFF; /* If not, clear anyway! */
00153     }
00154     if (LPC_GPDMA->DMACIntErrStat) {
00155         ((MODDMA_FN)oldDMAHandler)();
00156         LPC_GPDMA->DMACIntErrClr = (uint32_t)0xFF; /* If not, clear anyway! */
00157     }
00158 }
00159 
00160 }