Quellcode durchsuchen

firmware: First parts of an audio buffer type.

Mathias Gottschlag vor 5 Jahren
Ursprung
Commit
7f11ae4e31

+ 128
- 0
hackamp/firmware/src/audio_buffer.rs Datei anzeigen

@@ -0,0 +1,128 @@
1
+#![warn(missing_docs)]
2
+
3
+use core::cell::{Cell, UnsafeCell};
4
+
5
+use cortex_m::interrupt::{CriticalSection, Mutex};
6
+
7
+/// Each packet contains 1 millisecond of audio data (48 samples at 48000kHz).
8
+///
9
+/// This translates two twice the number of values, as each sample contains two channels.
10
+pub const SAMPLES_PER_PACKET: usize = 48;
11
+pub const CHANNELS: usize = 2;
12
+pub const PACKETS: usize = 3;
13
+
14
+pub type Packet = [u32; SAMPLES_PER_PACKET * CHANNELS];
15
+
16
+/// Type for audio packet buffering.
17
+///
18
+/// The audio packets always contain two channels with 32-bit samples. The type contains three
19
+/// buffers each containing the same fixed number of samples. This structure allows two buffers to
20
+/// be in use by the DMA engine while the third is used by the ARM core.
21
+pub struct AudioBuffer {
22
+    mutex: Mutex<AudioBufferInner>,
23
+}
24
+
25
+struct AudioBufferInner {
26
+    /// Packet contents.
27
+    packets: [UnsafeCell<Packet>; PACKETS],
28
+    /// Bitmask of packets which contain valid data and are not currently being read.
29
+    valid: Cell<u32>,
30
+    /// Bitmask of packets which do not contain valid data and which are not currently being
31
+    /// written.
32
+    invalid: Cell<u32>,
33
+    /// Bitmask of all packets which are currently borrowed via `borrow_read()`.
34
+    reading: Cell<u32>,
35
+    /// Bitmask of all packets which are currently borrowed via `borrow_write()`.
36
+    writing: Cell<u32>,
37
+}
38
+
39
+impl AudioBuffer {
40
+    /// Creates a new audio buffer.
41
+    pub const fn new() -> AudioBuffer {
42
+        // Initially, all packet contents are invalid and no packets are currently being read or
43
+        // written.
44
+        AudioBuffer {
45
+            mutex: Mutex::new(AudioBufferInner {
46
+                packets: [
47
+                    UnsafeCell::new([0; SAMPLES_PER_PACKET * CHANNELS]),
48
+                    UnsafeCell::new([0; SAMPLES_PER_PACKET * CHANNELS]),
49
+                    UnsafeCell::new([0; SAMPLES_PER_PACKET * CHANNELS]),
50
+                ],
51
+                valid: Cell::new(0),
52
+                invalid: Cell::new(((1 << PACKETS) - 1) as u32),
53
+                reading: Cell::new(0),
54
+                writing: Cell::new(0),
55
+            }),
56
+        }
57
+    }
58
+
59
+    /// Returns whether there are any buffers with valid data ready for reading.
60
+    pub fn read_data_available(&self, cs: &CriticalSection) -> bool {
61
+        let inner = self.mutex.borrow(cs);
62
+        inner.valid.get() != 0
63
+    }
64
+
65
+    pub fn borrow_read(&'static self, cs: &CriticalSection) -> Option<ReadPacket> {
66
+        let inner = self.mutex.borrow(cs);
67
+        let valid = inner.valid.get();
68
+        if valid != 0 {
69
+            return None;
70
+        }
71
+        let index = valid.trailing_zeros();
72
+        inner.valid.set(valid & !(1 << index));
73
+        inner.reading.set(inner.reading.get() | (1 << index));
74
+
75
+        let index = index as usize;
76
+        Some(ReadPacket {
77
+            buffer: self,
78
+            data: unsafe { &*inner.packets[index].get() },
79
+            index,
80
+        })
81
+    }
82
+
83
+    pub fn read_finished(&'static self, _packet: ReadPacket, _cs: &CriticalSection) {
84
+        // TODO
85
+        panic!("Not yet implemented.");
86
+    }
87
+
88
+    /// Returns whether there are any empty buffers ready for writing.
89
+    pub fn write_data_available(&self, cs: &CriticalSection) -> bool {
90
+        let inner = self.mutex.borrow(cs);
91
+        inner.invalid.get() != 0
92
+    }
93
+
94
+    pub fn borrow_write(&'static self, cs: &CriticalSection) -> Option<WritePacket> {
95
+        let inner = self.mutex.borrow(cs);
96
+        let invalid = inner.invalid.get();
97
+        if invalid != 0 {
98
+            return None;
99
+        }
100
+        let index = invalid.trailing_zeros();
101
+        inner.invalid.set(invalid & !(1 << index));
102
+        inner.writing.set(inner.writing.get() | (1 << index));
103
+
104
+        let index = index as usize;
105
+        Some(WritePacket {
106
+            buffer: self,
107
+            data: unsafe { &mut *inner.packets[index].get() },
108
+            index,
109
+        })
110
+    }
111
+
112
+    pub fn write_finished(&'static self, _packet: WritePacket, _cs: &CriticalSection) {
113
+        // TODO
114
+        panic!("Not yet implemented.");
115
+    }
116
+}
117
+
118
+pub struct ReadPacket {
119
+    buffer: &'static AudioBuffer,
120
+    data: &'static Packet,
121
+    index: usize,
122
+}
123
+
124
+pub struct WritePacket {
125
+    buffer: &'static AudioBuffer,
126
+    data: &'static mut Packet,
127
+    index: usize,
128
+}

+ 1
- 0
hackamp/firmware/src/halext/mod.rs Datei anzeigen

@@ -0,0 +1 @@
1
+#![warn(missing_docs)]

+ 23
- 1
hackamp/firmware/src/main.rs Datei anzeigen

@@ -2,15 +2,37 @@
2 2
 #![no_main]
3 3
 #![no_std]
4 4
 
5
+use cortex_m::interrupt;
5 6
 use panic_semihosting as _;
6 7
 
8
+use audio_buffer::AudioBuffer;
9
+use pins::Pins;
10
+
11
+mod audio_buffer;
12
+mod halext;
13
+mod mixer;
14
+mod pins;
15
+
7 16
 #[rtic::app(device = stm32f4xx_hal::stm32, peripherals = true)]
8 17
 const APP: () = {
9 18
     struct Resources {}
10 19
 
11 20
     #[init]
12 21
     fn init(_ctx: init::Context) {
13
-        // TODO
22
+        let _pins = Pins::configure();
23
+        static I2S_BUFFER: AudioBuffer = AudioBuffer::new();
24
+
25
+        let i2s_buffer = &I2S_BUFFER;
26
+
27
+        // Buffer example code.
28
+        interrupt::free(|cs| {
29
+            let write_packet = i2s_buffer.borrow_write(cs).unwrap();
30
+            // TODO
31
+            i2s_buffer.write_finished(write_packet, cs);
32
+            let read_packet = i2s_buffer.borrow_read(cs).unwrap();
33
+            // TODO
34
+            i2s_buffer.read_finished(read_packet, cs);
35
+        });
14 36
     }
15 37
 
16 38
     #[idle(resources = [])]

+ 1
- 0
hackamp/firmware/src/mixer.rs Datei anzeigen

@@ -0,0 +1 @@
1
+#![warn(missing_docs)]

+ 18
- 0
hackamp/firmware/src/pins.rs Datei anzeigen

@@ -0,0 +1,18 @@
1
+#![warn(missing_docs)]
2
+
3
+/// Type which contains all GPIO pins.
4
+///
5
+/// The pins are configured as the correct type. Whenever possible, the corresponding HAL driver is
6
+/// instantiated. The initial output state is set during configuration.
7
+pub struct Pins {
8
+    // TODO
9
+}
10
+
11
+impl Pins {
12
+    /// Configures the GPIO pins and sets their initial value.
13
+    pub fn configure() -> Pins {
14
+        Pins{
15
+            // TODO
16
+        }
17
+    }
18
+}

Laden…
Abbrechen
Speichern