A simple library to access the DMA functionality.

Fork of SimpleDMA by Erik -

Files at this revision

API Documentation at this revision

Comitter:
Sissors
Date:
Fri Dec 20 20:48:17 2013 +0000
Parent:
0:d77ea45fa625
Child:
2:fe2fcaa72434
Commit message:
v0.2, KL25, interrupts

Changed in this revision

SimpleDMA.h Show annotated file Show diff for this revision Revisions of this file
SimpleDMA_KL25.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/SimpleDMA.h	Fri Oct 18 07:44:42 2013 +0000
+++ b/SimpleDMA.h	Fri Dec 20 20:48:17 2013 +0000
@@ -2,6 +2,7 @@
 #define SIMPLEDMA_H
 
 #include "mbed.h"
+#include "rtos.h"
 #include "SimpleDMA_KL25.h"
 
 
@@ -79,28 +80,78 @@
 int start(int length);
 
 /**
-* Set the DMA channel
-*
-* @param chan - DMA channel to use
-*/
-void channel(int chan);
-
-/**
 * Is the DMA channel busy
 *
 * @return - true if it is busy
 */
 bool isBusy( void );
 
+/**
+* Attach an interrupt upon completion of DMA transfer or error
+*
+* @param function - function to call upon completion (may be a member function)
+*/
+void attach(void (*function)(void)) {
+    irq_en = function;
+    _callback.attach(function);
+    }
+    
+template<typename T>
+    void attach(T *object, void (T::*member)(void)) {
+        irq_en = object;
+        _callback.attach(object, member);
+    }
 
-
+void wait(void) {
+    id = Thread::gettid();
+    this->attach(this, &SimpleDMA::waitCallback);
+    this->start(8);
+    Thread::signal_wait(0x1);
+}
 
 
 protected:
+/**
+* Set the DMA channel
+*
+* @param chan - DMA channel to use
+*/
+void channel(int chan);
+
 int setMemory(uint32_t address, int wordsize, bool source, bool autoinc);
 int _channel;
+FunctionPointer _callback;
+bool irq_en;
+void irq_handler(void);
 
+//IRQ handlers
 
+static SimpleDMA *irq_owner[4];
+
+static void irq_handler0( void ) {
+    if (irq_owner[0]!=NULL)
+        irq_owner[0]->irq_handler();
+}
+static void irq_handler1( void ) {
+    if (irq_owner[1]!=NULL)
+        irq_owner[1]->irq_handler();
+}
+static void irq_handler2( void ) {
+    if (irq_owner[2]!=NULL)
+        irq_owner[2]->irq_handler();
+}
+static void irq_handler3( void ) {
+    if (irq_owner[3]!=NULL)
+        irq_owner[3]->irq_handler();
+}
+public:
+osThreadId id;
+void waitCallback(void) {
+
+    //id = Thread::gettid();
+    osSignalSet(id, 0x1);
+    
+}
 
 };
 #endif
\ No newline at end of file
--- a/SimpleDMA_KL25.cpp	Fri Oct 18 07:44:42 2013 +0000
+++ b/SimpleDMA_KL25.cpp	Fri Dec 20 20:48:17 2013 +0000
@@ -2,15 +2,41 @@
 
 #define DMA_CHANNELS        4
 
+SimpleDMA *SimpleDMA::irq_owner[4] = {NULL};
+
 SimpleDMA::SimpleDMA(int channel) {
     this->channel(channel);
-    trigger(Trigger_ALWAYS);
-    
+       
     //Enable DMA
     SIM->SCGC6 |= 1<<1;     //Enable clock to DMA mux
     SIM->SCGC7 |= 1<<8;     //Enable clock to DMA
     
+    trigger(Trigger_ALWAYS);
+    
     DMA0->DMA[_channel].DCR |= (1<<29) + (1<<30);   //Set to always use DMAMUX (If no trigger is needed we route via alwayson)
+
+    uint32_t handler = NULL;
+    switch (_channel) {
+        case 0:
+            handler = (uint32_t)&irq_handler0;
+            break;
+        case 1:
+            handler = (uint32_t)&irq_handler1;
+            break;
+        case 2:
+            handler = (uint32_t)&irq_handler2;
+            break;
+        case 3:
+            handler = (uint32_t)&irq_handler3;
+            break;
+        default:
+            break;
+    }
+
+    NVIC_SetVector((IRQn) (DMA0_IRQn + _channel), handler);
+    NVIC_EnableIRQ((IRQn) (DMA0_IRQn + _channel));
+
+    irq_owner[_channel] = this;
 }
 
 int SimpleDMA::setMemory(uint32_t address, int wordsize, bool source, bool autoinc) {
@@ -56,12 +82,13 @@
 };
 
 int SimpleDMA::trigger(SimpleDMA_Trigger trig){ 
-    DMAMUX0->CHCFG[_channel] = 0;
+    
     DMAMUX0->CHCFG[_channel] = trig;
     return 0;
 }
 
 int SimpleDMA::start(int length) {
+
     if (length > 0xFFFFF)
         return -1;
     
@@ -69,8 +96,13 @@
     DMA0->DMA[_channel].DSR_BCR &= ~0xFFFFFF;
     DMA0->DMA[_channel].DSR_BCR |= length;
     
+    //Enable interrupts
+    if (irq_en)
+        DMA0->DMA[_channel].DCR |= (uint32_t)(1<<31);
+    else
+        DMA0->DMA[_channel].DCR &= ~(1<<31);
+        
     //Start
-    //DMA0->DMA[_channel].DCR|=1<<16;
     DMAMUX0->CHCFG[_channel] |= 1<<7;
     
     return 0;
@@ -85,4 +117,10 @@
 
 bool SimpleDMA::isBusy( void ) {
     return (DMA0->DMA[_channel].DSR_BCR & (1<<25) == 1<<25);
-}
\ No newline at end of file
+}
+
+void SimpleDMA::irq_handler(void) {
+    DMAMUX0->CHCFG[_channel] = 0;
+    DMA0->DMA[0].DSR_BCR |= DMA_DSR_BCR_DONE_MASK ; 
+    _callback.call();
+}