DMA library for the KL25Z
Dependents: SimpleDMA_HelloWorld RTOS_SPI spiDMAtest Pinscape_Controller_v1 ... more
Introduction
SimpleDMA is a standard library for different DMA peripherals. Currently the LPC1768, KL46Z and KL25Z are supported. It provided one set of functions for different peripherals. It does not allow for usage of all the advanced functions, partially because the goal was to provide a simple interface, and partially because they are different for different microcontrollers.
Examples
Helloworld: http://mbed.org/users/Sissors/code/SimpleDMA_HelloWorld/
Example in a library (SPI): http://mbed.org/users/Sissors/code/RTOS_SPI/
SimpleDMA_LPC1768.cpp@6:e9ab0bb912c8, 2014-03-18 (annotated)
- Committer:
- BaderP
- Date:
- Tue Mar 18 12:44:46 2014 +0000
- Revision:
- 6:e9ab0bb912c8
- Parent:
- 5:d9f46ef80e20
- Child:
- 8:876f3b55e6f5
patched SimpleDMA to include additional 32 kb ram
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Sissors | 5:d9f46ef80e20 | 1 | #ifdef TARGET_LPC1768 |
Sissors | 5:d9f46ef80e20 | 2 | |
Sissors | 5:d9f46ef80e20 | 3 | #include "SimpleDMA.h" |
Sissors | 5:d9f46ef80e20 | 4 | |
Sissors | 5:d9f46ef80e20 | 5 | SimpleDMA *SimpleDMA::irq_owner[8] = {NULL}; |
Sissors | 5:d9f46ef80e20 | 6 | LPC_GPDMACH_TypeDef *LPC_GPDMACH[8] = {LPC_GPDMACH0, LPC_GPDMACH1, LPC_GPDMACH2, LPC_GPDMACH3, LPC_GPDMACH4, LPC_GPDMACH5, LPC_GPDMACH6, LPC_GPDMACH7}; |
Sissors | 5:d9f46ef80e20 | 7 | uint32_t getTransferType(SimpleDMA_Trigger trig, uint32_t source, uint32_t destination); |
Sissors | 5:d9f46ef80e20 | 8 | |
Sissors | 5:d9f46ef80e20 | 9 | SimpleDMA::SimpleDMA(int channel) { |
Sissors | 5:d9f46ef80e20 | 10 | this->channel(channel); |
Sissors | 5:d9f46ef80e20 | 11 | |
Sissors | 5:d9f46ef80e20 | 12 | //Power up |
Sissors | 5:d9f46ef80e20 | 13 | LPC_SC->PCONP |= 1<<29; |
Sissors | 5:d9f46ef80e20 | 14 | LPC_GPDMA->DMACConfig = 1; |
Sissors | 5:d9f46ef80e20 | 15 | trigger(Trigger_ALWAYS); |
Sissors | 5:d9f46ef80e20 | 16 | |
Sissors | 5:d9f46ef80e20 | 17 | NVIC_SetVector(DMA_IRQn, (uint32_t)&irq_handler0); |
Sissors | 5:d9f46ef80e20 | 18 | NVIC_EnableIRQ(DMA_IRQn); |
Sissors | 5:d9f46ef80e20 | 19 | } |
Sissors | 5:d9f46ef80e20 | 20 | |
Sissors | 5:d9f46ef80e20 | 21 | int SimpleDMA::start(int length) { |
Sissors | 5:d9f46ef80e20 | 22 | if (auto_channel) |
Sissors | 5:d9f46ef80e20 | 23 | _channel = getFreeChannel(); |
Sissors | 5:d9f46ef80e20 | 24 | else |
Sissors | 5:d9f46ef80e20 | 25 | while(isBusy()); |
Sissors | 5:d9f46ef80e20 | 26 | |
Sissors | 5:d9f46ef80e20 | 27 | uint32_t control = (source_inc << 26) | (destination_inc << 27) | (1UL << 31); |
Sissors | 5:d9f46ef80e20 | 28 | switch (source_size) { |
Sissors | 5:d9f46ef80e20 | 29 | case 16: |
Sissors | 5:d9f46ef80e20 | 30 | control |= (1<<18) | (length >> 1); |
Sissors | 5:d9f46ef80e20 | 31 | break; |
Sissors | 5:d9f46ef80e20 | 32 | case 32: |
Sissors | 5:d9f46ef80e20 | 33 | control |= (2<<18) | (length >> 2); |
Sissors | 5:d9f46ef80e20 | 34 | break; |
Sissors | 5:d9f46ef80e20 | 35 | default: |
Sissors | 5:d9f46ef80e20 | 36 | control |= length; |
Sissors | 5:d9f46ef80e20 | 37 | } |
Sissors | 5:d9f46ef80e20 | 38 | switch (destination_size) { |
Sissors | 5:d9f46ef80e20 | 39 | case 16: |
Sissors | 5:d9f46ef80e20 | 40 | control |= (1<<21); |
Sissors | 5:d9f46ef80e20 | 41 | break; |
Sissors | 5:d9f46ef80e20 | 42 | case 32: |
Sissors | 5:d9f46ef80e20 | 43 | control |= (2<<21); |
Sissors | 5:d9f46ef80e20 | 44 | break; |
Sissors | 5:d9f46ef80e20 | 45 | } |
Sissors | 5:d9f46ef80e20 | 46 | |
Sissors | 5:d9f46ef80e20 | 47 | LPC_GPDMACH[_channel]->DMACCSrcAddr = _source; |
Sissors | 5:d9f46ef80e20 | 48 | LPC_GPDMACH[_channel]->DMACCDestAddr = _destination; |
Sissors | 5:d9f46ef80e20 | 49 | LPC_GPDMACH[_channel]->DMACCLLI = 0; |
Sissors | 5:d9f46ef80e20 | 50 | LPC_GPDMACH[_channel]->DMACCControl = control; //Enable interrupt also |
Sissors | 5:d9f46ef80e20 | 51 | |
Sissors | 5:d9f46ef80e20 | 52 | irq_owner[_channel] = this; |
Sissors | 5:d9f46ef80e20 | 53 | |
Sissors | 5:d9f46ef80e20 | 54 | if (_trigger != Trigger_ALWAYS) { |
Sissors | 5:d9f46ef80e20 | 55 | if (_trigger & 16) |
Sissors | 5:d9f46ef80e20 | 56 | LPC_SC->DMAREQSEL |= 1 << (_trigger - 24); |
Sissors | 5:d9f46ef80e20 | 57 | else |
Sissors | 5:d9f46ef80e20 | 58 | LPC_SC->DMAREQSEL &= ~(1 << (_trigger - 24)); |
Sissors | 5:d9f46ef80e20 | 59 | |
Sissors | 5:d9f46ef80e20 | 60 | LPC_GPDMACH[_channel]->DMACCConfig = ((_trigger & 15) << 1) + ((_trigger & 15) << 6) + (getTransferType(_trigger, _source, _destination) << 11) + (1<<15) +1; //Both parts of the transfer get triggered at same time |
Sissors | 5:d9f46ef80e20 | 61 | } else |
Sissors | 5:d9f46ef80e20 | 62 | LPC_GPDMACH[_channel]->DMACCConfig = (getTransferType(_trigger, _source, _destination) << 11) + 1 + (1<<15); //Enable channel |
Sissors | 5:d9f46ef80e20 | 63 | |
Sissors | 5:d9f46ef80e20 | 64 | return 0; |
Sissors | 5:d9f46ef80e20 | 65 | } |
Sissors | 5:d9f46ef80e20 | 66 | |
Sissors | 5:d9f46ef80e20 | 67 | bool SimpleDMA::isBusy( int channel ) { |
Sissors | 5:d9f46ef80e20 | 68 | if (channel == -1) |
Sissors | 5:d9f46ef80e20 | 69 | channel = _channel; |
Sissors | 5:d9f46ef80e20 | 70 | return (LPC_GPDMA->DMACEnbldChns & (1<<channel)); |
Sissors | 5:d9f46ef80e20 | 71 | } |
Sissors | 5:d9f46ef80e20 | 72 | |
Sissors | 5:d9f46ef80e20 | 73 | void SimpleDMA::irq_handler0(void) { |
Sissors | 5:d9f46ef80e20 | 74 | while(LPC_GPDMA->DMACIntTCStat != 0) { |
Sissors | 5:d9f46ef80e20 | 75 | |
Sissors | 5:d9f46ef80e20 | 76 | uint32_t intloc = 31 - __CLZ(LPC_GPDMA->DMACIntTCStat & 0xFF); |
Sissors | 5:d9f46ef80e20 | 77 | if (irq_owner[intloc]!=NULL) |
Sissors | 5:d9f46ef80e20 | 78 | irq_owner[intloc]->irq_handler(); |
Sissors | 5:d9f46ef80e20 | 79 | } |
Sissors | 5:d9f46ef80e20 | 80 | } |
Sissors | 5:d9f46ef80e20 | 81 | |
Sissors | 5:d9f46ef80e20 | 82 | void SimpleDMA::irq_handler(void) { |
Sissors | 5:d9f46ef80e20 | 83 | LPC_GPDMA->DMACIntTCClear = 1<<_channel; |
Sissors | 5:d9f46ef80e20 | 84 | _callback.call(); |
Sissors | 5:d9f46ef80e20 | 85 | } |
Sissors | 5:d9f46ef80e20 | 86 | |
BaderP | 6:e9ab0bb912c8 | 87 | static inline bool isMemory(uint32_t addr) |
BaderP | 6:e9ab0bb912c8 | 88 | { |
BaderP | 6:e9ab0bb912c8 | 89 | return (addr >> 28) == 0 || (addr >> 28) == 1 || ((addr >= 0x2007C000) && (addr < (0x2007C000 + 0x8000))); |
BaderP | 6:e9ab0bb912c8 | 90 | } |
BaderP | 6:e9ab0bb912c8 | 91 | |
Sissors | 5:d9f46ef80e20 | 92 | uint32_t getTransferType(SimpleDMA_Trigger trig, uint32_t source, uint32_t destination) { |
Sissors | 5:d9f46ef80e20 | 93 | //If it is always, simply put it on memory-to-memory |
Sissors | 5:d9f46ef80e20 | 94 | if (trig == Trigger_ALWAYS) |
Sissors | 5:d9f46ef80e20 | 95 | return 0; |
BaderP | 6:e9ab0bb912c8 | 96 | else if (isMemory(source)) { //if source is RAM/Flash |
BaderP | 6:e9ab0bb912c8 | 97 | if (isMemory(destination)) //if destination is RAM/flash |
Sissors | 5:d9f46ef80e20 | 98 | return 3; //Return p2p for m2m with a trigger (since I have no idea wtf you are trying to do) |
Sissors | 5:d9f46ef80e20 | 99 | else |
Sissors | 5:d9f46ef80e20 | 100 | return 1; //Source is memory, destination is peripheral, so m2p |
Sissors | 5:d9f46ef80e20 | 101 | } |
Sissors | 5:d9f46ef80e20 | 102 | else { |
BaderP | 6:e9ab0bb912c8 | 103 | if (isMemory(destination)) |
Sissors | 5:d9f46ef80e20 | 104 | return 2; //Source is peripheral, destination is memory |
Sissors | 5:d9f46ef80e20 | 105 | else |
Sissors | 5:d9f46ef80e20 | 106 | return 3; //Both source and destination are peripherals |
Sissors | 5:d9f46ef80e20 | 107 | } |
Sissors | 5:d9f46ef80e20 | 108 | |
Sissors | 5:d9f46ef80e20 | 109 | } |
Sissors | 5:d9f46ef80e20 | 110 | #endif |