Mathias Gottschlag hace 4 años
commit
c0b41b7242
Se han modificado 11 ficheros con 2258 adiciones y 0 borrados
  1. 12
    0
      .cargo/config
  2. 2
    0
      .gitignore
  3. 984
    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. 63
    0
      src/usb.rs
  11. 568
    0
      src/usb_audio.rs

+ 12
- 0
.cargo/config Ver fichero

@@ -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 Ver fichero

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

+ 984
- 0
Cargo.lock Ver fichero

@@ -0,0 +1,984 @@
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
+source = "git+https://github.com/rp-rs/pio-rs.git?branch=main#8c12d426685ac23cac975341e728fc0a50ebfd6c"
590
+dependencies = [
591
+ "arrayvec",
592
+ "num_enum",
593
+ "paste",
594
+]
595
+
596
+[[package]]
597
+name = "pio-parser"
598
+version = "0.1.0"
599
+source = "git+https://github.com/rp-rs/pio-rs.git?branch=main#8c12d426685ac23cac975341e728fc0a50ebfd6c"
600
+dependencies = [
601
+ "lalrpop",
602
+ "lalrpop-util",
603
+ "pio",
604
+]
605
+
606
+[[package]]
607
+name = "pio-proc"
608
+version = "0.1.0"
609
+source = "git+https://github.com/rp-rs/pio-rs.git?branch=main#8c12d426685ac23cac975341e728fc0a50ebfd6c"
610
+dependencies = [
611
+ "codespan-reporting",
612
+ "lalrpop-util",
613
+ "pio",
614
+ "pio-parser",
615
+ "proc-macro2",
616
+ "quote",
617
+ "syn",
618
+]
619
+
620
+[[package]]
621
+name = "precomputed-hash"
622
+version = "0.1.1"
623
+source = "registry+https://github.com/rust-lang/crates.io-index"
624
+checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
625
+
626
+[[package]]
627
+name = "proc-macro-error"
628
+version = "1.0.4"
629
+source = "registry+https://github.com/rust-lang/crates.io-index"
630
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
631
+dependencies = [
632
+ "proc-macro-error-attr",
633
+ "proc-macro2",
634
+ "quote",
635
+ "syn",
636
+ "version_check",
637
+]
638
+
639
+[[package]]
640
+name = "proc-macro-error-attr"
641
+version = "1.0.4"
642
+source = "registry+https://github.com/rust-lang/crates.io-index"
643
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
644
+dependencies = [
645
+ "proc-macro2",
646
+ "quote",
647
+ "version_check",
648
+]
649
+
650
+[[package]]
651
+name = "proc-macro2"
652
+version = "1.0.29"
653
+source = "registry+https://github.com/rust-lang/crates.io-index"
654
+checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d"
655
+dependencies = [
656
+ "unicode-xid",
657
+]
658
+
659
+[[package]]
660
+name = "quote"
661
+version = "1.0.9"
662
+source = "registry+https://github.com/rust-lang/crates.io-index"
663
+checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
664
+dependencies = [
665
+ "proc-macro2",
666
+]
667
+
668
+[[package]]
669
+name = "rand_core"
670
+version = "0.6.3"
671
+source = "registry+https://github.com/rust-lang/crates.io-index"
672
+checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
673
+
674
+[[package]]
675
+name = "redox_syscall"
676
+version = "0.2.10"
677
+source = "registry+https://github.com/rust-lang/crates.io-index"
678
+checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
679
+dependencies = [
680
+ "bitflags",
681
+]
682
+
683
+[[package]]
684
+name = "redox_users"
685
+version = "0.4.0"
686
+source = "registry+https://github.com/rust-lang/crates.io-index"
687
+checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
688
+dependencies = [
689
+ "getrandom",
690
+ "redox_syscall",
691
+]
692
+
693
+[[package]]
694
+name = "regex"
695
+version = "1.5.4"
696
+source = "registry+https://github.com/rust-lang/crates.io-index"
697
+checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
698
+dependencies = [
699
+ "aho-corasick",
700
+ "memchr",
701
+ "regex-syntax",
702
+]
703
+
704
+[[package]]
705
+name = "regex-syntax"
706
+version = "0.6.25"
707
+source = "registry+https://github.com/rust-lang/crates.io-index"
708
+checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
709
+
710
+[[package]]
711
+name = "rp2040-boot2"
712
+version = "0.1.2"
713
+source = "registry+https://github.com/rust-lang/crates.io-index"
714
+checksum = "233203dcc51018ec08df8462fc84c0170aa4b4220bbcbe56901bc637ba98604a"
715
+dependencies = [
716
+ "crc-any",
717
+]
718
+
719
+[[package]]
720
+name = "rp2040-hal"
721
+version = "0.3.0"
722
+dependencies = [
723
+ "cortex-m",
724
+ "embedded-dma",
725
+ "embedded-hal",
726
+ "embedded-time",
727
+ "itertools",
728
+ "nb 1.0.0",
729
+ "paste",
730
+ "pio",
731
+ "pio-proc",
732
+ "rand_core",
733
+ "rp2040-pac",
734
+ "usb-device",
735
+ "vcell",
736
+ "void",
737
+]
738
+
739
+[[package]]
740
+name = "rp2040-pac"
741
+version = "0.1.5"
742
+dependencies = [
743
+ "cortex-m",
744
+ "cortex-m-rt",
745
+ "vcell",
746
+]
747
+
748
+[[package]]
749
+name = "rp2040-usb-sound-card"
750
+version = "0.1.0"
751
+dependencies = [
752
+ "cortex-m",
753
+ "cortex-m-rt",
754
+ "cortex-m-rtic",
755
+ "embedded-hal",
756
+ "embedded-time",
757
+ "nb 1.0.0",
758
+ "panic-halt",
759
+ "pio",
760
+ "pio-proc",
761
+ "rp2040-boot2",
762
+ "rp2040-hal",
763
+ "stable_deref_trait",
764
+ "systick-monotonic",
765
+ "usb-device",
766
+ "void",
767
+]
768
+
769
+[[package]]
770
+name = "rtic-core"
771
+version = "0.3.1"
772
+source = "registry+https://github.com/rust-lang/crates.io-index"
773
+checksum = "8bd58a6949de8ff797a346a28d9f13f7b8f54fa61bb5e3cb0985a4efb497a5ef"
774
+
775
+[[package]]
776
+name = "rtic-monotonic"
777
+version = "0.1.0-alpha.2"
778
+source = "registry+https://github.com/rust-lang/crates.io-index"
779
+checksum = "9cbf2b6e30a7e6d184be839e0858745fa15ca1af81755c9edcb7b612676604b9"
780
+dependencies = [
781
+ "embedded-time",
782
+]
783
+
784
+[[package]]
785
+name = "rtic-syntax"
786
+version = "0.5.0-alpha.4"
787
+source = "registry+https://github.com/rust-lang/crates.io-index"
788
+checksum = "7676b45b31022d31d9db7efe19a0c0f554e68cf569df389a75664f7b6b7aa8ef"
789
+dependencies = [
790
+ "indexmap",
791
+ "proc-macro2",
792
+ "quote",
793
+ "syn",
794
+]
795
+
796
+[[package]]
797
+name = "rustc_version"
798
+version = "0.2.3"
799
+source = "registry+https://github.com/rust-lang/crates.io-index"
800
+checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
801
+dependencies = [
802
+ "semver",
803
+]
804
+
805
+[[package]]
806
+name = "rustversion"
807
+version = "1.0.5"
808
+source = "registry+https://github.com/rust-lang/crates.io-index"
809
+checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088"
810
+
811
+[[package]]
812
+name = "semver"
813
+version = "0.9.0"
814
+source = "registry+https://github.com/rust-lang/crates.io-index"
815
+checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
816
+dependencies = [
817
+ "semver-parser",
818
+]
819
+
820
+[[package]]
821
+name = "semver-parser"
822
+version = "0.7.0"
823
+source = "registry+https://github.com/rust-lang/crates.io-index"
824
+checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
825
+
826
+[[package]]
827
+name = "siphasher"
828
+version = "0.3.7"
829
+source = "registry+https://github.com/rust-lang/crates.io-index"
830
+checksum = "533494a8f9b724d33625ab53c6c4800f7cc445895924a8ef649222dcb76e938b"
831
+
832
+[[package]]
833
+name = "stable_deref_trait"
834
+version = "1.2.0"
835
+source = "registry+https://github.com/rust-lang/crates.io-index"
836
+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
837
+
838
+[[package]]
839
+name = "string_cache"
840
+version = "0.8.1"
841
+source = "registry+https://github.com/rust-lang/crates.io-index"
842
+checksum = "8ddb1139b5353f96e429e1a5e19fbaf663bddedaa06d1dbd49f82e352601209a"
843
+dependencies = [
844
+ "lazy_static",
845
+ "new_debug_unreachable",
846
+ "phf_shared",
847
+ "precomputed-hash",
848
+]
849
+
850
+[[package]]
851
+name = "syn"
852
+version = "1.0.77"
853
+source = "registry+https://github.com/rust-lang/crates.io-index"
854
+checksum = "5239bc68e0fef57495900cfea4e8dc75596d9a319d7e16b1e0a440d24e6fe0a0"
855
+dependencies = [
856
+ "proc-macro2",
857
+ "quote",
858
+ "unicode-xid",
859
+]
860
+
861
+[[package]]
862
+name = "systick-monotonic"
863
+version = "0.1.0-alpha.0"
864
+source = "registry+https://github.com/rust-lang/crates.io-index"
865
+checksum = "92e07a7e9fc4dfc670d76938ec06fe11098bb6bae775d452dca220c156a4ae50"
866
+dependencies = [
867
+ "cortex-m",
868
+ "rtic-monotonic",
869
+]
870
+
871
+[[package]]
872
+name = "term"
873
+version = "0.7.0"
874
+source = "registry+https://github.com/rust-lang/crates.io-index"
875
+checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f"
876
+dependencies = [
877
+ "dirs-next",
878
+ "rustversion",
879
+ "winapi",
880
+]
881
+
882
+[[package]]
883
+name = "termcolor"
884
+version = "1.1.2"
885
+source = "registry+https://github.com/rust-lang/crates.io-index"
886
+checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
887
+dependencies = [
888
+ "winapi-util",
889
+]
890
+
891
+[[package]]
892
+name = "tiny-keccak"
893
+version = "2.0.2"
894
+source = "registry+https://github.com/rust-lang/crates.io-index"
895
+checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
896
+dependencies = [
897
+ "crunchy",
898
+]
899
+
900
+[[package]]
901
+name = "typenum"
902
+version = "1.14.0"
903
+source = "registry+https://github.com/rust-lang/crates.io-index"
904
+checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec"
905
+
906
+[[package]]
907
+name = "unicode-width"
908
+version = "0.1.9"
909
+source = "registry+https://github.com/rust-lang/crates.io-index"
910
+checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
911
+
912
+[[package]]
913
+name = "unicode-xid"
914
+version = "0.2.2"
915
+source = "registry+https://github.com/rust-lang/crates.io-index"
916
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
917
+
918
+[[package]]
919
+name = "usb-device"
920
+version = "0.2.8"
921
+
922
+[[package]]
923
+name = "vcell"
924
+version = "0.1.3"
925
+source = "registry+https://github.com/rust-lang/crates.io-index"
926
+checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002"
927
+
928
+[[package]]
929
+name = "version_check"
930
+version = "0.9.3"
931
+source = "registry+https://github.com/rust-lang/crates.io-index"
932
+checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
933
+
934
+[[package]]
935
+name = "void"
936
+version = "1.0.2"
937
+source = "registry+https://github.com/rust-lang/crates.io-index"
938
+checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
939
+
940
+[[package]]
941
+name = "volatile-register"
942
+version = "0.2.1"
943
+source = "registry+https://github.com/rust-lang/crates.io-index"
944
+checksum = "9ee8f19f9d74293faf70901bc20ad067dc1ad390d2cbf1e3f75f721ffee908b6"
945
+dependencies = [
946
+ "vcell",
947
+]
948
+
949
+[[package]]
950
+name = "wasi"
951
+version = "0.10.2+wasi-snapshot-preview1"
952
+source = "registry+https://github.com/rust-lang/crates.io-index"
953
+checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
954
+
955
+[[package]]
956
+name = "winapi"
957
+version = "0.3.9"
958
+source = "registry+https://github.com/rust-lang/crates.io-index"
959
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
960
+dependencies = [
961
+ "winapi-i686-pc-windows-gnu",
962
+ "winapi-x86_64-pc-windows-gnu",
963
+]
964
+
965
+[[package]]
966
+name = "winapi-i686-pc-windows-gnu"
967
+version = "0.4.0"
968
+source = "registry+https://github.com/rust-lang/crates.io-index"
969
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
970
+
971
+[[package]]
972
+name = "winapi-util"
973
+version = "0.1.5"
974
+source = "registry+https://github.com/rust-lang/crates.io-index"
975
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
976
+dependencies = [
977
+ "winapi",
978
+]
979
+
980
+[[package]]
981
+name = "winapi-x86_64-pc-windows-gnu"
982
+version = "0.4.0"
983
+source = "registry+https://github.com/rust-lang/crates.io-index"
984
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

+ 28
- 0
Cargo.toml Ver fichero

@@ -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 = { git = "https://github.com/rp-rs/pio-rs.git", branch = "main" }
18
+pio-proc = { git = "https://github.com/rp-rs/pio-rs.git", branch = "main" }
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 = { version = "0.2.8", features = ["control-buffer-256"] }
25
+void = { version = "*", default_features = false }
26
+
27
+[patch.crates-io]
28
+usb-device = { path = "../usb-device" }

+ 31
- 0
build.rs Ver fichero

@@ -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 Ver fichero

@@ -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 Ver fichero

@@ -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 Ver fichero

@@ -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 Ver fichero

@@ -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
+}

+ 63
- 0
src/usb.rs Ver fichero

@@ -0,0 +1,63 @@
1
+use crate::audio_buffer::{WriteBuffer, WritePacket};
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, WritePacket<4>>,
10
+    usb_dev: UsbDevice<'static, UsbBus>,
11
+    in_buffer: WriteBuffer<4>,
12
+
13
+    timer: Timer,
14
+}
15
+
16
+impl Usb {
17
+    pub fn init(
18
+        bus: &'static UsbBusAllocator<UsbBus>,
19
+        in_buffer: WriteBuffer<4>,
20
+        timer: Timer,
21
+    ) -> Usb {
22
+        let usb_audio = UsbAudioClass::new(bus);
23
+
24
+        // This PID/VID combination is selected from the pid.codes PID space and only intended for
25
+        // software development. It is not universally unique and should not be used outside of
26
+        // test environments!
27
+        let usb_dev = UsbDeviceBuilder::new(bus, UsbVidPid(0x1209, 0x000d))
28
+            .manufacturer("TEST")
29
+            .product("USB audio test")
30
+            .serial_number("TEST")
31
+            .build();
32
+
33
+        // TODO
34
+        Usb {
35
+            usb_audio,
36
+            usb_dev,
37
+            in_buffer,
38
+            timer,
39
+        }
40
+    }
41
+
42
+    pub fn poll(&mut self) {
43
+        // Safety: The read access does not have any side effect, and this function is the only one
44
+        // using the USB peripheral at this time.
45
+        let sof = unsafe { (&*USBCTRL_REGS::ptr()).intr.read().dev_sof().bit_is_set() };
46
+        if sof {
47
+            // Calculate the frequency difference (frames versus 1kHz derived from the system
48
+            // clock) and update the synchronization data for the USB audio class accordingly.
49
+            // Also, add a correction factor if the buffers are running low or high.
50
+            // TODO
51
+
52
+            /*let mut buffer = [0u8; 64];
53
+            for i in 0..64 {
54
+                buffer[i] = i as u8 * 4;
55
+            }
56
+            let _err = self.usb_audio.write_packet(&buffer);*/
57
+        }
58
+        if self.usb_dev.poll(&mut [&mut self.usb_audio]) {
59
+            // If we received audio data, move it into the buffer.
60
+            // TODO
61
+        }
62
+    }
63
+}

+ 568
- 0
src/usb_audio.rs Ver fichero

@@ -0,0 +1,568 @@
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
+use usb_device::endpoint::{IsochronousSynchronizationType, IsochronousUsageType};
7
+use usb_device::Result;
8
+
9
+const DEVICE_CLASS_AUDIO: u8 = 0x01;
10
+const AUDIO_SUBCLASS_CONTROL: u8 = 0x01;
11
+const AUDIO_SUBCLASS_STREAMING: u8 = 0x02;
12
+const AUDIO_PROTOCOL_NONE: u8 = 0x00;
13
+
14
+const AUDIO_INTERFACE_DESC_TYPE: u8 = 0x24;
15
+const AUDIO_ENDPOINT_DESC_TYPE: u8 = 0x25;
16
+
17
+const AUDIO_CONTROL_HEADER: u8 = 0x01;
18
+const AUDIO_CONTROL_INPUT_TERMINAL: u8 = 0x02;
19
+const AUDIO_CONTROL_OUTPUT_TERMINAL: u8 = 0x03;
20
+const AUDIO_CONTROL_FEATURE_UNIT: u8 = 0x06;
21
+
22
+const AUDIO_STREAMING_GENERAL: u8 = 0x01;
23
+const AUDIO_STREAMING_FORMAT_TYPE: u8 = 0x02;
24
+
25
+const AUDIO_ENDPOINT_GENERAL: u8 = 0x01;
26
+
27
+// TODO: Update bDelay.
28
+
29
+pub struct UsbAudioClass<'a, B: UsbBus, OUTBUF: AsRef<[u32]>> {
30
+    audio_control: InterfaceNumber,
31
+    audio_streaming_inactive: InterfaceNumber,
32
+    audio_streaming: InterfaceNumber,
33
+    audio_out: EndpointOut<'a, B>,
34
+    audio_out_sync: EndpointIn<'a, B>,
35
+    //audio_in: EndpointIn<'a, B>,
36
+    samples_per_frame: [u8; 3],
37
+
38
+    audio_out_buf: Option<OUTBUF>,
39
+}
40
+
41
+impl<'a, B: UsbBus, OUTBUF: AsRef<[u32]>> UsbAudioClass<'a, B, OUTBUF> {
42
+    pub fn new(bus_alloc: &'a UsbBusAllocator<B>) -> Self {
43
+        UsbAudioClass {
44
+            audio_control: bus_alloc.interface(),
45
+            audio_streaming_inactive: bus_alloc.interface(),
46
+            audio_streaming: bus_alloc.interface(),
47
+            // 48kHz * 2 * 16bit = 192B per packet. We allocate a bit more in case the device clock
48
+            // is faster than the host clock.
49
+            /*audio_out: bus_alloc.isochronous(
50
+                IsochronousSynchronizationType::Asynchronous,
51
+                IsochronousUsageType::Data,
52
+                256,
53
+                1,
54
+            ),*/
55
+            audio_out: bus_alloc.isochronous(
56
+                IsochronousSynchronizationType::Synchronous,
57
+                IsochronousUsageType::Data,
58
+                256,
59
+                1,
60
+            ),
61
+            audio_out_sync: bus_alloc.isochronous(
62
+                IsochronousSynchronizationType::Asynchronous,
63
+                IsochronousUsageType::Feedback,
64
+                3,
65
+                1,
66
+            ),
67
+            /*audio_in: bus_alloc.isochronous(
68
+                IsochronousSynchronizationType::Asynchronous,
69
+                IsochronousUsageType::Data,
70
+                256,
71
+                1,
72
+            ),*/
73
+            samples_per_frame: [48 >> 2, 48 << 6, 0], // 48 kHz
74
+            audio_out_buf: None,
75
+        }
76
+    }
77
+
78
+    // TODO: Functions to read and write data?
79
+}
80
+
81
+impl<B: UsbBus, OUTBUF: AsRef<[u32]>> UsbClass<B> for UsbAudioClass<'_, B, OUTBUF> {
82
+    fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> {
83
+        writer.iad(
84
+            self.audio_control,
85
+            2,   // Two interfaces (control + streaming).
86
+            0x0, // Each interface specifies its own class.
87
+            0x0, // Each interface specifies its own subclass.
88
+            0x0, // No class-specific protocols for this device.
89
+        )?;
90
+
91
+        // Audio control interface.
92
+        writer.interface(
93
+            self.audio_control,
94
+            DEVICE_CLASS_AUDIO,
95
+            AUDIO_SUBCLASS_CONTROL,
96
+            AUDIO_PROTOCOL_NONE,
97
+        )?;
98
+
99
+        writer.write(
100
+            AUDIO_INTERFACE_DESC_TYPE,
101
+            &[
102
+                AUDIO_CONTROL_HEADER,        // bDescriptorSubtype
103
+                0x00,                        // bcdADC
104
+                0x01,                        //
105
+                37,                          // wTotalLength
106
+                0,                           //
107
+                0x01,                        // bInCollection
108
+                self.audio_streaming.into(), // baInterfaceNr
109
+            ],
110
+        )?;
111
+
112
+        // Input terminal (USB streaming).
113
+        writer.write(
114
+            AUDIO_INTERFACE_DESC_TYPE,
115
+            &[
116
+                AUDIO_CONTROL_INPUT_TERMINAL, // bDescriptorSubtype
117
+                0x01,                         // bTerminalID
118
+                0x01,                         // wTerminalType
119
+                0x01,                         //
120
+                0x00,                         // bAssocTerminal
121
+                0x02,                         // bNrChannels
122
+                0x03,                         // wChannelConfig
123
+                0x00,                         //
124
+                0x00,                         // iChannelNames
125
+                0x00,                         // iTerminal
126
+            ],
127
+        )?;
128
+
129
+        // Feature unit (volume and mute).
130
+        writer.write(
131
+            AUDIO_INTERFACE_DESC_TYPE,
132
+            &[
133
+                AUDIO_CONTROL_FEATURE_UNIT, // bDescriptorSubtype
134
+                0x02,                       // bUnitID
135
+                0x01,                       // bSourceID
136
+                0x01,                       // bControlSize
137
+                0x03,                       // bmaControls(0)
138
+                0x00,                       // iFeature
139
+            ],
140
+        )?;
141
+
142
+        // Output terminal (speaker).
143
+        writer.write(
144
+            AUDIO_INTERFACE_DESC_TYPE,
145
+            &[
146
+                AUDIO_CONTROL_OUTPUT_TERMINAL, // bDescriptorSubtype
147
+                0x03,                          // bTerminalID
148
+                0x01,                          // wTerminalType
149
+                0x03,                          //
150
+                0x00,                          // bAssocTerminal
151
+                0x02,                          // bSourceID
152
+                0x00,                          // iTerminal
153
+            ],
154
+        )?;
155
+
156
+        // Audio streaming interface (zero-bandwidth).
157
+        writer.interface(
158
+            self.audio_streaming_inactive,
159
+            DEVICE_CLASS_AUDIO,
160
+            AUDIO_SUBCLASS_STREAMING,
161
+            AUDIO_PROTOCOL_NONE,
162
+        )?;
163
+
164
+        // Audio streaming interface (operational).
165
+        writer.interface_alt(
166
+            self.audio_streaming,
167
+            1,
168
+            DEVICE_CLASS_AUDIO,
169
+            AUDIO_SUBCLASS_STREAMING,
170
+            AUDIO_PROTOCOL_NONE,
171
+            None,
172
+        )?;
173
+
174
+        writer.write(
175
+            AUDIO_INTERFACE_DESC_TYPE,
176
+            &[
177
+                AUDIO_STREAMING_GENERAL, // bDescriptorSubtype
178
+                0x01,                    // bTerminalLink
179
+                0x03,                    // bDelay
180
+                0x01,                    // wFormatTag
181
+                0x00,                    //
182
+            ],
183
+        )?;
184
+
185
+        writer.write(
186
+            AUDIO_INTERFACE_DESC_TYPE,
187
+            &[
188
+                AUDIO_STREAMING_FORMAT_TYPE, // bDescriptorSubtype
189
+                0x01,                        // bFormatType
190
+                0x02,                        // bNrChannels
191
+                0x02,                        // bSubframeSize
192
+                0x10,                        // bBitResolution
193
+                0x01,                        // bSamFreqType
194
+            ],
195
+        )?;
196
+
197
+        /*writer.endpoint_ex(&self.audio_out, |data| {
198
+            // TODO: Faster refresh
199
+            data[0] = 0x09; // bRefresh
200
+            data[1] = self.audio_out_sync.address().into(); // bSynchAddress
201
+            Ok(2)
202
+        })?;*/
203
+        writer.endpoint(&self.audio_out)?;
204
+
205
+        writer.write(
206
+            AUDIO_ENDPOINT_DESC_TYPE,
207
+            &[
208
+                AUDIO_ENDPOINT_GENERAL, // bDescriptorSubtype
209
+                0x00,                   // bmAttributes
210
+                0x01,                   // bLockDelayUnits
211
+                0x00,                   // wLockDelay
212
+                0x00,
213
+            ],
214
+        )?;
215
+
216
+        /*writer.endpoint_ex(&self.audio_out_sync, |data| {
217
+            data[0] = 0x00; // bRefresh
218
+            data[1] = 0x00; // bSynchAddress
219
+            Ok(2)
220
+        })?;*/
221
+
222
+        Ok(())
223
+    }
224
+
225
+    fn get_string(&self, _index: StringIndex, _lang_id: u16) -> Option<&str> {
226
+        // TODO
227
+        None
228
+    }
229
+
230
+    fn reset(&mut self) {
231
+        // Start sending synchronization data.
232
+        self.endpoint_in_complete(self.audio_out_sync.address());
233
+    }
234
+
235
+    fn control_out(&mut self, xfer: ControlOut<B>) {
236
+        let req = xfer.request();
237
+
238
+        if !(req.request_type == control::RequestType::Class
239
+            && req.recipient == control::Recipient::Interface
240
+            && req.index == u8::from(self.audio_control) as u16)
241
+        {
242
+            return;
243
+        }
244
+
245
+        match req.request {
246
+            // TODO
247
+            _ => {
248
+                xfer.reject().ok();
249
+            }
250
+        };
251
+    }
252
+
253
+    fn control_in(&mut self, xfer: ControlIn<B>) {
254
+        let req = xfer.request();
255
+
256
+        if !(req.request_type == control::RequestType::Class
257
+            && req.recipient == control::Recipient::Interface
258
+            && req.index == u8::from(self.audio_control) as u16)
259
+        {
260
+            return;
261
+        }
262
+
263
+        match req.request {
264
+            // TODO
265
+            _ => {
266
+                xfer.reject().ok();
267
+            }
268
+        };
269
+    }
270
+
271
+    fn endpoint_out(&mut self, addr: EndpointAddress) {
272
+        if addr == self.audio_out.address() {
273
+            if self.audio_out_buf.is_some() {
274
+                // TODO: Write data into buffer, move buffer somewhere else.
275
+            } else {
276
+                // TODO
277
+            }
278
+            // TODO: Process incoming audio data.
279
+            let mut buffer = [0u8; 256];
280
+            self.audio_out.read(&mut buffer);
281
+        }
282
+    }
283
+
284
+    fn endpoint_in_complete(&mut self, addr: EndpointAddress) {
285
+        if addr == self.audio_out_sync.address() {
286
+            // Immediately write the next sync value.
287
+            //self.audio_out_sync.write(&self.samples_per_frame).unwrap();
288
+        }
289
+    }
290
+}
291
+
292
+/*use usb_device::class_prelude::*;
293
+use usb_device::endpoint::{IsochronousSynchronizationType, IsochronousUsageType};
294
+use usb_device::Result;
295
+
296
+/// This should be used as `device_class` when building the `UsbDevice`.
297
+pub const USB_INTERFACE_CLASS_AUDIO: u8 = 0x01;
298
+
299
+const USB_AUDIO_SUBCLASS_UNDEFINED: u8 = 0x0;
300
+const USB_AUDIO_SUBCLASS_AUDIOCONTROL: u8 = 0x01;
301
+const USB_AUDIO_SUBCLASS_AUDIOSTREAMING: u8 = 0x02;
302
+const USB_AUDIO_SUBCLASS_MIDISTREAMING: u8 = 0x03;
303
+
304
+const USB_CLASS_CDC_DATA: u8 = 0x0a;
305
+const CDC_SUBCLASS_ACM: u8 = 0x02;
306
+const USB_AUDIO_PROTOCOL_NONE: u8 = 0x00;
307
+
308
+const CS_DEVICE: u8 = 0x21;
309
+const CS_CONFIGURATION: u8 = 0x22;
310
+const CS_STRING: u8 = 0x23;
311
+const CS_INTERFACE: u8 = 0x24;
312
+const CS_ENDPOINT: u8 = 0x25;
313
+
314
+const EP_GENERAL: u8 = 0x1;
315
+
316
+const AC_DESC_TYPE_HEADER: u8 = 0x1;
317
+const AC_DESC_TYPE_INPUT_TERMINAL: u8 = 0x2;
318
+const AC_DESC_TYPE_OUTPUT_TERMINAL: u8 = 0x3;
319
+const AC_DESC_TYPE_MIXER_UNIT: u8 = 0x4;
320
+const AC_DESC_TYPE_SELECTOR_UNIT: u8 = 0x5;
321
+const AC_DESC_TYPE_FEATURE_UNIT: u8 = 0x6;
322
+const AC_DESC_TYPE_PROCESSING_UNIT: u8 = 0x7;
323
+const AC_DESC_TYPE_EXTENSION_UNIT: u8 = 0x8;
324
+
325
+const AC_DESC_ST_GENERAL: u8 = 0x1;
326
+const AC_DESC_ST_FORMAT_TYPE: u8 = 0x2;
327
+const AC_DESC_ST_FORMAT_SPECIFIC: u8 = 0x3;
328
+
329
+const AUDIO_SUB_TYPE_HEADER: u8 = 0x01;
330
+const AUDIO_SUB_TYPE_INPUT_TERMINAL: u8 = 0x02;
331
+const AUDIO_SUB_TYPE_FEATURE_UNIT: u8 = 0x06;
332
+const AUDIO_SUB_TYPE_OUTPUT_TERMINAL: u8 = 0x03;
333
+const AUDIO_SUB_TYPE_AS_GENERAL: u8 = 0x01;
334
+const AUDIO_SUB_TYPE_FORMAT_TYPE: u8 = 0x02;
335
+
336
+pub struct UsbAudioClass<'a, B: UsbBus> {
337
+    audio_control_if: InterfaceNumber,
338
+    audio_stream: InterfaceNumber,
339
+    alt_audio_stream: InterfaceNumber,
340
+    audio_in_ep: EndpointIn<'a, B>,
341
+}
342
+
343
+impl<B: UsbBus> UsbAudioClass<'_, B> {
344
+    /// Creates a new UsbAudioClass with the provided UsbBus and max_packet_size in bytes. For
345
+    /// full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64.
346
+    pub fn new(alloc: &UsbBusAllocator<B>, max_packet_size: u16) -> UsbAudioClass<'_, B> {
347
+        UsbAudioClass {
348
+            audio_control_if: alloc.interface(),
349
+            audio_stream: alloc.interface(),
350
+            alt_audio_stream: alloc.interface(),
351
+            audio_in_ep: alloc.isochronous(
352
+                IsochronousSynchronizationType::Synchronous,
353
+                IsochronousUsageType::Data,
354
+                max_packet_size,
355
+                4,
356
+            ),
357
+        }
358
+    }
359
+
360
+    /// Gets the maximum packet size in bytes.
361
+    pub fn max_packet_size(&self) -> u16 {
362
+        self.audio_in_ep.max_packet_size()
363
+    }
364
+
365
+    /// Writes a single packet into the IN endpoint.
366
+    pub fn write_packet(&mut self, data: &[u8]) -> Result<usize> {
367
+        //defmt::info!("write_packet");
368
+        self.audio_in_ep.write(data)
369
+    }
370
+
371
+    /// Gets the address of the IN endpoint.
372
+    pub(crate) fn write_ep_address(&self) -> EndpointAddress {
373
+        self.audio_in_ep.address()
374
+    }
375
+}
376
+
377
+impl<B: UsbBus> UsbClass<B> for UsbAudioClass<'_, B> {
378
+    fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> {
379
+        writer.iad(
380
+            self.audio_control_if,
381
+            3,
382
+            0x0, // device defined at interface level
383
+            0x0, // subclass unused
384
+            USB_AUDIO_PROTOCOL_NONE,
385
+        )?;
386
+
387
+        writer.interface(
388
+            self.audio_control_if,
389
+            USB_INTERFACE_CLASS_AUDIO,
390
+            USB_AUDIO_SUBCLASS_AUDIOCONTROL,
391
+            USB_AUDIO_PROTOCOL_NONE,
392
+        )?;
393
+
394
+        writer.write(
395
+            CS_INTERFACE,
396
+            &[
397
+                AUDIO_SUB_TYPE_HEADER, // bDescriptorSubtype
398
+                0x00,
399
+                0x1, // bcdADC (1.0),
400
+                43,
401
+                0,    // wTotalLength (Compute this!)
402
+                0x01, // bInCollection (1 streaming interface)
403
+                0x01, // baInterfaceNr (Interface 1 is stream)
404
+            ],
405
+        )?;
406
+
407
+        writer.write(
408
+            CS_INTERFACE,
409
+            &[
410
+                AUDIO_SUB_TYPE_INPUT_TERMINAL, // bDescriptorSubtype
411
+                0x01,                          // bTerminalID 1,
412
+                0x10,
413
+                0x07, // wTerminalType (radio receiver)
414
+                0x00, // bAssocTerminal (none)
415
+                0x02, // bNrChannels - 2 for I and Q
416
+                0x03,
417
+                0x00, // wChannelConfig (left, right)
418
+                0x00, // iChannelNames (none)
419
+                0x00, // iTerminal (none)
420
+            ],
421
+        )?;
422
+
423
+        writer.write(
424
+            CS_INTERFACE,
425
+            &[
426
+                AUDIO_SUB_TYPE_FEATURE_UNIT, // bDescriptorSubtype
427
+                0x02,                        // bUnitID,
428
+                0x01,                        // bSourceID (input terminal 1)
429
+                0x02,                        // bControlSize (2 bytes)
430
+                0x01,
431
+                0x00, // Master controls
432
+                0x00,
433
+                0x00, // Channel 0 controls
434
+                0x00,
435
+                0x00, // Channel 1 controls
436
+                0x00, // iFeature (none)
437
+            ],
438
+        )?;
439
+
440
+        writer.write(
441
+            CS_INTERFACE,
442
+            &[
443
+                AUDIO_SUB_TYPE_OUTPUT_TERMINAL, // bDescriptorSubtype
444
+                0x03,                           // bTerminalID,
445
+                0x01,
446
+                0x01, // wTerminalType (USB Streaming)
447
+                0x00, // bAssocTerminal (none)
448
+                0x02, // bSourceID (feature unit 2)
449
+                0x00, // iTerminal (none)
450
+            ],
451
+        )?;
452
+
453
+        writer.interface(
454
+            self.audio_stream,
455
+            USB_INTERFACE_CLASS_AUDIO,
456
+            USB_AUDIO_SUBCLASS_AUDIOSTREAMING,
457
+            USB_AUDIO_PROTOCOL_NONE,
458
+        )?;
459
+
460
+        //alternate audio stream
461
+        /*writer.interface_alt(
462
+            self.alt_audio_stream,
463
+            1,
464
+            USB_INTERFACE_CLASS_AUDIO,
465
+            USB_AUDIO_SUBCLASS_AUDIOSTREAMING,
466
+            USB_AUDIO_PROTOCOL_NONE,
467
+            None,
468
+        )?;*/
469
+
470
+        // Audio Stream Audio Class Descriptor
471
+        writer.write(
472
+            CS_INTERFACE,
473
+            &[
474
+                AUDIO_SUB_TYPE_AS_GENERAL, // bDescriptorSubtype
475
+                0x03,                      // bTerminalID,
476
+                0x00,                      // bDelay
477
+                0x01,
478
+                0x00, // wFormatTag (PCM Format)
479
+            ],
480
+        )?;
481
+
482
+        // Format Type Audio Descriptor
483
+        writer.write(
484
+            CS_INTERFACE,
485
+            &[
486
+                AUDIO_SUB_TYPE_FORMAT_TYPE, // bDescriptorSubtype
487
+                0x01,                       // bFormatType (TYPE_I)
488
+                0x02,                       // bNrChannels (2)
489
+                0x02,                       // bSubFrameSize (2)
490
+                0x10,                       // bBitResolution (16 bits)
491
+                0x01,                       // bSamFreqType (1 sample frequency)
492
+                0x80,                       // 8*2 = 16 KHz byte 0
493
+                0x3E,                       // 8*2 = 16 KHz byte 1
494
+                0x00,                       // 8*2 = 16 KHz byte 2
495
+            ],
496
+        )?;
497
+
498
+        // TODO: Set the necessary flags for Isochronous
499
+        writer.endpoint(&self.audio_in_ep)?;
500
+
501
+        // Isochronous endpoint Audio Class descriptor
502
+        writer.write(
503
+            CS_ENDPOINT,
504
+            &[
505
+                EP_GENERAL, // bDescriptorSubtype
506
+                0x00,       // bmAttributes (none)
507
+                0x02,       // bLockDelayUnits (PCM Samples)
508
+                0x00, 0x00, // wLockDelay (0)  - should be zero for asynchronous
509
+            ],
510
+        )?;
511
+        Ok(())
512
+    }
513
+
514
+    fn reset(&mut self) {}
515
+
516
+    fn control_in(&mut self, xfer: ControlIn<B>) {
517
+        let req = xfer.request();
518
+
519
+        if !(req.request_type == control::RequestType::Class
520
+            && req.recipient == control::Recipient::Interface
521
+            && req.index == u8::from(self.audio_control_if) as u16)
522
+        {
523
+            return;
524
+        }
525
+
526
+        //defmt::info!("control_in - req : {:?}", req.request);
527
+        match req.request {
528
+            /*
529
+            REQ_GET_LINE_CODING if req.length == 7 => {
530
+                xfer.accept(|data| {
531
+                    data[0..4].copy_from_slice(&self.line_coding.data_rate.to_le_bytes());
532
+                    data[4] = self.line_coding.stop_bits as u8;
533
+                    data[5] = self.line_coding.parity_type as u8;
534
+                    data[6] = self.line_coding.data_bits;
535
+
536
+                    Ok(7)
537
+                }).ok();
538
+            },
539
+            */
540
+            _ => {
541
+                xfer.reject().ok();
542
+            }
543
+        }
544
+    }
545
+
546
+    fn control_out(&mut self, xfer: ControlOut<B>) {
547
+        let req = xfer.request();
548
+
549
+        if !(req.request_type == control::RequestType::Class
550
+            && req.recipient == control::Recipient::Interface
551
+            && req.index == u8::from(self.audio_control_if) as u16)
552
+        {
553
+            return;
554
+        }
555
+
556
+        match req.request {
557
+            /*
558
+            REQ_SEND_ENCAPSULATED_COMMAND => {
559
+                // We don't actually support encapsulated commands but pretend we do for standards
560
+                // compatibility.
561
+                xfer.accept().ok();
562
+            },*/
563
+            _ => {
564
+                xfer.reject().ok();
565
+            }
566
+        };
567
+    }
568
+}*/

Loading…
Cancelar
Guardar