Skip to content

Commit aeb8322

Browse files
committed
feat(platform): add SystemControl integration example in baremetal mock
Add comprehensive SystemControl integration pattern for I2C hardware initialization and timing configuration. This demonstrates how external system controllers can manage peripheral clocks and resets during I2C setup. Changes: - Add MockSystemControl implementation with clock and reset control - Add MockI2cHardwareWithSystem showing dependency injection pattern - Remove closure-based SystemControl methods from I2C HAL trait - Add comprehensive test suite (31 tests) covering integration patterns - Clean up clippy warnings and improve error handling The new pattern uses composition over complex trait methods, providing clearer separation of concerns between system-level operations (clock/reset) and peripheral-specific operations (I2C timing).
1 parent b0f9cab commit aeb8322

File tree

4 files changed

+1088
-388
lines changed

4 files changed

+1088
-388
lines changed

hal/blocking/src/i2c_hardware.rs

Lines changed: 0 additions & 220 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
//!
3333
//! For non-blocking slave operations, see `openprot-hal-nb::i2c_hardware`.
3434
35-
use crate::system_control::{ErrorType, SystemControl};
3635
use embedded_hal::i2c::{AddressMode, Operation, SevenBitAddress};
3736

3837
/// Core I2C hardware interface providing basic operations
@@ -55,225 +54,6 @@ pub trait I2cHardwareCore {
5554
/// Initialize the I2C hardware with the given configuration
5655
fn init(&mut self, config: &mut Self::Config) -> Result<(), Self::Error>;
5756

58-
/// Initialize the I2C hardware with external system control configuration
59-
///
60-
/// This method provides a flexible way to initialize I2C hardware while allowing
61-
/// external system control configuration through a closure. The closure receives a mutable
62-
/// reference to a system controller implementing the `SystemControl` trait, enabling
63-
/// platform-specific clock and reset setup operations.
64-
///
65-
/// This approach supports dependency injection patterns while maintaining zero-cost
66-
/// abstractions through compile-time monomorphization of the closure.
67-
///
68-
/// # Arguments
69-
///
70-
/// * `config` - Mutable reference to I2C-specific configuration parameters
71-
/// * `system_setup` - Closure that configures the system controller for I2C operation.
72-
/// The closure receives a mutable reference to the system controller and should
73-
/// perform all necessary clock and reset configuration operations (enable clocks,
74-
/// set frequency, release from reset, etc.)
75-
///
76-
/// # Generic Parameters
77-
///
78-
/// * `F` - Closure type that takes a mutable system controller reference and returns
79-
/// a Result. The closure is called exactly once during initialization.
80-
/// * `S` - System controller type that implements the `SystemControl` trait, providing
81-
/// methods for enabling, disabling, and configuring peripheral clocks and resets.
82-
///
83-
/// # Returns
84-
///
85-
/// * `Ok(())` - I2C hardware initialization completed successfully
86-
/// * `Err(Self::Error)` - Initialization failed due to either I2C hardware error
87-
/// or system control error (automatically converted via `From<<S as ErrorType>::Error>`)
88-
///
89-
/// # Errors
90-
///
91-
/// This method can return errors from two sources:
92-
/// - **System control errors**: Any error returned by the system controller
93-
/// operations within the closure will be automatically converted to `Self::Error`
94-
/// - **I2C hardware errors**: Errors from I2C-specific initialization operations.
95-
/// # Examples
96-
///
97-
/// ## Basic System Setup
98-
/// ```text
99-
/// use openprot_hal_blocking::i2c_hardware::I2cHardwareCore;
100-
/// use openprot_hal_blocking::system_control::SystemControl;
101-
///
102-
/// fn initialize_i2c<T: I2cHardwareCore>(
103-
/// mut i2c: T,
104-
/// mut system_controller: impl SystemControl
105-
/// ) -> Result<(), T::Error> {
106-
/// let mut config = create_i2c_config();
107-
///
108-
/// i2c.init_with_system_control(&mut config, |system| {
109-
/// // Release I2C peripheral from reset
110-
/// system.reset_deassert(&ResetId::I2c1)?;
111-
///
112-
/// // Enable I2C peripheral clock
113-
/// system.enable(&ClockId::I2c1)?;
114-
///
115-
/// // Set desired frequency (400kHz)
116-
/// system.set_frequency(&ClockId::I2c1, 400_000)?;
117-
///
118-
/// Ok(())
119-
/// })?;
120-
///
121-
/// Ok(())
122-
/// }
123-
/// ```
124-
fn init_with_system_control<F, S>(
125-
&mut self,
126-
config: &mut Self::Config,
127-
system_setup: F,
128-
) -> Result<(), Self::Error>
129-
where
130-
F: FnOnce(&mut S) -> Result<(), <S as ErrorType>::Error>,
131-
S: SystemControl,
132-
Self::Error: From<<S as ErrorType>::Error>; // Let the I2C error type handle conversion
133-
134-
/// Configure I2C timing parameters with external system control
135-
///
136-
/// This method provides flexible timing configuration by accepting a closure
137-
/// that can interact with a system controller implementing the `SystemControl` trait.
138-
/// This enables runtime clock adjustments, reset management, frequency validation,
139-
/// and platform-specific system configuration during timing setup.
140-
///
141-
/// Unlike the basic `configure_timing` method, this version allows the timing
142-
/// configuration process to interact with comprehensive system-level management,
143-
/// enabling more sophisticated timing calculations and hardware optimization.
144-
///
145-
/// # Arguments
146-
///
147-
/// * `speed` - Target I2C bus speed (e.g., 100_000 for 100kHz, 400_000 for 400kHz)
148-
/// * `timing` - Platform-specific timing configuration parameters
149-
/// * `system_config` - Closure that configures the system controller for optimal I2C timing.
150-
/// The closure receives a mutable reference to the system controller and should
151-
/// perform any necessary clock and reset adjustments for the specified speed.
152-
///
153-
/// # Generic Parameters
154-
///
155-
/// * `F` - Closure type that takes a mutable system controller reference and returns
156-
/// a Result with the actual configured frequency. Called once during timing setup.
157-
/// * `S` - System controller type implementing the `SystemControl` trait, providing
158-
/// methods for clock frequency management, reset control, and configuration.
159-
///
160-
/// # Returns
161-
///
162-
/// * `Ok(actual_frequency)` - Timing configuration successful, returns the actual
163-
/// frequency achieved after system and timing adjustments
164-
/// * `Err(Self::Error)` - Configuration failed due to either I2C timing error
165-
/// or system control error (automatically converted via `From<S::Error>`)
166-
///
167-
/// # Errors
168-
///
169-
/// This method can return errors from multiple sources:
170-
/// - **System control errors**: Any error from system controller operations
171-
/// within the closure will be automatically converted to `Self::Error`
172-
/// - **Timing calculation errors**: Errors from I2C-specific timing calculations
173-
/// - **Hardware constraint errors**: When requested speed cannot be achieved
174-
/// with current system configuration
175-
/// - **Validation errors**: When the configured timing parameters are invalid
176-
///
177-
/// # Examples
178-
///
179-
/// ## Basic System-Aware Timing Configuration
180-
/// ```text
181-
/// use openprot_hal_blocking::i2c_hardware::I2cHardwareCore;
182-
/// use openprot_hal_blocking::system_control::SystemControl;
183-
///
184-
/// fn configure_i2c_timing<T: I2cHardwareCore>(
185-
/// mut i2c: T,
186-
/// mut system_controller: impl SystemControl
187-
/// ) -> Result<u32, T::Error> {
188-
/// let timing_config = create_timing_config();
189-
///
190-
/// let actual_freq = i2c.configure_timing_with_system_control(
191-
/// 400_000, // 400kHz target
192-
/// &timing_config,
193-
/// |system| {
194-
/// // Release from reset if needed
195-
/// system.reset_deassert(&ResetId::I2c1)?;
196-
///
197-
/// // Optimize clock for I2C timing
198-
/// system.enable(&ClockId::I2c1)?;
199-
///
200-
/// // Set optimal source frequency for I2C timing calculations
201-
/// system.set_frequency(&ClockId::I2c1, 48_000_000)?; // 48MHz source
202-
///
203-
/// // Return the actual source frequency for timing calculations
204-
/// system.get_frequency(&ClockId::I2c1)
205-
/// }
206-
/// )?;
207-
///
208-
/// Ok(actual_freq)
209-
/// }
210-
/// ```
211-
///
212-
/// ## Platform with Comprehensive System Setup
213-
/// ```text
214-
/// # use openprot_hal_blocking::i2c_hardware::I2cHardwareCore;
215-
/// # use openprot_hal_blocking::system_control::SystemControl;
216-
///
217-
/// fn platform_precise_timing_config(
218-
/// mut i2c: PlatformI2c
219-
/// ) -> Result<u32, PlatformI2cError> {
220-
/// let mut system_controller = PlatformSystemController::new();
221-
///
222-
/// let timing_config = PlatformTimingConfig {
223-
/// prescaler: 1,
224-
/// scl_delay: 4,
225-
/// sda_delay: 2,
226-
/// scl_high_period: 15,
227-
/// scl_low_period: 19,
228-
/// };
229-
///
230-
/// let actual_freq = i2c.configure_timing_with_system_control(
231-
/// 400_000,
232-
/// &timing_config,
233-
/// |system: &mut PlatformSystemController| {
234-
/// // Ensure clean reset state
235-
/// system.reset_pulse(&ResetId::I2c1, Duration::from_micros(10))?;
236-
///
237-
/// // Configure I2C clock source for precise timing
238-
/// let clock_config = PlatformClockConfig {
239-
/// source: ClockSource::Sysclk, // Use SYSCLK for precision
240-
/// prescaler: 1,
241-
/// };
242-
/// system.configure(&ClockId::I2c1, clock_config)?;
243-
///
244-
/// // Set the optimal frequency for timing calculations
245-
/// system.set_frequency(&ClockId::I2c1, 48_000_000)?;
246-
///
247-
/// // Verify the frequency is stable
248-
/// let freq = system.get_frequency(&ClockId::I2c1)?;
249-
/// if freq < 45_000_000 || freq > 50_000_000 {
250-
/// return Err(SystemError::FrequencyOutOfRange);
251-
/// }
252-
///
253-
/// Ok(freq)
254-
/// }
255-
/// )?;
256-
///
257-
/// Ok(actual_freq)
258-
/// }
259-
/// ```
260-
///
261-
/// # Design Notes
262-
///
263-
/// The integration with `SystemControl` allows the I2C timing configuration to be
264-
/// aware of and coordinate with comprehensive system-level management (clocks and resets),
265-
/// resulting in more accurate timing and better hardware utilization.
266-
fn configure_timing_with_system_control<F, S>(
267-
&mut self,
268-
speed: Self::I2cSpeed,
269-
timing: &Self::TimingConfig,
270-
system_config: F,
271-
) -> Result<u32, Self::Error>
272-
where
273-
F: FnOnce(&mut S) -> Result<u64, <S as ErrorType>::Error>,
274-
S: SystemControl,
275-
Self::Error: From<<S as ErrorType>::Error>;
276-
27757
/// Configure timing parameters (clock speed, setup/hold times)
27858
///
27959
/// Takes timing parameters as input and returns the calculated clock source frequency.

0 commit comments

Comments
 (0)