From de97392ffd91e31fe10e477df5eb05b50a5aff36 Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Fri, 29 Nov 2024 21:09:42 +0100 Subject: [PATCH 1/3] In examples, allow the static_mut_refs lint For the future, need to investigate: * How to implement DMA without requiring the lifetime of the buffer to be 'static * How to specific the link_section of non-static buffers --- examples/dma.rs | 1 + examples/ethernet-nucleo-h743zi2.rs | 1 + examples/ethernet-rtic-nucleo-h723zg.rs | 1 + examples/ethernet-rtic-stm32h735g-dk.rs | 1 + examples/ethernet-rtic-stm32h747i-disco.rs | 1 + examples/ethernet-stm32h747i-disco.rs | 1 + examples/i2c4_bdma.rs | 1 + examples/mdma.rs | 1 + examples/mdma_bursts.rs | 1 + examples/sai_dma_passthru.rs | 1 + examples/serial-dma.rs | 1 + examples/spi-dma-rtic.rs | 1 + examples/spi-dma.rs | 1 + examples/usb_passthrough.rs | 1 + examples/usb_phy_serial_interrupt.rs | 1 + examples/usb_rtic.rs | 1 + examples/usb_serial.rs | 1 + 17 files changed, 17 insertions(+) diff --git a/examples/dma.rs b/examples/dma.rs index c1ec1762..e0463819 100644 --- a/examples/dma.rs +++ b/examples/dma.rs @@ -1,6 +1,7 @@ //! Example of Memory to Memory Transfer with the DMA #![deny(warnings)] +#![allow(static_mut_refs)] #![no_main] #![no_std] diff --git a/examples/ethernet-nucleo-h743zi2.rs b/examples/ethernet-nucleo-h743zi2.rs index 917f56d8..e9c3408a 100644 --- a/examples/ethernet-nucleo-h743zi2.rs +++ b/examples/ethernet-nucleo-h743zi2.rs @@ -9,6 +9,7 @@ //! This demo does not use smoltcp - see the ethernet-rtic-stm32h747i-disco demo //! for an example of smoltcp #![deny(warnings)] +#![allow(static_mut_refs)] #![no_main] #![no_std] diff --git a/examples/ethernet-rtic-nucleo-h723zg.rs b/examples/ethernet-rtic-nucleo-h723zg.rs index b155bec7..ac00f672 100644 --- a/examples/ethernet-rtic-nucleo-h723zg.rs +++ b/examples/ethernet-rtic-nucleo-h723zg.rs @@ -12,6 +12,7 @@ //! //! `cargo flash --example ethernet-rtic-nucleo-h723zg --features=ethernet,stm32h735 --chip=STM32H723ZGTx` #![deny(warnings)] +#![allow(static_mut_refs)] #![no_main] #![no_std] diff --git a/examples/ethernet-rtic-stm32h735g-dk.rs b/examples/ethernet-rtic-stm32h735g-dk.rs index 9cedf52b..ae11cdcb 100644 --- a/examples/ethernet-rtic-stm32h735g-dk.rs +++ b/examples/ethernet-rtic-stm32h735g-dk.rs @@ -8,6 +8,7 @@ //! The ethernet ring buffers are placed in AXI SRAM, where they can be //! accessed by both the core and the Ethernet DMA. #![deny(warnings)] +#![allow(static_mut_refs)] #![no_main] #![no_std] diff --git a/examples/ethernet-rtic-stm32h747i-disco.rs b/examples/ethernet-rtic-stm32h747i-disco.rs index 682fa111..1ee4d28f 100644 --- a/examples/ethernet-rtic-stm32h747i-disco.rs +++ b/examples/ethernet-rtic-stm32h747i-disco.rs @@ -15,6 +15,7 @@ //! The ethernet ring buffers are placed in SRAM3, where they can be //! accessed by both the core and the Ethernet DMA. #![deny(warnings)] +#![allow(static_mut_refs)] #![no_main] #![no_std] diff --git a/examples/ethernet-stm32h747i-disco.rs b/examples/ethernet-stm32h747i-disco.rs index e4c1a199..95fef117 100644 --- a/examples/ethernet-stm32h747i-disco.rs +++ b/examples/ethernet-stm32h747i-disco.rs @@ -8,6 +8,7 @@ //! This demo does not use smoltcp - see the ethernet-rtic-stm32h747i-disco demo //! for an example of smoltcp #![deny(warnings)] +#![allow(static_mut_refs)] #![no_main] #![no_std] diff --git a/examples/i2c4_bdma.rs b/examples/i2c4_bdma.rs index e6402567..27b3dfa5 100644 --- a/examples/i2c4_bdma.rs +++ b/examples/i2c4_bdma.rs @@ -3,6 +3,7 @@ //! #![deny(warnings)] +#![allow(static_mut_refs)] #![no_std] #![no_main] diff --git a/examples/mdma.rs b/examples/mdma.rs index 1b3451af..9dd9fc90 100644 --- a/examples/mdma.rs +++ b/examples/mdma.rs @@ -1,6 +1,7 @@ //! Example of Memory to Memory Transfer with the Master DMA (MDMA) #![deny(warnings)] +#![allow(static_mut_refs)] #![no_main] #![no_std] diff --git a/examples/mdma_bursts.rs b/examples/mdma_bursts.rs index bfcd6083..a8c21796 100644 --- a/examples/mdma_bursts.rs +++ b/examples/mdma_bursts.rs @@ -6,6 +6,7 @@ //! beats/burst. The latter gives an approximately 25% speedup. #![deny(warnings)] +#![allow(static_mut_refs)] #![no_main] #![no_std] diff --git a/examples/sai_dma_passthru.rs b/examples/sai_dma_passthru.rs index ca6c14c9..7012cdb8 100644 --- a/examples/sai_dma_passthru.rs +++ b/examples/sai_dma_passthru.rs @@ -3,6 +3,7 @@ #![allow(unused_macros)] #![deny(warnings)] +#![allow(static_mut_refs)] #![no_main] #![no_std] diff --git a/examples/serial-dma.rs b/examples/serial-dma.rs index c61a36e2..38490f72 100644 --- a/examples/serial-dma.rs +++ b/examples/serial-dma.rs @@ -8,6 +8,7 @@ //! the transfer. #![deny(warnings)] +#![allow(static_mut_refs)] #![no_main] #![no_std] diff --git a/examples/spi-dma-rtic.rs b/examples/spi-dma-rtic.rs index bd78229c..94198285 100644 --- a/examples/spi-dma-rtic.rs +++ b/examples/spi-dma-rtic.rs @@ -3,6 +3,7 @@ //! //! This example demonstrates using DMA to write data over a TX-only SPI interface. #![deny(warnings)] +#![allow(static_mut_refs)] #![allow(clippy::type_complexity)] #![no_main] #![no_std] diff --git a/examples/spi-dma.rs b/examples/spi-dma.rs index b3a59a2e..ccf01667 100644 --- a/examples/spi-dma.rs +++ b/examples/spi-dma.rs @@ -8,6 +8,7 @@ //! the transfer. #![deny(warnings)] +#![allow(static_mut_refs)] #![no_main] #![no_std] diff --git a/examples/usb_passthrough.rs b/examples/usb_passthrough.rs index f7f68f80..83ee7d49 100644 --- a/examples/usb_passthrough.rs +++ b/examples/usb_passthrough.rs @@ -5,6 +5,7 @@ //! This example uses both USB1 and USB2. This is only possible on devices that //! have the USB2 peripheral. #![deny(warnings)] +#![allow(static_mut_refs)] #![no_std] #![no_main] diff --git a/examples/usb_phy_serial_interrupt.rs b/examples/usb_phy_serial_interrupt.rs index 90b2533a..f37b7ca8 100644 --- a/examples/usb_phy_serial_interrupt.rs +++ b/examples/usb_phy_serial_interrupt.rs @@ -3,6 +3,7 @@ //! This example is for RM0433/RM0399 parts. It has been tested on the Arduino //! Portenta H7 #![deny(warnings)] +#![allow(static_mut_refs)] #![allow(clippy::type_complexity)] #![no_std] #![no_main] diff --git a/examples/usb_rtic.rs b/examples/usb_rtic.rs index 418bb8b6..db48d917 100644 --- a/examples/usb_rtic.rs +++ b/examples/usb_rtic.rs @@ -7,6 +7,7 @@ //! NUCLEO-H743ZI2 board. //! #![deny(warnings)] +#![allow(static_mut_refs)] #![no_std] #![no_main] diff --git a/examples/usb_serial.rs b/examples/usb_serial.rs index ed9100b4..2499495e 100644 --- a/examples/usb_serial.rs +++ b/examples/usb_serial.rs @@ -9,6 +9,7 @@ //! NUCLEO-H743ZI2 board. //! #![deny(warnings)] +#![allow(static_mut_refs)] #![no_std] #![no_main] From d43631e5aae39ba9cfa6b977268e18d6ed0b15cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Levora?= Date: Sat, 7 Dec 2024 09:30:51 +0100 Subject: [PATCH 2/3] Remove static mut for Ethernet examples --- Cargo.toml | 1 + examples/ethernet-nucleo-h743zi2.rs | 50 +++++++-------- examples/ethernet-rtic-nucleo-h723zg.rs | 73 ++++++++------------- examples/ethernet-rtic-stm32h735g-dk.rs | 74 +++++++++------------- examples/ethernet-rtic-stm32h747i-disco.rs | 74 +++++++++------------- examples/ethernet-stm32h747i-disco.rs | 50 +++++++-------- 6 files changed, 131 insertions(+), 191 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e2c1df3d..d1b08e71 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,6 +83,7 @@ tinybmp = "0.5" embedded-graphics = "0.8" otm8009a = "0.1" eg-seven-segment = "0.2.0" +static_cell = "2.1.0" [features] default = ["rt"] diff --git a/examples/ethernet-nucleo-h743zi2.rs b/examples/ethernet-nucleo-h743zi2.rs index e9c3408a..e8aaede6 100644 --- a/examples/ethernet-nucleo-h743zi2.rs +++ b/examples/ethernet-nucleo-h743zi2.rs @@ -9,12 +9,10 @@ //! This demo does not use smoltcp - see the ethernet-rtic-stm32h747i-disco demo //! for an example of smoltcp #![deny(warnings)] -#![allow(static_mut_refs)] #![no_main] #![no_std] extern crate cortex_m_rt as rt; -use core::mem::MaybeUninit; use core::sync::atomic::{AtomicU32, Ordering}; use rt::{entry, exception}; @@ -23,6 +21,7 @@ extern crate cortex_m; #[macro_use] mod utilities; use log::info; +use static_cell::StaticCell; use stm32h7xx_hal::rcc::CoreClocks; use stm32h7xx_hal::{ethernet, ethernet::PHY}; @@ -53,8 +52,7 @@ const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44]; /// Ethernet descriptor rings are a global singleton #[link_section = ".sram3.eth"] -static mut DES_RING: MaybeUninit> = - MaybeUninit::uninit(); +static DES_RING: StaticCell> = StaticCell::new(); // the program entry point #[entry] @@ -114,30 +112,26 @@ fn main() -> ! { assert_eq!(ccdr.clocks.pclk4().raw(), 100_000_000); // PCLK 100MHz let mac_addr = smoltcp::wire::EthernetAddress::from_bytes(&MAC_ADDRESS); - let (_eth_dma, eth_mac) = unsafe { - DES_RING.write(ethernet::DesRing::new()); - - ethernet::new( - dp.ETHERNET_MAC, - dp.ETHERNET_MTL, - dp.ETHERNET_DMA, - ( - rmii_ref_clk, - rmii_mdio, - rmii_mdc, - rmii_crs_dv, - rmii_rxd0, - rmii_rxd1, - rmii_tx_en, - rmii_txd0, - rmii_txd1, - ), - DES_RING.assume_init_mut(), - mac_addr, - ccdr.peripheral.ETH1MAC, - &ccdr.clocks, - ) - }; + let (_eth_dma, eth_mac) = ethernet::new( + dp.ETHERNET_MAC, + dp.ETHERNET_MTL, + dp.ETHERNET_DMA, + ( + rmii_ref_clk, + rmii_mdio, + rmii_mdc, + rmii_crs_dv, + rmii_rxd0, + rmii_rxd1, + rmii_tx_en, + rmii_txd0, + rmii_txd1, + ), + DES_RING.init_with(ethernet::DesRing::new), + mac_addr, + ccdr.peripheral.ETH1MAC, + &ccdr.clocks, + ); // Initialise ethernet PHY... let mut lan8742a = ethernet::phy::LAN8742A::new(eth_mac.set_phy_addr(0)); diff --git a/examples/ethernet-rtic-nucleo-h723zg.rs b/examples/ethernet-rtic-nucleo-h723zg.rs index ac00f672..4d1d7593 100644 --- a/examples/ethernet-rtic-nucleo-h723zg.rs +++ b/examples/ethernet-rtic-nucleo-h723zg.rs @@ -12,7 +12,6 @@ //! //! `cargo flash --example ethernet-rtic-nucleo-h723zg --features=ethernet,stm32h735 --chip=STM32H723ZGTx` #![deny(warnings)] -#![allow(static_mut_refs)] #![no_main] #![no_std] @@ -20,14 +19,14 @@ #[allow(unused)] mod utilities; -use core::mem::MaybeUninit; -use core::ptr::addr_of_mut; use core::sync::atomic::AtomicU32; use smoltcp::iface::{Config, Interface, SocketSet, SocketStorage}; use smoltcp::time::Instant; use smoltcp::wire::{HardwareAddress, IpAddress, IpCidr}; +use static_cell::StaticCell; + use stm32h7xx_hal::{ethernet, rcc::CoreClocks, stm32}; /// Configure SYSTICK for 1ms timebase @@ -50,17 +49,16 @@ const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44]; /// Ethernet descriptor rings are a global singleton #[link_section = ".axisram.eth"] -static mut DES_RING: MaybeUninit> = - MaybeUninit::uninit(); +static DES_RING: StaticCell> = StaticCell::new(); /// Net storage with static initialisation - another global singleton pub struct NetStorageStatic<'a> { socket_storage: [SocketStorage<'a>; 8], } -// MaybeUninit allows us write code that is correct even if STORE is not +// StaticCell allows us write code that is correct even if STORE is not // initialised by the runtime -static mut STORE: MaybeUninit = MaybeUninit::uninit(); +static STORE: StaticCell = StaticCell::new(); pub struct Net<'a> { iface: Interface, @@ -164,30 +162,26 @@ mod app { assert_eq!(ccdr.clocks.pclk4().raw(), 100_000_000); // PCLK 100MHz let mac_addr = smoltcp::wire::EthernetAddress::from_bytes(&MAC_ADDRESS); - let (eth_dma, eth_mac) = unsafe { - DES_RING.write(ethernet::DesRing::new()); - - ethernet::new( - ctx.device.ETHERNET_MAC, - ctx.device.ETHERNET_MTL, - ctx.device.ETHERNET_DMA, - ( - rmii_ref_clk, - rmii_mdio, - rmii_mdc, - rmii_crs_dv, - rmii_rxd0, - rmii_rxd1, - rmii_tx_en, - rmii_txd0, - rmii_txd1, - ), - DES_RING.assume_init_mut(), - mac_addr, - ccdr.peripheral.ETH1MAC, - &ccdr.clocks, - ) - }; + let (eth_dma, eth_mac) = ethernet::new( + ctx.device.ETHERNET_MAC, + ctx.device.ETHERNET_MTL, + ctx.device.ETHERNET_DMA, + ( + rmii_ref_clk, + rmii_mdio, + rmii_mdc, + rmii_crs_dv, + rmii_rxd0, + rmii_rxd1, + rmii_tx_en, + rmii_txd0, + rmii_txd1, + ), + DES_RING.init_with(ethernet::DesRing::new), + mac_addr, + ccdr.peripheral.ETH1MAC, + &ccdr.clocks, + ); // Initialise ethernet PHY... let mut lan8742a = ethernet::phy::LAN8742A::new(eth_mac); @@ -197,20 +191,9 @@ mod app { unsafe { ethernet::enable_interrupt() }; - // unsafe: mutable reference to static storage, we only do this once - let store = unsafe { - let store_ptr = STORE.as_mut_ptr(); - - // Initialise the socket_storage field. Using `write` instead of - // assignment via `=` to not call `drop` on the old, uninitialised - // value - addr_of_mut!((*store_ptr).socket_storage) - .write([SocketStorage::EMPTY; 8]); - - // Now that all fields are initialised we can safely use - // assume_init_mut to return a mutable reference to STORE - STORE.assume_init_mut() - }; + let store = STORE.init_with(|| NetStorageStatic { + socket_storage: [SocketStorage::EMPTY; 8], + }); let net = Net::new(store, eth_dma, mac_addr.into()); diff --git a/examples/ethernet-rtic-stm32h735g-dk.rs b/examples/ethernet-rtic-stm32h735g-dk.rs index ae11cdcb..94f9ec02 100644 --- a/examples/ethernet-rtic-stm32h735g-dk.rs +++ b/examples/ethernet-rtic-stm32h735g-dk.rs @@ -8,7 +8,6 @@ //! The ethernet ring buffers are placed in AXI SRAM, where they can be //! accessed by both the core and the Ethernet DMA. #![deny(warnings)] -#![allow(static_mut_refs)] #![no_main] #![no_std] @@ -16,14 +15,14 @@ #[allow(unused)] mod utilities; -use core::mem::MaybeUninit; -use core::ptr::addr_of_mut; use core::sync::atomic::AtomicU32; use smoltcp::iface::{Config, Interface, SocketSet, SocketStorage}; use smoltcp::time::Instant; use smoltcp::wire::{HardwareAddress, IpAddress, IpCidr}; +use static_cell::StaticCell; + use stm32h7xx_hal::{ethernet, rcc::CoreClocks, stm32}; /// Configure SYSTICK for 1ms timebase @@ -46,16 +45,16 @@ const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44]; /// Ethernet descriptor rings are a global singleton #[link_section = ".axisram.eth"] -static mut DES_RING: MaybeUninit> = - MaybeUninit::uninit(); +static DES_RING: StaticCell> = StaticCell::new(); // This data will be held by Net through a mutable reference pub struct NetStorageStatic<'a> { socket_storage: [SocketStorage<'a>; 8], } -// MaybeUninit allows us write code that is correct even if STORE is not + +// StaticCell allows us write code that is correct even if STORE is not // initialised by the runtime -static mut STORE: MaybeUninit = MaybeUninit::uninit(); +static STORE: StaticCell = StaticCell::new(); pub struct Net<'a> { iface: Interface, @@ -158,30 +157,26 @@ mod app { assert_eq!(ccdr.clocks.pclk4().raw(), 100_000_000); // PCLK 100MHz let mac_addr = smoltcp::wire::EthernetAddress::from_bytes(&MAC_ADDRESS); - let (eth_dma, eth_mac) = unsafe { - DES_RING.write(ethernet::DesRing::new()); - - ethernet::new( - ctx.device.ETHERNET_MAC, - ctx.device.ETHERNET_MTL, - ctx.device.ETHERNET_DMA, - ( - rmii_ref_clk, - rmii_mdio, - rmii_mdc, - rmii_crs_dv, - rmii_rxd0, - rmii_rxd1, - rmii_tx_en, - rmii_txd0, - rmii_txd1, - ), - DES_RING.assume_init_mut(), - mac_addr, - ccdr.peripheral.ETH1MAC, - &ccdr.clocks, - ) - }; + let (eth_dma, eth_mac) = ethernet::new( + ctx.device.ETHERNET_MAC, + ctx.device.ETHERNET_MTL, + ctx.device.ETHERNET_DMA, + ( + rmii_ref_clk, + rmii_mdio, + rmii_mdc, + rmii_crs_dv, + rmii_rxd0, + rmii_rxd1, + rmii_tx_en, + rmii_txd0, + rmii_txd1, + ), + DES_RING.init_with(ethernet::DesRing::new), + mac_addr, + ccdr.peripheral.ETH1MAC, + &ccdr.clocks, + ); // Initialise ethernet PHY... let mut lan8742a = ethernet::phy::LAN8742A::new(eth_mac); @@ -191,20 +186,9 @@ mod app { unsafe { ethernet::enable_interrupt() }; - // unsafe: mutable reference to static storage, we only do this once - let store = unsafe { - let store_ptr = STORE.as_mut_ptr(); - - // Initialise the socket_storage field. Using `write` instead of - // assignment via `=` to not call `drop` on the old, uninitialised - // value - addr_of_mut!((*store_ptr).socket_storage) - .write([SocketStorage::EMPTY; 8]); - - // Now that all fields are initialised we can safely use - // assume_init_mut to return a mutable reference to STORE - STORE.assume_init_mut() - }; + let store = STORE.init_with(|| NetStorageStatic { + socket_storage: [SocketStorage::EMPTY; 8], + }); let net = Net::new(store, eth_dma, mac_addr.into(), Instant::ZERO); diff --git a/examples/ethernet-rtic-stm32h747i-disco.rs b/examples/ethernet-rtic-stm32h747i-disco.rs index 1ee4d28f..1c710f9e 100644 --- a/examples/ethernet-rtic-stm32h747i-disco.rs +++ b/examples/ethernet-rtic-stm32h747i-disco.rs @@ -15,7 +15,6 @@ //! The ethernet ring buffers are placed in SRAM3, where they can be //! accessed by both the core and the Ethernet DMA. #![deny(warnings)] -#![allow(static_mut_refs)] #![no_main] #![no_std] @@ -23,14 +22,14 @@ #[allow(unused)] mod utilities; -use core::mem::MaybeUninit; -use core::ptr::addr_of_mut; use core::sync::atomic::AtomicU32; use smoltcp::iface::{Config, Interface, SocketSet, SocketStorage}; use smoltcp::time::Instant; use smoltcp::wire::{HardwareAddress, IpAddress, IpCidr}; +use static_cell::StaticCell; + use stm32h7xx_hal::{ethernet, rcc::CoreClocks, stm32}; /// Configure SYSTICK for 1ms timebase @@ -53,16 +52,16 @@ const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44]; /// Ethernet descriptor rings are a global singleton #[link_section = ".sram3.eth"] -static mut DES_RING: MaybeUninit> = - MaybeUninit::uninit(); +static DES_RING: StaticCell> = StaticCell::new(); // This data will be held by Net through a mutable reference pub struct NetStorageStatic<'a> { socket_storage: [SocketStorage<'a>; 8], } -// MaybeUninit allows us write code that is correct even if STORE is not + +// StaticCell allows us write code that is correct even if STORE is not // initialised by the runtime -static mut STORE: MaybeUninit = MaybeUninit::uninit(); +static STORE: StaticCell = StaticCell::new(); pub struct Net<'a> { iface: Interface, @@ -168,30 +167,26 @@ mod app { assert_eq!(ccdr.clocks.pclk4().raw(), 100_000_000); // PCLK 100MHz let mac_addr = smoltcp::wire::EthernetAddress::from_bytes(&MAC_ADDRESS); - let (eth_dma, eth_mac) = unsafe { - DES_RING.write(ethernet::DesRing::new()); - - ethernet::new( - ctx.device.ETHERNET_MAC, - ctx.device.ETHERNET_MTL, - ctx.device.ETHERNET_DMA, - ( - rmii_ref_clk, - rmii_mdio, - rmii_mdc, - rmii_crs_dv, - rmii_rxd0, - rmii_rxd1, - rmii_tx_en, - rmii_txd0, - rmii_txd1, - ), - DES_RING.assume_init_mut(), - mac_addr, - ccdr.peripheral.ETH1MAC, - &ccdr.clocks, - ) - }; + let (eth_dma, eth_mac) = ethernet::new( + ctx.device.ETHERNET_MAC, + ctx.device.ETHERNET_MTL, + ctx.device.ETHERNET_DMA, + ( + rmii_ref_clk, + rmii_mdio, + rmii_mdc, + rmii_crs_dv, + rmii_rxd0, + rmii_rxd1, + rmii_tx_en, + rmii_txd0, + rmii_txd1, + ), + DES_RING.init_with(ethernet::DesRing::new), + mac_addr, + ccdr.peripheral.ETH1MAC, + &ccdr.clocks, + ); // Initialise ethernet PHY... let mut lan8742a = ethernet::phy::LAN8742A::new(eth_mac); @@ -201,20 +196,9 @@ mod app { unsafe { ethernet::enable_interrupt() }; - // unsafe: mutable reference to static storage, we only do this once - let store = unsafe { - let store_ptr = STORE.as_mut_ptr(); - - // Initialise the socket_storage field. Using `write` instead of - // assignment via `=` to not call `drop` on the old, uninitialised - // value - addr_of_mut!((*store_ptr).socket_storage) - .write([SocketStorage::EMPTY; 8]); - - // Now that all fields are initialised we can safely use - // assume_init_mut to return a mutable reference to STORE - STORE.assume_init_mut() - }; + let store = STORE.init_with(|| NetStorageStatic { + socket_storage: [SocketStorage::EMPTY; 8], + }); let net = Net::new(store, eth_dma, mac_addr.into(), Instant::ZERO); diff --git a/examples/ethernet-stm32h747i-disco.rs b/examples/ethernet-stm32h747i-disco.rs index 95fef117..653f4931 100644 --- a/examples/ethernet-stm32h747i-disco.rs +++ b/examples/ethernet-stm32h747i-disco.rs @@ -8,11 +8,9 @@ //! This demo does not use smoltcp - see the ethernet-rtic-stm32h747i-disco demo //! for an example of smoltcp #![deny(warnings)] -#![allow(static_mut_refs)] #![no_main] #![no_std] -use core::mem::MaybeUninit; use cortex_m_rt as rt; use rt::{entry, exception}; @@ -21,6 +19,7 @@ use rt::{entry, exception}; mod utilities; use log::info; +use static_cell::StaticCell; use stm32h7xx_hal::{ethernet, ethernet::PHY}; use stm32h7xx_hal::{prelude::*, stm32, stm32::interrupt}; @@ -30,8 +29,7 @@ const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44]; /// Ethernet descriptor rings are a global singleton #[link_section = ".sram3.eth"] -static mut DES_RING: MaybeUninit> = - MaybeUninit::uninit(); +static DES_RING: StaticCell> = StaticCell::new(); // the program entry point #[entry] @@ -87,30 +85,26 @@ fn main() -> ! { assert_eq!(ccdr.clocks.pclk4().raw(), 100_000_000); // PCLK 100MHz let mac_addr = smoltcp::wire::EthernetAddress::from_bytes(&MAC_ADDRESS); - let (_eth_dma, eth_mac) = unsafe { - DES_RING.write(ethernet::DesRing::new()); - - ethernet::new( - dp.ETHERNET_MAC, - dp.ETHERNET_MTL, - dp.ETHERNET_DMA, - ( - rmii_ref_clk, - rmii_mdio, - rmii_mdc, - rmii_crs_dv, - rmii_rxd0, - rmii_rxd1, - rmii_tx_en, - rmii_txd0, - rmii_txd1, - ), - DES_RING.assume_init_mut(), - mac_addr, - ccdr.peripheral.ETH1MAC, - &ccdr.clocks, - ) - }; + let (_eth_dma, eth_mac) = ethernet::new( + dp.ETHERNET_MAC, + dp.ETHERNET_MTL, + dp.ETHERNET_DMA, + ( + rmii_ref_clk, + rmii_mdio, + rmii_mdc, + rmii_crs_dv, + rmii_rxd0, + rmii_rxd1, + rmii_tx_en, + rmii_txd0, + rmii_txd1, + ), + DES_RING.init_with(ethernet::DesRing::new), + mac_addr, + ccdr.peripheral.ETH1MAC, + &ccdr.clocks, + ); // Initialise ethernet PHY... let mut lan8742a = ethernet::phy::LAN8742A::new(eth_mac.set_phy_addr(0)); From c8b76c5bb510b16124b5ea1da4554a6734fe49bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Levora?= Date: Sat, 7 Dec 2024 11:31:22 +0100 Subject: [PATCH 3/3] Replace static mut for some examples with StaticCell --- examples/serial-dma.rs | 36 +++++++++--------------------------- examples/spi-dma-rtic.rs | 23 ++++++----------------- examples/spi-dma.rs | 37 ++++++++----------------------------- examples/usb_passthrough.rs | 28 +++++++--------------------- examples/usb_serial.rs | 16 ++++------------ 5 files changed, 34 insertions(+), 106 deletions(-) diff --git a/examples/serial-dma.rs b/examples/serial-dma.rs index 38490f72..dc6fff06 100644 --- a/examples/serial-dma.rs +++ b/examples/serial-dma.rs @@ -8,11 +8,10 @@ //! the transfer. #![deny(warnings)] -#![allow(static_mut_refs)] #![no_main] #![no_std] -use core::{mem, mem::MaybeUninit}; +use core::{array, mem}; use cortex_m_rt::entry; #[macro_use] @@ -25,6 +24,7 @@ use stm32h7xx_hal::dma::{ }; use log::info; +use static_cell::StaticCell; // DMA1/DMA2 cannot interact with our stack. Instead, buffers for use with the // DMA must be placed somewhere that DMA1/DMA2 can access. In this case we use @@ -32,10 +32,10 @@ use log::info; // // The runtime does not initialise these SRAM banks #[link_section = ".axisram.buffers"] -static mut SHORT_BUFFER: MaybeUninit<[u8; 10]> = MaybeUninit::uninit(); +static SHORT_BUFFER: StaticCell<[u8; 10]> = StaticCell::new(); #[link_section = ".axisram.buffers"] -static mut LONG_BUFFER: MaybeUninit<[u32; 0x8000]> = MaybeUninit::uninit(); +static LONG_BUFFER: StaticCell<[u32; 0x8000]> = StaticCell::new(); #[entry] fn main() -> ! { @@ -81,30 +81,12 @@ fn main() -> ! { // Initialise the source buffer, without taking any references to // uninitialised memory - let short_buffer: &'static mut [u8; 10] = { - let buf: &mut [MaybeUninit; 10] = - unsafe { &mut *(core::ptr::addr_of_mut!(SHORT_BUFFER) as *mut _) }; - - for (i, value) in buf.iter_mut().enumerate() { - unsafe { - value.as_mut_ptr().write(i as u8 + 96); // 0x60, 0x61, 0x62... - } - } - unsafe { SHORT_BUFFER.assume_init_mut() } - }; + let short_buffer: &'static mut [u8; 10] = + SHORT_BUFFER.init_with(|| array::from_fn(|i| i as u8 + 0x60)); + // view u32 buffer as u8. Endianess is undefined (little-endian on STM32H7) - let long_buffer: &'static mut [u8; 0x2_0010] = { - let buf: &mut [MaybeUninit; 0x8004] = - unsafe { &mut *(core::ptr::addr_of_mut!(LONG_BUFFER) as *mut _) }; - - for (i, value) in buf.iter_mut().enumerate() { - unsafe { - value.as_mut_ptr().write(i as u32); - } - } - unsafe { - &mut *(core::ptr::addr_of_mut!(LONG_BUFFER) as *mut [u8; 0x2_0010]) - } + let long_buffer: &'static mut [u8; 0x2_0010] = unsafe { + mem::transmute(LONG_BUFFER.init_with(|| array::from_fn(|i| i as u32))) }; // Setup the DMA transfer on stream 0 diff --git a/examples/spi-dma-rtic.rs b/examples/spi-dma-rtic.rs index 94198285..16e067e5 100644 --- a/examples/spi-dma-rtic.rs +++ b/examples/spi-dma-rtic.rs @@ -3,12 +3,13 @@ //! //! This example demonstrates using DMA to write data over a TX-only SPI interface. #![deny(warnings)] -#![allow(static_mut_refs)] #![allow(clippy::type_complexity)] #![no_main] #![no_std] -use core::mem::MaybeUninit; +use core::array; + +use static_cell::StaticCell; #[macro_use] mod utilities; @@ -22,7 +23,7 @@ const BUFFER_SIZE: usize = 100; // // The runtime does not initialise these SRAM banks #[link_section = ".axisram.buffers"] -static mut BUFFER: MaybeUninit<[u8; BUFFER_SIZE]> = MaybeUninit::uninit(); +static BUFFER: StaticCell<[u8; BUFFER_SIZE]> = StaticCell::new(); #[rtic::app(device = stm32h7xx_hal::stm32, peripherals = true)] mod app { @@ -96,20 +97,8 @@ mod app { cs.set_high(); // Initialize our transmit buffer. - let buffer: &'static mut [u8; BUFFER_SIZE] = { - let buf: &mut [MaybeUninit; BUFFER_SIZE] = unsafe { - &mut *(core::ptr::addr_of_mut!(BUFFER) - as *mut [MaybeUninit; BUFFER_SIZE]) - }; - - for (i, value) in buf.iter_mut().enumerate() { - unsafe { - value.as_mut_ptr().write(i as u8 + 0x60); // 0x60, 0x61, 0x62... - } - } - - unsafe { BUFFER.assume_init_mut() } - }; + let buffer: &'static mut [u8; BUFFER_SIZE] = + BUFFER.init_with(|| array::from_fn(|i| i as u8 + 0x60)); let streams = hal::dma::dma::StreamsTuple::new( ctx.device.DMA1, diff --git a/examples/spi-dma.rs b/examples/spi-dma.rs index ccf01667..fd1de9db 100644 --- a/examples/spi-dma.rs +++ b/examples/spi-dma.rs @@ -8,11 +8,10 @@ //! the transfer. #![deny(warnings)] -#![allow(static_mut_refs)] #![no_main] #![no_std] -use core::{mem, mem::MaybeUninit}; +use core::{array, mem}; use cortex_m_rt::entry; #[macro_use] @@ -25,6 +24,7 @@ use stm32h7xx_hal::dma::{ }; use log::info; +use static_cell::StaticCell; // DMA1/DMA2 cannot interact with our stack. Instead, buffers for use with the // DMA must be placed somewhere that DMA1/DMA2 can access. In this case we use @@ -32,10 +32,10 @@ use log::info; // // The runtime does not initialise these SRAM banks #[link_section = ".axisram.buffers"] -static mut SHORT_BUFFER: MaybeUninit<[u8; 10]> = MaybeUninit::uninit(); +static SHORT_BUFFER: StaticCell<[u8; 10]> = StaticCell::new(); #[link_section = ".axisram.buffers"] -static mut LONG_BUFFER: MaybeUninit<[u32; 0x8000]> = MaybeUninit::uninit(); +static LONG_BUFFER: StaticCell<[u32; 0x8000]> = StaticCell::new(); #[entry] fn main() -> ! { @@ -81,32 +81,11 @@ fn main() -> ! { // SPI must be disabled to configure DMA let spi = spi.disable(); - // Initialise the source buffer, without taking any references to - // uninitialisated memory - let short_buffer: &'static mut [u8; 10] = { - let buf: &mut [MaybeUninit; 10] = - unsafe { &mut *(core::ptr::addr_of_mut!(SHORT_BUFFER) as *mut _) }; - - for (i, value) in buf.iter_mut().enumerate() { - unsafe { - value.as_mut_ptr().write(i as u8 + 96); // 0x60, 0x61, 0x62... - } - } - unsafe { SHORT_BUFFER.assume_init_mut() } - }; + let short_buffer: &'static mut [u8; 10] = + SHORT_BUFFER.init_with(|| array::from_fn(|i| i as u8 + 0x60)); // view u32 buffer as u8. Endianess is undefined (little-endian on STM32H7) - let long_buffer: &'static mut [u8; 0x2_0010] = { - let buf: &mut [MaybeUninit; 0x8004] = - unsafe { &mut *(core::ptr::addr_of_mut!(LONG_BUFFER) as *mut _) }; - - for (i, value) in buf.iter_mut().enumerate() { - unsafe { - value.as_mut_ptr().write(i as u32); - } - } - unsafe { - &mut *(core::ptr::addr_of_mut!(LONG_BUFFER) as *mut [u8; 0x2_0010]) - } + let long_buffer: &'static mut [u8; 0x2_0010] = unsafe { + mem::transmute(LONG_BUFFER.init_with(|| array::from_fn(|i| i as u32))) }; // Setup the DMA transfer on stream 0 diff --git a/examples/usb_passthrough.rs b/examples/usb_passthrough.rs index 83ee7d49..e816a8ac 100644 --- a/examples/usb_passthrough.rs +++ b/examples/usb_passthrough.rs @@ -5,24 +5,22 @@ //! This example uses both USB1 and USB2. This is only possible on devices that //! have the USB2 peripheral. #![deny(warnings)] -#![allow(static_mut_refs)] #![no_std] #![no_main] use panic_itm as _; -use core::mem::MaybeUninit; - use cortex_m_rt::entry; use stm32h7xx_hal::rcc::rec::UsbClkSel; use stm32h7xx_hal::usb_hs::{UsbBus, USB1, USB2}; use stm32h7xx_hal::{prelude::*, stm32}; +use static_cell::StaticCell; use usb_device::prelude::*; -static mut EP_MEMORY_1: MaybeUninit<[u32; 1024]> = MaybeUninit::uninit(); -static mut EP_MEMORY_2: MaybeUninit<[u32; 1024]> = MaybeUninit::uninit(); +static EP_MEMORY_1: StaticCell<[u32; 1024]> = StaticCell::new(); +static EP_MEMORY_2: StaticCell<[u32; 1024]> = StaticCell::new(); #[entry] fn main() -> ! { @@ -73,24 +71,12 @@ fn main() -> ! { ); // Initialise EP_MEMORY_1 to zero - unsafe { - let buf: &mut [MaybeUninit; 1024] = - &mut *(core::ptr::addr_of_mut!(EP_MEMORY_1) as *mut _); - for value in buf.iter_mut() { - value.as_mut_ptr().write(0); - } - } + let ep_memory_1 = EP_MEMORY_1.init_with(|| [0; 1024]); // Initialise EP_MEMORY_2 to zero - unsafe { - let buf: &mut [MaybeUninit; 1024] = - &mut *(core::ptr::addr_of_mut!(EP_MEMORY_2) as *mut _); - for value in buf.iter_mut() { - value.as_mut_ptr().write(0); - } - } + let ep_memory_2 = EP_MEMORY_2.init_with(|| [0; 1024]); // Port 1 - let usb1_bus = UsbBus::new(usb1, unsafe { EP_MEMORY_1.assume_init_mut() }); + let usb1_bus = UsbBus::new(usb1, ep_memory_1); let mut serial1 = usbd_serial::SerialPort::new(&usb1_bus); let mut usb1_dev = UsbDeviceBuilder::new(&usb1_bus, UsbVidPid(0x16c0, 0x27dd)) @@ -103,7 +89,7 @@ fn main() -> ! { .build(); // Port 2 - let usb2_bus = UsbBus::new(usb2, unsafe { EP_MEMORY_2.assume_init_mut() }); + let usb2_bus = UsbBus::new(usb2, ep_memory_2); let mut serial2 = usbd_serial::SerialPort::new(&usb2_bus); let mut usb2_dev = UsbDeviceBuilder::new(&usb2_bus, UsbVidPid(0x16c0, 0x27dd)) diff --git a/examples/usb_serial.rs b/examples/usb_serial.rs index 2499495e..d76ccb10 100644 --- a/examples/usb_serial.rs +++ b/examples/usb_serial.rs @@ -9,12 +9,9 @@ //! NUCLEO-H743ZI2 board. //! #![deny(warnings)] -#![allow(static_mut_refs)] #![no_std] #![no_main] -use core::mem::MaybeUninit; - #[macro_use] #[allow(unused)] mod utilities; @@ -25,9 +22,10 @@ use stm32h7xx_hal::rcc::rec::UsbClkSel; use stm32h7xx_hal::usb_hs::{UsbBus, USB1}; use stm32h7xx_hal::{prelude::*, stm32}; +use static_cell::StaticCell; use usb_device::prelude::*; -static mut EP_MEMORY: MaybeUninit<[u32; 1024]> = MaybeUninit::uninit(); +static EP_MEMORY: StaticCell<[u32; 1024]> = StaticCell::new(); #[entry] fn main() -> ! { @@ -77,16 +75,10 @@ fn main() -> ! { ); // Initialise EP_MEMORY to zero - unsafe { - let buf: &mut [MaybeUninit; 1024] = - &mut *(core::ptr::addr_of_mut!(EP_MEMORY) as *mut _); - for value in buf.iter_mut() { - value.as_mut_ptr().write(0); - } - } + let ep_memory = EP_MEMORY.init_with(|| [0; 1024]); // Now we may assume that EP_MEMORY is initialised - let usb_bus = UsbBus::new(usb, unsafe { EP_MEMORY.assume_init_mut() }); + let usb_bus = UsbBus::new(usb, ep_memory); let mut serial = usbd_serial::SerialPort::new(&usb_bus);