mDMA implements DMA APIs for mbed. It is inspired by modDMA and simpleDMA. Compared with other mbed DMA implementations, mDMA has new features like 1) support LLI 2) support more than 4KB data transfer 3) support vectorized transfer. 4) support burst transfer. 5) Improved memory-memory transfer. It could beat memcpy 6) The library implementation fit the code structure of mbed sdk. Currently only support LPC1768 but could be extended to other platforms.
dma.h@0:8e50c5fd42f6, 2015-03-09 (annotated)
- Committer:
- steniu01
- Date:
- Mon Mar 09 21:29:27 2015 +0000
- Revision:
- 0:8e50c5fd42f6
implement DMA API for mbed
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
steniu01 | 0:8e50c5fd42f6 | 1 | //To be done, |
steniu01 | 0:8e50c5fd42f6 | 2 | // 1. think of inline |
steniu01 | 0:8e50c5fd42f6 | 3 | // 2. |
steniu01 | 0:8e50c5fd42f6 | 4 | // 3. TriggerType |
steniu01 | 0:8e50c5fd42f6 | 5 | |
steniu01 | 0:8e50c5fd42f6 | 6 | |
steniu01 | 0:8e50c5fd42f6 | 7 | //1. use method to get access to class memebers than access directly. It could help to reduce coupling |
steniu01 | 0:8e50c5fd42f6 | 8 | //2. use MIL to initialize variables |
steniu01 | 0:8e50c5fd42f6 | 9 | //3. use const when necessary |
steniu01 | 0:8e50c5fd42f6 | 10 | //4. check memcpy / strecpy, memcpy might not do the right thing |
steniu01 | 0:8e50c5fd42f6 | 11 | //5. API design , what happens when some platform don;t need API. make sure the user code can be same across platform |
steniu01 | 0:8e50c5fd42f6 | 12 | //6. check the user input |
steniu01 | 0:8e50c5fd42f6 | 13 | |
steniu01 | 0:8e50c5fd42f6 | 14 | #ifndef MBED_DMA_H |
steniu01 | 0:8e50c5fd42f6 | 15 | #define MBED_DMA_H |
steniu01 | 0:8e50c5fd42f6 | 16 | |
steniu01 | 0:8e50c5fd42f6 | 17 | |
steniu01 | 0:8e50c5fd42f6 | 18 | #include "dma_api.h" |
steniu01 | 0:8e50c5fd42f6 | 19 | #include "platform.h" |
steniu01 | 0:8e50c5fd42f6 | 20 | #include "FunctionPointer.h" |
steniu01 | 0:8e50c5fd42f6 | 21 | #include "sleep_api.h" |
steniu01 | 0:8e50c5fd42f6 | 22 | /** A generic DMA for transfer data without hanging the CPU. |
steniu01 | 0:8e50c5fd42f6 | 23 | * It can be used for m2m, m2p, p2m, m2m transfer |
steniu01 | 0:8e50c5fd42f6 | 24 | * It will choose the DMA with the priority you have set. |
steniu01 | 0:8e50c5fd42f6 | 25 | * Lower number means higher prority. |
steniu01 | 0:8e50c5fd42f6 | 26 | * If no prority is set, it will choose which ever free channel. |
steniu01 | 0:8e50c5fd42f6 | 27 | * Example: |
steniu01 | 0:8e50c5fd42f6 | 28 | * @code |
steniu01 | 0:8e50c5fd42f6 | 29 | * // Send the memory data "Hello world" in source address to destination address via DMA |
steniu01 | 0:8e50c5fd42f6 | 30 | * // attach a function to swtich LED on when the transfer finish |
steniu01 | 0:8e50c5fd42f6 | 31 | * char src[] = "Hello world\r\n"; |
steniu01 | 0:8e50c5fd42f6 | 32 | * uint8_t size = sizeof (src); |
steniu01 | 0:8e50c5fd42f6 | 33 | * char *dst = (char *) malloc(size); |
steniu01 | 0:8e50c5fd42f6 | 34 | * memset (dst, '\0', size); |
steniu01 | 0:8e50c5fd42f6 | 35 | * LPC_SC->PCONP |= (1 << 29); // Enable LPC1768 GPDMA clock |
steniu01 | 0:8e50c5fd42f6 | 36 | * DMA dma1 (0) ; |
steniu01 | 0:8e50c5fd42f6 | 37 | * dma1.source (src,0,1); |
steniu01 | 0:8e50c5fd42f6 | 38 | * dma1.destination (dst,0,1); |
steniu01 | 0:8e50c5fd42f6 | 39 | * dma1.attach_TC(led_switchon) ; |
steniu01 | 0:8e50c5fd42f6 | 40 | * dma1.start(size); |
steniu01 | 0:8e50c5fd42f6 | 41 | * dma1.wait(); |
steniu01 | 0:8e50c5fd42f6 | 42 | * printf("dst text: %s", dst); |
steniu01 | 0:8e50c5fd42f6 | 43 | * @endcode |
steniu01 | 0:8e50c5fd42f6 | 44 | */ |
steniu01 | 0:8e50c5fd42f6 | 45 | |
steniu01 | 0:8e50c5fd42f6 | 46 | namespace mbed{ |
steniu01 | 0:8e50c5fd42f6 | 47 | class DMA |
steniu01 | 0:8e50c5fd42f6 | 48 | { |
steniu01 | 0:8e50c5fd42f6 | 49 | public: |
steniu01 | 0:8e50c5fd42f6 | 50 | /** @brief Create the DMA Channel according to the prority or choose whichever free if no prority given. |
steniu01 | 0:8e50c5fd42f6 | 51 | * Initialize the number of channels in the device |
steniu01 | 0:8e50c5fd42f6 | 52 | * @param priority: The DMA prority. |
steniu01 | 0:8e50c5fd42f6 | 53 | * @note If prority has been given but that channel is not avaiable, it will wait until the channel avaiable. |
steniu01 | 0:8e50c5fd42f6 | 54 | */ |
steniu01 | 0:8e50c5fd42f6 | 55 | DMA(int priority = -1); |
steniu01 | 0:8e50c5fd42f6 | 56 | |
steniu01 | 0:8e50c5fd42f6 | 57 | ~DMA (); |
steniu01 | 0:8e50c5fd42f6 | 58 | /** @brief Get source starting address, transfer width and setting auto increment. |
steniu01 | 0:8e50c5fd42f6 | 59 | * @param src. The source starting address. |
steniu01 | 0:8e50c5fd42f6 | 60 | * @param inc. Set memory automatice increment. |
steniu01 | 0:8e50c5fd42f6 | 61 | * @param width. The transfer data width |
steniu01 | 0:8e50c5fd42f6 | 62 | * @note If width is not given, it will set the width automatically according to the data type in the memory |
steniu01 | 0:8e50c5fd42f6 | 63 | */ |
steniu01 | 0:8e50c5fd42f6 | 64 | template<typename T> // To be reviewd, should put the template into the cpp rather than the header? |
steniu01 | 0:8e50c5fd42f6 | 65 | void source (T* src, bool inc, unsigned int width = sizeof(T)*8 ) { |
steniu01 | 0:8e50c5fd42f6 | 66 | //inc = isMemory ((uint32_t)src); // To be reviewed. How to put this line into the arguments? |
steniu01 | 0:8e50c5fd42f6 | 67 | uint32_t src_prt= (uint32_t) src; |
steniu01 | 0:8e50c5fd42f6 | 68 | DMA_source(dma_init_struct, src_prt, width, inc); |
steniu01 | 0:8e50c5fd42f6 | 69 | } |
steniu01 | 0:8e50c5fd42f6 | 70 | |
steniu01 | 0:8e50c5fd42f6 | 71 | /** @brief Get destination starting address, transfer width and setting auto increment. |
steniu01 | 0:8e50c5fd42f6 | 72 | * @param dst. The destination starting address. |
steniu01 | 0:8e50c5fd42f6 | 73 | * @param inc. Set memory automatice increment. |
steniu01 | 0:8e50c5fd42f6 | 74 | * @param width. The transfer data width |
steniu01 | 0:8e50c5fd42f6 | 75 | * @note If width is not given, it will set the width automatically according to the data type in the memory |
steniu01 | 0:8e50c5fd42f6 | 76 | * |
steniu01 | 0:8e50c5fd42f6 | 77 | */ |
steniu01 | 0:8e50c5fd42f6 | 78 | template<typename T> |
steniu01 | 0:8e50c5fd42f6 | 79 | void destination (T* dst, bool inc, unsigned int width =sizeof(T)*8 ) { |
steniu01 | 0:8e50c5fd42f6 | 80 | //inc = isMemory ((uint32_t) dst); |
steniu01 | 0:8e50c5fd42f6 | 81 | uint32_t dst_ptr=(uint32_t) dst; |
steniu01 | 0:8e50c5fd42f6 | 82 | DMA_destination(dma_init_struct, dst_ptr, width, inc); |
steniu01 | 0:8e50c5fd42f6 | 83 | } |
steniu01 | 0:8e50c5fd42f6 | 84 | |
steniu01 | 0:8e50c5fd42f6 | 85 | /** @brief Get source trigger type |
steniu01 | 0:8e50c5fd42f6 | 86 | * @param trig. The source triggert type. |
steniu01 | 0:8e50c5fd42f6 | 87 | * @note If the source is memory. The trigger type would be ALWAYS even you set it differently. |
steniu01 | 0:8e50c5fd42f6 | 88 | */ |
steniu01 | 0:8e50c5fd42f6 | 89 | void TriggerSource(TriggerType trig = ALWAYS); |
steniu01 | 0:8e50c5fd42f6 | 90 | |
steniu01 | 0:8e50c5fd42f6 | 91 | /** @brief Get destination trigger type |
steniu01 | 0:8e50c5fd42f6 | 92 | * @param trig. The destination triggert type. |
steniu01 | 0:8e50c5fd42f6 | 93 | * @note If the destination is memory. The trigger type would be ALWAYS even you set it differently. |
steniu01 | 0:8e50c5fd42f6 | 94 | */ |
steniu01 | 0:8e50c5fd42f6 | 95 | void TriggerDestination(TriggerType trig = ALWAYS ); |
steniu01 | 0:8e50c5fd42f6 | 96 | |
steniu01 | 0:8e50c5fd42f6 | 97 | |
steniu01 | 0:8e50c5fd42f6 | 98 | /** @brief Start the DMA to transfer data |
steniu01 | 0:8e50c5fd42f6 | 99 | * @param lengh. Define how many data the DMA needs to transfer |
steniu01 | 0:8e50c5fd42f6 | 100 | */ |
steniu01 | 0:8e50c5fd42f6 | 101 | void start(unsigned int len); |
steniu01 | 0:8e50c5fd42f6 | 102 | |
steniu01 | 0:8e50c5fd42f6 | 103 | /** @brief Get the address storing next linked list item |
steniu01 | 0:8e50c5fd42f6 | 104 | * @param src. Next transfer source address |
steniu01 | 0:8e50c5fd42f6 | 105 | * @param dst. Next transfer destination address |
steniu01 | 0:8e50c5fd42f6 | 106 | * @param size. Next transfer size |
steniu01 | 0:8e50c5fd42f6 | 107 | * @retval None |
steniu01 | 0:8e50c5fd42f6 | 108 | */ |
steniu01 | 0:8e50c5fd42f6 | 109 | // void next(LLI* list); |
steniu01 | 0:8e50c5fd42f6 | 110 | void next(const uint32_t src, const uint32_t dst, uint32_t size); |
steniu01 | 0:8e50c5fd42f6 | 111 | |
steniu01 | 0:8e50c5fd42f6 | 112 | /** @brief Wait for DMA transaction finishes or err interrupt happens |
steniu01 | 0:8e50c5fd42f6 | 113 | * @retval None |
steniu01 | 0:8e50c5fd42f6 | 114 | */ |
steniu01 | 0:8e50c5fd42f6 | 115 | void wait(); |
steniu01 | 0:8e50c5fd42f6 | 116 | |
steniu01 | 0:8e50c5fd42f6 | 117 | |
steniu01 | 0:8e50c5fd42f6 | 118 | /** @brief Check whether DMA transaction has finished or generated errors |
steniu01 | 0:8e50c5fd42f6 | 119 | * @retval 0 if not finished or 1 if finished |
steniu01 | 0:8e50c5fd42f6 | 120 | */ |
steniu01 | 0:8e50c5fd42f6 | 121 | bool finished(); |
steniu01 | 0:8e50c5fd42f6 | 122 | |
steniu01 | 0:8e50c5fd42f6 | 123 | /** @brief Attach a function to DMA IRQ handler. The attached function will be called when the transfer has completed successfully. |
steniu01 | 0:8e50c5fd42f6 | 124 | * @param *fptr. The function pointer. |
steniu01 | 0:8e50c5fd42f6 | 125 | */ |
steniu01 | 0:8e50c5fd42f6 | 126 | void attach_TC(func_ptr fptr) { |
steniu01 | 0:8e50c5fd42f6 | 127 | DMA_IRQ_attach(chan, FINISH, fptr); |
steniu01 | 0:8e50c5fd42f6 | 128 | NVIC_SetVector(DMA_IRQn, (uint32_t)&DMA_IRQ_handler); |
steniu01 | 0:8e50c5fd42f6 | 129 | NVIC_EnableIRQ(DMA_IRQn); |
steniu01 | 0:8e50c5fd42f6 | 130 | } |
steniu01 | 0:8e50c5fd42f6 | 131 | |
steniu01 | 0:8e50c5fd42f6 | 132 | |
steniu01 | 0:8e50c5fd42f6 | 133 | /** @brief Attach a function to DMA IRQ handler. The attached function will be called when the transfer has completed successfully. |
steniu01 | 0:8e50c5fd42f6 | 134 | * @param *fptr. The function pointer. |
steniu01 | 0:8e50c5fd42f6 | 135 | * @note There are two attach function attach_TC and attach_Err in case you want to attach different functions when tranfer finishs or fails |
steniu01 | 0:8e50c5fd42f6 | 136 | */ |
steniu01 | 0:8e50c5fd42f6 | 137 | void attach_Err(func_ptr fptr) { |
steniu01 | 0:8e50c5fd42f6 | 138 | DMA_IRQ_attach(chan, ERR, fptr); |
steniu01 | 0:8e50c5fd42f6 | 139 | NVIC_SetVector(_DMA_IRQ, (uint32_t)&DMA_IRQ_handler); |
steniu01 | 0:8e50c5fd42f6 | 140 | NVIC_EnableIRQ(_DMA_IRQ); |
steniu01 | 0:8e50c5fd42f6 | 141 | } |
steniu01 | 0:8e50c5fd42f6 | 142 | |
steniu01 | 0:8e50c5fd42f6 | 143 | |
steniu01 | 0:8e50c5fd42f6 | 144 | protected: |
steniu01 | 0:8e50c5fd42f6 | 145 | int chan; // the chosen channel number |
steniu01 | 0:8e50c5fd42f6 | 146 | int chooseFreeChannel(int channel); |
steniu01 | 0:8e50c5fd42f6 | 147 | int channel_num; |
steniu01 | 0:8e50c5fd42f6 | 148 | DMA_InitTypeDef* dma_init_struct; |
steniu01 | 0:8e50c5fd42f6 | 149 | }; |
steniu01 | 0:8e50c5fd42f6 | 150 | |
steniu01 | 0:8e50c5fd42f6 | 151 | } |
steniu01 | 0:8e50c5fd42f6 | 152 | #endif |