Bug: DMA macros only work for Teensy 3.0

christoph

Well-known member
The following macros only work for the Teensy 3.0 (4 DMA channels), because they use a fixed, hard coded number of DMA channels. The Teensy 3.1 has 16 channels, so I suggest changing in mk20x128.h:
Code:
#define DMA_CEEI_CEEI(n) ((uint8_t)(n & 3)<<0)
#define DMA_SEEI_SEEI(n) ((uint8_t)(n & 3)<<0)
#define DMA_CERQ_CERQ(n) ((uint8_t)(n & 3)<<0)
#define DMA_SERQ_SERQ(n) ((uint8_t)(n & 3)<<0)
#define DMA_CDNE_CDNE(n) ((uint8_t)(n & 3)<<0)
#define DMA_SSRT_SSRT(n) ((uint8_t)(n & 3)<<0)
#define DMA_CERR_CERR(n) ((uint8_t)(n & 3)<<0)
#define DMA_CINT_CINT(n) ((uint8_t)(n & 3)<<0)

to

Code:
#ifdef(__MK20DX128__)
#define NUM_DMA_CHANNELS 4

... <we should/could add other IO restrictions for the T3.0 here> ...

#elif defined(__MK20DX256__)
#define NUM_DMA_CHANNELS 16

... <we should/could add other IO restrictions for the T3.1 here> ...

#else
  #warning I don't know your chip. That's bad.
#endif

#define DMA_CHANNEL_N_MASK (NUM_DMA_CHANNELS-1) // generic

... <other existing IO defines here> ...

#define DMA_CEEI_CEEI(n) ((uint8_t)(n & DMA_CHANNEL_N_MASK)<<0)
#define DMA_SEEI_SEEI(n) ((uint8_t)(n & DMA_CHANNEL_N_MASK)<<0)
#define DMA_CERQ_CERQ(n) ((uint8_t)(n & DMA_CHANNEL_N_MASK)<<0)
#define DMA_SERQ_SERQ(n) ((uint8_t)(n & DMA_CHANNEL_N_MASK)<<0)
#define DMA_CDNE_CDNE(n) ((uint8_t)(n & DMA_CHANNEL_N_MASK)<<0)
#define DMA_SSRT_SSRT(n) ((uint8_t)(n & DMA_CHANNEL_N_MASK)<<0)
#define DMA_CERR_CERR(n) ((uint8_t)(n & DMA_CHANNEL_N_MASK)<<0)
#define DMA_CINT_CINT(n) ((uint8_t)(n & DMA_CHANNEL_N_MASK)<<0)

There might be more, these are just the macros that pedvide and I have found to be not adapted to T3.1. The "restrictions" block can easily be adapted for the upcoming Teensy++3, if that has a different chip. We could also split mk20dx128.h into a chip-specific and generic headers, which I like better than including mk20dx128.h when actually writing code for the '256.

Regards

Christoph
 
Good work!
Also
Code:
#define DMA_ERQ *(volatile uint32_t *)0x4000800C // Enable Request Register
#define DMA_ERQ_ERQ0 ((uint32_t)1<<0) // Enable DMA Request 0
#define DMA_ERQ_ERQ1 ((uint32_t)1<<1) // Enable DMA Request 1
... etc

#define DMA_EEI *(volatile uint32_t *)0x40008014 // Enable Error Interrupt Register
#define DMA_EEI_EEI0 ((uint32_t)1<<0) // Enable Error Interrupt 0
#define DMA_EEI_EEI1 ((uint32_t)1<<1) // Enable Error Interrupt 1
... etc

#define DMA_INT *(volatile uint32_t *)0x40008024 // Interrupt Request Register
#define DMA_INT_INT0 ((uint32_t)1<<0) // Interrupt Request 0
#define DMA_INT_INT1 ((uint32_t)1<<1) // Interrupt Request 1
... etc

#define DMA_ERR *(volatile uint32_t *)0x4000802C // Error Register
#define DMA_ERR_ERR0 ((uint32_t)1<<0) // Error in Channel 0
#define DMA_ERR_ERR1 ((uint32_t)1<<1) // Error in Channel 1
... etc.

#define DMA_HRS *(volatile uint32_t *)0x40008034 // Hardware Request Status Register
#define DMA_HRS_HRS0 ((uint32_t)1<<0) // Hardware Request Status Channel 0
#define DMA_HRS_HRS1 ((uint32_t)1<<1) // Hardware Request Status Channel 1
... etc.

#define DMA_DCHPRI_CHPRI(n) ((uint8_t)(n & 3)<<0) // Channel Arbitration Priority

and 

#define DMA_DCHPRI3 *(volatile uint8_t *)0x40008100 // Channel 3 Priority Register
#define DMA_DCHPRI2 *(volatile uint8_t *)0x40008101 // Channel 2 Priority Register
should be changed to
Code:
#define DMA_ERQ *(volatile uint32_t *)0x4000800C // Enable Request Register
#define DMA_ERQ_ERQ(n) ((uint32_t)1<<(n)) // Enable DMA Request n

#define DMA_EEI *(volatile uint32_t *)0x40008014 // Enable Error Interrupt Register
#define DMA_EEI_EEI(n) ((uint32_t)1<<(n)) // Enable Error Interrupt n

#define DMA_INT *(volatile uint32_t *)0x40008024 // Interrupt Request Register
#define DMA_INT_INT(n) ((uint32_t)1<<(n)) // Interrupt Request n

#define DMA_ERR *(volatile uint32_t *)0x4000802C // Error Register
#define DMA_ERR_ERR(n) ((uint32_t)1<<(n)) // Error in Channel n

#define DMA_HRS *(volatile uint32_t *)0x40008034 // Hardware Request Status Register
#define DMA_HRS_HRS(n) ((uint32_t)1<<(n)) // Hardware Request Status Channel n

#define DMA_DCHPRI_CHPRI(n) ((uint8_t)(n & DMA_CHANNEL_N_MASK)<<0) // Channel Arbitration Priority

and add all DMA_DCHPRIn channels: 
// Teensy 3.0
#ifdef(__MK20DX128__)
#define DMA_DCHPRI3 *(volatile uint8_t *)0x40008100 // Channel 3 Priority Register
#define DMA_DCHPRI2 *(volatile uint8_t *)0x40008101 // Channel 2 Priority Register
#define DMA_DCHPRI1 *(volatile uint8_t *)0x40008102 // Channel 1 Priority Register
#define DMA_DCHPRI0 *(volatile uint8_t *)0x40008103 // Channel 0 Priority Register
// Teensy 3.1, see that it's ordered the other way around!
#elif defined(__MK20DX256__)
#define DMA_DCHPRI0 *(volatile uint8_t *)0x40008100 // Channel 0 Priority Register
#define DMA_DCHPRI1 *(volatile uint8_t *)0x40008101 // Channel 1 Priority Register
...
#define DMA_DCHPRI15 *(volatile uint8_t *)0x40008115 // Channel 15 Priority Register
#endif

I think that's all.
 
Last edited:
This is my new mk20dx128.h, all DMA channels work now!
View attachment mk20dx128.h
As far as I remember/know the only changes with respect to the original version are the DMA stuff we just posted.
See that I deleted some definitions like
Code:
#define DMA_ERQ_ERQ0 ((uint32_t)1<<0) // Enable DMA Request 0
#define DMA_ERQ_ERQ1 ((uint32_t)1<<1) // Enable DMA Request 1
etc.
 
The difference in DMA_DCHPRIn might give us a headache should we somewhen decide to introduce an interface that allows index access to those registers, as in
Code:
DMA_DCHPRI[n] = ...
But that's not really relevant now.
 
A minor suggestion, you might want to wrap those pointer literal macros in a set of parentheses to be safer. I.e.:

#define DMA_ERQ (*(volatile uint32_t *)0x4000800C)
 
Back
Top