-
Notifications
You must be signed in to change notification settings - Fork 1
/
pwm_dma_eti_sys.h
295 lines (274 loc) · 15.3 KB
/
pwm_dma_eti_sys.h
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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
#pragma once
#include <stdint.h> //for uint32_t
#define PAGE_SIZE 4096 //mmap maps pages of memory, so we must give it multiples of this size
#define GPFSEL0 0x00000000 //gpio function select. There are 6 of these (32 bit registers)
#define GPFSEL1 0x00000004
#define GPFSEL2 0x00000008
#define GPFSEL3 0x0000000c
#define GPFSEL4 0x00000010
#define GPFSEL5 0x00000014
//bits 2-0 of GPFSEL0: set to 000 to make Pin 0 an output. 001 is an input. Other combinations represent alternate functions
//bits 3-5 are for pin 1.
//...
//bits 27-29 are for pin 9.
//GPFSEL1 repeats, but bits 2-0 are Pin 10, 27-29 are pin 19.
//...
#define GPSET0 0x0000001C //GPIO Pin Output Set. There are 2 of these (32 bit registers)
#define GPSET1 0x00000020
//writing a '1' to bit N of GPSET0 makes that pin HIGH.
//writing a '0' has no effect.
//GPSET0[0-31] maps to pins 0-31
//GPSET1[0-21] maps to pins 32-53
#define GPCLR0 0x00000028 //GPIO Pin Output Clear. There are 2 of these (32 bits each)
#define GPCLR1 0x0000002C
//GPCLR acts the same way as GPSET, but clears the pin instead.
#define GPLEV0 0x00000034 //GPIO Pin Level. There are 2 of these (32 bits each)
// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define OUT_GPIO(g) *(gpio+((g)/10)) |= (1<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
#define GPIO_SET *(gpio+7) // sets bits which are 1 ignores bits which are 0
#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0
#define GPIO_GET *(gpio+13) // sets bits which are 1 ignores bits which are 0
//physical addresses for the DMA peripherals, as found in the processor documentation:
#define DMACH(n) (0x100*(n))
//DMA Channel register sets (format of these registers is found in DmaChannelHeader struct):
//#define DMACH0 0x00000000
//#define DMACH1 0x00000100
//#define DMACH2 0x00000200
//#define DMACH3 0x00000300
//...
//Each DMA channel has some associated registers, but only CS (control and status), CONBLK_AD (control block address), and DEBUG are writeable
//DMA is started by writing address of the first Control Block to the DMA channel's CONBLK_AD register and then setting the ACTIVE bit inside the CS register (bit 0)
//Note: DMA channels are connected directly to peripherals, so physical addresses should be used (affects control block's SOURCE, DEST and NEXTCONBK addresses).
#define DMAENABLE 0x00000ff0 //bit 0 should be set to 1 to enable channel 0. bit 1 enables channel 1, etc.
//flags used in the DmaChannelHeader struct:
#define DMA_CS_RESET (1<<31)
#define DMA_CS_ABORT (1<<30)
#define DMA_CS_DISDEBUG (1<<29) //DMA will not stop when debug signal is asserted
#define DMA_CS_WAIT_FOR_OUTSTANDING_WRITES (1<<28) //DMA will not stop when debug signal is asserted
#define DMA_CS_PRIORITY(x) ((x)&0xf << 16) //higher priority DMA transfers are serviced first, it would appear
#define DMA_CS_PRIORITY_MAX DMA_CS_PRIORITY(7)
#define DMA_CS_PANIC_PRIORITY(x) ((x)&0xf << 20)
#define DMA_CS_PANIC_PRIORITY_MAX DMA_CS_PANIC_PRIORITY(7)
#define DMA_CS_END (1<<1)
#define DMA_CS_ACTIVE (1<<0)
#define DMA_DEBUG_READ_ERROR (1<<2)
#define DMA_DEBUG_FIFO_ERROR (1<<1)
#define DMA_DEBUG_READ_LAST_NOT_SET_ERROR (1<<0)
//flags used in the DmaControlBlock struct:
#define DMA_CB_TI_NO_WIDE_BURSTS (1<<26)
#define DMA_CB_TI_PERMAP_NONE (0<<16)
#define DMA_CB_TI_PERMAP_DSI (1<<16)
//... (more found on page 61 of BCM2835 pdf
#define DMA_CB_TI_PERMAP_PWM (5<<16)
//...
#define DMA_CB_TI_SRC_IGNORE (1<<11)
#define DMA_CB_TI_SRC_DREQ (1<<10)
#define DMA_CB_TI_SRC_WIDTH (1<<9)
#define DMA_CB_TI_SRC_INC (1<<8)
#define DMA_CB_TI_DEST_DREQ (1<<6)
#define DMA_CB_TI_DEST_INC (1<<4)
#define DMA_CB_TI_WAIT_RESP (1<<3)
#define DMA_CB_TI_TDMODE (1<<1)
//https://dev.openwrt.org/browser/trunk/target/linux/brcm2708/patches-3.10/0070-bcm2708_fb-DMA-acceleration-for-fb_copyarea.patch?rev=39770 says that YLENGTH should actually be written as # of copies *MINUS ONE*
#define DMA_CB_TXFR_LEN_YLENGTH(y) (((y-1)&0x4fff) << 16)
#define DMA_CB_TXFR_LEN_XLENGTH(x) ((x)&0xffff)
#define DMA_CB_TXFR_YLENGTH_MASK (0x4fff << 16)
#define DMA_CB_STRIDE_D_STRIDE(x) (((x)&0xffff) << 16)
#define DMA_CB_STRIDE_S_STRIDE(x) ((x)&0xffff)
//Dma Control Blocks must be located at addresses that are multiples of 32 bytes
#define DMA_CONTROL_BLOCK_ALIGNMENT 32
#define PWM_CTL 0x00000000 //control register
#define PWM_STA 0x00000004 //status register
#define PWM_DMAC 0x00000008 //DMA control register
#define PWM_RNG1 0x00000010 //channel 1 range register (# output bits to use per sample)
#define PWM_DAT1 0x00000014 //channel 1 data
#define PWM_FIF1 0x00000018 //channel 1 fifo (write to this register to queue an output)
#define PWM_RNG2 0x00000020 //channel 2 range register
#define PWM_DAT2 0x00000024 //channel 2 data
#define PWM_CTL_USEFIFO2 (1<<13)
#define PWM_CTL_REPEATEMPTY2 (1<<10)
#define PWM_CTL_SERIAL2 (1<<9)
#define PWM_CTL_ENABLE2 (1<<8)
#define PWM_CTL_CLRFIFO (1<<6)
#define PWM_CTL_USEFIFO1 (1<<5)
#define PWM_CTL_REPEATEMPTY1 (1<<2)
#define PWM_CTL_SERIAL1 (1<<1)
#define PWM_CTL_ENABLE1 (1<<0)
#define PWM_STA_BUSERR (1<<8)
#define PWM_STA_GAPERRS (0xf << 4)
#define PWM_STA_FIFOREADERR (1<<3)
#define PWM_STA_FIFOWRITEERR (1<<2)
#define PWM_STA_ERRS PWM_STA_BUSERR | PWM_STA_GAPERRS | PWM_STA_FIFOREADERR | PWM_STA_FIFOWRITEERR
#define PWM_DMAC_EN (1<<31)
#define PWM_DMAC_PANIC(P) (((P)&0xff)<<8)
#define PWM_DMAC_DREQ(D) (((D)&0xff)<<0)
//The following is undocumented :( Taken from http://www.scribd.com/doc/127599939/BCM2835-Audio-clocks
//each write to CM_PWMTL and CM_PWMDIV requires the password to be written:
#define CM_CTL_PASSWD 0x5a000000
#define CM_DIV_PASSWD 0x5a000000
//MASH is used to achieve fractional clock dividers by introducing artificial jitter.
//if you want constant frequency (even if it may not be at 100% CORRECT frequency), use MASH0
//if clock divisor is integral, then there's no need to use MASH, and anything above MASH1 can introduce jitter.
#define CM_CTL_MASH(x) (((x)&0x3) << 9)
#define CM_CTL_MASH0 CM_CTL_MASH(0)
#define CM_CTL_MASH1 CM_CTL_MASH(1)
#define CM_CTL_MASH2 CM_CTL_MASH(2)
#define CM_CTL_MASH3 CM_CTL_MASH(3)
#define CM_CTL_FLIP (1<<8) //use to inverse clock polarity
#define CM_CTL_BUSY (1<<7) //read-only flag that indicates clock generator is running.
#define CM_CTL_KILL (1<<5) //write a 1 to stop & reset clock generator. USED FOR DEBUG ONLY
#define CM_CTL_ENAB (1<<4) //gracefully stop/start clock generator. BUSY flag will go low once clock is off.
#define CM_CTL_SRC(x) ((x)&0xf) //clock source. 0=gnd. 1=oscillator. 2-3=debug. 4=PLLA per. 5=PLLC per. 6=PLLD per. 7=HDMI aux. 8-15=GND
#define CM_CTL_SRC_OSC CM_CTL_SRC(1)
#define CM_CTL_SRC_PLLA CM_CTL_SRC(4)
#define CM_CTL_SRC_PLLC CM_CTL_SRC(5)
#define CM_CTL_SRC_PLLD CM_CTL_SRC(6)
#define CM_CTL_SRC_HDMI CM_CTL_SRC(7)
//max clock divisor is 4095
#define CM_DIV_DIVI(x) (((x)&0xfff) << 12)
#define CM_DIV_DIVF(x) ((x)&0xfff)
struct DmaChannelHeader {
//Note: dma channels 7-15 are 'LITE' dma engines (or is it 8-15?), with reduced performance & functionality.
//Note: only CS, CONBLK_AD and DEBUG are directly writeable
volatile uint32_t CS; //Control and Status
//31 RESET; set to 1 to reset DMA
//30 ABORT; set to 1 to abort current DMA control block (next one will be loaded & continue)
//29 DISDEBUG; set to 1 and DMA won't be paused when debug signal is sent
//28 WAIT_FOR_OUTSTANDING_WRITES(0x10000000); set to 1 and DMA will wait until peripheral says all writes have gone through before loading next CB
//24-27 reserved
//20-23 PANIC_PRIORITY; 0 is lowest priority
//16-19 PRIORITY; bus scheduling priority. 0 is lowest
//9-15 reserved
//8 ERROR; read as 1 when error is encountered. error can be found in DEBUG register.
//7 reserved
//6 WAITING_FOR_OUTSTANDING_WRITES; read as 1 when waiting for outstanding writes
//5 DREQ_STOPS_DMA(0x20); read as 1 if DREQ is currently preventing DMA
//4 PAUSED(0x10); read as 1 if DMA is paused
//3 DREQ; copy of the data request signal from the peripheral, if DREQ is enabled. reads as 1 if data is being requested (or PERMAP=0), else 0
//2 INT; set when current CB ends and its INTEN=1. Write a 1 to this register to clear it
//1 END; set when the transfer defined by current CB is complete. Write 1 to clear.
//0 ACTIVE(0x01); write 1 to activate DMA (load the CB before hand)
volatile uint32_t CONBLK_AD; //Control Block Address
volatile uint32_t TI; //transfer information; see DmaControlBlock.TI for description
volatile uint32_t SOURCE_AD; //Source address
volatile uint32_t DEST_AD; //Destination address
volatile uint32_t TXFR_LEN; //transfer length. ONLY THE LOWER 16 BITS ARE USED IN LITE DMA ENGINES
volatile uint32_t STRIDE; //2D Mode Stride. Only used if TI.TDMODE = 1. NOT AVAILABLE IN LITE DMA ENGINES
volatile uint32_t NEXTCONBK; //Next control block. Must be 256-bit aligned (32 bytes; 8 words)
volatile uint32_t DEBUG; //controls debug settings
//29-31 unused
//28 LITE (0x10000000)
//25-27 VERSION
//16-24 DMA_STATE (dma engine state machine)
//8-15 DMA_ID (AXI bus id)
//4-7 OUTSTANDING_WRITES
//3 unused
//2 READ_ERROR
//1 WRITE_ERROR
//0 READ_LAST_NOT_SET_ERROR
};
struct DmaControlBlock {
volatile uint32_t TI; //transfer information
//31:27 unused
//26 NO_WIDE_BURSTS
//21:25 WAITS; number of cycles to wait between each DMA read/write operation
//16:20 PERMAP(0x000Y0000); peripheral number to be used for DREQ signal (pacing). set to 0 for unpaced DMA.
//12:15 BURST_LENGTH
//11 SRC_IGNORE; set to 1 to not perform reads. Used to manually fill caches
//10 SRC_DREQ; set to 1 to have the DREQ from PERMAP gate requests.
//9 SRC_WIDTH; set to 1 for 128-bit moves, 0 for 32-bit moves
//8 SRC_INC; set to 1 to automatically increment the source address after each read (you'll want this if you're copying a range of memory)
//7 DEST_IGNORE; set to 1 to not perform writes.
//6 DEST_DREQ; set to 1 to have the DREQ from PERMAP gate *writes*
//5 DEST_WIDTH; set to 1 for 128-bit moves, 0 for 32-bit moves
//4 DEST_INC; set to 1 to automatically increment the destination address after each read (Tyou'll want this if you're copying a range of memory)
//3 WAIT_RESP; make DMA wait for a response from the peripheral during each write. Ensures multiple writes don't get stacked in the pipeline
//2 unused (0)
//1 TDMODE; set to 1 to enable 2D mode
//0 INTEN; set to 1 to generate an interrupt upon completion
volatile uint32_t SOURCE_AD; //Source address
volatile uint32_t DEST_AD; //Destination address
volatile uint32_t TXFR_LEN; //transfer length.
//in 2D mode, TXFR_LEN is separated into two half-words to indicate Y transfers of length X, and STRIDE is added to the src/dest address after each transfer of length X.
//30:31 unused
//16-29 YLENGTH
//0-15 XLENGTH
volatile uint32_t STRIDE; //2D Mode Stride (amount to increment/decrement src/dest after each 1d copy when in 2d mode). Only used if TI.TDMODE = 1
//16-31 D_STRIDE; signed (2's complement) byte increment/decrement to apply to destination addr after each XLENGTH transfer
//0-15 S_STRIDE; signed (2's complement) byte increment/decrement to apply to source addr after each XLENGTH transfer
volatile uint32_t NEXTCONBK; //Next control block. Must be 256-bit aligned (32 bytes; 8 words)
uint32_t _reserved[2];
};
struct PwmHeader {
volatile uint32_t CTL; // 0x00000000 //control register
//16-31 reserved
//15 MSEN2 (0: PWM algorithm, 1:M/S transmission used)
//14 reserved
//13 USEF2 (0: data register is used for transmission, 1: FIFO is used for transmission)
//12 POLA2 (0: 0=low, 1=high. 1: 0=high, 1=low (inversion))
//11 SBIT2; defines the state of the output when no transmission is in place
//10 RPTL2; 0: transmission interrupts when FIFO is empty. 1: last data in FIFO is retransmitted when FIFO is empty
//9 MODE2; 0: PWM mode. 1: serializer mode
//8 PWMEN2; 0: channel is disabled. 1: channel is enabled
//7 MSEN1;
//6 CLRF1; writing a 1 to this bit clears the channel 1 (and channel 2?) fifo
//5 USEF1;
//4 POLA1;
//3 SBIT1;
//2 RPTL1;
//1 MODE1;
//0 PWMEN1;
volatile uint32_t STA; // 0x00000004 //status register
//13-31 reserved
//9-12 STA1-4; indicates whether each channel is transmitting
//8 BERR; Bus Error Flag. Write 1 to clear
//4-7 GAPO1-4; Gap Occured Flag. Write 1 to clear
//3 RERR1; Fifo Read Error Flag (attempt to read empty fifo). Write 1 to clear
//2 WERR1; Fifo Write Error Flag (attempt to write to full fifo). Write 1 to clear
//1 EMPT1; Reads as 1 if fifo is empty
//0 FULL1; Reads as 1 if fifo is full
volatile uint32_t DMAC; // 0x00000008 //DMA control register
//31 ENAB; set to 1 to enable DMA
//16-30 reserved
//8-15 PANIC; DMA threshold for panic signal
//0-7 DREQ; DMA threshold for DREQ signal
uint32_t _padding1;
volatile uint32_t RNG1; // 0x00000010 //channel 1 range register (# output bits to use per sample)
//0-31 PWM_RNGi; #of bits to modulate PWM. (eg if PWM_RNGi=1024, then each 32-bit sample sent through the FIFO will be modulated into 1024 bits.)
volatile uint32_t DAT1; // 0x00000014 //channel 1 data
//0-31 PWM_DATi; Stores the 32-bit data to be sent to the PWM controller ONLY WHEN USEFi=0 (FIFO is disabled)
volatile uint32_t FIF1; // 0x00000018 //channel 1 fifo (write to this register to queue an output)
//writing to this register will queue a sample into the fifo. If 2 channels are enabled, then each even sample (0-indexed) is sent to channel 1, and odd samples are sent to channel 2. WRITE-ONLY
uint32_t _padding2;
volatile uint32_t RNG2; // 0x00000020 //channel 2 range register
volatile uint32_t DAT2; // 0x00000024 //channel 2 data
//0-31 PWM_DATi; Stores the 32-bit data to be sent to the PWM controller ONLY WHEN USEFi=1 (FIFO is enabled). TODO: Typo???
};
struct ClockManagerClockHeader {
volatile uint32_t CTL;
//24-31 PASSWD "5a"
//11-23 unused
//9-10 MASH
//8 FLIP
//7 BUSY
//6 unused
//5 KILL
//4 ENAB
//0-3 SRC; 0: GND, 1=oscillator, 2=testdebug0, 3=testdebug1, 4=PLLA per, 5=PLLC, 6=PLLD, 7=HDMI, 8-15=GND
volatile uint32_t DIV;
//24-31 PASSWD "5a"
//12-23 DIVI Integer part of divisor
//11-0 DIVF Fractional part of divisor
};
struct ClockManagerHeader {
struct ClockManagerClockHeader GP0;
struct ClockManagerClockHeader GP1;
struct ClockManagerClockHeader GP2;
//Unknown:
uint32_t unknown[4]; //0x88, 0x8C, 0x90, 0x94
//https://de.scribd.com/doc/127599939/BCM2835-Audio-clocks says PCM is 0x98 and PWM 0xA0
struct ClockManagerClockHeader PCM;
struct ClockManagerClockHeader PWM;
};