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.

Dependents:   test_mDMA

Committer:
steniu01
Date:
Mon Mar 09 21:47:24 2015 +0000
Revision:
1:9421d79fb372
Parent:
0:8e50c5fd42f6
improved the coding style

Who changed what in which revision?

UserRevisionLine numberNew 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