An I/O controller for virtual pinball machines: accelerometer nudge sensing, analog plunger input, button input encoding, LedWiz compatible output controls, and more.

Dependencies:   mbed FastIO FastPWM USBDevice

Fork of Pinscape_Controller by Mike R

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SimpleDMA.h Source File

SimpleDMA.h

00001 #ifndef SIMPLEDMA_H
00002 #define SIMPLEDMA_H
00003 
00004 #ifdef RTOS_H
00005 #include "rtos.h"
00006 #endif
00007 
00008 #include "mbed.h"
00009 #include "SimpleDMA_KL25.h"
00010 #include "SimpleDMA_KL46.h"
00011 #include "SimpleDMA_LPC1768.h"
00012 
00013 
00014 /**
00015 * SimpleDMA, DMA made simple! (Okay that was bad)
00016 *
00017 * A class to easily make basic DMA operations happen. Not all features
00018 * of the DMA peripherals are used, but the main ones are: From and to memory
00019 * and peripherals, either continiously or triggered
00020 */
00021 class SimpleDMA {
00022 public:
00023 /**
00024 * Constructor
00025 *
00026 * @param channel - optional parameter which channel should be used, default is automatic channel selection
00027 */
00028 SimpleDMA(int channel = -1);
00029 
00030 /**
00031 * Set the source of the DMA transfer
00032 *
00033 * Autoincrement increments the pointer after each transfer. If the source
00034 * is an array this should be true, if it is a peripheral or a single memory
00035 * location it should be false.
00036 *
00037 * The source can be any pointer to any memory location. Automatically
00038 * the wordsize is calculated depending on the type, if required you can
00039 * also override this.
00040 *
00041 * @param pointer - pointer to the memory location
00042 * @param autoinc - should the pointer be incremented by the DMA module
00043 * @param size - wordsize in bits (optional, generally can be omitted)
00044 * @return - 0 on success
00045 */
00046 template<typename Type>
00047 void source(Type* pointer, bool autoinc, int size = sizeof(Type) * 8) {
00048     _source = (uint32_t)pointer;
00049     source_inc = autoinc;
00050     source_size = size;
00051 }
00052 
00053 /**
00054 * Set the destination of the DMA transfer
00055 *
00056 * Autoincrement increments the pointer after each transfer. If the source
00057 * is an array this should be true, if it is a peripheral or a single memory
00058 * location it should be false.
00059 *
00060 * The destination can be any pointer to any memory location. Automatically
00061 * the wordsize is calculated depending on the type, if required you can
00062 * also override this.
00063 *
00064 * @param pointer - pointer to the memory location
00065 * @param autoinc - should the pointer be incremented by the DMA module
00066 * @param size - wordsize in bits (optional, generally can be omitted)
00067 * @return - 0 on success
00068 */
00069 template<typename Type>
00070 void destination(Type* pointer, bool autoinc, int size = sizeof(Type) * 8) {
00071     _destination = (uint32_t)pointer;
00072     destination_inc = autoinc;
00073     destination_size = size;
00074 }
00075 
00076 
00077 /**
00078 * Set the trigger for the DMA operation
00079 *
00080 * In SimpleDMA_[yourdevice].h you can find the names of the different triggers.
00081 * Trigger_ALWAYS is defined for all devices, it will simply move the data
00082 * as fast as possible. Used for memory-memory transfers. If nothing else is set
00083 * that will be used by default.
00084 *
00085 * @param trig - trigger to use
00086 * @param return - 0 on success
00087 */
00088 void trigger(SimpleDMA_Trigger trig) {
00089     _trigger = trig;
00090 }
00091 
00092 /**
00093 * Set the DMA channel
00094 *
00095 * Generally you will not need to call this function, the constructor does so for you
00096 *
00097 * @param chan - DMA channel to use, -1 = variable channel (highest priority channel which is available)
00098 */
00099 void channel(int chan);
00100 int getChannel() { return _channel; }
00101 
00102 /**
00103 * Start the transfer
00104 *
00105 * @param length - number of BYTES to be moved by the DMA
00106 */
00107 int start(uint32_t length, bool wait);
00108 
00109 /**
00110 * Prepare a transfer.  This sets everything up for a transfer, but leaves it up
00111 * to the caller to trigger the start of the transfer.  This gives the caller
00112 * precise control over the timing of the transfer, for transfers that must be
00113 * synchronized with other functions.  To start the DMA transfer, the caller
00114 * must simply "OR" DMAMUX_CHCFG_ENBL_MASK into the byte at the returned 
00115 * address.
00116 */
00117 volatile uint8_t *prepare(uint32_t length, bool wait);
00118 
00119 /**
00120 * Is the DMA channel busy
00121 *
00122 * @param channel - channel to check, -1 = current channel
00123 * @return - true if it is busy
00124 */
00125 bool isBusy( int channel = -1 );
00126 
00127 /**
00128 * Number of bytes remaining in running transfer.  This reads the controller
00129 * register with the remaining byte count, which the hardware updates each
00130 * time it completes a destination transfer.
00131 */
00132 uint32_t remaining(int channel = -1);
00133 
00134 /**
00135 * Attach an interrupt upon completion of DMA transfer or error
00136 *
00137 * @param function - function to call upon completion (may be a member function)
00138 */
00139 void attach(void (*function)(void)) {
00140     _callback.attach(function);
00141     }
00142     
00143 template<typename T>
00144     void attach(T *object, void (T::*member)(void)) {
00145         _callback.attach(object, member);
00146     }
00147     
00148 /**
00149 * Link to another channel.  This triggers the given destination
00150 * channel when a transfer on this channel is completed.  If 'all' 
00151 * is true, the link occurs after the entire transfer is complete 
00152 * (i.e., the byte count register in this channel reaches zero).
00153 * Otherwise, the link is triggered once for each transfer on this
00154 * channel.
00155 */
00156 void link(SimpleDMA &dest, bool all = false);
00157 
00158 /**
00159 * Link to two other channels.  This triggers the 'dest1' channel
00160 * once for each transfer on this channel, and then triggers the
00161 * 'dest2' channel once when the entire transfer has been completed
00162 * (i.e., the byte count register on this channel reaches zero).
00163 */
00164 void link(SimpleDMA &dest1, SimpleDMA &dest2);
00165 
00166 
00167 #ifdef RTOS_H
00168 /**
00169 * Start a DMA transfer similar to start, however block current Thread
00170 * until the transfer is finished
00171 *
00172 * When using this function only the current Thread is halted.
00173 * The Thread is moved to Waiting state: other Threads will continue
00174 * to run normally. 
00175 *
00176 * This function is only available if you included rtos.h before 
00177 * including SimpleDMA.h.
00178 *
00179 * @param length - number of BYTES to be moved by the DMA
00180 */
00181 void wait(int length) {
00182     id = Thread::gettid();
00183     this->attach(this, &SimpleDMA::waitCallback);
00184     this->start(length);
00185     Thread::signal_wait(0x1);
00186 }
00187 #endif
00188 
00189 protected:
00190 uint8_t _channel;
00191 SimpleDMA_Trigger _trigger;
00192 uint32_t _source;
00193 uint32_t _destination;
00194 uint8_t source_size;
00195 uint8_t destination_size;
00196 uint8_t linkChannel1;
00197 uint8_t linkChannel2;
00198 bool source_inc : 1;
00199 bool destination_inc : 1;
00200 bool auto_channel : 1;
00201 uint8_t linkMode : 2;
00202 
00203 
00204 //IRQ handlers
00205 FunctionPointer _callback;
00206 void irq_handler(void);
00207 
00208 static SimpleDMA *irq_owner[DMA_CHANNELS];
00209 
00210 static void class_init();
00211 static void irq_handler0( void ); 
00212 
00213 #if DMA_IRQS > 1
00214 static void irq_handler1( void );
00215 static void irq_handler2( void );
00216 static void irq_handler3( void );
00217 #endif
00218 
00219 //Keep searching until we find a non-busy channel, start with lowest channel number
00220 int getFreeChannel(void);
00221 
00222 #ifdef RTOS_H
00223 osThreadId id;
00224 void waitCallback(void) {
00225     osSignalSet(id, 0x1);    
00226 }
00227 #endif
00228 };
00229 #endif