forked from manitou48/teensy3
-
Notifications
You must be signed in to change notification settings - Fork 0
/
spiDMA.ino
167 lines (146 loc) · 4.85 KB
/
spiDMA.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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// teensy SPI + DMA TODO
// CS,MOSI,MISO,CLK pins 10-13
// dma ch0 xmit (mem to SPI) ch1 recv (SPI to mem)
// try byte, 16-bit, and 32-bit dma transfers ? SPI 16-bit
// do exchange, read/write 0xff, write/sink read
// don't need ISR for now, spin wait
// ref https://github.com/hughpyle/teensy-i2s our mem2mem
#include <SPI.h>
#define CSpin 10
#define RSER_RFDF_DIRS (1<<16)
#define RSER_RFDF_RE (1<<17)
#define RSER_TFFF_DIRS (1<<24)
#define RSER_TFFF_RE (1<<25)
#define DMA_TCD_CSR_BWC(n) (((n) & 0x3) << 14)
#define DMA_CSR_DREQ ((uint16_t)0x8)
#define DMA_CSR_ACTIVE ((uint16_t)0x40)
#define DMA_CR_ERCA ((uint32_t)0x04) // Enable Round Robin Channel Arbitration
#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX)
#define BUFSIZ 1000
volatile int DMAdone=0;
#define DMA_CINT_CINT(n) ((uint8_t)(n & 3)<<0) // Clear Interrupt Request
void dma_ch0_isr(void)
{
DMAdone=1;
DMA_CINT = DMA_CINT_CINT(0); // use the Clear Intr. Request register
}
void dma_ch1_isr(void)
{
DMAdone=1;
DMA_CINT = DMA_CINT_CINT(1); // use the Clear Intr. Request register
}
void spidma_init() {
// set size, and SPI address for xmit and recv dma
// enable DMA in SPI regs ...
SPI0_RSER = RSER_RFDF_DIRS | RSER_RFDF_RE | RSER_TFFF_DIRS | RSER_TFFF_RE;
// DMAMUX setup
// Enable clock to the DMAMUX module
SIM_SCGC6 |= SIM_SCGC6_DMAMUX;
// And clock to the DMA module
SIM_SCGC7 |= SIM_SCGC7_DMA;
DMAMUX0_CHCFG0 = /* DMAMUX_ENABLE | */ DMAMUX_SOURCE_SPI0_TX;
DMAMUX0_CHCFG1 = /* DMAMUX_ENABLE | */ DMAMUX_SOURCE_SPI0_RX;
DMA_TCD0_DADDR = &SPI0_PUSHR;
DMA_TCD0_DOFF = 0; // no increment
DMA_TCD1_SADDR = &SPI0_POPR;
DMA_TCD1_SOFF = 0; // no increment
DMA_TCD0_ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(0); //8 bit
DMA_TCD1_ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(0); //8 bit
DMA_TCD0_SLAST = 0;
DMA_TCD1_SLAST = 0;
DMA_TCD0_CITER_ELINKNO = 1;
DMA_TCD1_CITER_ELINKNO = 1;
DMA_TCD0_DLASTSGA = 0;
DMA_TCD1_DLASTSGA = 0;
DMA_TCD0_BITER_ELINKNO = 1;
DMA_TCD1_BITER_ELINKNO = 1;
DMAdone=0;
// NVIC_ENABLE_IRQ(IRQ_DMA_CH1);
// DMA_TCD1_CSR = DMA_TCD_CSR_INTMAJOR; // interrupt on major loop completion
}
void myspi_init() {
// set up SPI speed and dma ? FIFO
SPI.begin();
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
// SPI.setClockDivider(SPI_CLOCK_DIV2); // DIV4 default 4mhz
pinMode(CSpin,OUTPUT);
spidma_init();
}
void spidma_transfer(char *inbuf, char *outbuf, int bytes) {
digitalWrite(CSpin,LOW);
DMA_TCD0_SADDR = outbuf;
DMA_TCD1_DADDR = inbuf;
DMA_TCD0_NBYTES_MLNO = bytes;
DMA_TCD1_NBYTES_MLNO = bytes;
DMA_TCD0_SOFF = 1; // increment
DMA_TCD1_DOFF = 1; // increment
DMA_ERQ =3; // enable channels 0 and 1
DMA_TCD1_CSR |= DMA_TCD_CSR_START | (1<<3); // active and clear SERQ
DMA_TCD0_CSR |= DMA_TCD_CSR_START | (1<<3); // start transmit
while (!(DMA_TCD0_CSR & DMA_TCD_CSR_DONE)) /* wait */ ;
digitalWrite(CSpin,HIGH);
}
void spidma_write(char *outbuf, int bytes) {
static int sink;
digitalWrite(CSpin,LOW);
DMA_TCD0_SADDR = outbuf;
DMA_TCD1_DADDR = &sink; // ignore bytes from SPI
DMA_TCD0_NBYTES_MLNO = bytes;
DMA_TCD1_NBYTES_MLNO = bytes;
DMA_TCD0_SOFF = 1; // increment
DMA_TCD1_DOFF = 0; // increment
// ? enable before start or not
DMA_ERQ =3; // enable channels 0 and 1
// DMA_SERQ =0; // enable channel
// DMA_SERQ =1; // enable channel
DMA_TCD1_CSR |= DMA_TCD_CSR_START | (1<<3); // start and clear SERQ
DMA_TCD0_CSR |= DMA_TCD_CSR_START | (1<<3); // start transmit
while (!(DMA_TCD1_CSR & DMA_TCD_CSR_DONE)) /* wait */ ;
digitalWrite(CSpin,HIGH);
// ? disable dma/spi
}
void spidma_read(char *inbuf, int bytes) {
static int whatever = 0xffffffff;
digitalWrite(CSpin,LOW);
DMA_TCD0_SADDR = &whatever;
DMA_TCD1_DADDR = inbuf;
DMA_TCD0_NBYTES_MLNO = bytes;
DMA_TCD1_NBYTES_MLNO = bytes;
DMA_TCD0_SOFF = 0; // increment
DMA_TCD1_DOFF = 1; // increment
DMA_TCD1_CSR |= DMA_TCD_CSR_START | (1<<3); // start and clear SERQ
DMA_TCD0_CSR |= DMA_TCD_CSR_START | (1<<3); // start transmit
DMA_SERQ =0; // enable channel
DMA_SERQ =1; // enable channel
while (!(DMA_TCD1_CSR & DMA_TCD_CSR_DONE)) /* wait */ ;
digitalWrite(CSpin,HIGH);
}
void setup() {
Serial.begin(9600);
while(!Serial);
Serial.println("ok");
myspi_init();
PRREG(SPI0_CTAR0);
PRREG(SPI0_RSER);
delay(2000);
}
void loop() {
char buff[BUFSIZ],inbuff[BUFSIZ];
unsigned int i,t1,t2;
Serial.println("looping");
for(i=0;i<BUFSIZ;i++) buff[i]=i;
t1 = micros();
spidma_write(buff,BUFSIZ);
t2 = micros() - t1;
Serial.println(t2);
PRREG(SPI0_CTAR0);
PRREG(SPI0_RSER);
PRREG(SPI0_SR);
PRREG(SPI0_MCR);
PRREG(SPI0_TCR);
PRREG(DMA_TCD0_CSR);
PRREG(DMA_TCD1_CSR);
PRREG(DMA_ES);
delay(2000);
}