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/

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();
+}