Mirror with some correction
Dependencies: mbed FastIO FastPWM USBDevice
SimpleDMA/SimpleDMA.h@116:7a67265d7c19, 2021-10-01 (annotated)
- Committer:
- arnoz
- Date:
- Fri Oct 01 08:19:46 2021 +0000
- Revision:
- 116:7a67265d7c19
- Parent:
- 100:1ff35c07217c
- Correct information regarding your last merge
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 | 48:058ace2aed1d | 47 | void source(Type* pointer, bool autoinc, int size = sizeof(Type) * 8) { |
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 | } |
mjr | 45:c42166b2878c | 52 | |
mjr | 45:c42166b2878c | 53 | /** |
mjr | 45:c42166b2878c | 54 | * Set the destination of the DMA transfer |
mjr | 45:c42166b2878c | 55 | * |
mjr | 45:c42166b2878c | 56 | * Autoincrement increments the pointer after each transfer. If the source |
mjr | 45:c42166b2878c | 57 | * is an array this should be true, if it is a peripheral or a single memory |
mjr | 45:c42166b2878c | 58 | * location it should be false. |
mjr | 45:c42166b2878c | 59 | * |
mjr | 45:c42166b2878c | 60 | * The destination can be any pointer to any memory location. Automatically |
mjr | 45:c42166b2878c | 61 | * the wordsize is calculated depending on the type, if required you can |
mjr | 45:c42166b2878c | 62 | * also override this. |
mjr | 45:c42166b2878c | 63 | * |
mjr | 45:c42166b2878c | 64 | * @param pointer - pointer to the memory location |
mjr | 45:c42166b2878c | 65 | * @param autoinc - should the pointer be incremented by the DMA module |
mjr | 45:c42166b2878c | 66 | * @param size - wordsize in bits (optional, generally can be omitted) |
mjr | 45:c42166b2878c | 67 | * @return - 0 on success |
mjr | 45:c42166b2878c | 68 | */ |
mjr | 45:c42166b2878c | 69 | template<typename Type> |
mjr | 48:058ace2aed1d | 70 | void destination(Type* pointer, bool autoinc, int size = sizeof(Type) * 8) { |
mjr | 45:c42166b2878c | 71 | _destination = (uint32_t)pointer; |
mjr | 45:c42166b2878c | 72 | destination_inc = autoinc; |
mjr | 45:c42166b2878c | 73 | destination_size = size; |
mjr | 45:c42166b2878c | 74 | } |
mjr | 45:c42166b2878c | 75 | |
mjr | 45:c42166b2878c | 76 | |
mjr | 45:c42166b2878c | 77 | /** |
mjr | 45:c42166b2878c | 78 | * Set the trigger for the DMA operation |
mjr | 45:c42166b2878c | 79 | * |
mjr | 45:c42166b2878c | 80 | * In SimpleDMA_[yourdevice].h you can find the names of the different triggers. |
mjr | 45:c42166b2878c | 81 | * Trigger_ALWAYS is defined for all devices, it will simply move the data |
mjr | 45:c42166b2878c | 82 | * as fast as possible. Used for memory-memory transfers. If nothing else is set |
mjr | 45:c42166b2878c | 83 | * that will be used by default. |
mjr | 45:c42166b2878c | 84 | * |
mjr | 45:c42166b2878c | 85 | * @param trig - trigger to use |
mjr | 45:c42166b2878c | 86 | * @param return - 0 on success |
mjr | 45:c42166b2878c | 87 | */ |
mjr | 45:c42166b2878c | 88 | void trigger(SimpleDMA_Trigger trig) { |
mjr | 45:c42166b2878c | 89 | _trigger = trig; |
mjr | 45:c42166b2878c | 90 | } |
mjr | 45:c42166b2878c | 91 | |
mjr | 45:c42166b2878c | 92 | /** |
mjr | 45:c42166b2878c | 93 | * Set the DMA channel |
mjr | 45:c42166b2878c | 94 | * |
mjr | 45:c42166b2878c | 95 | * Generally you will not need to call this function, the constructor does so for you |
mjr | 45:c42166b2878c | 96 | * |
mjr | 45:c42166b2878c | 97 | * @param chan - DMA channel to use, -1 = variable channel (highest priority channel which is available) |
mjr | 45:c42166b2878c | 98 | */ |
mjr | 45:c42166b2878c | 99 | void channel(int chan); |
mjr | 47:df7a88cd249c | 100 | int getChannel() { return _channel; } |
mjr | 45:c42166b2878c | 101 | |
mjr | 45:c42166b2878c | 102 | /** |
mjr | 45:c42166b2878c | 103 | * Start the transfer |
mjr | 45:c42166b2878c | 104 | * |
mjr | 45:c42166b2878c | 105 | * @param length - number of BYTES to be moved by the DMA |
mjr | 45:c42166b2878c | 106 | */ |
mjr | 54:fd77a6b2f76c | 107 | int start(uint32_t length, bool wait); |
mjr | 45:c42166b2878c | 108 | |
mjr | 45:c42166b2878c | 109 | /** |
mjr | 100:1ff35c07217c | 110 | * Prepare a transfer. This sets everything up for a transfer, but leaves it up |
mjr | 100:1ff35c07217c | 111 | * to the caller to trigger the start of the transfer. This gives the caller |
mjr | 100:1ff35c07217c | 112 | * precise control over the timing of the transfer, for transfers that must be |
mjr | 100:1ff35c07217c | 113 | * synchronized with other functions. To start the DMA transfer, the caller |
mjr | 100:1ff35c07217c | 114 | * must simply "OR" DMAMUX_CHCFG_ENBL_MASK into the byte at the returned |
mjr | 100:1ff35c07217c | 115 | * address. |
mjr | 100:1ff35c07217c | 116 | */ |
mjr | 100:1ff35c07217c | 117 | volatile uint8_t *prepare(uint32_t length, bool wait); |
mjr | 100:1ff35c07217c | 118 | |
mjr | 100:1ff35c07217c | 119 | /** |
mjr | 45:c42166b2878c | 120 | * Is the DMA channel busy |
mjr | 45:c42166b2878c | 121 | * |
mjr | 45:c42166b2878c | 122 | * @param channel - channel to check, -1 = current channel |
mjr | 45:c42166b2878c | 123 | * @return - true if it is busy |
mjr | 45:c42166b2878c | 124 | */ |
mjr | 45:c42166b2878c | 125 | bool isBusy( int channel = -1 ); |
mjr | 45:c42166b2878c | 126 | |
mjr | 45:c42166b2878c | 127 | /** |
mjr | 45:c42166b2878c | 128 | * Number of bytes remaining in running transfer. This reads the controller |
mjr | 45:c42166b2878c | 129 | * register with the remaining byte count, which the hardware updates each |
mjr | 45:c42166b2878c | 130 | * time it completes a destination transfer. |
mjr | 45:c42166b2878c | 131 | */ |
mjr | 45:c42166b2878c | 132 | uint32_t remaining(int channel = -1); |
mjr | 45:c42166b2878c | 133 | |
mjr | 45:c42166b2878c | 134 | /** |
mjr | 45:c42166b2878c | 135 | * Attach an interrupt upon completion of DMA transfer or error |
mjr | 45:c42166b2878c | 136 | * |
mjr | 45:c42166b2878c | 137 | * @param function - function to call upon completion (may be a member function) |
mjr | 45:c42166b2878c | 138 | */ |
mjr | 45:c42166b2878c | 139 | void attach(void (*function)(void)) { |
mjr | 45:c42166b2878c | 140 | _callback.attach(function); |
mjr | 45:c42166b2878c | 141 | } |
mjr | 45:c42166b2878c | 142 | |
mjr | 45:c42166b2878c | 143 | template<typename T> |
mjr | 45:c42166b2878c | 144 | void attach(T *object, void (T::*member)(void)) { |
mjr | 45:c42166b2878c | 145 | _callback.attach(object, member); |
mjr | 45:c42166b2878c | 146 | } |
mjr | 47:df7a88cd249c | 147 | |
mjr | 47:df7a88cd249c | 148 | /** |
mjr | 47:df7a88cd249c | 149 | * Link to another channel. This triggers the given destination |
mjr | 47:df7a88cd249c | 150 | * channel when a transfer on this channel is completed. If 'all' |
mjr | 47:df7a88cd249c | 151 | * is true, the link occurs after the entire transfer is complete |
mjr | 47:df7a88cd249c | 152 | * (i.e., the byte count register in this channel reaches zero). |
mjr | 47:df7a88cd249c | 153 | * Otherwise, the link is triggered once for each transfer on this |
mjr | 47:df7a88cd249c | 154 | * channel. |
mjr | 47:df7a88cd249c | 155 | */ |
mjr | 47:df7a88cd249c | 156 | void link(SimpleDMA &dest, bool all = false); |
mjr | 47:df7a88cd249c | 157 | |
mjr | 47:df7a88cd249c | 158 | /** |
mjr | 47:df7a88cd249c | 159 | * Link to two other channels. This triggers the 'dest1' channel |
mjr | 47:df7a88cd249c | 160 | * once for each transfer on this channel, and then triggers the |
mjr | 47:df7a88cd249c | 161 | * 'dest2' channel once when the entire transfer has been completed |
mjr | 47:df7a88cd249c | 162 | * (i.e., the byte count register on this channel reaches zero). |
mjr | 47:df7a88cd249c | 163 | */ |
mjr | 47:df7a88cd249c | 164 | void link(SimpleDMA &dest1, SimpleDMA &dest2); |
mjr | 47:df7a88cd249c | 165 | |
mjr | 45:c42166b2878c | 166 | |
mjr | 45:c42166b2878c | 167 | #ifdef RTOS_H |
mjr | 45:c42166b2878c | 168 | /** |
mjr | 45:c42166b2878c | 169 | * Start a DMA transfer similar to start, however block current Thread |
mjr | 45:c42166b2878c | 170 | * until the transfer is finished |
mjr | 45:c42166b2878c | 171 | * |
mjr | 45:c42166b2878c | 172 | * When using this function only the current Thread is halted. |
mjr | 45:c42166b2878c | 173 | * The Thread is moved to Waiting state: other Threads will continue |
mjr | 45:c42166b2878c | 174 | * to run normally. |
mjr | 45:c42166b2878c | 175 | * |
mjr | 45:c42166b2878c | 176 | * This function is only available if you included rtos.h before |
mjr | 45:c42166b2878c | 177 | * including SimpleDMA.h. |
mjr | 45:c42166b2878c | 178 | * |
mjr | 45:c42166b2878c | 179 | * @param length - number of BYTES to be moved by the DMA |
mjr | 45:c42166b2878c | 180 | */ |
mjr | 45:c42166b2878c | 181 | void wait(int length) { |
mjr | 45:c42166b2878c | 182 | id = Thread::gettid(); |
mjr | 45:c42166b2878c | 183 | this->attach(this, &SimpleDMA::waitCallback); |
mjr | 45:c42166b2878c | 184 | this->start(length); |
mjr | 45:c42166b2878c | 185 | Thread::signal_wait(0x1); |
mjr | 45:c42166b2878c | 186 | } |
mjr | 45:c42166b2878c | 187 | #endif |
mjr | 45:c42166b2878c | 188 | |
mjr | 45:c42166b2878c | 189 | protected: |
mjr | 48:058ace2aed1d | 190 | uint8_t _channel; |
mjr | 45:c42166b2878c | 191 | SimpleDMA_Trigger _trigger; |
mjr | 45:c42166b2878c | 192 | uint32_t _source; |
mjr | 45:c42166b2878c | 193 | uint32_t _destination; |
mjr | 45:c42166b2878c | 194 | uint8_t source_size; |
mjr | 45:c42166b2878c | 195 | uint8_t destination_size; |
mjr | 48:058ace2aed1d | 196 | uint8_t linkChannel1; |
mjr | 48:058ace2aed1d | 197 | uint8_t linkChannel2; |
mjr | 48:058ace2aed1d | 198 | bool source_inc : 1; |
mjr | 48:058ace2aed1d | 199 | bool destination_inc : 1; |
mjr | 48:058ace2aed1d | 200 | bool auto_channel : 1; |
mjr | 48:058ace2aed1d | 201 | uint8_t linkMode : 2; |
mjr | 45:c42166b2878c | 202 | |
mjr | 45:c42166b2878c | 203 | |
mjr | 45:c42166b2878c | 204 | //IRQ handlers |
mjr | 45:c42166b2878c | 205 | FunctionPointer _callback; |
mjr | 45:c42166b2878c | 206 | void irq_handler(void); |
mjr | 45:c42166b2878c | 207 | |
mjr | 45:c42166b2878c | 208 | static SimpleDMA *irq_owner[DMA_CHANNELS]; |
mjr | 45:c42166b2878c | 209 | |
mjr | 48:058ace2aed1d | 210 | static void class_init(); |
mjr | 45:c42166b2878c | 211 | static void irq_handler0( void ); |
mjr | 45:c42166b2878c | 212 | |
mjr | 45:c42166b2878c | 213 | #if DMA_IRQS > 1 |
mjr | 45:c42166b2878c | 214 | static void irq_handler1( void ); |
mjr | 45:c42166b2878c | 215 | static void irq_handler2( void ); |
mjr | 45:c42166b2878c | 216 | static void irq_handler3( void ); |
mjr | 45:c42166b2878c | 217 | #endif |
mjr | 45:c42166b2878c | 218 | |
mjr | 45:c42166b2878c | 219 | //Keep searching until we find a non-busy channel, start with lowest channel number |
mjr | 45:c42166b2878c | 220 | int getFreeChannel(void); |
mjr | 45:c42166b2878c | 221 | |
mjr | 45:c42166b2878c | 222 | #ifdef RTOS_H |
mjr | 45:c42166b2878c | 223 | osThreadId id; |
mjr | 45:c42166b2878c | 224 | void waitCallback(void) { |
mjr | 45:c42166b2878c | 225 | osSignalSet(id, 0x1); |
mjr | 45:c42166b2878c | 226 | } |
mjr | 45:c42166b2878c | 227 | #endif |
mjr | 45:c42166b2878c | 228 | }; |
mjr | 45:c42166b2878c | 229 | #endif |