-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathmem2mem.ino
101 lines (88 loc) · 3.03 KB
/
mem2mem.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// DMA memory to memory ZERO
// ch 18 beat burst block
// xdk sam0/drivers/dma/dma.c
// packages/arduino/tools/CMSIS/4.0.0-atmel/Device/ATMEL/samd21/include/component/dmac.h
#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX)
#define BYTES 1024
#define WORDS BYTES/sizeof(int)
char src[BYTES] __attribute__ ((aligned (8)));
char dst[BYTES] __attribute__ ((aligned (8)));
int *srcw = (int *) src, *dstw = (int *)dst;
void prmbs(char *lbl,unsigned long us,int bits) {
float mbs = (float)bits/us;
Serial.print(mbs,2); Serial.print(" mbs ");
Serial.print(us); Serial.print(" us ");
Serial.println(lbl);
}
// DMA 12 channels
typedef struct {
uint16_t btctrl;
uint16_t btcnt;
uint32_t srcaddr;
uint32_t dstaddr;
uint32_t descaddr;
} dmacdescriptor ;
volatile dmacdescriptor wrb[12] __attribute__ ((aligned (16)));
dmacdescriptor descriptor_section[12] __attribute__ ((aligned (16)));
dmacdescriptor descriptor __attribute__ ((aligned (16)));
static uint32_t chnl = 0; // DMA channel
volatile uint32_t dmadone;
void DMAC_Handler() {
// interrupts DMAC_CHINTENCLR_TERR DMAC_CHINTENCLR_TCMPL DMAC_CHINTENCLR_SUSP
uint8_t active_channel;
// disable irqs ?
active_channel = DMAC->INTPEND.reg & DMAC_INTPEND_ID_Msk; // get channel number
DMAC->CHID.reg = DMAC_CHID_ID(active_channel);
dmadone = DMAC->CHINTFLAG.reg;
DMAC->CHINTFLAG.reg = DMAC_CHINTENCLR_TCMPL; // clear
DMAC->CHINTFLAG.reg = DMAC_CHINTENCLR_TERR;
DMAC->CHINTFLAG.reg = DMAC_CHINTENCLR_SUSP;
}
void dma_init() {
// probably on by default
PM->AHBMASK.reg |= PM_AHBMASK_DMAC ;
PM->APBBMASK.reg |= PM_APBBMASK_DMAC ;
NVIC_EnableIRQ( DMAC_IRQn ) ;
DMAC->BASEADDR.reg = (uint32_t)descriptor_section;
DMAC->WRBADDR.reg = (uint32_t)wrb;
DMAC->CTRL.reg = DMAC_CTRL_DMAENABLE | DMAC_CTRL_LVLEN(0xf);
DMAC->CHID.reg = DMAC_CHID_ID(chnl);
DMAC->CHCTRLA.reg &= ~DMAC_CHCTRLA_ENABLE;
DMAC->CHCTRLA.reg = DMAC_CHCTRLA_SWRST;
}
void memcpy32(void *dst, const void *src, size_t n) {
DMAC->CHID.reg = DMAC_CHID_ID(chnl); // channel
DMAC->CHINTENSET.reg = DMAC_CHINTENSET_MASK ; // enable all 3 interrupts
dmadone = 0;
descriptor.descaddr = 0;
descriptor.dstaddr = (uint32_t)dst + n;
descriptor.srcaddr = (uint32_t)src + n;
descriptor.btcnt = n/4;
descriptor.btctrl = DMAC_BTCTRL_BEATSIZE_WORD | DMAC_BTCTRL_DSTINC | DMAC_BTCTRL_SRCINC | DMAC_BTCTRL_VALID;
memcpy(&descriptor_section[chnl],&descriptor, sizeof(dmacdescriptor));
DMAC->CHCTRLA.reg |= DMAC_CHCTRLA_ENABLE;
DMAC->SWTRIGCTRL.reg |= (1 << chnl); // trigger channel
while(!dmadone); // await DMA done isr
}
void setup() {
Serial.begin(9600);
dma_init();
}
void loop() {
int i, errs=0;
unsigned long t1;
for (i=0;i<BYTES;i++) src[i] = i;
memset(dst,0,BYTES);
t1 = micros();
memcpy(dst,src,BYTES);
t1 = micros() -t1;
prmbs("memcpy",t1,BYTES*8);
memset(dst,0,BYTES);
t1 = micros();
memcpy32(dst,src,BYTES);
t1 = micros() -t1;
prmbs("dma",t1,BYTES*8);
for (i=0;i<BYTES;i++) if (dst[i] != i%256)errs++;
Serial.print("errs "); Serial.println(errs);
delay(3000);
}