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

} }
} }
channel = ch; 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 = *(TCD_t *)(0x40009000 + ch * 32);
TCD.CSR = 0; TCD.CSR = 0;
TCD.ATTR = 0; TCD.ATTR = 0;
TCD.NBYTES = 0; TCD.NBYTES = 0;
TCD.BITER = 0; TCD.BITER = 0;
TCD.CITER = 0; TCD.CITER = 0;
SIM_SCGC7 |= SIM_SCGC7_DMA;
SIM_SCGC6 |= SIM_SCGC6_DMAMUX;
DMA_CR = 0;
} }



+ 98
- 42
teensy3/DMAChannel.h View File

typedef struct __attribute__((packed)) { typedef struct __attribute__((packed)) {
volatile const void * volatile SADDR; volatile const void * volatile SADDR;
int16_t SOFF; 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; int32_t SLAST;
volatile void * volatile DADDR; volatile void * volatile DADDR;
int16_t DOFF; 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; int32_t DLASTSGA;
volatile uint16_t CSR; 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; } TCD_t;
public: public:
/*************************************************/ /*************************************************/
/** Triggering **/ /** 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 // Use a hardware trigger to make the DMA channel run
void attachTrigger(uint8_t source) { void attachTrigger(uint8_t source) {
volatile uint8_t *mux; volatile uint8_t *mux;
mux = (volatile uint8_t *)&(DMAMUX0_CHCFG0) + channel; mux = (volatile uint8_t *)&(DMAMUX0_CHCFG0) + channel;
*mux = 0; *mux = 0;
*mux = source | DMAMUX_ENABLE;
*mux = (source & 63) | DMAMUX_ENABLE;
} }


// Use another DMA channel as the trigger, causing this // 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 // Use another DMA channel as the trigger, causing this
// channel to trigger when the other channel completes. // 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. // Manually trigger the DMA channel.
void trigger(void) { void trigger(void) {

DMA_SSRT = channel;
} }




/***************************************/ /***************************************/


// An interrupt routine can be run when the DMA channel completes // 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)) { void attachInterrupt(void (*isr)(void)) {
_VectorsRam[channel + IRQ_DMA_CH0 + 16] = isr; _VectorsRam[channel + IRQ_DMA_CH0 + 16] = isr;
NVIC_ENABLE_IRQ(IRQ_DMA_CH0 + channel); 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) { void clearInterrupt(void) {


DMA_CINT = channel;
} }




/***************************************/ /***************************************/


void enable(void) { void enable(void) {
DMA_SERQ = channel;
} }


void disable(void) { void disable(void) {
DMA_CERQ = channel;
} }


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






// Use a buffer (array of data) as the data source. Typically a // Use a buffer (array of data) as the data source. Typically a
// buffer for transmitting data is used. // 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) { void sourceBuffer(const unsigned char p[], unsigned int len) {
TCD.SADDR = p; TCD.SADDR = p;
TCD.SOFF = 1; TCD.SOFF = 1;
TCD.BITER = len; TCD.BITER = len;
TCD.CITER = 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) { void sourceBuffer(const unsigned short p[], unsigned int len) {
TCD.SADDR = p; TCD.SADDR = p;
TCD.SOFF = 2; TCD.SOFF = 2;
TCD.BITER = len / 2; TCD.BITER = len / 2;
TCD.CITER = 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) { void sourceBuffer(const unsigned long p[], unsigned int len) {
TCD.SADDR = p; TCD.SADDR = p;
TCD.SOFF = 4; TCD.SOFF = 4;
} }


// Use a circular buffer as the data source // 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) { void sourceCircular(const unsigned char p[], unsigned int len) {
TCD.SADDR = p; TCD.SADDR = p;
TCD.SOFF = 1; TCD.SOFF = 1;
TCD.BITER = len; TCD.BITER = len;
TCD.CITER = 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) { void sourceCircular(const unsigned short p[], unsigned int len) {
TCD.SADDR = p; TCD.SADDR = p;
TCD.SOFF = 2; TCD.SOFF = 2;
TCD.BITER = len / 2; TCD.BITER = len / 2;
TCD.CITER = 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) { void sourceCircular(const unsigned long p[], unsigned int len) {
TCD.SADDR = p; TCD.SADDR = p;
TCD.SOFF = 4; TCD.SOFF = 4;


// Use a buffer (array of data) as the data destination. Typically a // Use a buffer (array of data) as the data destination. Typically a
// buffer for receiving data is used. // 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) { void destinationBuffer(unsigned char p[], unsigned int len) {
TCD.DADDR = p; TCD.DADDR = p;
TCD.DOFF = 1; TCD.DOFF = 1;
TCD.BITER = len; TCD.BITER = len;
TCD.CITER = 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) { void destinationBuffer(unsigned short p[], unsigned int len) {
TCD.DADDR = p; TCD.DADDR = p;
TCD.DOFF = 2; TCD.DOFF = 2;
TCD.BITER = len / 2; TCD.BITER = len / 2;
TCD.CITER = 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) { void destinationBuffer(unsigned long p[], unsigned int len) {
TCD.DADDR = p; TCD.DADDR = p;
TCD.DOFF = 4; TCD.DOFF = 4;
} }


// Use a circular buffer as the data destination // 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) { void destinationCircular(unsigned char p[], unsigned int len) {
TCD.DADDR = p; TCD.DADDR = p;
TCD.DOFF = 1; TCD.DOFF = 1;
TCD.BITER = len; TCD.BITER = len;
TCD.CITER = 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) { void destinationCircular(unsigned short p[], unsigned int len) {
TCD.DADDR = p; TCD.DADDR = p;
TCD.DOFF = 2; TCD.DOFF = 2;
TCD.BITER = len / 2; TCD.BITER = len / 2;
TCD.CITER = 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) { void destinationCircular(unsigned long p[], unsigned int len) {
TCD.DADDR = p; TCD.DADDR = p;
TCD.DOFF = 4; TCD.DOFF = 4;

+ 20
- 5
teensy3/mk20dx128.h View File

#define DMAMUX_SOURCE_ALWAYS7 61 #define DMAMUX_SOURCE_ALWAYS7 61
#define DMAMUX_SOURCE_ALWAYS8 62 #define DMAMUX_SOURCE_ALWAYS8 62
#define DMAMUX_SOURCE_ALWAYS9 63 #define DMAMUX_SOURCE_ALWAYS9 63
#define DMAMUX_NUM_SOURCE_ALWAYS 10


// Chapter 21: Direct Memory Access Controller (eDMA) // Chapter 21: Direct Memory Access Controller (eDMA)
#define DMA_CR (*(volatile uint32_t *)0x40008000) // Control Register #define DMA_CR (*(volatile uint32_t *)0x40008000) // Control Register
#define DMA_TCD_ATTR_SIZE_16BYTE 4 #define DMA_TCD_ATTR_SIZE_16BYTE 4
#define DMA_TCD_ATTR_SIZE_32BYTE 5 #define DMA_TCD_ATTR_SIZE_32BYTE 5
#define DMA_TCD_CSR_BWC(n) (((n) & 0x3) << 14) #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_DONE 0x0080
#define DMA_TCD_CSR_ACTIVE 0x0040 #define DMA_TCD_CSR_ACTIVE 0x0040
#define DMA_TCD_CSR_MAJORELINK 0x0020 #define DMA_TCD_CSR_MAJORELINK 0x0020
#define DMA_TCD_CSR_INTHALF 0x0004 #define DMA_TCD_CSR_INTHALF 0x0004
#define DMA_TCD_CSR_INTMAJOR 0x0002 #define DMA_TCD_CSR_INTMAJOR 0x0002
#define DMA_TCD_CSR_START 0x0001 #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_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_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 #define DMA_TCD_NBYTES_MLOFFNO_NBYTES(n) ((uint32_t)(n)) // NBytes transfer count when minor loop disabled
#define IRQ_PORTE 44 #define IRQ_PORTE 44
#define IRQ_SOFTWARE 45 #define IRQ_SOFTWARE 45
#define NVIC_NUM_INTERRUPTS 46 #define NVIC_NUM_INTERRUPTS 46
#define DMA_NUM_CHANNELS 4


#elif defined(__MK20DX256__) #elif defined(__MK20DX256__)
#define IRQ_DMA_CH0 0 #define IRQ_DMA_CH0 0
#define IRQ_PORTE 91 #define IRQ_PORTE 91
#define IRQ_SOFTWARE 94 #define IRQ_SOFTWARE 94
#define NVIC_NUM_INTERRUPTS 95 #define NVIC_NUM_INTERRUPTS 95
#define DMA_NUM_CHANNELS 16


#endif #endif



Loading…
Cancel
Save