Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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
Generated on Sat Jul 16 2022 23:21:49 by
1.7.2