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/

Committer:
Sissors
Date:
Thu Dec 26 16:31:54 2013 +0000
Revision:
4:c3a84c6c432c
Parent:
3:34f5bf8adfa0
Child:
5:d9f46ef80e20
Always enable IRQ to finish the DMA transfer
; (Shouldn't be needed, but works for now)

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Sissors 0:d77ea45fa625 1 #ifndef SIMPLEDMA_H
Sissors 0:d77ea45fa625 2 #define SIMPLEDMA_H
Sissors 0:d77ea45fa625 3
Sissors 2:fe2fcaa72434 4 #ifdef RTOS_H
Sissors 2:fe2fcaa72434 5 #include "rtos.h"
Sissors 2:fe2fcaa72434 6 #endif
Sissors 2:fe2fcaa72434 7
Sissors 0:d77ea45fa625 8 #include "mbed.h"
Sissors 0:d77ea45fa625 9 #include "SimpleDMA_KL25.h"
Sissors 0:d77ea45fa625 10
Sissors 0:d77ea45fa625 11
Sissors 0:d77ea45fa625 12 /**
Sissors 0:d77ea45fa625 13 * SimpleDMA, DMA made simple! (Okay that was bad)
Sissors 0:d77ea45fa625 14 *
Sissors 0:d77ea45fa625 15 * A class to easily make basic DMA operations happen. Not all features
Sissors 0:d77ea45fa625 16 * of the DMA peripherals are used, but the main ones are: From and to memory
Sissors 0:d77ea45fa625 17 * and peripherals, either continiously or triggered
Sissors 0:d77ea45fa625 18 */
Sissors 0:d77ea45fa625 19 class SimpleDMA {
Sissors 0:d77ea45fa625 20 public:
Sissors 3:34f5bf8adfa0 21 /**
Sissors 3:34f5bf8adfa0 22 * Constructor
Sissors 3:34f5bf8adfa0 23 *
Sissors 3:34f5bf8adfa0 24 * @param channel - optional parameter which channel should be used, default is automatic channel selection
Sissors 3:34f5bf8adfa0 25 */
Sissors 3:34f5bf8adfa0 26 SimpleDMA(int channel = -1);
Sissors 0:d77ea45fa625 27
Sissors 0:d77ea45fa625 28 /**
Sissors 0:d77ea45fa625 29 * Set the source of the DMA transfer
Sissors 0:d77ea45fa625 30 *
Sissors 0:d77ea45fa625 31 * Autoincrement increments the pointer after each transfer. If the source
Sissors 0:d77ea45fa625 32 * is an array this should be true, if it is a peripheral or a single memory
Sissors 0:d77ea45fa625 33 * location it should be false.
Sissors 0:d77ea45fa625 34 *
Sissors 0:d77ea45fa625 35 * The source can be any pointer to any memory location. Automatically
Sissors 0:d77ea45fa625 36 * the wordsize is calculated depending on the type, if required you can
Sissors 0:d77ea45fa625 37 * also override this.
Sissors 0:d77ea45fa625 38 *
Sissors 0:d77ea45fa625 39 * @param pointer - pointer to the memory location
Sissors 0:d77ea45fa625 40 * @param autoinc - should the pointer be incremented by the DMA module
Sissors 3:34f5bf8adfa0 41 * @param size - wordsize in bits (optional, generally can be omitted)
Sissors 0:d77ea45fa625 42 * @return - 0 on success
Sissors 0:d77ea45fa625 43 */
Sissors 0:d77ea45fa625 44 template<typename Type>
Sissors 3:34f5bf8adfa0 45 int source(Type* pointer, bool autoinc, int size = sizeof(Type) * 8) {
Sissors 2:fe2fcaa72434 46 return setAddress((uint32_t)pointer, size, true, autoinc);
Sissors 0:d77ea45fa625 47 }
Sissors 0:d77ea45fa625 48
Sissors 0:d77ea45fa625 49 /**
Sissors 0:d77ea45fa625 50 * Set the destination of the DMA transfer
Sissors 0:d77ea45fa625 51 *
Sissors 0:d77ea45fa625 52 * Autoincrement increments the pointer after each transfer. If the source
Sissors 0:d77ea45fa625 53 * is an array this should be true, if it is a peripheral or a single memory
Sissors 0:d77ea45fa625 54 * location it should be false.
Sissors 0:d77ea45fa625 55 *
Sissors 0:d77ea45fa625 56 * The destination can be any pointer to any memory location. Automatically
Sissors 0:d77ea45fa625 57 * the wordsize is calculated depending on the type, if required you can
Sissors 0:d77ea45fa625 58 * also override this.
Sissors 0:d77ea45fa625 59 *
Sissors 0:d77ea45fa625 60 * @param pointer - pointer to the memory location
Sissors 0:d77ea45fa625 61 * @param autoinc - should the pointer be incremented by the DMA module
Sissors 3:34f5bf8adfa0 62 * @param size - wordsize in bits (optional, generally can be omitted)
Sissors 0:d77ea45fa625 63 * @return - 0 on success
Sissors 0:d77ea45fa625 64 */
Sissors 0:d77ea45fa625 65 template<typename Type>
Sissors 3:34f5bf8adfa0 66 int destination(Type* pointer, bool autoinc, int size = sizeof(Type) * 8) {
Sissors 2:fe2fcaa72434 67 return setAddress((uint32_t)pointer, size, false, autoinc);
Sissors 0:d77ea45fa625 68 }
Sissors 0:d77ea45fa625 69
Sissors 0:d77ea45fa625 70 /**
Sissors 0:d77ea45fa625 71 * Set the trigger for the DMA operation
Sissors 0:d77ea45fa625 72 *
Sissors 0:d77ea45fa625 73 * In SimpleDMA_[yourdevice].h you can find the names of the different triggers.
Sissors 0:d77ea45fa625 74 * Trigger_ALWAYS is defined for all devices, it will simply move the data
Sissors 0:d77ea45fa625 75 * as fast as possible. Used for memory-memory transfers. If nothing else is set
Sissors 0:d77ea45fa625 76 * that will be used by default.
Sissors 0:d77ea45fa625 77 *
Sissors 0:d77ea45fa625 78 * @param trig - trigger to use
Sissors 0:d77ea45fa625 79 * @param return - 0 on success
Sissors 0:d77ea45fa625 80 */
Sissors 0:d77ea45fa625 81 int trigger(SimpleDMA_Trigger trig);
Sissors 0:d77ea45fa625 82
Sissors 0:d77ea45fa625 83 /**
Sissors 3:34f5bf8adfa0 84 * Set the DMA channel
Sissors 3:34f5bf8adfa0 85 *
Sissors 3:34f5bf8adfa0 86 * Generally you will not need to call this function, the constructor does so for you
Sissors 3:34f5bf8adfa0 87 *
Sissors 3:34f5bf8adfa0 88 * @param chan - DMA channel to use, -1 = variable channel (highest priority channel which is available)
Sissors 3:34f5bf8adfa0 89 */
Sissors 3:34f5bf8adfa0 90 void channel(int chan);
Sissors 3:34f5bf8adfa0 91
Sissors 3:34f5bf8adfa0 92 /**
Sissors 0:d77ea45fa625 93 * Start the transfer
Sissors 0:d77ea45fa625 94 *
Sissors 0:d77ea45fa625 95 * @param length - number of BYTES to be moved by the DMA
Sissors 0:d77ea45fa625 96 */
Sissors 0:d77ea45fa625 97 int start(int length);
Sissors 0:d77ea45fa625 98
Sissors 0:d77ea45fa625 99 /**
Sissors 0:d77ea45fa625 100 * Is the DMA channel busy
Sissors 0:d77ea45fa625 101 *
Sissors 3:34f5bf8adfa0 102 * @param channel - channel to check, -1 = current channel
Sissors 0:d77ea45fa625 103 * @return - true if it is busy
Sissors 0:d77ea45fa625 104 */
Sissors 3:34f5bf8adfa0 105 bool isBusy( int channel = -1 );
Sissors 0:d77ea45fa625 106
Sissors 1:0b73b00bcee8 107 /**
Sissors 1:0b73b00bcee8 108 * Attach an interrupt upon completion of DMA transfer or error
Sissors 1:0b73b00bcee8 109 *
Sissors 1:0b73b00bcee8 110 * @param function - function to call upon completion (may be a member function)
Sissors 1:0b73b00bcee8 111 */
Sissors 1:0b73b00bcee8 112 void attach(void (*function)(void)) {
Sissors 1:0b73b00bcee8 113 _callback.attach(function);
Sissors 1:0b73b00bcee8 114 }
Sissors 1:0b73b00bcee8 115
Sissors 1:0b73b00bcee8 116 template<typename T>
Sissors 1:0b73b00bcee8 117 void attach(T *object, void (T::*member)(void)) {
Sissors 1:0b73b00bcee8 118 _callback.attach(object, member);
Sissors 1:0b73b00bcee8 119 }
Sissors 0:d77ea45fa625 120
Sissors 2:fe2fcaa72434 121 #ifdef RTOS_H
Sissors 3:34f5bf8adfa0 122 /**
Sissors 3:34f5bf8adfa0 123 * Start a DMA transfer similar to start, however block current Thread
Sissors 3:34f5bf8adfa0 124 * until the transfer is finished
Sissors 3:34f5bf8adfa0 125 *
Sissors 3:34f5bf8adfa0 126 * When using this function only the current Thread is halted.
Sissors 3:34f5bf8adfa0 127 * The Thread is moved to Waiting state: other Threads will continue
Sissors 3:34f5bf8adfa0 128 * to run normally.
Sissors 3:34f5bf8adfa0 129 *
Sissors 3:34f5bf8adfa0 130 * This function is only available if you included rtos.h before
Sissors 3:34f5bf8adfa0 131 * including SimpleDMA.h.
Sissors 3:34f5bf8adfa0 132 *
Sissors 3:34f5bf8adfa0 133 * @param length - number of BYTES to be moved by the DMA
Sissors 3:34f5bf8adfa0 134 */
Sissors 2:fe2fcaa72434 135 void wait(int length) {
Sissors 1:0b73b00bcee8 136 id = Thread::gettid();
Sissors 1:0b73b00bcee8 137 this->attach(this, &SimpleDMA::waitCallback);
Sissors 2:fe2fcaa72434 138 this->start(length);
Sissors 1:0b73b00bcee8 139 Thread::signal_wait(0x1);
Sissors 1:0b73b00bcee8 140 }
Sissors 2:fe2fcaa72434 141 #endif
Sissors 0:d77ea45fa625 142
Sissors 0:d77ea45fa625 143 protected:
Sissors 2:fe2fcaa72434 144 int setAddress(uint32_t address, int wordsize, bool source, bool autoinc);
Sissors 1:0b73b00bcee8 145
Sissors 0:d77ea45fa625 146 int _channel;
Sissors 3:34f5bf8adfa0 147 bool auto_channel;
Sissors 2:fe2fcaa72434 148 uint32_t SAR, DAR, DSR, DCR;
Sissors 2:fe2fcaa72434 149 uint8_t CHCFG;
Sissors 2:fe2fcaa72434 150
Sissors 2:fe2fcaa72434 151 //IRQ handlers
Sissors 1:0b73b00bcee8 152 FunctionPointer _callback;
Sissors 1:0b73b00bcee8 153 void irq_handler(void);
Sissors 0:d77ea45fa625 154
Sissors 1:0b73b00bcee8 155 static SimpleDMA *irq_owner[4];
Sissors 1:0b73b00bcee8 156
Sissors 1:0b73b00bcee8 157 static void irq_handler0( void ) {
Sissors 1:0b73b00bcee8 158 if (irq_owner[0]!=NULL)
Sissors 1:0b73b00bcee8 159 irq_owner[0]->irq_handler();
Sissors 1:0b73b00bcee8 160 }
Sissors 1:0b73b00bcee8 161 static void irq_handler1( void ) {
Sissors 1:0b73b00bcee8 162 if (irq_owner[1]!=NULL)
Sissors 1:0b73b00bcee8 163 irq_owner[1]->irq_handler();
Sissors 1:0b73b00bcee8 164 }
Sissors 1:0b73b00bcee8 165 static void irq_handler2( void ) {
Sissors 1:0b73b00bcee8 166 if (irq_owner[2]!=NULL)
Sissors 1:0b73b00bcee8 167 irq_owner[2]->irq_handler();
Sissors 1:0b73b00bcee8 168 }
Sissors 1:0b73b00bcee8 169 static void irq_handler3( void ) {
Sissors 1:0b73b00bcee8 170 if (irq_owner[3]!=NULL)
Sissors 1:0b73b00bcee8 171 irq_owner[3]->irq_handler();
Sissors 1:0b73b00bcee8 172 }
Sissors 2:fe2fcaa72434 173
Sissors 2:fe2fcaa72434 174
Sissors 2:fe2fcaa72434 175 #ifdef RTOS_H
Sissors 1:0b73b00bcee8 176 osThreadId id;
Sissors 1:0b73b00bcee8 177 void waitCallback(void) {
Sissors 2:fe2fcaa72434 178 osSignalSet(id, 0x1);
Sissors 1:0b73b00bcee8 179 }
Sissors 2:fe2fcaa72434 180 #endif
Sissors 0:d77ea45fa625 181
Sissors 3:34f5bf8adfa0 182 //Keep searching until we find a non-busy channel, start with lowest channel number
Sissors 3:34f5bf8adfa0 183 int getFreeChannel(void) {
Sissors 3:34f5bf8adfa0 184 int retval = 0;
Sissors 3:34f5bf8adfa0 185 while(1) {
Sissors 3:34f5bf8adfa0 186 if (!isBusy(retval))
Sissors 3:34f5bf8adfa0 187 return retval;
Sissors 3:34f5bf8adfa0 188 retval++;
Sissors 3:34f5bf8adfa0 189 if (retval >= DMA_CHANNELS)
Sissors 3:34f5bf8adfa0 190 retval = 0;
Sissors 3:34f5bf8adfa0 191 }
Sissors 3:34f5bf8adfa0 192 }
Sissors 0:d77ea45fa625 193 };
Sissors 0:d77ea45fa625 194 #endif