Skip to content

Commit 4efc06a

Browse files
authored
Merge pull request #116 from Neotron-Compute/fix-rust-183
Removed all the static mut.
2 parents 4bf443c + 33778cb commit 4efc06a

File tree

8 files changed

+171
-158
lines changed

8 files changed

+171
-158
lines changed

Cargo.lock

Lines changed: 17 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 25 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -8,56 +8,31 @@ name = "neotron-pico-bios"
88
version = "0.7.0"
99

1010
[dependencies]
11-
# Useful Cortex-M specific functions (e.g. SysTick)
12-
cortex-m = {version = "0.7", features = ["inline-asm"]}
13-
# The Raspberry Pi RP2040 HAL (so we can turn defmt on)
14-
rp2040-hal = { version = "0.10", features = [ "defmt", "rt", "critical-section-impl", "rom-func-cache" ] }
15-
# Cortex-M run-time (or start-up) code
16-
cortex-m-rt = "0.7"
17-
# The BIOS to OS API
18-
neotron-common-bios = "0.12.0"
19-
# For the RP2040 bootloader
20-
rp2040-boot2 = "0.3.0"
21-
# For hardware abstraction traits
22-
embedded-hal = "0.2"
23-
# Gives us formatted PC-side logging
24-
defmt = "=0.3.2"
25-
# Sends defmt logs to the SWD debugger
26-
defmt-rtt = "0.4"
27-
# Send panics to the debugger
28-
panic-probe = "0.2"
29-
# RP2040 PIO assembler
30-
pio = "0.2.1"
31-
# Macros for RP2040 PIO assembler
32-
pio-proc = "0.2"
33-
# Hardware locks for sharing data with interrupts
34-
critical-section = "1.0"
35-
# Commands for talking to a Neotron BMC. The tag is for the repo as a whole, of which the commands crate is a small part.
36-
neotron-bmc-commands = { version = "0.2.0" }
37-
# Protocol for talking to a Neotron BMC. The tag is for the repo as a whole, of which the protocol crate is a small part.
38-
neotron-bmc-protocol = { version = "0.1.0", features = ["defmt"] }
39-
# Time and frequency related functions
40-
fugit = "0.3"
41-
# PS/2 scancode decoding
42-
pc-keyboard = "0.7.0"
43-
# Useful queues and other structures
44-
heapless = "0.7"
45-
# The Dallas DS1307 RTC driver
46-
ds1307 = "0.5.0"
47-
# The Microchip MCP7940x RTC driver
48-
mcp794xx = "0.3.0"
49-
# I2C Bus Sharing
50-
shared-bus = "0.3"
51-
# Gets us compare-swap atomic operations
52-
atomic-polyfill = "1.0.2"
53-
# SD Card driver
54-
embedded-sdmmc = { version = "0.6", default-features = false, features = [
55-
"defmt-log"
56-
] }
57-
# CODEC register control
58-
tlv320aic23 = "0.1.0"
59-
# Calendar/Date/Time functions and types
60-
chrono = { version = "0.4.38", default-features = false }
11+
chrono = { version = "0.4.38", default-features = false } # Calendar/Date/Time functions and types
12+
cortex-m = {version = "0.7", features = ["inline-asm"]} # Useful Cortex-M specific functions (e.g. SysTick)
13+
cortex-m-rt = "0.7" # Cortex-M run-time (or start-up) code
14+
critical-section = "1.0" # Hardware locks for sharing data with interrupts
15+
defmt = "=0.3.2" # Gives us formatted PC-side logging
16+
defmt-rtt = "0.4" # Sends defmt logs to the SWD debugger
17+
ds1307 = "0.5.0" # The Dallas DS1307 RTC driver
18+
embedded-hal = "0.2" # For hardware abstraction traits
19+
embedded-sdmmc = { version = "0.6", default-features = false, features = [ "defmt-log" ] } # SD Card driver
20+
fugit = "0.3" # Time and frequency related functions
21+
grounded = { version = "0.2.0", features = ["critical-section"] }
22+
heapless = "0.7" # Useful queues and other structures
23+
mcp794xx = "0.3.0" # The Microchip MCP7940x RTC driver
24+
neotron-bmc-commands = { version = "0.2.0" } # Commands for talking to a Neotron BMC. The tag is for the repo as a whole, of which the commands crate is a small part.
25+
neotron-bmc-protocol = { version = "0.1.0", features = ["defmt"] } # Protocol for talking to a Neotron BMC. The tag is for the repo as a whole, of which the protocol crate is a small part.
26+
neotron-common-bios = "0.12.0" # The BIOS to OS API
27+
panic-probe = "0.2" # Send panics to the debugger
28+
pc-keyboard = "0.7.0" # PS/2 scancode decoding
29+
pio = "0.2.1" # RP2040 PIO assembler
30+
pio-proc = "0.2" # Macros for RP2040 PIO assembler
31+
portable-atomic = { version = "1.10.0", features = ["critical-section"] } # Atomic CAS for non-CAS CPUs
32+
rp2040-boot2 = "0.3.0" # For the RP2040 bootloader
33+
rp2040-hal = { version = "0.10", features = [ "defmt", "rt", "critical-section-impl", "rom-func-cache" ] } # The Raspberry Pi RP2040 HAL (so we can turn defmt on)
34+
shared-bus = "0.3" # I2C Bus Sharing
35+
tlv320aic23 = "0.1.0" # CODEC register control
6136

6237
[build-dependencies]
6338
neotron-common-bios = "0.12.0"

memory.x

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,18 @@ MEMORY {
2525
/*
2626
* This is the bottom of the four striped banks of SRAM in the RP2040.
2727
*/
28-
RAM_OS : ORIGIN = 0x20000000, LENGTH = 0x42000 - 0x9680
28+
RAM_OS : ORIGIN = 0x20000000, LENGTH = 0x42000 - 0x9630
2929
/*
3030
* This is the top of the four striped banks of SRAM in the RP2040, plus
3131
* SRAM_BANK4 and SRAM_BANK5.
3232
*
3333
* This is carefully calculated to give us 8 KiB of stack space and ensure
3434
* the defmt buffer doesn't span across SRAM_BANK3 and SRAM_BANK4.
3535
*
36-
* 0x9680 should be the (size of .data + size of .bss + size of .uninit +
36+
* 0x9630 should be the (size of .data + size of .bss + size of .uninit +
3737
* 0x2000 for the stack).
3838
*/
39-
RAM : ORIGIN = 0x20042000 - 0x9680, LENGTH = 0x9680
39+
RAM : ORIGIN = 0x20042000 - 0x9630, LENGTH = 0x9630
4040
}
4141

4242
/*

src/i2s.rs

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
//! Code to set up a PIO to generate I2S Audio
22
3+
use core::cell::UnsafeCell;
4+
5+
use grounded::uninit::GroundedCell;
6+
37
use crate::hal::{pac::interrupt, prelude::*};
48

59
/// Holds the objects we need to read from the RAM fifo and write to the PIO hardware FIFO.
6-
static mut PLAYBACK_TO_PIO: Option<PlaybackToPio> = None;
10+
static PLAYBACK_TO_PIO: GroundedCell<PlaybackToPio> = GroundedCell::uninit();
711

812
/// The reader end of the RAM FIFO and the writer end of the PIO hardware FIFO.
913
struct PlaybackToPio {
1014
pio_fifo: crate::hal::pio::Tx<(crate::pac::PIO1, crate::hal::pio::SM0)>,
1115
ram_fifo: heapless::spsc::Consumer<'static, u32, 1024>,
1216
}
1317

18+
unsafe impl Sync for PlaybackToPio {}
19+
1420
/// Used to 'play' samples by writing them to the RAM FIFO.
1521
///
1622
/// Holds the writer end of the RAM FIFO.
@@ -181,17 +187,21 @@ pub fn init(pio: super::pac::PIO1, resets: &mut super::pac::RESETS) -> Player {
181187

182188
let _running_sam = samples_sm.start();
183189

184-
static mut SAMPLE_QUEUE: heapless::spsc::Queue<u32, 1024> = heapless::spsc::Queue::new();
190+
static SAMPLE_QUEUE: QueueWrapper = QueueWrapper::new();
191+
// # Safety
192+
// Interrupts are disabled at this point, so we can split the queue.
185193
let (q_producer, q_consumer) = unsafe { SAMPLE_QUEUE.split() };
186194

187195
pio_tx_fifo.enable_tx_not_full_interrupt(crate::hal::pio::PioIRQ::Irq0);
188196

189-
critical_section::with(|_| unsafe {
190-
PLAYBACK_TO_PIO.replace(PlaybackToPio {
197+
// # Safety
198+
// the PIO interrupt is currently disabled, so this is OK
199+
unsafe {
200+
PLAYBACK_TO_PIO.get().write(PlaybackToPio {
191201
pio_fifo: pio_tx_fifo,
192202
ram_fifo: q_consumer,
193203
});
194-
});
204+
}
195205

196206
unsafe {
197207
cortex_m::peripheral::NVIC::unmask(crate::pac::Interrupt::PIO1_IRQ_0);
@@ -200,6 +210,28 @@ pub fn init(pio: super::pac::PIO1, resets: &mut super::pac::RESETS) -> Player {
200210
Player { fifo: q_producer }
201211
}
202212

213+
struct QueueWrapper(UnsafeCell<heapless::spsc::Queue<u32, 1024>>);
214+
215+
impl QueueWrapper {
216+
const fn new() -> QueueWrapper {
217+
QueueWrapper(UnsafeCell::new(heapless::spsc::Queue::new()))
218+
}
219+
220+
/// Only call this when interrupts are off and the queue isn't being used
221+
unsafe fn split(
222+
&self,
223+
) -> (
224+
heapless::spsc::Producer<'_, u32, 1024>,
225+
heapless::spsc::Consumer<'_, u32, 1024>,
226+
) {
227+
let ptr = self.0.get();
228+
let queue_ref = unsafe { &mut *ptr };
229+
queue_ref.split()
230+
}
231+
}
232+
233+
unsafe impl Sync for QueueWrapper {}
234+
203235
/// Called when the PIO1 IRQ fires.
204236
///
205237
/// We mapped this to "TX FIFO is not empty", so this interrupt will be
@@ -209,9 +241,7 @@ fn PIO1_IRQ_0() {
209241
// This is the only function (apart from `init`) which accesses this
210242
// variable, and `init()` is sure to disable interrupts until the global is
211243
// set up, so this is safe.
212-
let Some(fifo) = (unsafe { PLAYBACK_TO_PIO.as_mut() }) else {
213-
return;
214-
};
244+
let fifo = unsafe { &mut *PLAYBACK_TO_PIO.get() };
215245
// Read from fifo.ram_fifo
216246
if let Some(sample) = fifo.ram_fifo.dequeue() {
217247
// .. and write to fifo.pio_fifo

src/main.rs

Lines changed: 16 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -742,9 +742,13 @@ fn paint_stacks() {
742742
*b = CORE0_STACK_PAINT_WORD;
743743
}
744744

745-
info!("Painting Core 1 stack: {:?}", CORE1_STACK.as_ptr_range());
746-
for b in CORE1_STACK.iter_mut() {
747-
*b = CORE1_STACK_PAINT_WORD;
745+
let stack_start = addr_of_mut!(CORE1_STACK) as *mut usize;
746+
let stack_end = addr_of_mut!(CORE1_STACK).add(1) as *mut usize;
747+
info!("Painting Core 1 stack @ {:?}", stack_start..stack_end);
748+
let mut p = stack_start;
749+
while p != stack_end {
750+
p.write_volatile(CORE1_STACK_PAINT_WORD);
751+
p = p.add(1);
748752
}
749753
}
750754
}
@@ -764,17 +768,12 @@ fn check_stacks() {
764768
static mut __sheap: usize;
765769
static mut _stack_start: usize;
766770
}
767-
let stack_len = unsafe { (addr_of!(_stack_start) as usize) - (addr_of!(__sheap) as usize) };
768-
check_stack(
769-
unsafe { addr_of!(__sheap) },
770-
stack_len,
771-
CORE0_STACK_PAINT_WORD,
772-
);
773-
check_stack(
774-
unsafe { CORE1_STACK.as_ptr() },
775-
unsafe { CORE1_STACK.len() * core::mem::size_of::<usize>() },
776-
CORE1_STACK_PAINT_WORD,
777-
);
771+
let stack_len = (addr_of!(_stack_start) as usize) - (addr_of!(__sheap) as usize);
772+
check_stack(addr_of!(__sheap), stack_len, CORE0_STACK_PAINT_WORD);
773+
let stack_start = addr_of!(CORE1_STACK) as *const usize;
774+
let stack_end = unsafe { addr_of!(CORE1_STACK).add(1) } as *const usize;
775+
let stack_len = unsafe { stack_end.offset_from(stack_start) } as usize;
776+
check_stack(stack_start, stack_len, CORE1_STACK_PAINT_WORD);
778777
}
779778

780779
/// Dummy stack checker that does nothing
@@ -1915,8 +1914,8 @@ pub extern "C" fn memory_get_region(region: u8) -> FfiOption<common::MemoryRegio
19151914
0 => {
19161915
// Application Region
19171916
FfiOption::Some(MemoryRegion {
1918-
start: unsafe { addr_of!(_ram_os_start) } as *mut u8,
1919-
length: unsafe { addr_of!(_ram_os_len) } as usize,
1917+
start: addr_of!(_ram_os_start) as *mut u8,
1918+
length: addr_of!(_ram_os_len) as usize,
19201919
kind: common::MemoryKind::Ram.into(),
19211920
})
19221921
}
@@ -2663,17 +2662,7 @@ extern "C" fn compare_and_swap_bool(value: &AtomicBool, old_value: bool, new_val
26632662
/// This should only be when the MCP23S17 has driven our IRQ pin low.
26642663
#[interrupt]
26652664
fn IO_IRQ_BANK0() {
2666-
// The `#[interrupt]` attribute covertly converts this to `&'static mut
2667-
// Option<IrqPin>`
2668-
static mut LOCAL_IRQ_PIN: Option<IrqPin> = None;
2669-
2670-
// This is one-time lazy initialisation. We steal the variables given to us
2671-
// via `IRQ_PIN`.
2672-
if LOCAL_IRQ_PIN.is_none() {
2673-
let mut lock = IRQ_PIN.lock();
2674-
*LOCAL_IRQ_PIN = lock.take();
2675-
}
2676-
if let Some(pin) = LOCAL_IRQ_PIN {
2665+
if let Some(pin) = IRQ_PIN.lock().as_mut() {
26772666
let is_low = pin.is_low().unwrap();
26782667
INTERRUPT_PENDING.store(is_low, Ordering::Relaxed);
26792668
pin.clear_interrupt(hal::gpio::Interrupt::EdgeLow);

src/mutex/mod.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
//! Unlock the cortex-m mutex, it panics on collision, rather than disabling
44
//! interrupts while the lock is held.
55
6-
use atomic_polyfill::{AtomicBool, Ordering};
6+
use portable_atomic::{AtomicBool, Ordering};
77

88
/// A simple no-std mutex.
99
///
1010
/// Uses critical-section to hold an atomic bool, for when you don't have
1111
/// atomic-compare-swap.
1212
pub struct NeoMutex<T> {
13-
locked: atomic_polyfill::AtomicBool,
13+
locked: AtomicBool,
1414
value: core::cell::UnsafeCell<T>,
1515
}
1616

@@ -48,21 +48,21 @@ pub struct NeoMutexGuard<'a, T> {
4848
parent: &'a NeoMutex<T>,
4949
}
5050

51-
impl<'a, T> Drop for NeoMutexGuard<'a, T> {
51+
impl<T> Drop for NeoMutexGuard<'_, T> {
5252
fn drop(&mut self) {
5353
self.parent.locked.store(false, Ordering::Release);
5454
}
5555
}
5656

57-
impl<'a, T> core::ops::Deref for NeoMutexGuard<'a, T> {
57+
impl<T> core::ops::Deref for NeoMutexGuard<'_, T> {
5858
type Target = T;
5959

6060
fn deref(&self) -> &Self::Target {
6161
unsafe { &*self.parent.value.get() }
6262
}
6363
}
6464

65-
impl<'a, T> core::ops::DerefMut for NeoMutexGuard<'a, T> {
65+
impl<T> core::ops::DerefMut for NeoMutexGuard<'_, T> {
6666
fn deref_mut(&mut self) -> &mut Self::Target {
6767
unsafe { &mut *self.parent.value.get() }
6868
}

src/sdcard.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
// Imports
2828
// -----------------------------------------------------------------------------
2929

30-
use atomic_polyfill::{AtomicBool, Ordering};
30+
use core::sync::atomic::{AtomicBool, Ordering};
3131

3232
use super::Hardware;
3333

@@ -38,7 +38,7 @@ use super::Hardware;
3838
/// A type that `embedded-sdmmc` can use to talk over our SPI bus.
3939
pub(crate) struct FakeSpi<'a>(pub(crate) &'a mut Hardware, pub bool);
4040

41-
impl<'a> embedded_hal::blocking::spi::Transfer<u8> for FakeSpi<'a> {
41+
impl embedded_hal::blocking::spi::Transfer<u8> for FakeSpi<'_> {
4242
type Error = core::convert::Infallible;
4343

4444
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
@@ -68,7 +68,7 @@ impl<'a> embedded_hal::blocking::spi::Transfer<u8> for FakeSpi<'a> {
6868
}
6969
}
7070

71-
impl<'a> embedded_hal::blocking::spi::Write<u8> for FakeSpi<'a> {
71+
impl embedded_hal::blocking::spi::Write<u8> for FakeSpi<'_> {
7272
type Error = core::convert::Infallible;
7373

7474
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {

0 commit comments

Comments
 (0)