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 Oct 18 07:44:42 2013 +0000
Child:
1:0b73b00bcee8
Commit message:
v0.1, KL25, no interrupt

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
SimpleDMA_KL25.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SimpleDMA.h	Fri Oct 18 07:44:42 2013 +0000
@@ -0,0 +1,106 @@
+#ifndef SIMPLEDMA_H
+#define SIMPLEDMA_H
+
+#include "mbed.h"
+#include "SimpleDMA_KL25.h"
+
+
+/**
+* SimpleDMA, DMA made simple! (Okay that was bad)
+*
+* A class to easily make basic DMA operations happen. Not all features
+* of the DMA peripherals are used, but the main ones are: From and to memory
+* and peripherals, either continiously or triggered
+*/
+class SimpleDMA {
+public:
+SimpleDMA(int channel = 0);
+
+/**
+* Set the source of the DMA transfer
+*
+* Autoincrement increments the pointer after each transfer. If the source
+* is an array this should be true, if it is a peripheral or a single memory
+* location it should be false.
+*
+* The source can be any pointer to any memory location. Automatically
+* the wordsize is calculated depending on the type, if required you can
+* also override this.
+*
+* @param pointer - pointer to the memory location
+* @param autoinc - should the pointer be incremented by the DMA module
+* @param size - size of the transfer (optional, generally can be omitted)
+* @return - 0 on success
+*/
+template<typename Type>
+int source(Type* pointer, bool autoinc, int size = sizeof(Type*)) {
+    return setMemory((uint32_t)pointer, size, true, autoinc);
+}
+
+/**
+* Set the destination of the DMA transfer
+*
+* Autoincrement increments the pointer after each transfer. If the source
+* is an array this should be true, if it is a peripheral or a single memory
+* location it should be false.
+*
+* The destination can be any pointer to any memory location. Automatically
+* the wordsize is calculated depending on the type, if required you can
+* also override this.
+*
+* @param pointer - pointer to the memory location
+* @param autoinc - should the pointer be incremented by the DMA module
+* @param size - size of the transfer (optional, generally can be omitted)
+* @return - 0 on success
+*/
+template<typename Type>
+int destination(Type* pointer, bool autoinc, int size = sizeof(Type*)) {
+    return setMemory((uint32_t)pointer, size, false, autoinc);
+}
+
+/**
+* Set the trigger for the DMA operation
+*
+* In SimpleDMA_[yourdevice].h you can find the names of the different triggers.
+* Trigger_ALWAYS is defined for all devices, it will simply move the data
+* as fast as possible. Used for memory-memory transfers. If nothing else is set
+* that will be used by default.
+*
+* @param trig - trigger to use
+* @param return - 0 on success
+*/
+int trigger(SimpleDMA_Trigger trig);
+
+/**
+* Start the transfer
+*
+* @param length - number of BYTES to be moved by the DMA
+*/
+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 );
+
+
+
+
+
+protected:
+int setMemory(uint32_t address, int wordsize, bool source, bool autoinc);
+int _channel;
+
+
+
+};
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SimpleDMA_KL25.cpp	Fri Oct 18 07:44:42 2013 +0000
@@ -0,0 +1,88 @@
+#include "SimpleDMA.h"
+
+#define DMA_CHANNELS        4
+
+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
+    
+    DMA0->DMA[_channel].DCR |= (1<<29) + (1<<30);   //Set to always use DMAMUX (If no trigger is needed we route via alwayson)
+}
+
+int SimpleDMA::setMemory(uint32_t address, int wordsize, bool source, bool autoinc) {
+    //Check if it is an allowed address
+    switch ((uint32_t) address >> 20) {
+        case 0x000:
+        case 0x1FF:
+        case 0x200:
+        case 0x400:
+        break;
+        default:
+            return -1;
+        }
+    
+    char _size;
+    switch (wordsize) {
+        case 8:
+            _size = 1;
+            break;
+        case 16:
+            _size = 2;
+            break;
+        case 32:
+            _size = 0;
+            break;
+        default:
+            _size = 1;
+        }
+    
+    //Check if source or destination
+    if (source) {
+        DMA0->DMA[_channel].SAR = address;
+        DMA0->DMA[_channel].DCR &= ~(7<<20);
+        DMA0->DMA[_channel].DCR |= autoinc << 22;
+        DMA0->DMA[_channel].DCR |= _size << 20;
+    } else {
+        DMA0->DMA[_channel].DAR = address;
+        DMA0->DMA[_channel].DCR &= ~(7<<17);
+        DMA0->DMA[_channel].DCR |= autoinc << 19;
+        DMA0->DMA[_channel].DCR |= _size << 17;
+    }
+    return 0;
+};
+
+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;
+    
+    //Set length
+    DMA0->DMA[_channel].DSR_BCR &= ~0xFFFFFF;
+    DMA0->DMA[_channel].DSR_BCR |= length;
+    
+    //Start
+    //DMA0->DMA[_channel].DCR|=1<<16;
+    DMAMUX0->CHCFG[_channel] |= 1<<7;
+    
+    return 0;
+}
+
+void SimpleDMA::channel(int chan) {
+    if (chan >= 0 && chan < DMA_CHANNELS)
+        _channel = chan;
+    else
+        _channel = 3;
+}
+
+bool SimpleDMA::isBusy( void ) {
+    return (DMA0->DMA[_channel].DSR_BCR & (1<<25) == 1<<25);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SimpleDMA_KL25.h	Fri Oct 18 07:44:42 2013 +0000
@@ -0,0 +1,42 @@
+#ifdef TARGET_KL25Z
+
+enum SimpleDMA_Trigger {
+    Trigger_ALWAYS = 60,
+    Trigger_UART0_RX = 2,
+    Trigger_UART0_TX,
+    Trigger_UART1_RX,
+    Trigger_UART1_TX,
+    Trigger_UART2_RX,
+    Trigger_UART2_TX,
+    Trigger_SPI0_RX = 16,
+    Trigger_SPI0_TX,
+    Trigger_SPI1_RX,
+    Trigger_SPI1_TX,
+    Trigger_I2C0 = 22,
+    Trigger_I2C1,
+    Trigger_TPM0_C0,
+    Trigger_TPM0_C1,
+    Trigger_TPM0_C2,
+    Trigger_TPM0_C3,
+    Trigger_TPM0_C4,
+    Trigger_TPM0_C5,
+    Trigger_TPM1_C0 = 32,
+    Trigger_TPM1_C1,
+    Trigger_TPM2_C0,
+    Trigger_TPM2_C1,
+    Trigger_ADC0 = 40,
+    Trigger_CMP0 = 42,
+    Trigger_DAC0 = 45,
+    Trigger_PORTA = 49,
+    Trigger_PORTD = 52,
+    Trigger_TPM0 = 54,
+    Trigger_TPM1,
+    Trigger_TPM2,
+    Trigger_TSI,
+    Trigger_ALWAYS0 = 60,
+    Trigger_ALWAYS1,
+    Trigger_ALWAYS2,
+    Trigger_ALWAYS3,
+};    
+
+#endif
\ No newline at end of file