Mathias Gottschlag 4 yıl önce
işleme
c551a0eee7
11 değiştirilmiş dosya ile 1968 ekleme ve 0 silme
  1. 12
    0
      .cargo/config
  2. 2
    0
      .gitignore
  3. 981
    0
      Cargo.lock
  4. 28
    0
      Cargo.toml
  5. 31
    0
      build.rs
  6. 13
    0
      memory.x
  7. 205
    0
      src/audio_buffer.rs
  8. 121
    0
      src/i2s_master.rs
  9. 231
    0
      src/main.rs
  10. 54
    0
      src/usb.rs
  11. 290
    0
      src/usb_audio.rs

+ 12
- 0
.cargo/config Dosyayı Görüntüle

@@ -0,0 +1,12 @@
1
+[build]
2
+# Instruction set of Cortex-M0+
3
+target = "thumbv6m-none-eabi"
4
+
5
+[target.'cfg(all(target_arch = "arm", target_os = "none"))']
6
+rustflags = [
7
+    "-C", "link-arg=--nmagic",
8
+    "-C", "link-arg=-Tlink.x",
9
+    "-C", "inline-threshold=5",
10
+    "-C", "no-vectorize-loops",
11
+]
12
+runner = "elf2uf2-rs -d"

+ 2
- 0
.gitignore Dosyayı Görüntüle

@@ -0,0 +1,2 @@
1
+/target
2
+*.swp

+ 981
- 0
Cargo.lock Dosyayı Görüntüle

@@ -0,0 +1,981 @@
1
+# This file is automatically @generated by Cargo.
2
+# It is not intended for manual editing.
3
+version = 3
4
+
5
+[[package]]
6
+name = "aho-corasick"
7
+version = "0.7.18"
8
+source = "registry+https://github.com/rust-lang/crates.io-index"
9
+checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
10
+dependencies = [
11
+ "memchr",
12
+]
13
+
14
+[[package]]
15
+name = "arrayvec"
16
+version = "0.7.1"
17
+source = "registry+https://github.com/rust-lang/crates.io-index"
18
+checksum = "be4dc07131ffa69b8072d35f5007352af944213cde02545e2103680baed38fcd"
19
+
20
+[[package]]
21
+name = "as-slice"
22
+version = "0.1.5"
23
+source = "registry+https://github.com/rust-lang/crates.io-index"
24
+checksum = "45403b49e3954a4b8428a0ac21a4b7afadccf92bfd96273f1a58cd4812496ae0"
25
+dependencies = [
26
+ "generic-array 0.12.4",
27
+ "generic-array 0.13.3",
28
+ "generic-array 0.14.4",
29
+ "stable_deref_trait",
30
+]
31
+
32
+[[package]]
33
+name = "ascii-canvas"
34
+version = "3.0.0"
35
+source = "registry+https://github.com/rust-lang/crates.io-index"
36
+checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6"
37
+dependencies = [
38
+ "term",
39
+]
40
+
41
+[[package]]
42
+name = "atty"
43
+version = "0.2.14"
44
+source = "registry+https://github.com/rust-lang/crates.io-index"
45
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
46
+dependencies = [
47
+ "hermit-abi",
48
+ "libc",
49
+ "winapi",
50
+]
51
+
52
+[[package]]
53
+name = "autocfg"
54
+version = "1.0.1"
55
+source = "registry+https://github.com/rust-lang/crates.io-index"
56
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
57
+
58
+[[package]]
59
+name = "bare-metal"
60
+version = "0.2.5"
61
+source = "registry+https://github.com/rust-lang/crates.io-index"
62
+checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3"
63
+dependencies = [
64
+ "rustc_version",
65
+]
66
+
67
+[[package]]
68
+name = "bare-metal"
69
+version = "1.0.0"
70
+source = "registry+https://github.com/rust-lang/crates.io-index"
71
+checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603"
72
+
73
+[[package]]
74
+name = "bit-set"
75
+version = "0.5.2"
76
+source = "registry+https://github.com/rust-lang/crates.io-index"
77
+checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de"
78
+dependencies = [
79
+ "bit-vec",
80
+]
81
+
82
+[[package]]
83
+name = "bit-vec"
84
+version = "0.6.3"
85
+source = "registry+https://github.com/rust-lang/crates.io-index"
86
+checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
87
+
88
+[[package]]
89
+name = "bitfield"
90
+version = "0.13.2"
91
+source = "registry+https://github.com/rust-lang/crates.io-index"
92
+checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719"
93
+
94
+[[package]]
95
+name = "bitflags"
96
+version = "1.3.2"
97
+source = "registry+https://github.com/rust-lang/crates.io-index"
98
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
99
+
100
+[[package]]
101
+name = "byteorder"
102
+version = "1.3.4"
103
+source = "registry+https://github.com/rust-lang/crates.io-index"
104
+checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
105
+
106
+[[package]]
107
+name = "cfg-if"
108
+version = "1.0.0"
109
+source = "registry+https://github.com/rust-lang/crates.io-index"
110
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
111
+
112
+[[package]]
113
+name = "codespan-reporting"
114
+version = "0.11.1"
115
+source = "registry+https://github.com/rust-lang/crates.io-index"
116
+checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
117
+dependencies = [
118
+ "termcolor",
119
+ "unicode-width",
120
+]
121
+
122
+[[package]]
123
+name = "cortex-m"
124
+version = "0.7.3"
125
+source = "registry+https://github.com/rust-lang/crates.io-index"
126
+checksum = "2ac919ef424449ec8c08d515590ce15d9262c0ca5f0da5b0c901e971a3b783b3"
127
+dependencies = [
128
+ "bare-metal 0.2.5",
129
+ "bitfield",
130
+ "embedded-hal",
131
+ "volatile-register",
132
+]
133
+
134
+[[package]]
135
+name = "cortex-m-rt"
136
+version = "0.7.0"
137
+source = "registry+https://github.com/rust-lang/crates.io-index"
138
+checksum = "069533b58e25b635fac881eb6556616bd8f83a3e0ffe2b4b9619289ed14d465e"
139
+dependencies = [
140
+ "cortex-m-rt-macros",
141
+]
142
+
143
+[[package]]
144
+name = "cortex-m-rt-macros"
145
+version = "0.7.0"
146
+source = "registry+https://github.com/rust-lang/crates.io-index"
147
+checksum = "f0f6f3e36f203cfedbc78b357fb28730aa2c6dc1ab060ee5c2405e843988d3c7"
148
+dependencies = [
149
+ "proc-macro2",
150
+ "quote",
151
+ "syn",
152
+]
153
+
154
+[[package]]
155
+name = "cortex-m-rtic"
156
+version = "0.6.0-alpha.5"
157
+source = "registry+https://github.com/rust-lang/crates.io-index"
158
+checksum = "74081ae0575d772472789aa6a642a1632303fd64529078d7be06fdcbec31401a"
159
+dependencies = [
160
+ "bare-metal 1.0.0",
161
+ "cortex-m",
162
+ "cortex-m-rtic-macros",
163
+ "generic-array 0.14.4",
164
+ "heapless",
165
+ "rtic-core",
166
+ "rtic-monotonic",
167
+ "version_check",
168
+]
169
+
170
+[[package]]
171
+name = "cortex-m-rtic-macros"
172
+version = "0.6.0-alpha.5"
173
+source = "registry+https://github.com/rust-lang/crates.io-index"
174
+checksum = "c537c47b1d14be9bc6781f0bdfc514a043dd03d33796fa4f1052ac8e13c7f7d4"
175
+dependencies = [
176
+ "proc-macro-error",
177
+ "proc-macro2",
178
+ "quote",
179
+ "rtic-syntax",
180
+ "syn",
181
+]
182
+
183
+[[package]]
184
+name = "crc-any"
185
+version = "2.4.0"
186
+source = "registry+https://github.com/rust-lang/crates.io-index"
187
+checksum = "44c268ef4daf6fe48c6794ffb5e138afb6ea405b7987ec8f8501b817a84a56d6"
188
+dependencies = [
189
+ "debug-helper",
190
+]
191
+
192
+[[package]]
193
+name = "crunchy"
194
+version = "0.2.2"
195
+source = "registry+https://github.com/rust-lang/crates.io-index"
196
+checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
197
+
198
+[[package]]
199
+name = "debug-helper"
200
+version = "0.3.12"
201
+source = "registry+https://github.com/rust-lang/crates.io-index"
202
+checksum = "76fbd10dce159c002b9c688ae8ab7cd531151e185e0ad360f4bfea3b0eede3a8"
203
+
204
+[[package]]
205
+name = "derivative"
206
+version = "2.2.0"
207
+source = "registry+https://github.com/rust-lang/crates.io-index"
208
+checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
209
+dependencies = [
210
+ "proc-macro2",
211
+ "quote",
212
+ "syn",
213
+]
214
+
215
+[[package]]
216
+name = "diff"
217
+version = "0.1.12"
218
+source = "registry+https://github.com/rust-lang/crates.io-index"
219
+checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
220
+
221
+[[package]]
222
+name = "dirs-next"
223
+version = "2.0.0"
224
+source = "registry+https://github.com/rust-lang/crates.io-index"
225
+checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
226
+dependencies = [
227
+ "cfg-if",
228
+ "dirs-sys-next",
229
+]
230
+
231
+[[package]]
232
+name = "dirs-sys-next"
233
+version = "0.1.2"
234
+source = "registry+https://github.com/rust-lang/crates.io-index"
235
+checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
236
+dependencies = [
237
+ "libc",
238
+ "redox_users",
239
+ "winapi",
240
+]
241
+
242
+[[package]]
243
+name = "either"
244
+version = "1.6.1"
245
+source = "registry+https://github.com/rust-lang/crates.io-index"
246
+checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
247
+
248
+[[package]]
249
+name = "embedded-dma"
250
+version = "0.1.2"
251
+source = "registry+https://github.com/rust-lang/crates.io-index"
252
+checksum = "46c8c02e4347a0267ca60813c952017f4c5948c232474c6010a381a337f1bda4"
253
+dependencies = [
254
+ "stable_deref_trait",
255
+]
256
+
257
+[[package]]
258
+name = "embedded-hal"
259
+version = "0.2.6"
260
+source = "registry+https://github.com/rust-lang/crates.io-index"
261
+checksum = "e36cfb62ff156596c892272f3015ef952fe1525e85261fa3a7f327bd6b384ab9"
262
+dependencies = [
263
+ "nb 0.1.3",
264
+ "void",
265
+]
266
+
267
+[[package]]
268
+name = "embedded-time"
269
+version = "0.12.0"
270
+source = "registry+https://github.com/rust-lang/crates.io-index"
271
+checksum = "86fbafcea0dea120d8ed8af67ddbf82afc031f1d3b064920645db8d061781e2c"
272
+dependencies = [
273
+ "num",
274
+]
275
+
276
+[[package]]
277
+name = "ena"
278
+version = "0.14.0"
279
+source = "registry+https://github.com/rust-lang/crates.io-index"
280
+checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3"
281
+dependencies = [
282
+ "log",
283
+]
284
+
285
+[[package]]
286
+name = "fixedbitset"
287
+version = "0.2.0"
288
+source = "registry+https://github.com/rust-lang/crates.io-index"
289
+checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
290
+
291
+[[package]]
292
+name = "generic-array"
293
+version = "0.12.4"
294
+source = "registry+https://github.com/rust-lang/crates.io-index"
295
+checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd"
296
+dependencies = [
297
+ "typenum",
298
+]
299
+
300
+[[package]]
301
+name = "generic-array"
302
+version = "0.13.3"
303
+source = "registry+https://github.com/rust-lang/crates.io-index"
304
+checksum = "f797e67af32588215eaaab8327027ee8e71b9dd0b2b26996aedf20c030fce309"
305
+dependencies = [
306
+ "typenum",
307
+]
308
+
309
+[[package]]
310
+name = "generic-array"
311
+version = "0.14.4"
312
+source = "registry+https://github.com/rust-lang/crates.io-index"
313
+checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
314
+dependencies = [
315
+ "typenum",
316
+ "version_check",
317
+]
318
+
319
+[[package]]
320
+name = "getrandom"
321
+version = "0.2.3"
322
+source = "registry+https://github.com/rust-lang/crates.io-index"
323
+checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
324
+dependencies = [
325
+ "cfg-if",
326
+ "libc",
327
+ "wasi",
328
+]
329
+
330
+[[package]]
331
+name = "hash32"
332
+version = "0.1.1"
333
+source = "registry+https://github.com/rust-lang/crates.io-index"
334
+checksum = "d4041af86e63ac4298ce40e5cca669066e75b6f1aa3390fe2561ffa5e1d9f4cc"
335
+dependencies = [
336
+ "byteorder",
337
+]
338
+
339
+[[package]]
340
+name = "hashbrown"
341
+version = "0.11.2"
342
+source = "registry+https://github.com/rust-lang/crates.io-index"
343
+checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
344
+
345
+[[package]]
346
+name = "heapless"
347
+version = "0.6.1"
348
+source = "registry+https://github.com/rust-lang/crates.io-index"
349
+checksum = "634bd4d29cbf24424d0a4bfcbf80c6960129dc24424752a7d1d1390607023422"
350
+dependencies = [
351
+ "as-slice",
352
+ "generic-array 0.14.4",
353
+ "hash32",
354
+ "stable_deref_trait",
355
+]
356
+
357
+[[package]]
358
+name = "hermit-abi"
359
+version = "0.1.19"
360
+source = "registry+https://github.com/rust-lang/crates.io-index"
361
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
362
+dependencies = [
363
+ "libc",
364
+]
365
+
366
+[[package]]
367
+name = "indexmap"
368
+version = "1.7.0"
369
+source = "registry+https://github.com/rust-lang/crates.io-index"
370
+checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
371
+dependencies = [
372
+ "autocfg",
373
+ "hashbrown",
374
+]
375
+
376
+[[package]]
377
+name = "itertools"
378
+version = "0.10.1"
379
+source = "registry+https://github.com/rust-lang/crates.io-index"
380
+checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
381
+dependencies = [
382
+ "either",
383
+]
384
+
385
+[[package]]
386
+name = "lalrpop"
387
+version = "0.19.6"
388
+source = "registry+https://github.com/rust-lang/crates.io-index"
389
+checksum = "b15174f1c529af5bf1283c3bc0058266b483a67156f79589fab2a25e23cf8988"
390
+dependencies = [
391
+ "ascii-canvas",
392
+ "atty",
393
+ "bit-set",
394
+ "diff",
395
+ "ena",
396
+ "itertools",
397
+ "lalrpop-util",
398
+ "petgraph",
399
+ "pico-args",
400
+ "regex",
401
+ "regex-syntax",
402
+ "string_cache",
403
+ "term",
404
+ "tiny-keccak",
405
+ "unicode-xid",
406
+]
407
+
408
+[[package]]
409
+name = "lalrpop-util"
410
+version = "0.19.6"
411
+source = "registry+https://github.com/rust-lang/crates.io-index"
412
+checksum = "d3e58cce361efcc90ba8a0a5f982c741ff86b603495bb15a998412e957dcd278"
413
+dependencies = [
414
+ "regex",
415
+]
416
+
417
+[[package]]
418
+name = "lazy_static"
419
+version = "1.4.0"
420
+source = "registry+https://github.com/rust-lang/crates.io-index"
421
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
422
+
423
+[[package]]
424
+name = "libc"
425
+version = "0.2.102"
426
+source = "registry+https://github.com/rust-lang/crates.io-index"
427
+checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103"
428
+
429
+[[package]]
430
+name = "log"
431
+version = "0.4.14"
432
+source = "registry+https://github.com/rust-lang/crates.io-index"
433
+checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
434
+dependencies = [
435
+ "cfg-if",
436
+]
437
+
438
+[[package]]
439
+name = "memchr"
440
+version = "2.4.1"
441
+source = "registry+https://github.com/rust-lang/crates.io-index"
442
+checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
443
+
444
+[[package]]
445
+name = "nb"
446
+version = "0.1.3"
447
+source = "registry+https://github.com/rust-lang/crates.io-index"
448
+checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
449
+dependencies = [
450
+ "nb 1.0.0",
451
+]
452
+
453
+[[package]]
454
+name = "nb"
455
+version = "1.0.0"
456
+source = "registry+https://github.com/rust-lang/crates.io-index"
457
+checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae"
458
+
459
+[[package]]
460
+name = "new_debug_unreachable"
461
+version = "1.0.4"
462
+source = "registry+https://github.com/rust-lang/crates.io-index"
463
+checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
464
+
465
+[[package]]
466
+name = "num"
467
+version = "0.3.1"
468
+source = "registry+https://github.com/rust-lang/crates.io-index"
469
+checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f"
470
+dependencies = [
471
+ "num-complex",
472
+ "num-integer",
473
+ "num-iter",
474
+ "num-rational",
475
+ "num-traits",
476
+]
477
+
478
+[[package]]
479
+name = "num-complex"
480
+version = "0.3.1"
481
+source = "registry+https://github.com/rust-lang/crates.io-index"
482
+checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5"
483
+dependencies = [
484
+ "num-traits",
485
+]
486
+
487
+[[package]]
488
+name = "num-integer"
489
+version = "0.1.44"
490
+source = "registry+https://github.com/rust-lang/crates.io-index"
491
+checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
492
+dependencies = [
493
+ "autocfg",
494
+ "num-traits",
495
+]
496
+
497
+[[package]]
498
+name = "num-iter"
499
+version = "0.1.42"
500
+source = "registry+https://github.com/rust-lang/crates.io-index"
501
+checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59"
502
+dependencies = [
503
+ "autocfg",
504
+ "num-integer",
505
+ "num-traits",
506
+]
507
+
508
+[[package]]
509
+name = "num-rational"
510
+version = "0.3.2"
511
+source = "registry+https://github.com/rust-lang/crates.io-index"
512
+checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07"
513
+dependencies = [
514
+ "autocfg",
515
+ "num-integer",
516
+ "num-traits",
517
+]
518
+
519
+[[package]]
520
+name = "num-traits"
521
+version = "0.2.14"
522
+source = "registry+https://github.com/rust-lang/crates.io-index"
523
+checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
524
+dependencies = [
525
+ "autocfg",
526
+]
527
+
528
+[[package]]
529
+name = "num_enum"
530
+version = "0.5.4"
531
+source = "registry+https://github.com/rust-lang/crates.io-index"
532
+checksum = "3f9bd055fb730c4f8f4f57d45d35cd6b3f0980535b056dc7ff119cee6a66ed6f"
533
+dependencies = [
534
+ "derivative",
535
+ "num_enum_derive",
536
+]
537
+
538
+[[package]]
539
+name = "num_enum_derive"
540
+version = "0.5.4"
541
+source = "registry+https://github.com/rust-lang/crates.io-index"
542
+checksum = "486ea01961c4a818096de679a8b740b26d9033146ac5291b1c98557658f8cdd9"
543
+dependencies = [
544
+ "proc-macro2",
545
+ "quote",
546
+ "syn",
547
+]
548
+
549
+[[package]]
550
+name = "panic-halt"
551
+version = "0.2.0"
552
+source = "registry+https://github.com/rust-lang/crates.io-index"
553
+checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812"
554
+
555
+[[package]]
556
+name = "paste"
557
+version = "1.0.5"
558
+source = "registry+https://github.com/rust-lang/crates.io-index"
559
+checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58"
560
+
561
+[[package]]
562
+name = "petgraph"
563
+version = "0.5.1"
564
+source = "registry+https://github.com/rust-lang/crates.io-index"
565
+checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
566
+dependencies = [
567
+ "fixedbitset",
568
+ "indexmap",
569
+]
570
+
571
+[[package]]
572
+name = "phf_shared"
573
+version = "0.8.0"
574
+source = "registry+https://github.com/rust-lang/crates.io-index"
575
+checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7"
576
+dependencies = [
577
+ "siphasher",
578
+]
579
+
580
+[[package]]
581
+name = "pico-args"
582
+version = "0.4.2"
583
+source = "registry+https://github.com/rust-lang/crates.io-index"
584
+checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468"
585
+
586
+[[package]]
587
+name = "pio"
588
+version = "0.1.0"
589
+dependencies = [
590
+ "arrayvec",
591
+ "num_enum",
592
+ "paste",
593
+]
594
+
595
+[[package]]
596
+name = "pio-parser"
597
+version = "0.1.0"
598
+dependencies = [
599
+ "lalrpop",
600
+ "lalrpop-util",
601
+ "pio",
602
+]
603
+
604
+[[package]]
605
+name = "pio-proc"
606
+version = "0.1.0"
607
+dependencies = [
608
+ "codespan-reporting",
609
+ "lalrpop-util",
610
+ "pio",
611
+ "pio-parser",
612
+ "proc-macro2",
613
+ "quote",
614
+ "syn",
615
+]
616
+
617
+[[package]]
618
+name = "precomputed-hash"
619
+version = "0.1.1"
620
+source = "registry+https://github.com/rust-lang/crates.io-index"
621
+checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
622
+
623
+[[package]]
624
+name = "proc-macro-error"
625
+version = "1.0.4"
626
+source = "registry+https://github.com/rust-lang/crates.io-index"
627
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
628
+dependencies = [
629
+ "proc-macro-error-attr",
630
+ "proc-macro2",
631
+ "quote",
632
+ "syn",
633
+ "version_check",
634
+]
635
+
636
+[[package]]
637
+name = "proc-macro-error-attr"
638
+version = "1.0.4"
639
+source = "registry+https://github.com/rust-lang/crates.io-index"
640
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
641
+dependencies = [
642
+ "proc-macro2",
643
+ "quote",
644
+ "version_check",
645
+]
646
+
647
+[[package]]
648
+name = "proc-macro2"
649
+version = "1.0.29"
650
+source = "registry+https://github.com/rust-lang/crates.io-index"
651
+checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d"
652
+dependencies = [
653
+ "unicode-xid",
654
+]
655
+
656
+[[package]]
657
+name = "quote"
658
+version = "1.0.9"
659
+source = "registry+https://github.com/rust-lang/crates.io-index"
660
+checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
661
+dependencies = [
662
+ "proc-macro2",
663
+]
664
+
665
+[[package]]
666
+name = "rand_core"
667
+version = "0.6.3"
668
+source = "registry+https://github.com/rust-lang/crates.io-index"
669
+checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
670
+
671
+[[package]]
672
+name = "redox_syscall"
673
+version = "0.2.10"
674
+source = "registry+https://github.com/rust-lang/crates.io-index"
675
+checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
676
+dependencies = [
677
+ "bitflags",
678
+]
679
+
680
+[[package]]
681
+name = "redox_users"
682
+version = "0.4.0"
683
+source = "registry+https://github.com/rust-lang/crates.io-index"
684
+checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
685
+dependencies = [
686
+ "getrandom",
687
+ "redox_syscall",
688
+]
689
+
690
+[[package]]
691
+name = "regex"
692
+version = "1.5.4"
693
+source = "registry+https://github.com/rust-lang/crates.io-index"
694
+checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
695
+dependencies = [
696
+ "aho-corasick",
697
+ "memchr",
698
+ "regex-syntax",
699
+]
700
+
701
+[[package]]
702
+name = "regex-syntax"
703
+version = "0.6.25"
704
+source = "registry+https://github.com/rust-lang/crates.io-index"
705
+checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
706
+
707
+[[package]]
708
+name = "rp2040-boot2"
709
+version = "0.1.2"
710
+source = "registry+https://github.com/rust-lang/crates.io-index"
711
+checksum = "233203dcc51018ec08df8462fc84c0170aa4b4220bbcbe56901bc637ba98604a"
712
+dependencies = [
713
+ "crc-any",
714
+]
715
+
716
+[[package]]
717
+name = "rp2040-hal"
718
+version = "0.3.0"
719
+dependencies = [
720
+ "cortex-m",
721
+ "embedded-dma",
722
+ "embedded-hal",
723
+ "embedded-time",
724
+ "itertools",
725
+ "nb 1.0.0",
726
+ "paste",
727
+ "pio",
728
+ "pio-proc",
729
+ "rand_core",
730
+ "rp2040-pac",
731
+ "usb-device",
732
+ "vcell",
733
+ "void",
734
+]
735
+
736
+[[package]]
737
+name = "rp2040-pac"
738
+version = "0.1.5"
739
+dependencies = [
740
+ "cortex-m",
741
+ "cortex-m-rt",
742
+ "vcell",
743
+]
744
+
745
+[[package]]
746
+name = "rp2040-usb-sound-card"
747
+version = "0.1.0"
748
+dependencies = [
749
+ "cortex-m",
750
+ "cortex-m-rt",
751
+ "cortex-m-rtic",
752
+ "embedded-hal",
753
+ "embedded-time",
754
+ "nb 1.0.0",
755
+ "panic-halt",
756
+ "pio",
757
+ "pio-proc",
758
+ "rp2040-boot2",
759
+ "rp2040-hal",
760
+ "stable_deref_trait",
761
+ "systick-monotonic",
762
+ "usb-device",
763
+ "void",
764
+]
765
+
766
+[[package]]
767
+name = "rtic-core"
768
+version = "0.3.1"
769
+source = "registry+https://github.com/rust-lang/crates.io-index"
770
+checksum = "8bd58a6949de8ff797a346a28d9f13f7b8f54fa61bb5e3cb0985a4efb497a5ef"
771
+
772
+[[package]]
773
+name = "rtic-monotonic"
774
+version = "0.1.0-alpha.2"
775
+source = "registry+https://github.com/rust-lang/crates.io-index"
776
+checksum = "9cbf2b6e30a7e6d184be839e0858745fa15ca1af81755c9edcb7b612676604b9"
777
+dependencies = [
778
+ "embedded-time",
779
+]
780
+
781
+[[package]]
782
+name = "rtic-syntax"
783
+version = "0.5.0-alpha.4"
784
+source = "registry+https://github.com/rust-lang/crates.io-index"
785
+checksum = "7676b45b31022d31d9db7efe19a0c0f554e68cf569df389a75664f7b6b7aa8ef"
786
+dependencies = [
787
+ "indexmap",
788
+ "proc-macro2",
789
+ "quote",
790
+ "syn",
791
+]
792
+
793
+[[package]]
794
+name = "rustc_version"
795
+version = "0.2.3"
796
+source = "registry+https://github.com/rust-lang/crates.io-index"
797
+checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
798
+dependencies = [
799
+ "semver",
800
+]
801
+
802
+[[package]]
803
+name = "rustversion"
804
+version = "1.0.5"
805
+source = "registry+https://github.com/rust-lang/crates.io-index"
806
+checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088"
807
+
808
+[[package]]
809
+name = "semver"
810
+version = "0.9.0"
811
+source = "registry+https://github.com/rust-lang/crates.io-index"
812
+checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
813
+dependencies = [
814
+ "semver-parser",
815
+]
816
+
817
+[[package]]
818
+name = "semver-parser"
819
+version = "0.7.0"
820
+source = "registry+https://github.com/rust-lang/crates.io-index"
821
+checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
822
+
823
+[[package]]
824
+name = "siphasher"
825
+version = "0.3.7"
826
+source = "registry+https://github.com/rust-lang/crates.io-index"
827
+checksum = "533494a8f9b724d33625ab53c6c4800f7cc445895924a8ef649222dcb76e938b"
828
+
829
+[[package]]
830
+name = "stable_deref_trait"
831
+version = "1.2.0"
832
+source = "registry+https://github.com/rust-lang/crates.io-index"
833
+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
834
+
835
+[[package]]
836
+name = "string_cache"
837
+version = "0.8.1"
838
+source = "registry+https://github.com/rust-lang/crates.io-index"
839
+checksum = "8ddb1139b5353f96e429e1a5e19fbaf663bddedaa06d1dbd49f82e352601209a"
840
+dependencies = [
841
+ "lazy_static",
842
+ "new_debug_unreachable",
843
+ "phf_shared",
844
+ "precomputed-hash",
845
+]
846
+
847
+[[package]]
848
+name = "syn"
849
+version = "1.0.77"
850
+source = "registry+https://github.com/rust-lang/crates.io-index"
851
+checksum = "5239bc68e0fef57495900cfea4e8dc75596d9a319d7e16b1e0a440d24e6fe0a0"
852
+dependencies = [
853
+ "proc-macro2",
854
+ "quote",
855
+ "unicode-xid",
856
+]
857
+
858
+[[package]]
859
+name = "systick-monotonic"
860
+version = "0.1.0-alpha.0"
861
+source = "registry+https://github.com/rust-lang/crates.io-index"
862
+checksum = "92e07a7e9fc4dfc670d76938ec06fe11098bb6bae775d452dca220c156a4ae50"
863
+dependencies = [
864
+ "cortex-m",
865
+ "rtic-monotonic",
866
+]
867
+
868
+[[package]]
869
+name = "term"
870
+version = "0.7.0"
871
+source = "registry+https://github.com/rust-lang/crates.io-index"
872
+checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f"
873
+dependencies = [
874
+ "dirs-next",
875
+ "rustversion",
876
+ "winapi",
877
+]
878
+
879
+[[package]]
880
+name = "termcolor"
881
+version = "1.1.2"
882
+source = "registry+https://github.com/rust-lang/crates.io-index"
883
+checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
884
+dependencies = [
885
+ "winapi-util",
886
+]
887
+
888
+[[package]]
889
+name = "tiny-keccak"
890
+version = "2.0.2"
891
+source = "registry+https://github.com/rust-lang/crates.io-index"
892
+checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
893
+dependencies = [
894
+ "crunchy",
895
+]
896
+
897
+[[package]]
898
+name = "typenum"
899
+version = "1.14.0"
900
+source = "registry+https://github.com/rust-lang/crates.io-index"
901
+checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec"
902
+
903
+[[package]]
904
+name = "unicode-width"
905
+version = "0.1.9"
906
+source = "registry+https://github.com/rust-lang/crates.io-index"
907
+checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
908
+
909
+[[package]]
910
+name = "unicode-xid"
911
+version = "0.2.2"
912
+source = "registry+https://github.com/rust-lang/crates.io-index"
913
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
914
+
915
+[[package]]
916
+name = "usb-device"
917
+version = "0.2.8"
918
+
919
+[[package]]
920
+name = "vcell"
921
+version = "0.1.3"
922
+source = "registry+https://github.com/rust-lang/crates.io-index"
923
+checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002"
924
+
925
+[[package]]
926
+name = "version_check"
927
+version = "0.9.3"
928
+source = "registry+https://github.com/rust-lang/crates.io-index"
929
+checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
930
+
931
+[[package]]
932
+name = "void"
933
+version = "1.0.2"
934
+source = "registry+https://github.com/rust-lang/crates.io-index"
935
+checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
936
+
937
+[[package]]
938
+name = "volatile-register"
939
+version = "0.2.1"
940
+source = "registry+https://github.com/rust-lang/crates.io-index"
941
+checksum = "9ee8f19f9d74293faf70901bc20ad067dc1ad390d2cbf1e3f75f721ffee908b6"
942
+dependencies = [
943
+ "vcell",
944
+]
945
+
946
+[[package]]
947
+name = "wasi"
948
+version = "0.10.2+wasi-snapshot-preview1"
949
+source = "registry+https://github.com/rust-lang/crates.io-index"
950
+checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
951
+
952
+[[package]]
953
+name = "winapi"
954
+version = "0.3.9"
955
+source = "registry+https://github.com/rust-lang/crates.io-index"
956
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
957
+dependencies = [
958
+ "winapi-i686-pc-windows-gnu",
959
+ "winapi-x86_64-pc-windows-gnu",
960
+]
961
+
962
+[[package]]
963
+name = "winapi-i686-pc-windows-gnu"
964
+version = "0.4.0"
965
+source = "registry+https://github.com/rust-lang/crates.io-index"
966
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
967
+
968
+[[package]]
969
+name = "winapi-util"
970
+version = "0.1.5"
971
+source = "registry+https://github.com/rust-lang/crates.io-index"
972
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
973
+dependencies = [
974
+ "winapi",
975
+]
976
+
977
+[[package]]
978
+name = "winapi-x86_64-pc-windows-gnu"
979
+version = "0.4.0"
980
+source = "registry+https://github.com/rust-lang/crates.io-index"
981
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

+ 28
- 0
Cargo.toml Dosyayı Görüntüle

@@ -0,0 +1,28 @@
1
+[package]
2
+name = "rp2040-usb-sound-card"
3
+version = "0.1.0"
4
+edition = "2018"
5
+resolver = "2"
6
+
7
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8
+
9
+[dependencies]
10
+cortex-m = "0.7.2"
11
+cortex-m-rt = "0.7"
12
+cortex-m-rtic = "0.6.0-alpha.5"
13
+embedded-hal ="0.2.5"
14
+embedded-time = "0.12.0"
15
+nb = "1.0"
16
+panic-halt = "0.2.0"
17
+pio = { path = "../pio-rs" }
18
+pio-proc = { path = "../pio-rs/pio-proc" }
19
+#rp2040-hal = { git = "https://github.com/rp-rs/rp-hal.git", features = ["rt"] }
20
+rp2040-hal = { path = "../rp-hal/rp2040-hal", features = ["rt"] }
21
+rp2040-boot2 = "0.1.2"
22
+stable_deref_trait = { version = "1.2.0", default-features = false }
23
+systick-monotonic = "0.1.0-alpha.0"
24
+usb-device= "0.2.8"
25
+void = { version = "*", default_features = false }
26
+
27
+[patch.crates-io]
28
+usb-device = { path = "../usb-device" }

+ 31
- 0
build.rs Dosyayı Görüntüle

@@ -0,0 +1,31 @@
1
+//! This build script copies the `memory.x` file from the crate root into
2
+//! a directory where the linker can always find it at build time.
3
+//! For many projects this is optional, as the linker always searches the
4
+//! project root directory -- wherever `Cargo.toml` is. However, if you
5
+//! are using a workspace or have a more complicated build setup, this
6
+//! build script becomes required. Additionally, by requesting that
7
+//! Cargo re-run the build script whenever `memory.x` is changed,
8
+//! updating `memory.x` ensures a rebuild of the application with the
9
+//! new memory settings.
10
+
11
+use std::env;
12
+use std::fs::File;
13
+use std::io::Write;
14
+use std::path::PathBuf;
15
+
16
+fn main() {
17
+    // Put `memory.x` in our output directory and ensure it's
18
+    // on the linker search path.
19
+    let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20
+    File::create(out.join("memory.x"))
21
+        .unwrap()
22
+        .write_all(include_bytes!("memory.x"))
23
+        .unwrap();
24
+    println!("cargo:rustc-link-search={}", out.display());
25
+
26
+    // By default, Cargo will re-run a build script whenever
27
+    // any file in the project changes. By specifying `memory.x`
28
+    // here, we ensure the build script is only re-run when
29
+    // `memory.x` is changed.
30
+    println!("cargo:rerun-if-changed=memory.x");
31
+}

+ 13
- 0
memory.x Dosyayı Görüntüle

@@ -0,0 +1,13 @@
1
+MEMORY {
2
+    BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
3
+    FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100
4
+    RAM   : ORIGIN = 0x20000000, LENGTH = 256K
5
+}
6
+
7
+SECTIONS {
8
+    /* ### Boot loader */
9
+    .boot2 ORIGIN(BOOT2) :
10
+    {
11
+        KEEP(*(.boot2));
12
+    } > BOOT2
13
+} INSERT BEFORE .text;

+ 205
- 0
src/audio_buffer.rs Dosyayı Görüntüle

@@ -0,0 +1,205 @@
1
+//! Audio buffer type to transfer audio data within different software/hardware components.
2
+#![warn(missing_docs)]
3
+
4
+use core::cell::{Cell, UnsafeCell};
5
+use core::ops::Deref;
6
+
7
+use cortex_m::interrupt::{CriticalSection, Mutex};
8
+use stable_deref_trait::StableDeref;
9
+
10
+/// Each packet contains 1 millisecond of audio data (48 samples at 48000kHz).
11
+///
12
+/// This translates two twice the number of values, as each sample contains two channels.
13
+pub const SAMPLES_PER_PACKET: usize = 48;
14
+/// Number of channels for all audio data.
15
+pub const CHANNELS: usize = 2;
16
+
17
+/// Buffer for a single packet with audio data.
18
+pub type Packet = [u32; SAMPLES_PER_PACKET * CHANNELS];
19
+
20
+/// Type for audio packet buffering.
21
+///
22
+/// The audio packets always contain two channels with 32-bit samples. The type contains a number
23
+/// of buffers each containing the same fixed number of samples.
24
+pub struct AudioBuffer<const PACKETS: usize> {
25
+    mutex: Mutex<AudioBufferInner<PACKETS>>,
26
+}
27
+
28
+struct AudioBufferInner<const PACKETS: usize> {
29
+    /// Packet contents.
30
+    packets: [UnsafeCell<Packet>; PACKETS],
31
+    /// Bitmask of packets which contain valid data and are not currently being read.
32
+    valid: Cell<u32>,
33
+    /// Bitmask of packets which do not contain valid data and which are not currently being
34
+    /// written.
35
+    invalid: Cell<u32>,
36
+    /// Bitmask of all packets which are currently borrowed via `borrow_read()`.
37
+    reading: Cell<u32>,
38
+    /// Bitmask of all packets which are currently borrowed via `borrow_write()`.
39
+    writing: Cell<u32>,
40
+}
41
+
42
+impl AudioBuffer<4> {
43
+    /// Creates a new audio buffer.
44
+    pub const fn new() -> Self {
45
+        const PACKETS: usize = 4;
46
+        // Initially, all packet contents are invalid and no packets are currently being read or
47
+        // written.
48
+        AudioBuffer {
49
+            mutex: Mutex::new(AudioBufferInner {
50
+                packets: [
51
+                    UnsafeCell::new([0; SAMPLES_PER_PACKET * CHANNELS]),
52
+                    UnsafeCell::new([0; SAMPLES_PER_PACKET * CHANNELS]),
53
+                    UnsafeCell::new([0; SAMPLES_PER_PACKET * CHANNELS]),
54
+                    UnsafeCell::new([0; SAMPLES_PER_PACKET * CHANNELS]),
55
+                ],
56
+                valid: Cell::new(0),
57
+                invalid: Cell::new(((1 << PACKETS) - 1) as u32),
58
+                reading: Cell::new(0),
59
+                writing: Cell::new(0),
60
+            }),
61
+        }
62
+    }
63
+}
64
+
65
+impl<const PACKETS: usize> AudioBuffer<PACKETS> {
66
+    /// Returns an interface to read packets from this buffer.
67
+    pub fn read(&'static self) -> ReadBuffer<PACKETS> {
68
+        ReadBuffer { buffer: self }
69
+    }
70
+
71
+    /// Returns an interface to write packets to this buffer.
72
+    pub fn write(&'static self) -> WriteBuffer<PACKETS> {
73
+        WriteBuffer { buffer: self }
74
+    }
75
+}
76
+
77
+/// Interface to read packets from a buffer.
78
+pub struct ReadBuffer<const PACKETS: usize> {
79
+    buffer: &'static AudioBuffer<PACKETS>,
80
+}
81
+
82
+impl<const PACKETS: usize> ReadBuffer<PACKETS> {
83
+    /// Returns whether there are any buffers with valid data ready for reading.
84
+    pub fn can_read(&self, cs: &CriticalSection) -> bool {
85
+        let inner = self.buffer.mutex.borrow(cs);
86
+        inner.valid.get() != 0
87
+    }
88
+
89
+    /// Borrows a single buffer for reading, returns `None` if no buffer with valid data is
90
+    /// available.
91
+    ///
92
+    /// The caller needs to return the buffer via `read_finished()` once the data has been
93
+    /// processed.
94
+    pub fn borrow_read(&self, cs: &CriticalSection) -> Option<ReadPacket<PACKETS>> {
95
+        let inner = self.buffer.mutex.borrow(cs);
96
+        let valid = inner.valid.get();
97
+        if valid == 0 {
98
+            return None;
99
+        }
100
+        let index = valid.trailing_zeros();
101
+        inner.valid.set(valid & !(1 << index));
102
+        inner.reading.set(inner.reading.get() | (1 << index));
103
+
104
+        let index = index as usize;
105
+        Some(ReadPacket {
106
+            buffer: self.buffer,
107
+            data: unsafe { &*inner.packets[index].get() },
108
+            index,
109
+        })
110
+    }
111
+
112
+    /// Returns a buffer that was allocated via `borrow_read()` and marks it as empty.
113
+    pub fn read_finished(&self, packet: ReadPacket<PACKETS>, cs: &CriticalSection) {
114
+        assert!((self.buffer as *const _) == (packet.buffer as *const _));
115
+        let inner = self.buffer.mutex.borrow(cs);
116
+        let index = packet.index;
117
+        inner.reading.set(inner.reading.get() & !(1 << index));
118
+        inner.invalid.set(inner.invalid.get() | (1 << index));
119
+    }
120
+}
121
+
122
+/// Interface to write packets to a buffer.
123
+pub struct WriteBuffer<const PACKETS: usize> {
124
+    buffer: &'static AudioBuffer<PACKETS>,
125
+}
126
+
127
+impl<const PACKETS: usize> WriteBuffer<PACKETS> {
128
+    /// Returns whether there are any empty buffers ready for writing.
129
+    pub fn can_write(&self, cs: &CriticalSection) -> bool {
130
+        let inner = self.buffer.mutex.borrow(cs);
131
+        inner.invalid.get() != 0
132
+    }
133
+
134
+    /// Borrows a single buffer for writing, returns `None` if no empty buffer is available.
135
+    ///
136
+    /// The caller needs to return the buffer via `write_finished()` once it was filled with data.
137
+    pub fn borrow_write(&self, cs: &CriticalSection) -> Option<WritePacket<PACKETS>> {
138
+        let inner = self.buffer.mutex.borrow(cs);
139
+        let invalid = inner.invalid.get();
140
+        if invalid == 0 {
141
+            return None;
142
+        }
143
+        let index = invalid.trailing_zeros();
144
+        inner.invalid.set(invalid & !(1 << index));
145
+        inner.writing.set(inner.writing.get() | (1 << index));
146
+
147
+        let index = index as usize;
148
+        Some(WritePacket {
149
+            buffer: self.buffer,
150
+            data: unsafe { &mut *inner.packets[index].get() },
151
+            index,
152
+        })
153
+    }
154
+
155
+    /// Returns a buffer that was allocated via `borrow_write()` and marks it as ready for reading.
156
+    pub fn write_finished(&self, packet: WritePacket<PACKETS>, cs: &CriticalSection) {
157
+        assert!((self.buffer as *const _) == (packet.buffer as *const _));
158
+        let inner = self.buffer.mutex.borrow(cs);
159
+        let index = packet.index;
160
+        inner.writing.set(inner.writing.get() & !(1 << index));
161
+        inner.valid.set(inner.valid.get() | (1 << index));
162
+    }
163
+}
164
+
165
+/// Packet buffer that has been borrowed for reading (i.e., the buffer contains valid data).
166
+pub struct ReadPacket<const PACKETS: usize> {
167
+    buffer: &'static AudioBuffer<PACKETS>,
168
+    data: &'static Packet,
169
+    index: usize,
170
+}
171
+
172
+impl<const PACKETS: usize> AsRef<[u32]> for ReadPacket<PACKETS> {
173
+    fn as_ref(&self) -> &[u32] {
174
+        self.data
175
+    }
176
+}
177
+
178
+impl<const PACKETS: usize> Deref for ReadPacket<PACKETS> {
179
+    type Target = Packet;
180
+
181
+    fn deref(&self) -> &Self::Target {
182
+        &self.data
183
+    }
184
+}
185
+
186
+unsafe impl<const PACKETS: usize> StableDeref for ReadPacket<PACKETS> {}
187
+
188
+/// Packet buffer that has been borrowed for writing (i.e., the buffer was previously empty).
189
+pub struct WritePacket<const PACKETS: usize> {
190
+    buffer: &'static AudioBuffer<PACKETS>,
191
+    data: &'static mut Packet,
192
+    index: usize,
193
+}
194
+
195
+impl<const PACKETS: usize> AsRef<[u32]> for WritePacket<PACKETS> {
196
+    fn as_ref(&self) -> &[u32] {
197
+        self.data
198
+    }
199
+}
200
+
201
+impl<const PACKETS: usize> AsMut<[u32]> for WritePacket<PACKETS> {
202
+    fn as_mut(&mut self) -> &mut [u32] {
203
+        self.data
204
+    }
205
+}

+ 121
- 0
src/i2s_master.rs Dosyayı Görüntüle

@@ -0,0 +1,121 @@
1
+use crate::audio_buffer::{ReadBuffer, ReadPacket};
2
+use core::marker::PhantomData;
3
+use cortex_m::interrupt;
4
+use rp2040_hal::dma::{Channel, ChannelIndex, SingleBuffering, SingleBufferingConfig};
5
+use rp2040_hal::gpio::bank0::{Gpio0, Gpio1, Gpio3, Gpio6};
6
+use rp2040_hal::gpio::{Function, Pin, Pio0};
7
+use rp2040_hal::pac::PIO0;
8
+use rp2040_hal::pio::{
9
+    PIOBuilder, PIOExt, StateMachineIndex, Tx, UninitStateMachine, ValidStateMachine, PIO,
10
+};
11
+
12
+pub trait PinConfig {
13
+    type PIO;
14
+
15
+    const OUT_MASK: u32;
16
+}
17
+
18
+impl PinConfig
19
+    for (
20
+        Pin<Gpio0, Function<Pio0>>,
21
+        Pin<Gpio1, Function<Pio0>>,
22
+        Pin<Gpio6, Function<Pio0>>,
23
+        Pin<Gpio3, Function<Pio0>>,
24
+    )
25
+{
26
+    type PIO = PIO0;
27
+
28
+    const OUT_MASK: u32 = 0x4b;
29
+}
30
+
31
+pub struct I2sMaster<SM: ValidStateMachine, DMACH: ChannelIndex, LRCLK, BCLK, SDO, SDI> {
32
+    tx: Option<SingleBuffering<Channel<DMACH>, ReadPacket<4>, Tx<SM>>>,
33
+    out_buffer: ReadBuffer<4>,
34
+    _phantom: PhantomData<(SM, LRCLK, BCLK, SDO, SDI)>,
35
+}
36
+
37
+impl<P: PIOExt, SM: StateMachineIndex, DMACH: ChannelIndex, LRCLK, BCLK, SDO, SDI>
38
+    I2sMaster<(P, SM), DMACH, LRCLK, BCLK, SDO, SDI>
39
+where
40
+    (LRCLK, BCLK, SDO, SDI): PinConfig,
41
+{
42
+    pub fn init(
43
+        pio: &mut PIO<P>,
44
+        sm: UninitStateMachine<(P, SM)>,
45
+        dma: Channel<DMACH>,
46
+        out_buffer: ReadBuffer<4>,
47
+        _lrclk: LRCLK,
48
+        _bclk: BCLK,
49
+        _sdo: SDO,
50
+        _sdi: SDI,
51
+    ) -> Self {
52
+        let program = pio_proc::pio!(
53
+            32,
54
+            "
55
+        .side_set 2
56
+
57
+        .wrap_target
58
+            pull noblock      side 0b11 [0]
59
+            set x, 14         side 0b11 [0]
60
+
61
+        leftloop:
62
+            out pins, 1       side 0b00 [6]
63
+            in pins, 1        side 0b01 [5]
64
+            jmp x-- leftloop  side 0b01 [0]
65
+
66
+            out pins, 1       side 0b00 [6]
67
+            in pins, 1        side 0b01 [5]
68
+            set x, 14         side 0b01 [0]
69
+        rightloop:
70
+            out pins, 1       side 0b10 [6]
71
+            in pins, 1        side 0b11 [5]
72
+            jmp x-- rightloop side 0b11 [0]
73
+
74
+            out pins, 1       side 0b10 [6]
75
+            in pins, 1        side 0b11 [3]
76
+            push noblock      side 0b11 [0]
77
+        .wrap
78
+                    "
79
+        );
80
+
81
+        let installed = pio.install(&program.program).unwrap();
82
+        let (mut sm, _rx, tx) = PIOBuilder::from_program(installed)
83
+            .side_set_pin_base(0)
84
+            //.set_pins(6, 1)
85
+            .out_pins(6, 1)
86
+            .in_pin_base(3)
87
+            .clock_divisor(4.0)
88
+            .build(sm);
89
+        sm.set_pindirs_with_mask(
90
+            <(LRCLK, BCLK, SDO, SDI)>::OUT_MASK,
91
+            <(LRCLK, BCLK, SDO, SDI)>::OUT_MASK,
92
+        );
93
+
94
+        // Start the first DMA transfer.
95
+        let packet = interrupt::free(|cs| out_buffer.borrow_read(cs).unwrap());
96
+        let tx = SingleBufferingConfig::new(dma, packet, tx).start();
97
+
98
+        // Start I2S.
99
+        // TODO: Synchronized start of multiple I2S instances?
100
+        sm.start();
101
+
102
+        I2sMaster {
103
+            tx: Some(tx),
104
+            out_buffer,
105
+            _phantom: PhantomData,
106
+        }
107
+    }
108
+
109
+    pub fn next_packet(&mut self) {
110
+        if !self.tx.as_mut().unwrap().check_irq0() {
111
+            return;
112
+        }
113
+
114
+        let (dma, prev_packet, tx) = self.tx.take().unwrap().wait();
115
+        let packet = interrupt::free(|cs| {
116
+            self.out_buffer.read_finished(prev_packet, cs);
117
+            self.out_buffer.borrow_read(cs).unwrap()
118
+        });
119
+        self.tx = Some(SingleBufferingConfig::new(dma, packet, tx).start());
120
+    }
121
+}

+ 231
- 0
src/main.rs Dosyayı Görüntüle

@@ -0,0 +1,231 @@
1
+#![no_std]
2
+#![no_main]
3
+
4
+use panic_halt as _;
5
+
6
+mod audio_buffer;
7
+mod i2s_master;
8
+mod usb;
9
+mod usb_audio;
10
+
11
+#[link_section = ".boot2"]
12
+#[used]
13
+pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER;
14
+
15
+#[rtic::app(device = rp2040_hal::pac, peripherals = true, dispatchers = [RTC_IRQ, XIP_IRQ])]
16
+mod app {
17
+    use embedded_hal::digital::v2::OutputPin;
18
+    use embedded_time::duration::Milliseconds;
19
+    use embedded_time::rate::{Extensions, Megahertz};
20
+    use rp2040_hal::clocks::ClocksManager;
21
+    use rp2040_hal::gpio;
22
+    //use rp2040_hal::pio::{PIOBuilder, PIOExt};
23
+    use crate::audio_buffer::AudioBuffer;
24
+    use crate::i2s_master::I2sMaster;
25
+    use crate::usb::Usb;
26
+    use cortex_m::interrupt;
27
+    use rp2040_hal::dma::{DMAExt, SingleChannel, CH0};
28
+    use rp2040_hal::gpio::bank0::{Gpio0, Gpio1, Gpio3, Gpio6};
29
+    use rp2040_hal::gpio::{Function, Pin, Pio0};
30
+    use rp2040_hal::pio::{PIOExt, PIO0SM0};
31
+    use rp2040_hal::pll::common_configs::PLL_USB_48MHZ;
32
+    use rp2040_hal::pll::{setup_pll_blocking, PLLConfig};
33
+    use rp2040_hal::sio::Sio;
34
+    use rp2040_hal::timer::Timer;
35
+    use rp2040_hal::usb::UsbBus;
36
+    use rp2040_hal::watchdog::Watchdog;
37
+    use rp2040_hal::xosc::setup_xosc_blocking;
38
+    use systick_monotonic::Systick;
39
+    use usb_device::class_prelude::*;
40
+
41
+    const XOSC_CRYSTAL_FREQ: u32 = 12_000_000;
42
+    pub const PLL_SYS_86MHZ: PLLConfig<Megahertz> = PLLConfig {
43
+        vco_freq: Megahertz(1032),
44
+        refdiv: 1,
45
+        post_div1: 6,
46
+        post_div2: 2,
47
+    };
48
+
49
+    static AUDIO_BUFFER: AudioBuffer<4> = AudioBuffer::new();
50
+
51
+    #[monotonic(binds = SysTick, default = true)]
52
+    type SystickMono = Systick<100>;
53
+
54
+    #[shared]
55
+    struct Shared {}
56
+
57
+    #[local]
58
+    struct Local {
59
+        led: gpio::Pin<gpio::pin::bank0::Gpio25, gpio::PushPullOutput>,
60
+        i2s: I2sMaster<
61
+            PIO0SM0,
62
+            CH0,
63
+            Pin<Gpio0, Function<Pio0>>,
64
+            Pin<Gpio1, Function<Pio0>>,
65
+            Pin<Gpio6, Function<Pio0>>,
66
+            Pin<Gpio3, Function<Pio0>>,
67
+        >,
68
+        usb: Usb,
69
+    }
70
+
71
+    #[init]
72
+    fn init(c: init::Context) -> (Shared, Local, init::Monotonics) {
73
+        let mut resets = c.device.RESETS;
74
+
75
+        // The timer needs a 1MHz input from the watchdog.
76
+        let mut watchdog = Watchdog::new(c.device.WATCHDOG);
77
+        watchdog.enable_tick_generation((XOSC_CRYSTAL_FREQ / 1000000) as u8);
78
+
79
+        // We let an LED blink to show that the system is still alive.
80
+        let sio = Sio::new(c.device.SIO);
81
+        let pins = gpio::Pins::new(
82
+            c.device.IO_BANK0,
83
+            c.device.PADS_BANK0,
84
+            sio.gpio_bank0,
85
+            &mut resets,
86
+        );
87
+
88
+        // We select a 86 MHz system clock as that lets us generate a clean and precise 12.288 MHz
89
+        // master clock by dividing the system clock by 7.
90
+        // TODO: Select 123 MHz instead (0.1% deviation, whereas 86 MHz results in 0.02%
91
+        // deviation), or look for an even better frequency that is not a multiple of 1MHz.
92
+        let mut clocks = ClocksManager::new(c.device.CLOCKS);
93
+        let xosc = setup_xosc_blocking(c.device.XOSC, XOSC_CRYSTAL_FREQ.Hz())
94
+            .ok()
95
+            .unwrap();
96
+        let pll_sys = setup_pll_blocking(
97
+            c.device.PLL_SYS,
98
+            xosc.operating_frequency().into(),
99
+            PLL_SYS_86MHZ,
100
+            &mut clocks,
101
+            &mut resets,
102
+        )
103
+        .ok()
104
+        .unwrap();
105
+        let pll_usb = setup_pll_blocking(
106
+            c.device.PLL_USB,
107
+            xosc.operating_frequency().into(),
108
+            PLL_USB_48MHZ,
109
+            &mut clocks,
110
+            &mut resets,
111
+        )
112
+        .ok()
113
+        .unwrap();
114
+        let _clocks = clocks.init_default(&xosc, &pll_sys, &pll_usb).ok().unwrap();
115
+
116
+        let mut led = pins.gpio25.into_push_pull_output();
117
+        led.set_low().ok().unwrap();
118
+
119
+        // We need a timer so that we can determine the USB SOF frequency for asynchronous USB
120
+        // audio.
121
+        let timer = Timer::new(c.device.TIMER, &mut resets);
122
+
123
+        // We initialize the output audio buffers with some data. As the I2S input buffers are
124
+        // filled at the same rate as the I2S output buffers, this initial state ensures that the
125
+        // output buffers never run empty (note that the USB audio interface performs its own
126
+        // adaptive synchronization).
127
+        interrupt::free(|cs| {
128
+            let write = AUDIO_BUFFER.write();
129
+            for _ in 0..2 {
130
+                let mut packet = write.borrow_write(cs).unwrap();
131
+                let data = packet.as_mut();
132
+                for i in 0..data.len() {
133
+                    //data[i] = 0x80000000; // "0"
134
+                    data[i] = 0xa5a5aa55;
135
+                }
136
+                write.write_finished(packet, cs);
137
+            }
138
+        });
139
+
140
+        // Configure USB audio.
141
+        static mut USB_BUS: Option<UsbBusAllocator<UsbBus>> = None;
142
+        unsafe {
143
+            USB_BUS = Some(UsbBusAllocator::new(UsbBus::new(
144
+                c.device.USBCTRL_REGS,
145
+                c.device.USBCTRL_DPRAM,
146
+                clocks.usb_clock,
147
+                true,
148
+                &mut resets,
149
+            )))
150
+        };
151
+
152
+        let usb = Usb::init(
153
+            unsafe { USB_BUS.as_ref().unwrap() },
154
+            AUDIO_BUFFER.write(),
155
+            timer,
156
+        );
157
+
158
+        // Configure the PIO unit and start I2S.
159
+        let mut dma = c.device.DMA.split(&mut resets);
160
+        let (mut pio, sm0, _sm1, _sm2, _sm3) = c.device.PIO0.split(&mut resets);
161
+        dma.ch0.listen_irq0();
162
+        let i2s = I2sMaster::init(
163
+            &mut pio,
164
+            sm0,
165
+            dma.ch0,
166
+            AUDIO_BUFFER.read(),
167
+            pins.gpio0.into_mode(),
168
+            pins.gpio1.into_mode(),
169
+            pins.gpio6.into_mode(),
170
+            pins.gpio3.into_mode(),
171
+        );
172
+
173
+        // A speaker amplifier (TAS5760) is connected to I2S - we need to configure it via I2C.
174
+        // TODO
175
+        // TODO: I2C stuff should happen in a low-priority task as we do not want to make data
176
+        // streaming to I2S wait.
177
+
178
+        let systick = c.core.SYST;
179
+        let mono = Systick::new(systick, 86_000_000);
180
+        blink::spawn().ok().unwrap();
181
+        (Shared {}, Local { led, i2s, usb }, init::Monotonics(mono))
182
+    }
183
+
184
+    #[task(shared = [], local = [led, state: bool = false])]
185
+    fn blink(ctx: blink::Context) {
186
+        blink::spawn_after(Milliseconds(500_u32)).ok().unwrap();
187
+        *ctx.local.state = !*ctx.local.state;
188
+        if *ctx.local.state {
189
+            ctx.local.led.set_high().ok().unwrap();
190
+        } else {
191
+            ctx.local.led.set_low().ok().unwrap();
192
+        }
193
+    }
194
+
195
+    /// DMA interrupt handler.
196
+    ///
197
+    /// DMA interrupts need to have highest priority as we need to quickly restart the DMA transfer
198
+    /// to ensure that the PIO FIFO always contains data.
199
+    #[task(binds = DMA_IRQ_0, priority = 3, local = [i2s])]
200
+    fn dma(ctx: dma::Context) {
201
+        ctx.local.i2s.next_packet();
202
+        process_buffers::spawn().unwrap();
203
+    }
204
+
205
+    #[task]
206
+    fn process_buffers(_: process_buffers::Context) {
207
+        interrupt::free(|cs| {
208
+            // If we have run out of data from USB, insert a packet filled with zeros.
209
+            // TODO
210
+
211
+            let write = AUDIO_BUFFER.write();
212
+            let mut packet = write.borrow_write(cs).unwrap();
213
+            let data = packet.as_mut();
214
+            for i in 0..data.len() {
215
+                //data[i] = 0x80000000; // "0"
216
+                data[i] = 0xa5a5aa55;
217
+            }
218
+            write.write_finished(packet, cs);
219
+        });
220
+    }
221
+
222
+    /// USB interrupt handler.
223
+    ///
224
+    /// USB interrupts have a high priority (albeit not as high as DMA) so that we can precisely
225
+    /// measure the SOF frequency relative to our system clock. The frequency ratio is required for
226
+    /// asynchronous USB audio.
227
+    #[task(binds = USBCTRL_IRQ, priority = 2, local = [usb])]
228
+    fn usb(ctx: usb::Context) {
229
+        ctx.local.usb.poll();
230
+    }
231
+}

+ 54
- 0
src/usb.rs Dosyayı Görüntüle

@@ -0,0 +1,54 @@
1
+use crate::audio_buffer::WriteBuffer;
2
+use crate::usb_audio::UsbAudioClass;
3
+use rp2040_hal::pac::USBCTRL_REGS;
4
+use rp2040_hal::timer::Timer;
5
+use rp2040_hal::usb::UsbBus;
6
+use usb_device::{class_prelude::*, prelude::*};
7
+
8
+pub struct Usb {
9
+    usb_audio: UsbAudioClass<'static, UsbBus>,
10
+    usb_dev: UsbDevice<'static, UsbBus>,
11
+    in_buffer: WriteBuffer<4>,
12
+}
13
+
14
+impl Usb {
15
+    pub fn init(
16
+        bus: &'static UsbBusAllocator<UsbBus>,
17
+        in_buffer: WriteBuffer<4>,
18
+        timer: Timer,
19
+    ) -> Usb {
20
+        let usb_audio = UsbAudioClass::new(bus, 64);
21
+
22
+        // This PID/VID combination is selected from the pid.codes PID space and only intended for
23
+        // software development. It is not universally unique and should not be used outside of
24
+        // test environments!
25
+        let usb_dev = UsbDeviceBuilder::new(bus, UsbVidPid(0x1209, 0x000d))
26
+            .manufacturer("TEST")
27
+            .product("USB audio test")
28
+            .serial_number("TEST")
29
+            .build();
30
+
31
+        // TODO
32
+        Usb {
33
+            usb_audio,
34
+            usb_dev,
35
+            in_buffer,
36
+        }
37
+    }
38
+
39
+    pub fn poll(&mut self) {
40
+        // Safety: The read access does not have any side effect, and this function is the only one
41
+        // using the USB peripheral at this time.
42
+        let sof = unsafe { (&*USBCTRL_REGS::ptr()).intr.read().dev_sof().bit_is_set() };
43
+        if sof {
44
+            let mut buffer = [0u8; 64];
45
+            for i in 0..64 {
46
+                buffer[i] = i as u8 * 4;
47
+            }
48
+            let _err = self.usb_audio.write_packet(&buffer);
49
+        }
50
+        if self.usb_dev.poll(&mut [&mut self.usb_audio]) {
51
+            // TODO
52
+        }
53
+    }
54
+}

+ 290
- 0
src/usb_audio.rs Dosyayı Görüntüle

@@ -0,0 +1,290 @@
1
+//! USB audio class for asynchronous, bidirectional (microphone + speakers) 48kHz audio.
2
+//!
3
+//! See "Universal Serial Bus Device Class Definition for Audio Devices", release 1.0 (March 18,
4
+//! 1998) for a specification of the USB audio class.
5
+use usb_device::class_prelude::*;
6
+
7
+pub struct UsbAudioClass<'a, BUS: UsbBus> {
8
+    audio_control: InterfaceNumber,
9
+    audio_streaming: InterfaceNumber,
10
+    audio_streaming: InterfaceNumber,
11
+    // TODO
12
+}
13
+
14
+/*use usb_device::class_prelude::*;
15
+use usb_device::endpoint::{IsochronousSynchronizationType, IsochronousUsageType};
16
+use usb_device::Result;
17
+
18
+/// This should be used as `device_class` when building the `UsbDevice`.
19
+pub const USB_INTERFACE_CLASS_AUDIO: u8 = 0x01;
20
+
21
+const USB_AUDIO_SUBCLASS_UNDEFINED: u8 = 0x0;
22
+const USB_AUDIO_SUBCLASS_AUDIOCONTROL: u8 = 0x01;
23
+const USB_AUDIO_SUBCLASS_AUDIOSTREAMING: u8 = 0x02;
24
+const USB_AUDIO_SUBCLASS_MIDISTREAMING: u8 = 0x03;
25
+
26
+const USB_CLASS_CDC_DATA: u8 = 0x0a;
27
+const CDC_SUBCLASS_ACM: u8 = 0x02;
28
+const USB_AUDIO_PROTOCOL_NONE: u8 = 0x00;
29
+
30
+const CS_DEVICE: u8 = 0x21;
31
+const CS_CONFIGURATION: u8 = 0x22;
32
+const CS_STRING: u8 = 0x23;
33
+const CS_INTERFACE: u8 = 0x24;
34
+const CS_ENDPOINT: u8 = 0x25;
35
+
36
+const EP_GENERAL: u8 = 0x1;
37
+
38
+const AC_DESC_TYPE_HEADER: u8 = 0x1;
39
+const AC_DESC_TYPE_INPUT_TERMINAL: u8 = 0x2;
40
+const AC_DESC_TYPE_OUTPUT_TERMINAL: u8 = 0x3;
41
+const AC_DESC_TYPE_MIXER_UNIT: u8 = 0x4;
42
+const AC_DESC_TYPE_SELECTOR_UNIT: u8 = 0x5;
43
+const AC_DESC_TYPE_FEATURE_UNIT: u8 = 0x6;
44
+const AC_DESC_TYPE_PROCESSING_UNIT: u8 = 0x7;
45
+const AC_DESC_TYPE_EXTENSION_UNIT: u8 = 0x8;
46
+
47
+const AC_DESC_ST_GENERAL: u8 = 0x1;
48
+const AC_DESC_ST_FORMAT_TYPE: u8 = 0x2;
49
+const AC_DESC_ST_FORMAT_SPECIFIC: u8 = 0x3;
50
+
51
+const AUDIO_SUB_TYPE_HEADER: u8 = 0x01;
52
+const AUDIO_SUB_TYPE_INPUT_TERMINAL: u8 = 0x02;
53
+const AUDIO_SUB_TYPE_FEATURE_UNIT: u8 = 0x06;
54
+const AUDIO_SUB_TYPE_OUTPUT_TERMINAL: u8 = 0x03;
55
+const AUDIO_SUB_TYPE_AS_GENERAL: u8 = 0x01;
56
+const AUDIO_SUB_TYPE_FORMAT_TYPE: u8 = 0x02;
57
+
58
+pub struct UsbAudioClass<'a, B: UsbBus> {
59
+    audio_control_if: InterfaceNumber,
60
+    audio_stream: InterfaceNumber,
61
+    alt_audio_stream: InterfaceNumber,
62
+    audio_in_ep: EndpointIn<'a, B>,
63
+}
64
+
65
+impl<B: UsbBus> UsbAudioClass<'_, B> {
66
+    /// Creates a new UsbAudioClass with the provided UsbBus and max_packet_size in bytes. For
67
+    /// full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64.
68
+    pub fn new(alloc: &UsbBusAllocator<B>, max_packet_size: u16) -> UsbAudioClass<'_, B> {
69
+        UsbAudioClass {
70
+            audio_control_if: alloc.interface(),
71
+            audio_stream: alloc.interface(),
72
+            alt_audio_stream: alloc.interface(),
73
+            audio_in_ep: alloc.isochronous(
74
+                IsochronousSynchronizationType::Synchronous,
75
+                IsochronousUsageType::Data,
76
+                max_packet_size,
77
+                4,
78
+            ),
79
+        }
80
+    }
81
+
82
+    /// Gets the maximum packet size in bytes.
83
+    pub fn max_packet_size(&self) -> u16 {
84
+        self.audio_in_ep.max_packet_size()
85
+    }
86
+
87
+    /// Writes a single packet into the IN endpoint.
88
+    pub fn write_packet(&mut self, data: &[u8]) -> Result<usize> {
89
+        //defmt::info!("write_packet");
90
+        self.audio_in_ep.write(data)
91
+    }
92
+
93
+    /// Gets the address of the IN endpoint.
94
+    pub(crate) fn write_ep_address(&self) -> EndpointAddress {
95
+        self.audio_in_ep.address()
96
+    }
97
+}
98
+
99
+impl<B: UsbBus> UsbClass<B> for UsbAudioClass<'_, B> {
100
+    fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> {
101
+        writer.iad(
102
+            self.audio_control_if,
103
+            3,
104
+            0x0, // device defined at interface level
105
+            0x0, // subclass unused
106
+            USB_AUDIO_PROTOCOL_NONE,
107
+        )?;
108
+
109
+        writer.interface(
110
+            self.audio_control_if,
111
+            USB_INTERFACE_CLASS_AUDIO,
112
+            USB_AUDIO_SUBCLASS_AUDIOCONTROL,
113
+            USB_AUDIO_PROTOCOL_NONE,
114
+        )?;
115
+
116
+        writer.write(
117
+            CS_INTERFACE,
118
+            &[
119
+                AUDIO_SUB_TYPE_HEADER, // bDescriptorSubtype
120
+                0x00,
121
+                0x1, // bcdADC (1.0),
122
+                43,
123
+                0,    // wTotalLength (Compute this!)
124
+                0x01, // bInCollection (1 streaming interface)
125
+                0x01, // baInterfaceNr (Interface 1 is stream)
126
+            ],
127
+        )?;
128
+
129
+        writer.write(
130
+            CS_INTERFACE,
131
+            &[
132
+                AUDIO_SUB_TYPE_INPUT_TERMINAL, // bDescriptorSubtype
133
+                0x01,                          // bTerminalID 1,
134
+                0x10,
135
+                0x07, // wTerminalType (radio receiver)
136
+                0x00, // bAssocTerminal (none)
137
+                0x02, // bNrChannels - 2 for I and Q
138
+                0x03,
139
+                0x00, // wChannelConfig (left, right)
140
+                0x00, // iChannelNames (none)
141
+                0x00, // iTerminal (none)
142
+            ],
143
+        )?;
144
+
145
+        writer.write(
146
+            CS_INTERFACE,
147
+            &[
148
+                AUDIO_SUB_TYPE_FEATURE_UNIT, // bDescriptorSubtype
149
+                0x02,                        // bUnitID,
150
+                0x01,                        // bSourceID (input terminal 1)
151
+                0x02,                        // bControlSize (2 bytes)
152
+                0x01,
153
+                0x00, // Master controls
154
+                0x00,
155
+                0x00, // Channel 0 controls
156
+                0x00,
157
+                0x00, // Channel 1 controls
158
+                0x00, // iFeature (none)
159
+            ],
160
+        )?;
161
+
162
+        writer.write(
163
+            CS_INTERFACE,
164
+            &[
165
+                AUDIO_SUB_TYPE_OUTPUT_TERMINAL, // bDescriptorSubtype
166
+                0x03,                           // bTerminalID,
167
+                0x01,
168
+                0x01, // wTerminalType (USB Streaming)
169
+                0x00, // bAssocTerminal (none)
170
+                0x02, // bSourceID (feature unit 2)
171
+                0x00, // iTerminal (none)
172
+            ],
173
+        )?;
174
+
175
+        writer.interface(
176
+            self.audio_stream,
177
+            USB_INTERFACE_CLASS_AUDIO,
178
+            USB_AUDIO_SUBCLASS_AUDIOSTREAMING,
179
+            USB_AUDIO_PROTOCOL_NONE,
180
+        )?;
181
+
182
+        //alternate audio stream
183
+        /*writer.interface_alt(
184
+            self.alt_audio_stream,
185
+            1,
186
+            USB_INTERFACE_CLASS_AUDIO,
187
+            USB_AUDIO_SUBCLASS_AUDIOSTREAMING,
188
+            USB_AUDIO_PROTOCOL_NONE,
189
+            None,
190
+        )?;*/
191
+
192
+        // Audio Stream Audio Class Descriptor
193
+        writer.write(
194
+            CS_INTERFACE,
195
+            &[
196
+                AUDIO_SUB_TYPE_AS_GENERAL, // bDescriptorSubtype
197
+                0x03,                      // bTerminalID,
198
+                0x00,                      // bDelay
199
+                0x01,
200
+                0x00, // wFormatTag (PCM Format)
201
+            ],
202
+        )?;
203
+
204
+        // Format Type Audio Descriptor
205
+        writer.write(
206
+            CS_INTERFACE,
207
+            &[
208
+                AUDIO_SUB_TYPE_FORMAT_TYPE, // bDescriptorSubtype
209
+                0x01,                       // bFormatType (TYPE_I)
210
+                0x02,                       // bNrChannels (2)
211
+                0x02,                       // bSubFrameSize (2)
212
+                0x10,                       // bBitResolution (16 bits)
213
+                0x01,                       // bSamFreqType (1 sample frequency)
214
+                0x80,                       // 8*2 = 16 KHz byte 0
215
+                0x3E,                       // 8*2 = 16 KHz byte 1
216
+                0x00,                       // 8*2 = 16 KHz byte 2
217
+            ],
218
+        )?;
219
+
220
+        // TODO: Set the necessary flags for Isochronous
221
+        writer.endpoint(&self.audio_in_ep)?;
222
+
223
+        // Isochronous endpoint Audio Class descriptor
224
+        writer.write(
225
+            CS_ENDPOINT,
226
+            &[
227
+                EP_GENERAL, // bDescriptorSubtype
228
+                0x00,       // bmAttributes (none)
229
+                0x02,       // bLockDelayUnits (PCM Samples)
230
+                0x00, 0x00, // wLockDelay (0)  - should be zero for asynchronous
231
+            ],
232
+        )?;
233
+        Ok(())
234
+    }
235
+
236
+    fn reset(&mut self) {}
237
+
238
+    fn control_in(&mut self, xfer: ControlIn<B>) {
239
+        let req = xfer.request();
240
+
241
+        if !(req.request_type == control::RequestType::Class
242
+            && req.recipient == control::Recipient::Interface
243
+            && req.index == u8::from(self.audio_control_if) as u16)
244
+        {
245
+            return;
246
+        }
247
+
248
+        //defmt::info!("control_in - req : {:?}", req.request);
249
+        match req.request {
250
+            /*
251
+            REQ_GET_LINE_CODING if req.length == 7 => {
252
+                xfer.accept(|data| {
253
+                    data[0..4].copy_from_slice(&self.line_coding.data_rate.to_le_bytes());
254
+                    data[4] = self.line_coding.stop_bits as u8;
255
+                    data[5] = self.line_coding.parity_type as u8;
256
+                    data[6] = self.line_coding.data_bits;
257
+
258
+                    Ok(7)
259
+                }).ok();
260
+            },
261
+            */
262
+            _ => {
263
+                xfer.reject().ok();
264
+            }
265
+        }
266
+    }
267
+
268
+    fn control_out(&mut self, xfer: ControlOut<B>) {
269
+        let req = xfer.request();
270
+
271
+        if !(req.request_type == control::RequestType::Class
272
+            && req.recipient == control::Recipient::Interface
273
+            && req.index == u8::from(self.audio_control_if) as u16)
274
+        {
275
+            return;
276
+        }
277
+
278
+        match req.request {
279
+            /*
280
+            REQ_SEND_ENCAPSULATED_COMMAND => {
281
+                // We don't actually support encapsulated commands but pretend we do for standards
282
+                // compatibility.
283
+                xfer.accept().ok();
284
+            },*/
285
+            _ => {
286
+                xfer.reject().ok();
287
+            }
288
+        };
289
+    }
290
+}*/

Loading…
İptal
Kaydet