steven niu / mDMA Featured

Dependents:   test_mDMA

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers dma_api.c Source File

dma_api.c

00001 #include "dma_api.h"
00002 #include <assert.h>
00003 
00004 
00005 int _channel_num = 8;
00006 
00007 //Define LPC1768 DMA IRQ. Different platforms might have different name
00008 IRQn_Type _DMA_IRQ = DMA_IRQn;
00009 
00010 //DMA channel control register bit set
00011 #define DMA_CCxControl_TransferSize_Pos 0
00012 #define DMA_CCxControl_SBSize_Pos 12
00013 #define DMA_CCxControl_DBSize_Pos 15
00014 #define DMA_CCxControl_SWidth_Pos 18
00015 #define DMA_CCxControl_DWidth_Pos 21
00016 #define DMA_CCxControl_SI_Pos 26
00017 #define DMA_CCxControl_DI_Pos 27
00018 #define DMA_CCxControl_I_Pos 31
00019 
00020 //DMA Channel config register bit set
00021 #define DMA_CCxConfig_E_Pos 0
00022 #define DMA_CCxConfig_SrcPeripheral_Pos 1
00023 #define DMA_CCxConfig_DestPeripheral_Pos 6
00024 #define DMA_CCxConfig_TransferType_Pos 11
00025 #define DMA_CCxConfig_IE_Pos 14
00026 #define DMA_CCxConfig_ITC_Pos 15
00027 #define DMA_CCxConfig_L_Pos 16
00028 #define DMA_CCxConfig_A_Pos 17
00029 #define DMA_CCxConfig_H_Pos 18
00030 
00031 // DMA interrupt callback
00032 func_ptr dma_irq_finish[8];
00033 func_ptr dma_irq_error[8];
00034 
00035 
00036 
00037 // Optimisation 1. Use burst mode
00038 #define BURST_ENABLED 1
00039 // Optimisation 2. Pack bytes/half  to word
00040 #define  WORD_TRANSFER 1
00041 // define whether transfer large size data supported
00042 //#define LARGE_DATA_TRANSFER 1
00043 
00044 
00045 // map the trigger index
00046 int trigger_value [33] = {
00047     -1, // ALWAYS ,
00048     0, // _SSP0_TX,
00049     1, // _SSP0_RX,
00050     2, // _SSP1_TX,
00051     3, // _SSP1_RX,
00052     4, // _ADC,
00053     5, // _I2S0,
00054     6, // _I2S1,
00055     7, // _DAC,
00056     8, // _UART0_TX,
00057     9, // _UART0_RX,
00058     10, // _UART1_TX,
00059     11, // _UART1_RX,
00060     12, // _UART2_TX,
00061     13, // _UART2_RX,
00062     14, // _UART3_TX,
00063     15, // _UART3_RX,
00064     24, // _MATCH0_0,
00065     25, // _MATCH0_1,
00066     26, // _MATCH1_0,
00067     27, // _MATCH1_1,
00068     28, // _MATCH2_0,
00069     29, // _MATCH2_1,
00070     30, // _MATCH3_0,
00071     31 // _MATCH3_1,
00072 };
00073 
00074 
00075 
00076 typedef struct DMA_InitTypeDef{
00077     uint32_t DMA_DstAddr; //Specifies the destination base address for DMAy Channelx. 
00078     uint32_t DMA_SrcAddr;     // Specifies the source base address for DMAy Channelx. 
00079     uint32_t DMA_TransferSize;// Specifies the source  transfer size  
00080     uint32_t DMA_SrcBurst; // Specifies the source  burst size    
00081     uint32_t DMA_DestBurst; // Specifies the destination burst size   
00082     uint32_t DMA_SrcWidth; //Specifies the source transfer width   
00083     uint32_t DMA_DestWidth; // Specifies the destination transfer width   
00084     uint32_t DMA_LLI; // Specifies the next link address   
00085     LLI* LLI_list[32]; // Declare an array to store up to 32 linked lists. We probably won't need that much
00086     unsigned int LLI_count; 
00087     bool DMA_SrcInc;  // Specifies whether the source is incremented or not 
00088     bool DMA_DestInc; // Specifies whether the destination is incremented or not 
00089     bool DMA_TermInt; // Specifies whether the terminal count interrupt enabled or not 
00090     uint32_t DMA_TriggerSource; // Specifies the source trigger 
00091     uint32_t DMA_TriggerDestination; // Specifies the destination trigger 
00092     TransferType  DMA_TransferType;
00093 }DMA_InitTypeDef ;
00094 
00095 
00096 
00097 /**
00098   * @brief  Check whether the address is with memory ranage.
00099   * @param  src: the physical address
00100   * @retval 0 or 1
00101   */
00102 inline static bool is_memory(uint32_t addr);
00103 
00104 /**
00105  * @brief  Static function. Automatice cacluate the transfer type according to the source and destination address
00106  * @param  src_addr. Source starting address.
00107  * @param  dst_addr. Destination starting address.
00108  * @retval Transfer type. It can be M2M,M2P,P2M or P2P
00109  */
00110 static TransferType get_transfer_type(uint32_t src_addr, uint32_t dst_addr );
00111 
00112 /**
00113   * @brief  Static function. Get the channel address according to the channel number
00114   * @param  channel. The chosen channel number
00115   * @retval Chosen channel base address
00116   */
00117     
00118 inline static LPC_GPDMACH_TypeDef* return_channel(int channel)
00119 {
00120     return (LPC_GPDMACH_TypeDef*)(LPC_GPDMACH0_BASE + 0x20*channel);
00121 }
00122 
00123 
00124 /**
00125   * @brief    Enable DMA Burst mode for optimisation
00126   */
00127 
00128 
00129 void DMA_destination(DMA_InitTypeDef* DMA_InitStruct, uint32_t dst, unsigned int width, bool inc)
00130 {
00131     DMA_InitStruct->DMA_DstAddr = dst;
00132     DMA_InitStruct->DMA_SrcBurst = 0x00; // 1 byte To be done
00133     DMA_InitStruct->DMA_DestWidth = (width >>4);
00134     DMA_InitStruct->DMA_DestInc = inc;
00135 }
00136 
00137 
00138 void DMA_source(DMA_InitTypeDef* DMA_InitStruct, uint32_t src, unsigned int width, bool inc)
00139 {
00140     DMA_InitStruct->DMA_SrcAddr = src;
00141     DMA_InitStruct->DMA_SrcBurst = 0x00; // 1 byte
00142     DMA_InitStruct->DMA_SrcInc = inc;
00143     DMA_InitStruct->DMA_SrcWidth = (width >> 4);
00144 }
00145 
00146     
00147 void DMA_trigger_source(DMA_InitTypeDef* DMA_InitStruct, TriggerType trig)
00148 {
00149     DMA_InitStruct->DMA_TriggerSource = trigger_value[trig];
00150 }
00151 
00152 
00153 void DMA_trigger_destination(DMA_InitTypeDef* DMA_InitStruct, TriggerType trig)
00154 {
00155     DMA_InitStruct->DMA_TriggerDestination = trigger_value[trig];
00156 }
00157 // Currently, not support more than 4K transfer in LLI
00158 void DMA_next(DMA_InitTypeDef* DMA_InitStruct, const uint32_t src, const uint32_t dst, uint32_t size)
00159 {
00160       //static int count = 0; 
00161       DMA_InitStruct->LLI_list[DMA_InitStruct->LLI_count] = malloc(sizeof(LLI));
00162       DMA_InitStruct->LLI_list[DMA_InitStruct->LLI_count]->LLI_dst = dst;
00163       DMA_InitStruct->LLI_list[DMA_InitStruct->LLI_count]->LLI_src = src;
00164       DMA_InitStruct->LLI_list[DMA_InitStruct->LLI_count]->LLI_next = 0; // 0 not NULL as the programmer manual says LLI_next should be 0 if it is the last of the lists
00165       DMA_InitStruct->LLI_list[DMA_InitStruct->LLI_count]->LLI_control = size & 0xFFF; 
00166       DMA_InitStruct->LLI_count++;
00167 //  TBD: need to add assert to check the input size;
00168 }
00169 
00170 
00171 /*
00172 void DMA_next(DMA_InitTypeDef* DMA_InitStruct, LLI* list)
00173 {
00174   DMA_InitStruct->DMA_LLI = (uint32_t)list; 
00175 }
00176 */
00177 
00178 
00179 void DMA_init(int channel, DMA_InitTypeDef* DMA_InitStruct)
00180 {
00181 
00182     LPC_GPDMACH_TypeDef* GPDMA_channel;
00183     // Get DMA channel address
00184     GPDMA_channel = return_channel(channel);
00185     // Calcuate transfer type according to source address and destination address
00186     DMA_InitStruct->DMA_TransferType = get_transfer_type(DMA_InitStruct->DMA_SrcAddr, DMA_InitStruct->DMA_DstAddr);
00187     // Reset interrupt pending bits for DMA Channel
00188     LPC_GPDMA->DMACIntTCClear = 1<<channel;
00189     LPC_GPDMA->DMACIntErrClr = 1<<channel;
00190        
00191 
00192     /*--------------------------- DMAy channelx request select register ----------------*/
00193     // Choose UART or Timer DMA request for DMA inputs 8 through 15
00194     if ((DMA_InitStruct->DMA_TriggerSource & 0x10) || (DMA_InitStruct->DMA_TriggerDestination & 0x10))
00195         LPC_SC->DMAREQSEL |= 1 << ((DMA_InitStruct->DMA_TriggerSource || DMA_InitStruct->DMA_TriggerSource) - 24); // I don't know why. The user manual says DMAREQSET is GPDMA register, but in mbed, it is LPC_SC register
00196     else
00197         LPC_SC->DMAREQSEL &= ~(1 << ((DMA_InitStruct->DMA_TriggerSource - 24)&& (DMA_InitStruct->DMA_TriggerDestination - 24)));
00198 
00199 
00200     /*--------------------------- DMAy channelx source and destination ----------------*/
00201     // Write to DMA channel source address
00202     GPDMA_channel->DMACCSrcAddr = DMA_InitStruct->DMA_SrcAddr;
00203     // Write to DMA channel destination address
00204     GPDMA_channel->DMACCDestAddr = DMA_InitStruct->DMA_DstAddr;
00205 
00206     #ifdef BURST_ENABLED
00207     if (DMA_InitStruct->DMA_TransferType == M2M)
00208     {
00209       /*always set burst size as 256 as the performance is same no matter what the burst size is. Need to double confirm, it seems the 
00210         interconnect would wrap the burst size as 4 no matter what the DMA AHB has set. This is to avoid DMA AHB bus take over too many bus bandwidth*/
00211         DMA_InitStruct->DMA_SrcBurst = 7; // 
00212         DMA_InitStruct->DMA_DestBurst = 7; 
00213     }
00214         #endif
00215 
00216     /*--------------------------- DMAy channelx control register ----------------*/
00217     // Set TransferSize
00218     // Set source burst size
00219     // Set destination burst size
00220     // Set source width size
00221     // Set destination width size
00222     // Set source increment
00223     // Set destination increment
00224     // Set destination increment
00225     // Enable terminal count interrupt
00226     GPDMA_channel->DMACCControl |= (DMA_InitStruct->DMA_SrcBurst << DMA_CCxControl_SBSize_Pos)  |
00227                                    (DMA_InitStruct->DMA_DestBurst << DMA_CCxControl_DBSize_Pos) |
00228                                    (DMA_InitStruct->DMA_SrcWidth << DMA_CCxControl_SWidth_Pos)  |
00229                                    (DMA_InitStruct->DMA_DestWidth << DMA_CCxControl_DWidth_Pos) |
00230                                    (DMA_InitStruct->DMA_SrcInc << DMA_CCxControl_SI_Pos)    |
00231                                    (DMA_InitStruct->DMA_DestInc << DMA_CCxControl_DI_Pos)   |
00232                                    (DMA_InitStruct->DMA_TermInt << DMA_CCxControl_I_Pos );
00233 
00234     /*--------------------------- DMAy channelx configuration register ----------------*/
00235     // Set source periheral trigger. If the source is memory, this bit is ignored. Set according to low 4 bit of DMA_Trigger
00236     // Set destination periheral trigger. If the destination is memory, this bit is ignored. Set according low 4 bit of DMA_Trigger
00237     // Set transfer type: M2M, M2P, P2M, M2M
00238     GPDMA_channel->DMACCConfig |= ((DMA_InitStruct->DMA_TriggerSource & 0x0f) << DMA_CCxConfig_SrcPeripheral_Pos)|    //set SrcPeripheral according low 4 bit of DMA_Trigger
00239                                   ((DMA_InitStruct->DMA_TriggerDestination & 0x0f) << DMA_CCxConfig_DestPeripheral_Pos)|      //set DstPeripheral according low 4 bit of DMA_Trigger
00240                                   (DMA_InitStruct->DMA_TransferType << DMA_CCxConfig_TransferType_Pos);
00241         
00242     /* set link list items register*/
00243     if(DMA_InitStruct->LLI_count != 0)
00244     {
00245         int j;
00246         for (j=0; j < DMA_InitStruct->LLI_count; j++) 
00247         {
00248             DMA_InitStruct->LLI_list[j]->LLI_control |= GPDMA_channel->DMACCControl;
00249             if (j< DMA_InitStruct->LLI_count - 1)
00250                 DMA_InitStruct->LLI_list[j]->LLI_next = (uint32_t)DMA_InitStruct->LLI_list[j+1];
00251             }
00252             GPDMA_channel->DMACCLLI = (uint32_t)DMA_InitStruct->LLI_list[0];  
00253         }
00254             //LPC_GPDMA->DMACSync =0x1;                                                         
00255 }//end of DMA_init
00256 
00257 
00258 void DMA_start(int channel, DMA_InitTypeDef* DMA_InitStruct, unsigned int length)
00259 {
00260     LPC_GPDMACH_TypeDef* volatile GPDMA_channel;
00261     // Get DMA channel address
00262     GPDMA_channel = return_channel(channel);
00263 
00264     // Set the transfer size
00265     // Put it here rather than in DMA_Init. So that one could send new transfer data without reinit other registers
00266 
00267     int length_low;
00268     int length_high;
00269     int length_unalligned; 
00270     int length_alligned; 
00271     
00272     if ((DMA_InitStruct->DMA_DstAddr % sizeof(long) == 0) && (DMA_InitStruct->DMA_SrcAddr % sizeof(long) == 0) && // Only use word aligned when starting addresss is at 4 bytes boundary
00273         (length_low >=4) && // Only use word aligned when length is no less than 4
00274         (DMA_InitStruct->DMA_SrcInc == 1) &&   // Only use word aligned when the source is incretmental 
00275         (DMA_InitStruct->DMA_DestInc == 1) &&  // Only use word aligned when the address is incretmental
00276         (DMA_InitStruct->DMA_SrcWidth < 0x2))  // Only use word aligned when the source width is less than 4 bytes      
00277     {
00278                 
00279         unsigned int old_SrcWidth = DMA_InitStruct->DMA_SrcWidth;
00280         unsigned int old_DstWidth = DMA_InitStruct->DMA_DestWidth;
00281         unsigned int new_width = 2; // New width will be word
00282             
00283 
00284         length_unalligned = (length & 0x3) >> DMA_InitStruct->DMA_SrcWidth;
00285         length_alligned = length - length_unalligned;
00286                  
00287         int length_new = length_alligned << DMA_InitStruct->DMA_SrcWidth >> new_width;
00288             
00289         GPDMA_channel->DMACCConfig &= ~(1ul << DMA_CCxConfig_ITC_Pos); // mask DMA terminate count IRQ
00290         GPDMA_channel->DMACCControl |= 1ul << DMA_CCxControl_I_Pos;
00291         // Unmask IE
00292         GPDMA_channel->DMACCConfig |= 1ul << DMA_CCxConfig_IE_Pos;  // unmask DMA Errr IRQ
00293             
00294         while (length_new > 0xfff)
00295         {
00296                     
00297             GPDMA_channel->DMACCControl = 0xfff << DMA_CCxControl_TransferSize_Pos |
00298                                           (DMA_InitStruct->DMA_SrcBurst << DMA_CCxControl_SBSize_Pos)  |
00299                                           (DMA_InitStruct->DMA_DestBurst << DMA_CCxControl_DBSize_Pos) |
00300                                           (2 << DMA_CCxControl_SWidth_Pos)  |
00301                                           (2 << DMA_CCxControl_DWidth_Pos) |
00302                                           (DMA_InitStruct->DMA_SrcInc << DMA_CCxControl_SI_Pos)    |
00303                                           (DMA_InitStruct->DMA_DestInc << DMA_CCxControl_DI_Pos)   |
00304                                           (DMA_InitStruct->DMA_TermInt << DMA_CCxControl_I_Pos);  
00305                     
00306                     
00307                     
00308             LPC_GPDMA->DMACConfig = 0x01;
00309             GPDMA_channel->DMACCConfig |= 1ul << DMA_CCxConfig_E_Pos;
00310             length_new -= 0xfff;
00311                     
00312             // DMACCSrcAddr currently hold the end address of first part
00313             GPDMA_channel->DMACCSrcAddr = GPDMA_channel->DMACCSrcAddr  + 1;
00314             GPDMA_channel->DMACCDestAddr = GPDMA_channel->DMACCDestAddr +  1;
00315             while (DMA_channel_active(channel));
00316         }
00317                 
00318         GPDMA_channel->DMACCControl = length_new << DMA_CCxControl_TransferSize_Pos |
00319                                       (DMA_InitStruct->DMA_SrcBurst << DMA_CCxControl_SBSize_Pos)  |
00320                                       (DMA_InitStruct->DMA_DestBurst << DMA_CCxControl_DBSize_Pos) |
00321                                       (2 << DMA_CCxControl_SWidth_Pos)  |
00322                                       (2 << DMA_CCxControl_DWidth_Pos) |
00323                                       (DMA_InitStruct->DMA_SrcInc << DMA_CCxControl_SI_Pos)    |
00324                                       (DMA_InitStruct->DMA_DestInc << DMA_CCxControl_DI_Pos)   |
00325                                       (DMA_InitStruct->DMA_TermInt << DMA_CCxControl_I_Pos);  
00326                                     
00327         LPC_GPDMA->DMACConfig = 0x01;
00328         GPDMA_channel->DMACCConfig |= 1ul << DMA_CCxConfig_E_Pos;
00329         while (DMA_channel_active(channel));
00330                 
00331         GPDMA_channel->DMACCSrcAddr = GPDMA_channel->DMACCSrcAddr  + 4;
00332         GPDMA_channel->DMACCDestAddr = GPDMA_channel->DMACCDestAddr +  4;
00333                 
00334         DMA_InitStruct->DMA_TransferSize = length_unalligned;
00335         GPDMA_channel->DMACCControl = length_unalligned << DMA_CCxControl_TransferSize_Pos |
00336                                       (DMA_InitStruct->DMA_SrcBurst << DMA_CCxControl_SBSize_Pos)  |
00337                                       (DMA_InitStruct->DMA_DestBurst << DMA_CCxControl_DBSize_Pos) |
00338                                       (DMA_InitStruct->DMA_SrcWidth << DMA_CCxControl_SWidth_Pos)  |
00339                                       (DMA_InitStruct->DMA_DestWidth << DMA_CCxControl_DWidth_Pos) |
00340                                       (DMA_InitStruct->DMA_SrcInc << DMA_CCxControl_SI_Pos)    |
00341                                       (DMA_InitStruct->DMA_DestInc << DMA_CCxControl_DI_Pos)   |
00342                                       (DMA_InitStruct->DMA_TermInt << DMA_CCxControl_I_Pos);                                                                              
00343         }
00344         
00345         
00346         else
00347         {
00348             GPDMA_channel->DMACCConfig &= ~(1ul << DMA_CCxConfig_ITC_Pos); // mask DMA terminate count IRQ
00349             GPDMA_channel->DMACCControl |= 1ul << DMA_CCxControl_I_Pos;
00350             // Unmask IE
00351             GPDMA_channel->DMACCConfig |= 1ul << DMA_CCxConfig_IE_Pos;  // unmask DMA Errr IRQ
00352             
00353             while (length > 0xfff)
00354             {
00355                 GPDMA_channel->DMACCControl = 0xfff << DMA_CCxControl_TransferSize_Pos |
00356                                                (DMA_InitStruct->DMA_SrcBurst << DMA_CCxControl_SBSize_Pos)  |
00357                                                (DMA_InitStruct->DMA_DestBurst << DMA_CCxControl_DBSize_Pos) |
00358                                                (DMA_InitStruct->DMA_SrcWidth << DMA_CCxControl_SWidth_Pos)  |
00359                                                (DMA_InitStruct->DMA_DestWidth << DMA_CCxControl_DWidth_Pos) |
00360                                                (DMA_InitStruct->DMA_SrcInc << DMA_CCxControl_SI_Pos)    |
00361                                                (DMA_InitStruct->DMA_DestInc << DMA_CCxControl_DI_Pos)   |
00362                                                (DMA_InitStruct->DMA_TermInt << DMA_CCxControl_I_Pos);  
00363                     
00364                     
00365                     
00366                  LPC_GPDMA->DMACConfig = 0x01;
00367                  GPDMA_channel->DMACCConfig |= 1ul << DMA_CCxConfig_E_Pos;
00368                  length -= 0xfff;
00369                     
00370                  // DMACCSrcAddr currently hold the end address of first part
00371                  GPDMA_channel->DMACCSrcAddr = GPDMA_channel->DMACCSrcAddr  + 1;
00372                  GPDMA_channel->DMACCDestAddr = GPDMA_channel->DMACCDestAddr +  1;
00373                  while (DMA_channel_active(channel));
00374             }
00375                 
00376 
00377                 
00378             GPDMA_channel->DMACCSrcAddr = GPDMA_channel->DMACCSrcAddr  + 1;
00379             GPDMA_channel->DMACCDestAddr = GPDMA_channel->DMACCDestAddr +  1;
00380                 
00381             DMA_InitStruct->DMA_TransferSize = length;
00382         }
00383                 
00384         
00385     // Enable Interrupt
00386     // Unmask ITC
00387     GPDMA_channel->DMACCConfig |= 1ul << DMA_CCxConfig_ITC_Pos;
00388 
00389   
00390     GPDMA_channel->DMACCControl |= DMA_InitStruct->DMA_TransferSize << DMA_CCxControl_TransferSize_Pos;
00391         
00392     DMA_InitStruct->LLI_count = 0; // Clear the LLI lists count so that we could reuse this channel next time
00393     // Enable DMA 
00394     LPC_GPDMA->DMACConfig = 0x01;
00395     GPDMA_channel->DMACCConfig |= 1ul << DMA_CCxConfig_E_Pos;
00396 }
00397 
00398 
00399 bool DMA_channel_active(int channel)
00400 {
00401     LPC_SC->PCONP |= (1 << 29);
00402     return (LPC_GPDMA->DMACEnbldChns && (1<<channel));
00403 }
00404 
00405 
00406 
00407 void DMA_reset(int channel)
00408 {
00409     assert (channel <= _channel_num && channel>=0); 
00410     LPC_SC->PCONP |= (1 << 29);
00411     LPC_GPDMACH_TypeDef* GPDMA_channel;
00412     //Get DMA channel address
00413     GPDMA_channel = return_channel(channel);
00414     GPDMA_channel->DMACCConfig = 0;
00415     GPDMA_channel->DMACCControl = 0;
00416     GPDMA_channel->DMACCLLI = 0;
00417     GPDMA_channel->DMACCSrcAddr = 0;
00418     LPC_GPDMA->DMACIntErrClr |= 1 << channel; // clear the interrupt
00419     LPC_GPDMA->DMACIntTCClear |= 1 << channel;
00420     dma_irq_error [channel] = 0;
00421     dma_irq_finish[channel] = 0;  
00422 }
00423 
00424 
00425 DMA_InitTypeDef* DMA_struct_create(void)
00426 {
00427     DMA_InitTypeDef* DMA_InitStruct = (DMA_InitTypeDef*) malloc(sizeof(DMA_InitTypeDef));
00428     /*-------------- Reset DMA init structure parameters values ------------------*/
00429     DMA_InitStruct->DMA_DstAddr = 0;
00430     DMA_InitStruct->DMA_SrcAddr = 0;
00431     DMA_InitStruct->DMA_TransferSize = 0;
00432     DMA_InitStruct->DMA_SrcBurst = 0;
00433     DMA_InitStruct->DMA_DestBurst = 0;
00434     DMA_InitStruct->DMA_SrcWidth = 0;
00435     DMA_InitStruct->DMA_DestWidth = 0;
00436     DMA_InitStruct->DMA_LLI = 0;
00437     DMA_InitStruct->LLI_count = 0 ; 
00438     DMA_InitStruct->DMA_SrcInc = 0;
00439     DMA_InitStruct->DMA_DestInc = 0;
00440     DMA_InitStruct->DMA_TermInt = 1; // always enable terminal count interrupt in default
00441     DMA_InitStruct->DMA_TriggerSource = trigger_value[ALWAYS];
00442     DMA_InitStruct->DMA_TriggerDestination = trigger_value[ALWAYS];
00443     DMA_InitStruct->DMA_TransferType = M2M;
00444     return DMA_InitStruct;
00445 } //end of DMA_StructInit
00446 
00447 void DMA_struct_delete(DMA_InitTypeDef* ptr)
00448 {
00449     free(ptr);
00450 }
00451 
00452 inline static bool is_memory(uint32_t addr)
00453 {
00454     if ((addr >> 28) == 0 || (addr >> 28)== 1)
00455         return 1;
00456     else
00457         return 0;
00458 }
00459 
00460 
00461 void DMA_IRQ_handler(void)
00462 {
00463     //only call the attached function when certain interrupt happened on the right channel
00464     unsigned i ; 
00465     uint32_t FinishStatus=0;
00466     uint32_t ErrStatus=0;
00467     FinishStatus = LPC_GPDMA->DMACIntTCStat & 0xFF;
00468     ErrStatus = LPC_GPDMA->DMACIntErrStat & 0xFF;
00469     
00470      
00471     if (FinishStatus !=0) //only checking when there is interrupt happened
00472         for (i =0; i < 8; i++) // roundrobin checking how many channels get interrupts 
00473         {
00474             if (FinishStatus & 1 << i)
00475                 dma_irq_finish[i]();
00476         }
00477     if (ErrStatus !=0)          
00478          for (i =0; i < 8; i++) 
00479          {
00480              if (ErrStatus & 1 << i)
00481                  dma_irq_error[i]();
00482          }       
00483   
00484     LPC_GPDMA->DMACIntTCClear |= FinishStatus;
00485     LPC_GPDMA->DMACIntErrClr |= ErrStatus;
00486 }
00487 
00488 
00489 void DMA_IRQ_attach(int channel, int status, func_ptr ptr)
00490 {
00491     assert(channel <= _channel_num && channel >= 0);
00492     assert(status == ERR || status == FINISH);
00493     
00494     if (status == ERR)
00495         dma_irq_error[channel] = ptr;
00496     else if (status == FINISH)
00497         dma_irq_finish[channel] = ptr;
00498 }
00499 
00500 
00501 
00502 void DMA_IRQ_detach(int channel)
00503 {
00504     dma_irq_error[channel] = 0;
00505     dma_irq_finish[channel] = 0;
00506 }
00507 
00508 
00509 
00510 static TransferType get_transfer_type(uint32_t src_addr, uint32_t dst_addr)
00511 {
00512     if (is_memory(src_addr)) {   //if source is memory
00513         if(is_memory(dst_addr))  //if destination is memory
00514             return M2M;    //return M2M if source is memory and destination is memory.
00515         else    //if destination is peripheral
00516             return M2P;    //return M2P if source is memory and destination is peripheral
00517     } else {        //if source is peripheral
00518         if(is_memory(dst_addr))      //if destination is memory
00519             return P2M;     //return P2M if source is peripheral and destination is memory
00520         else        //if destination is peripheral
00521             return P2P;     //return P2P if source is peripheral and destination is peripheral
00522     }
00523 }    
00524