Browse Source

DMAChannel stuff (even work in progress)

teensy4-core
PaulStoffregen 10 years ago
parent
commit
8c7df73ac0
3 changed files with 126 additions and 50 deletions
  1. +8
    -3
      teensy3/DMAChannel.cpp
  2. +98
    -42
      teensy3/DMAChannel.h
  3. +20
    -5
      teensy3/mk20dx128.h

+ 8
- 3
teensy3/DMAChannel.cpp View File

@@ -23,14 +23,19 @@ DMAChannel::DMAChannel(uint8_t channelRequest) : TCD(*(TCD_t *)0), channel(16)
}
}
channel = ch;
SIM_SCGC7 |= SIM_SCGC7_DMA;
SIM_SCGC6 |= SIM_SCGC6_DMAMUX;
DMA_CR = DMA_CR_EMLM | DMA_CR_EDBG ; // minor loop mapping is available
DMA_CERQ = ch;
DMA_CERR = ch;
DMA_CEEI = ch;
DMA_CINT = ch;

TCD = *(TCD_t *)(0x40009000 + ch * 32);
TCD.CSR = 0;
TCD.ATTR = 0;
TCD.NBYTES = 0;
TCD.BITER = 0;
TCD.CITER = 0;
SIM_SCGC7 |= SIM_SCGC7_DMA;
SIM_SCGC6 |= SIM_SCGC6_DMAMUX;
DMA_CR = 0;
}


+ 98
- 42
teensy3/DMAChannel.h View File

@@ -24,15 +24,20 @@ class DMAChannel {
typedef struct __attribute__((packed)) {
volatile const void * volatile SADDR;
int16_t SOFF;
union { uint16_t ATTR; struct { uint8_t ATTR_DST; uint8_t ATTR_SRC; }; };
uint32_t NBYTES;
union { uint16_t ATTR;
struct { uint8_t ATTR_DST; uint8_t ATTR_SRC; }; };
union { uint32_t NBYTES; uint32_t NBYTES_MLNO;
uint32_t NBYTES_MLOFFNO; uint32_t NBYTES_MLOFFYES; };
int32_t SLAST;
volatile void * volatile DADDR;
int16_t DOFF;
volatile uint16_t CITER;
union { volatile uint16_t CITER;
volatile uint16_t CITER_ELINKYES; volatile uint16_t CITER_ELINKNO; };
int32_t DLASTSGA;
volatile uint16_t CSR;
volatile uint16_t BITER;
union { volatile uint16_t BITER;
volatile uint16_t BITER_ELINKYES; volatile uint16_t BITER_ELINKNO; };

} TCD_t;
public:
/*************************************************/
@@ -48,36 +53,62 @@ public:
/** Triggering **/
/***************************************/

// Triggers cause the DMA channel to actually move data.
// Triggers cause the DMA channel to actually move data. Each
// trigger moves a single data unit, which is typically 8, 16 or 32 bits.

// Use a hardware trigger to make the DMA channel run
void attachTrigger(uint8_t source) {
volatile uint8_t *mux;
mux = (volatile uint8_t *)&(DMAMUX0_CHCFG0) + channel;
*mux = 0;
*mux = source | DMAMUX_ENABLE;
*mux = (source & 63) | DMAMUX_ENABLE;
}

// Use another DMA channel as the trigger, causing this
// channel to trigger every time it triggers. This
// effectively makes the 2 channels run in parallel.
void attachTrigger(DMAChannel &channel) {

// channel to trigger after each transfer is makes, except
// the its last transfer. This effectively makes the 2
// channels run in parallel.
void attachTriggerBeforeCompletion(DMAChannel &ch) {
ch.TCD.BITER = (ch.TCD.BITER & ~DMA_TCD_BITER_ELINKYES_LINKCH_MASK)
| DMA_TCD_BITER_ELINKYES_LINKCH(channel) | DMA_TCD_BITER_ELINKYES_ELINK;
ch.TCD.CITER = ch.TCD.BITER ;
}

// Use another DMA channel as the trigger, causing this
// channel to trigger when the other channel completes.
void attachTriggerOnCompletion(DMAChannel &channel) {

void attachTriggerAtCompletion(DMAChannel &ch) {
ch.TCD.CSR = (ch.TCD.CSR & ~DMA_TCD_CSR_MAJORLINKCH_MASK)
| DMA_TCD_CSR_MAJORLINKCH(channel) | DMA_TCD_CSR_MAJORELINK;
}

void attachTriggerContinuous(DMAChannel &channel) {

// Cause this DMA channel to be continuously triggered, so
// it will move data as rapidly as possible, without waiting.
// Normally this would be used with disableOnCompletion().
void attachTriggerContinuous(void) {
volatile uint8_t *mux = (volatile uint8_t *)&DMAMUX0_CHCFG0;
mux[channel] = 0;
#if DMAMUX_NUM_SOURCE_ALWAYS >= DMA_NUM_CHANNELS
mux[channel] = DMAMUX_SOURCE_ALWAYS0 + channel;
#else
// search for an unused "always on" source
unsigned int i = DMAMUX_SOURCE_ALWAYS0;
for (i = DMAMUX_SOURCE_ALWAYS0;
i < DMAMUX_SOURCE_ALWAYS0 + DMAMUX_NUM_SOURCE_ALWAYS; i++) {
unsigned int ch;
for (ch=0; ch < DMA_NUM_CHANNELS; ch++) {
if (mux[ch] == i) break;
}
if (ch >= DMA_NUM_CHANNELS) {
mux[channel] = i;
return;
}
}
#endif
}

// Manually trigger the DMA channel.
void trigger(void) {

DMA_SSRT = channel;
}


@@ -86,19 +117,24 @@ public:
/***************************************/

// An interrupt routine can be run when the DMA channel completes
// the entire transfer.
// the entire transfer, and also optionally when half of the
// transfer is completed.
void attachInterrupt(void (*isr)(void)) {
_VectorsRam[channel + IRQ_DMA_CH0 + 16] = isr;
NVIC_ENABLE_IRQ(IRQ_DMA_CH0 + channel);
TCD.CSR |= DMA_TCD_CSR_INTMAJOR;
}

void interruptAtHalf(void) {
void detachInterrupt(void) {
NVIC_DISABLE_IRQ(IRQ_DMA_CH0 + channel);
}

void interruptAtHalf(void) {
TCD.CSR |= DMA_TCD_CSR_INTHALF;
}

void clearInterrupt(void) {


DMA_CINT = channel;
}


@@ -107,15 +143,15 @@ public:
/***************************************/

void enable(void) {
DMA_SERQ = channel;
}

void disable(void) {
DMA_CERQ = channel;
}

void disableOnCompletion(void) {
TCD.CSR |= DMA_TCD_CSR_DREQ;
}


@@ -154,7 +190,8 @@ public:

// Use a buffer (array of data) as the data source. Typically a
// buffer for transmitting data is used.
void sourceBuffer(const signed char p[], unsigned int len) { sourceBuffer((uint8_t *)p, len); }
void sourceBuffer(const signed char p[], unsigned int len) {
sourceBuffer((uint8_t *)p, len); }
void sourceBuffer(const unsigned char p[], unsigned int len) {
TCD.SADDR = p;
TCD.SOFF = 1;
@@ -164,7 +201,8 @@ public:
TCD.BITER = len;
TCD.CITER = len;
}
void sourceBuffer(const signed short p[], unsigned int len) { sourceBuffer((uint16_t *)p, len); }
void sourceBuffer(const signed short p[], unsigned int len) {
sourceBuffer((uint16_t *)p, len); }
void sourceBuffer(const unsigned short p[], unsigned int len) {
TCD.SADDR = p;
TCD.SOFF = 2;
@@ -174,9 +212,12 @@ public:
TCD.BITER = len / 2;
TCD.CITER = len / 2;
}
void sourceBuffer(const signed int p[], unsigned int len) { sourceBuffer((uint32_t *)p, len); }
void sourceBuffer(const unsigned int p[], unsigned int len) {sourceBuffer((uint32_t *)p, len); }
void sourceBuffer(const signed long p[], unsigned int len) { sourceBuffer((uint32_t *)p, len); }
void sourceBuffer(const signed int p[], unsigned int len) {
sourceBuffer((uint32_t *)p, len); }
void sourceBuffer(const unsigned int p[], unsigned int len) {
sourceBuffer((uint32_t *)p, len); }
void sourceBuffer(const signed long p[], unsigned int len) {
sourceBuffer((uint32_t *)p, len); }
void sourceBuffer(const unsigned long p[], unsigned int len) {
TCD.SADDR = p;
TCD.SOFF = 4;
@@ -188,7 +229,8 @@ public:
}

// Use a circular buffer as the data source
void sourceCircular(const signed char p[], unsigned int len) { sourceCircular((uint8_t *)p, len); }
void sourceCircular(const signed char p[], unsigned int len) {
sourceCircular((uint8_t *)p, len); }
void sourceCircular(const unsigned char p[], unsigned int len) {
TCD.SADDR = p;
TCD.SOFF = 1;
@@ -198,7 +240,8 @@ public:
TCD.BITER = len;
TCD.CITER = len;
}
void sourceCircular(const signed short p[], unsigned int len) { sourceCircular((uint16_t *)p, len); }
void sourceCircular(const signed short p[], unsigned int len) {
sourceCircular((uint16_t *)p, len); }
void sourceCircular(const unsigned short p[], unsigned int len) {
TCD.SADDR = p;
TCD.SOFF = 2;
@@ -208,9 +251,12 @@ public:
TCD.BITER = len / 2;
TCD.CITER = len / 2;
}
void sourceCircular(const signed int p[], unsigned int len) { sourceCircular((uint32_t *)p, len); }
void sourceCircular(const unsigned int p[], unsigned int len) { sourceCircular((uint32_t *)p, len); }
void sourceCircular(const signed long p[], unsigned int len) { sourceCircular((uint32_t *)p, len); }
void sourceCircular(const signed int p[], unsigned int len) {
sourceCircular((uint32_t *)p, len); }
void sourceCircular(const unsigned int p[], unsigned int len) {
sourceCircular((uint32_t *)p, len); }
void sourceCircular(const signed long p[], unsigned int len) {
sourceCircular((uint32_t *)p, len); }
void sourceCircular(const unsigned long p[], unsigned int len) {
TCD.SADDR = p;
TCD.SOFF = 4;
@@ -252,7 +298,8 @@ public:

// Use a buffer (array of data) as the data destination. Typically a
// buffer for receiving data is used.
void destinationBuffer(signed char p[], unsigned int len) { destinationBuffer((uint8_t *)p, len); }
void destinationBuffer(signed char p[], unsigned int len) {
destinationBuffer((uint8_t *)p, len); }
void destinationBuffer(unsigned char p[], unsigned int len) {
TCD.DADDR = p;
TCD.DOFF = 1;
@@ -262,7 +309,8 @@ public:
TCD.BITER = len;
TCD.CITER = len;
}
void destinationBuffer(signed short p[], unsigned int len) { destinationBuffer((uint16_t *)p, len); }
void destinationBuffer(signed short p[], unsigned int len) {
destinationBuffer((uint16_t *)p, len); }
void destinationBuffer(unsigned short p[], unsigned int len) {
TCD.DADDR = p;
TCD.DOFF = 2;
@@ -272,9 +320,12 @@ public:
TCD.BITER = len / 2;
TCD.CITER = len / 2;
}
void destinationBuffer(signed int p[], unsigned int len) { destinationBuffer((uint32_t *)p, len); }
void destinationBuffer(unsigned int p[], unsigned int len) { destinationBuffer((uint32_t *)p, len); }
void destinationBuffer(signed long p[], unsigned int len) { destinationBuffer((uint32_t *)p, len); }
void destinationBuffer(signed int p[], unsigned int len) {
destinationBuffer((uint32_t *)p, len); }
void destinationBuffer(unsigned int p[], unsigned int len) {
destinationBuffer((uint32_t *)p, len); }
void destinationBuffer(signed long p[], unsigned int len) {
destinationBuffer((uint32_t *)p, len); }
void destinationBuffer(unsigned long p[], unsigned int len) {
TCD.DADDR = p;
TCD.DOFF = 4;
@@ -286,7 +337,8 @@ public:
}

// Use a circular buffer as the data destination
void destinationCircular(signed char p[], unsigned int len) { destinationCircular((uint8_t *)p, len); }
void destinationCircular(signed char p[], unsigned int len) {
destinationCircular((uint8_t *)p, len); }
void destinationCircular(unsigned char p[], unsigned int len) {
TCD.DADDR = p;
TCD.DOFF = 1;
@@ -296,7 +348,8 @@ public:
TCD.BITER = len;
TCD.CITER = len;
}
void destinationCircular(signed short p[], unsigned int len) { destinationCircular((uint16_t *)p, len); }
void destinationCircular(signed short p[], unsigned int len) {
destinationCircular((uint16_t *)p, len); }
void destinationCircular(unsigned short p[], unsigned int len) {
TCD.DADDR = p;
TCD.DOFF = 2;
@@ -306,9 +359,12 @@ public:
TCD.BITER = len / 2;
TCD.CITER = len / 2;
}
void destinationCircular(signed int p[], unsigned int len) { destinationCircular((uint32_t *)p, len); }
void destinationCircular(unsigned int p[], unsigned int len) { destinationCircular((uint32_t *)p, len); }
void destinationCircular(signed long p[], unsigned int len) { destinationCircular((uint32_t *)p, len); }
void destinationCircular(signed int p[], unsigned int len) {
destinationCircular((uint32_t *)p, len); }
void destinationCircular(unsigned int p[], unsigned int len) {
destinationCircular((uint32_t *)p, len); }
void destinationCircular(signed long p[], unsigned int len) {
destinationCircular((uint32_t *)p, len); }
void destinationCircular(unsigned long p[], unsigned int len) {
TCD.DADDR = p;
TCD.DOFF = 4;

+ 20
- 5
teensy3/mk20dx128.h View File

@@ -519,6 +519,7 @@ extern "C" {
#define DMAMUX_SOURCE_ALWAYS7 61
#define DMAMUX_SOURCE_ALWAYS8 62
#define DMAMUX_SOURCE_ALWAYS9 63
#define DMAMUX_NUM_SOURCE_ALWAYS 10

// Chapter 21: Direct Memory Access Controller (eDMA)
#define DMA_CR (*(volatile uint32_t *)0x40008000) // Control Register
@@ -679,7 +680,9 @@ extern "C" {
#define DMA_TCD_ATTR_SIZE_16BYTE 4
#define DMA_TCD_ATTR_SIZE_32BYTE 5
#define DMA_TCD_CSR_BWC(n) (((n) & 0x3) << 14)
#define DMA_TCD_CSR_MAJORLINKCH(n) (((n) & 0x3) << 8)
#define DMA_TCD_CSR_BWC_MASK 0xC000
#define DMA_TCD_CSR_MAJORLINKCH(n) (((n) & 0xF) << 8)
#define DMA_TCD_CSR_MAJORLINKCH_MASK 0x0F00
#define DMA_TCD_CSR_DONE 0x0080
#define DMA_TCD_CSR_ACTIVE 0x0040
#define DMA_TCD_CSR_MAJORELINK 0x0020
@@ -688,10 +691,20 @@ extern "C" {
#define DMA_TCD_CSR_INTHALF 0x0004
#define DMA_TCD_CSR_INTMAJOR 0x0002
#define DMA_TCD_CSR_START 0x0001
#define DMA_TCD_CITER_MASK ((uint16_t)0x7FFF) // Loop count mask
#define DMA_TCD_CITER_ELINK ((uint16_t)1<<15) // Enable channel linking on minor-loop complete
#define DMA_TCD_BITER_MASK ((uint16_t)0x7FFF) // Loop count mask
#define DMA_TCD_BITER_ELINK ((uint16_t)1<<15) // Enable channel linking on minor-loop complete
#define DMA_TCD_CITER_MASK ((uint16_t)0x7FFF) // Loop count mask
#define DMA_TCD_CITER_ELINK ((uint16_t)1<<15) // Enable channel linking on minor-loop complete
#define DMA_TCD_BITER_MASK ((uint16_t)0x7FFF) // Loop count mask
#define DMA_TCD_BITER_ELINK ((uint16_t)1<<15) // Enable channel linking on minor-loop complete
#define DMA_TCD_BITER_ELINKYES_ELINK 0x8000
#define DMA_TCD_BITER_ELINKYES_LINKCH(n) (((n) & 0xF) << 9)
#define DMA_TCD_BITER_ELINKYES_LINKCH_MASK 0x1E00
#define DMA_TCD_BITER_ELINKYES_BITER(n) (((n) & 0x1FF) << 0)
#define DMA_TCD_BITER_ELINKYES_BITER_MASK 0x01FF
#define DMA_TCD_CITER_ELINKYES_ELINK 0x8000
#define DMA_TCD_CITER_ELINKYES_LINKCH(n) (((n) & 0xF) << 9)
#define DMA_TCD_CITER_ELINKYES_LINKCH_MASK 0x1E00
#define DMA_TCD_CITER_ELINKYES_CITER(n) (((n) & 0x1FF) << 0)
#define DMA_TCD_CITER_ELINKYES_CITER_MASK 0x01FF
#define DMA_TCD_NBYTES_SMLOE ((uint32_t)1<<31) // Source Minor Loop Offset Enable
#define DMA_TCD_NBYTES_DMLOE ((uint32_t)1<<30) // Destination Minor Loop Offset Enable
#define DMA_TCD_NBYTES_MLOFFNO_NBYTES(n) ((uint32_t)(n)) // NBytes transfer count when minor loop disabled
@@ -2346,6 +2359,7 @@ typedef struct {
#define IRQ_PORTE 44
#define IRQ_SOFTWARE 45
#define NVIC_NUM_INTERRUPTS 46
#define DMA_NUM_CHANNELS 4

#elif defined(__MK20DX256__)
#define IRQ_DMA_CH0 0
@@ -2418,6 +2432,7 @@ typedef struct {
#define IRQ_PORTE 91
#define IRQ_SOFTWARE 94
#define NVIC_NUM_INTERRUPTS 95
#define DMA_NUM_CHANNELS 16

#endif


Loading…
Cancel
Save