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.
Dependencies: mbed FastIO FastPWM USBDevice
SimpleDMA/SimpleDMA.h@47:df7a88cd249c, 2016-02-18 (annotated)
- Committer:
- mjr
- Date:
- Thu Feb 18 07:32:20 2016 +0000
- Revision:
- 47:df7a88cd249c
- Parent:
- 45:c42166b2878c
- Child:
- 48:058ace2aed1d
3-channel linked DMA scheme for CCD image capture working
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| mjr | 45:c42166b2878c | 1 | #ifndef SIMPLEDMA_H |
| mjr | 45:c42166b2878c | 2 | #define SIMPLEDMA_H |
| mjr | 45:c42166b2878c | 3 | |
| mjr | 45:c42166b2878c | 4 | #ifdef RTOS_H |
| mjr | 45:c42166b2878c | 5 | #include "rtos.h" |
| mjr | 45:c42166b2878c | 6 | #endif |
| mjr | 45:c42166b2878c | 7 | |
| mjr | 45:c42166b2878c | 8 | #include "mbed.h" |
| mjr | 45:c42166b2878c | 9 | #include "SimpleDMA_KL25.h" |
| mjr | 45:c42166b2878c | 10 | #include "SimpleDMA_KL46.h" |
| mjr | 45:c42166b2878c | 11 | #include "SimpleDMA_LPC1768.h" |
| mjr | 45:c42166b2878c | 12 | |
| mjr | 45:c42166b2878c | 13 | |
| mjr | 45:c42166b2878c | 14 | /** |
| mjr | 45:c42166b2878c | 15 | * SimpleDMA, DMA made simple! (Okay that was bad) |
| mjr | 45:c42166b2878c | 16 | * |
| mjr | 45:c42166b2878c | 17 | * A class to easily make basic DMA operations happen. Not all features |
| mjr | 45:c42166b2878c | 18 | * of the DMA peripherals are used, but the main ones are: From and to memory |
| mjr | 45:c42166b2878c | 19 | * and peripherals, either continiously or triggered |
| mjr | 45:c42166b2878c | 20 | */ |
| mjr | 45:c42166b2878c | 21 | class SimpleDMA { |
| mjr | 45:c42166b2878c | 22 | public: |
| mjr | 45:c42166b2878c | 23 | /** |
| mjr | 45:c42166b2878c | 24 | * Constructor |
| mjr | 45:c42166b2878c | 25 | * |
| mjr | 45:c42166b2878c | 26 | * @param channel - optional parameter which channel should be used, default is automatic channel selection |
| mjr | 45:c42166b2878c | 27 | */ |
| mjr | 45:c42166b2878c | 28 | SimpleDMA(int channel = -1); |
| mjr | 45:c42166b2878c | 29 | |
| mjr | 45:c42166b2878c | 30 | /** |
| mjr | 45:c42166b2878c | 31 | * Set the source of the DMA transfer |
| mjr | 45:c42166b2878c | 32 | * |
| mjr | 45:c42166b2878c | 33 | * Autoincrement increments the pointer after each transfer. If the source |
| mjr | 45:c42166b2878c | 34 | * is an array this should be true, if it is a peripheral or a single memory |
| mjr | 45:c42166b2878c | 35 | * location it should be false. |
| mjr | 45:c42166b2878c | 36 | * |
| mjr | 45:c42166b2878c | 37 | * The source can be any pointer to any memory location. Automatically |
| mjr | 45:c42166b2878c | 38 | * the wordsize is calculated depending on the type, if required you can |
| mjr | 45:c42166b2878c | 39 | * also override this. |
| mjr | 45:c42166b2878c | 40 | * |
| mjr | 45:c42166b2878c | 41 | * @param pointer - pointer to the memory location |
| mjr | 45:c42166b2878c | 42 | * @param autoinc - should the pointer be incremented by the DMA module |
| mjr | 45:c42166b2878c | 43 | * @param size - wordsize in bits (optional, generally can be omitted) |
| mjr | 45:c42166b2878c | 44 | * @return - 0 on success |
| mjr | 45:c42166b2878c | 45 | */ |
| mjr | 45:c42166b2878c | 46 | template<typename Type> |
| mjr | 45:c42166b2878c | 47 | void source(Type* pointer, bool autoinc, int size = sizeof(Type) * 8, int mod = 0) { |
| mjr | 45:c42166b2878c | 48 | _source = (uint32_t)pointer; |
| mjr | 45:c42166b2878c | 49 | source_inc = autoinc; |
| mjr | 45:c42166b2878c | 50 | source_size = size; |
| mjr | 45:c42166b2878c | 51 | source_mod = mod; |
| mjr | 45:c42166b2878c | 52 | } |
| mjr | 45:c42166b2878c | 53 | |
| mjr | 45:c42166b2878c | 54 | /** |
| mjr | 45:c42166b2878c | 55 | * Set the destination of the DMA transfer |
| mjr | 45:c42166b2878c | 56 | * |
| mjr | 45:c42166b2878c | 57 | * Autoincrement increments the pointer after each transfer. If the source |
| mjr | 45:c42166b2878c | 58 | * is an array this should be true, if it is a peripheral or a single memory |
| mjr | 45:c42166b2878c | 59 | * location it should be false. |
| mjr | 45:c42166b2878c | 60 | * |
| mjr | 45:c42166b2878c | 61 | * The destination can be any pointer to any memory location. Automatically |
| mjr | 45:c42166b2878c | 62 | * the wordsize is calculated depending on the type, if required you can |
| mjr | 45:c42166b2878c | 63 | * also override this. |
| mjr | 45:c42166b2878c | 64 | * |
| mjr | 45:c42166b2878c | 65 | * @param pointer - pointer to the memory location |
| mjr | 45:c42166b2878c | 66 | * @param autoinc - should the pointer be incremented by the DMA module |
| mjr | 45:c42166b2878c | 67 | * @param size - wordsize in bits (optional, generally can be omitted) |
| mjr | 45:c42166b2878c | 68 | * @return - 0 on success |
| mjr | 45:c42166b2878c | 69 | */ |
| mjr | 45:c42166b2878c | 70 | template<typename Type> |
| mjr | 45:c42166b2878c | 71 | void destination(Type* pointer, bool autoinc, int size = sizeof(Type) * 8, int mod = 0) { |
| mjr | 45:c42166b2878c | 72 | _destination = (uint32_t)pointer; |
| mjr | 45:c42166b2878c | 73 | destination_inc = autoinc; |
| mjr | 45:c42166b2878c | 74 | destination_size = size; |
| mjr | 45:c42166b2878c | 75 | destination_mod = mod; |
| mjr | 45:c42166b2878c | 76 | } |
| mjr | 45:c42166b2878c | 77 | |
| mjr | 45:c42166b2878c | 78 | /** |
| mjr | 45:c42166b2878c | 79 | * Set cycle-steal mode. In cycle-steal mode, we do one DMA transfer per |
| mjr | 45:c42166b2878c | 80 | * trigger. In continuous mode, we do the entire transfer on a single trigger. |
| mjr | 45:c42166b2878c | 81 | */ |
| mjr | 45:c42166b2878c | 82 | void setCycleSteal(bool f) { cycle_steal = f; } |
| mjr | 45:c42166b2878c | 83 | |
| mjr | 45:c42166b2878c | 84 | /** |
| mjr | 45:c42166b2878c | 85 | * Set the trigger for the DMA operation |
| mjr | 45:c42166b2878c | 86 | * |
| mjr | 45:c42166b2878c | 87 | * In SimpleDMA_[yourdevice].h you can find the names of the different triggers. |
| mjr | 45:c42166b2878c | 88 | * Trigger_ALWAYS is defined for all devices, it will simply move the data |
| mjr | 45:c42166b2878c | 89 | * as fast as possible. Used for memory-memory transfers. If nothing else is set |
| mjr | 45:c42166b2878c | 90 | * that will be used by default. |
| mjr | 45:c42166b2878c | 91 | * |
| mjr | 45:c42166b2878c | 92 | * @param trig - trigger to use |
| mjr | 45:c42166b2878c | 93 | * @param return - 0 on success |
| mjr | 45:c42166b2878c | 94 | */ |
| mjr | 45:c42166b2878c | 95 | void trigger(SimpleDMA_Trigger trig) { |
| mjr | 45:c42166b2878c | 96 | _trigger = trig; |
| mjr | 45:c42166b2878c | 97 | } |
| mjr | 45:c42166b2878c | 98 | |
| mjr | 45:c42166b2878c | 99 | /** |
| mjr | 45:c42166b2878c | 100 | * Set the DMA channel |
| mjr | 45:c42166b2878c | 101 | * |
| mjr | 45:c42166b2878c | 102 | * Generally you will not need to call this function, the constructor does so for you |
| mjr | 45:c42166b2878c | 103 | * |
| mjr | 45:c42166b2878c | 104 | * @param chan - DMA channel to use, -1 = variable channel (highest priority channel which is available) |
| mjr | 45:c42166b2878c | 105 | */ |
| mjr | 45:c42166b2878c | 106 | void channel(int chan); |
| mjr | 47:df7a88cd249c | 107 | int getChannel() { return _channel; } |
| mjr | 45:c42166b2878c | 108 | |
| mjr | 45:c42166b2878c | 109 | /** |
| mjr | 45:c42166b2878c | 110 | * Start the transfer |
| mjr | 45:c42166b2878c | 111 | * |
| mjr | 45:c42166b2878c | 112 | * @param length - number of BYTES to be moved by the DMA |
| mjr | 45:c42166b2878c | 113 | */ |
| mjr | 45:c42166b2878c | 114 | int start(uint32_t length); |
| mjr | 45:c42166b2878c | 115 | |
| mjr | 45:c42166b2878c | 116 | /** |
| mjr | 45:c42166b2878c | 117 | * Start a new transfer with the same parameters as last time |
| mjr | 45:c42166b2878c | 118 | */ |
| mjr | 45:c42166b2878c | 119 | int restart(uint32_t length); |
| mjr | 45:c42166b2878c | 120 | |
| mjr | 45:c42166b2878c | 121 | /** |
| mjr | 45:c42166b2878c | 122 | * Is the DMA channel busy |
| mjr | 45:c42166b2878c | 123 | * |
| mjr | 45:c42166b2878c | 124 | * @param channel - channel to check, -1 = current channel |
| mjr | 45:c42166b2878c | 125 | * @return - true if it is busy |
| mjr | 45:c42166b2878c | 126 | */ |
| mjr | 45:c42166b2878c | 127 | bool isBusy( int channel = -1 ); |
| mjr | 45:c42166b2878c | 128 | |
| mjr | 45:c42166b2878c | 129 | /** |
| mjr | 45:c42166b2878c | 130 | * Number of bytes remaining in running transfer. This reads the controller |
| mjr | 45:c42166b2878c | 131 | * register with the remaining byte count, which the hardware updates each |
| mjr | 45:c42166b2878c | 132 | * time it completes a destination transfer. |
| mjr | 45:c42166b2878c | 133 | */ |
| mjr | 45:c42166b2878c | 134 | uint32_t remaining(int channel = -1); |
| mjr | 45:c42166b2878c | 135 | |
| mjr | 45:c42166b2878c | 136 | /** |
| mjr | 45:c42166b2878c | 137 | * Attach an interrupt upon completion of DMA transfer or error |
| mjr | 45:c42166b2878c | 138 | * |
| mjr | 45:c42166b2878c | 139 | * @param function - function to call upon completion (may be a member function) |
| mjr | 45:c42166b2878c | 140 | */ |
| mjr | 45:c42166b2878c | 141 | void attach(void (*function)(void)) { |
| mjr | 45:c42166b2878c | 142 | _callback.attach(function); |
| mjr | 45:c42166b2878c | 143 | } |
| mjr | 45:c42166b2878c | 144 | |
| mjr | 45:c42166b2878c | 145 | template<typename T> |
| mjr | 45:c42166b2878c | 146 | void attach(T *object, void (T::*member)(void)) { |
| mjr | 45:c42166b2878c | 147 | _callback.attach(object, member); |
| mjr | 45:c42166b2878c | 148 | } |
| mjr | 47:df7a88cd249c | 149 | |
| mjr | 47:df7a88cd249c | 150 | /** |
| mjr | 47:df7a88cd249c | 151 | * Link to another channel. This triggers the given destination |
| mjr | 47:df7a88cd249c | 152 | * channel when a transfer on this channel is completed. If 'all' |
| mjr | 47:df7a88cd249c | 153 | * is true, the link occurs after the entire transfer is complete |
| mjr | 47:df7a88cd249c | 154 | * (i.e., the byte count register in this channel reaches zero). |
| mjr | 47:df7a88cd249c | 155 | * Otherwise, the link is triggered once for each transfer on this |
| mjr | 47:df7a88cd249c | 156 | * channel. |
| mjr | 47:df7a88cd249c | 157 | */ |
| mjr | 47:df7a88cd249c | 158 | void link(SimpleDMA &dest, bool all = false); |
| mjr | 47:df7a88cd249c | 159 | |
| mjr | 47:df7a88cd249c | 160 | /** |
| mjr | 47:df7a88cd249c | 161 | * Link to two other channels. This triggers the 'dest1' channel |
| mjr | 47:df7a88cd249c | 162 | * once for each transfer on this channel, and then triggers the |
| mjr | 47:df7a88cd249c | 163 | * 'dest2' channel once when the entire transfer has been completed |
| mjr | 47:df7a88cd249c | 164 | * (i.e., the byte count register on this channel reaches zero). |
| mjr | 47:df7a88cd249c | 165 | */ |
| mjr | 47:df7a88cd249c | 166 | void link(SimpleDMA &dest1, SimpleDMA &dest2); |
| mjr | 47:df7a88cd249c | 167 | |
| mjr | 45:c42166b2878c | 168 | |
| mjr | 45:c42166b2878c | 169 | #ifdef RTOS_H |
| mjr | 45:c42166b2878c | 170 | /** |
| mjr | 45:c42166b2878c | 171 | * Start a DMA transfer similar to start, however block current Thread |
| mjr | 45:c42166b2878c | 172 | * until the transfer is finished |
| mjr | 45:c42166b2878c | 173 | * |
| mjr | 45:c42166b2878c | 174 | * When using this function only the current Thread is halted. |
| mjr | 45:c42166b2878c | 175 | * The Thread is moved to Waiting state: other Threads will continue |
| mjr | 45:c42166b2878c | 176 | * to run normally. |
| mjr | 45:c42166b2878c | 177 | * |
| mjr | 45:c42166b2878c | 178 | * This function is only available if you included rtos.h before |
| mjr | 45:c42166b2878c | 179 | * including SimpleDMA.h. |
| mjr | 45:c42166b2878c | 180 | * |
| mjr | 45:c42166b2878c | 181 | * @param length - number of BYTES to be moved by the DMA |
| mjr | 45:c42166b2878c | 182 | */ |
| mjr | 45:c42166b2878c | 183 | void wait(int length) { |
| mjr | 45:c42166b2878c | 184 | id = Thread::gettid(); |
| mjr | 45:c42166b2878c | 185 | this->attach(this, &SimpleDMA::waitCallback); |
| mjr | 45:c42166b2878c | 186 | this->start(length); |
| mjr | 45:c42166b2878c | 187 | Thread::signal_wait(0x1); |
| mjr | 45:c42166b2878c | 188 | } |
| mjr | 45:c42166b2878c | 189 | #endif |
| mjr | 45:c42166b2878c | 190 | |
| mjr | 45:c42166b2878c | 191 | protected: |
| mjr | 45:c42166b2878c | 192 | int _channel; |
| mjr | 45:c42166b2878c | 193 | SimpleDMA_Trigger _trigger; |
| mjr | 45:c42166b2878c | 194 | uint32_t _source; |
| mjr | 45:c42166b2878c | 195 | uint32_t _destination; |
| mjr | 45:c42166b2878c | 196 | bool source_inc; |
| mjr | 45:c42166b2878c | 197 | bool destination_inc; |
| mjr | 45:c42166b2878c | 198 | uint8_t source_size; |
| mjr | 45:c42166b2878c | 199 | uint8_t destination_size; |
| mjr | 45:c42166b2878c | 200 | uint32_t source_mod; |
| mjr | 45:c42166b2878c | 201 | uint32_t destination_mod; |
| mjr | 45:c42166b2878c | 202 | bool cycle_steal; |
| mjr | 47:df7a88cd249c | 203 | int linkChannel1; |
| mjr | 47:df7a88cd249c | 204 | int linkChannel2; |
| mjr | 47:df7a88cd249c | 205 | int linkMode; |
| mjr | 45:c42166b2878c | 206 | |
| mjr | 45:c42166b2878c | 207 | bool auto_channel; |
| mjr | 45:c42166b2878c | 208 | |
| mjr | 45:c42166b2878c | 209 | //IRQ handlers |
| mjr | 45:c42166b2878c | 210 | FunctionPointer _callback; |
| mjr | 45:c42166b2878c | 211 | void irq_handler(void); |
| mjr | 45:c42166b2878c | 212 | |
| mjr | 45:c42166b2878c | 213 | static SimpleDMA *irq_owner[DMA_CHANNELS]; |
| mjr | 45:c42166b2878c | 214 | |
| mjr | 45:c42166b2878c | 215 | static void irq_handler0( void ); |
| mjr | 45:c42166b2878c | 216 | |
| mjr | 45:c42166b2878c | 217 | #if DMA_IRQS > 1 |
| mjr | 45:c42166b2878c | 218 | static void irq_handler1( void ); |
| mjr | 45:c42166b2878c | 219 | static void irq_handler2( void ); |
| mjr | 45:c42166b2878c | 220 | static void irq_handler3( void ); |
| mjr | 45:c42166b2878c | 221 | #endif |
| mjr | 45:c42166b2878c | 222 | |
| mjr | 45:c42166b2878c | 223 | //Keep searching until we find a non-busy channel, start with lowest channel number |
| mjr | 45:c42166b2878c | 224 | int getFreeChannel(void); |
| mjr | 45:c42166b2878c | 225 | |
| mjr | 45:c42166b2878c | 226 | #ifdef RTOS_H |
| mjr | 45:c42166b2878c | 227 | osThreadId id; |
| mjr | 45:c42166b2878c | 228 | void waitCallback(void) { |
| mjr | 45:c42166b2878c | 229 | osSignalSet(id, 0x1); |
| mjr | 45:c42166b2878c | 230 | } |
| mjr | 45:c42166b2878c | 231 | #endif |
| mjr | 45:c42166b2878c | 232 | }; |
| mjr | 45:c42166b2878c | 233 | #endif |