You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

102 lines
2.9 KiB
Rust

//! GPIO module.
use super::memory_map::gpio::*;
/// The number of pin for the raspberry 3.
const NUMBER_PIN: usize = 54;
/// Value to select the INPUT function of a PIN.
const FSEL_INPUT: u32 = 0b000;
/// Value to select the OUTPUT function of a PIN.
const FSEL_OUTPUT: u32 = 0b001;
/// Value to select the Alternate function 0 of a PIN.
const FSEL_ALTF0: u32 = 0b100;
/// Value to select the Alternate function 1 of a PIN.
const FSEL_ALTF1: u32 = 0b101;
/// Value to select the Alternate function 2 of a PIN.
const FSEL_ALTF2: u32 = 0b110;
/// Value to select the Alternate function 3 of a PIN.
const FSEL_ALTF3: u32 = 0b111;
/// Value to select the Alternate function 4 of a PIN.
const FSEL_ALTF4: u32 = 0b011;
/// Value to select the Alternate function 5 of a PIN.
const FSEL_ALTF5: u32 = 0b010;
/// The possible PIN functions.
pub enum PinFunction {
Input,
Output,
AltFunc0,
AltFunc1,
AltFunc2,
AltFunc3,
AltFunc4,
AltFunc5,
}
/// The possible PIN state when in Output mode.
pub enum PinOutputState {
High,
Low,
}
impl From<PinFunction> for u32 {
fn from(function: PinFunction) -> u32 {
match function {
PinFunction::Input => FSEL_INPUT,
PinFunction::Output => FSEL_OUTPUT,
PinFunction::AltFunc0 => FSEL_ALTF0,
PinFunction::AltFunc1 => FSEL_ALTF1,
PinFunction::AltFunc2 => FSEL_ALTF2,
PinFunction::AltFunc3 => FSEL_ALTF3,
PinFunction::AltFunc4 => FSEL_ALTF4,
PinFunction::AltFunc5 => FSEL_ALTF5,
}
}
}
// TODO: remove Result and use an enum instead of usize
/// Set the function of a Pin.
///
/// # Result
///
/// Return an error if the PIN does not exist.
pub fn set_pin_fonction(n: usize, function: PinFunction) -> Result<(), &'static str> {
if n >= NUMBER_PIN {
return Err("The pin does not exist.");
}
let field = get_fsel(n);
// TODO: SYNC
let address = field.get_address();
let mut val = unsafe { core::ptr::read_volatile(address as *mut u32) };
val &= !field.get_mask();
val |= Into::<u32>::into(function) << field.get_offset();
unsafe {
core::ptr::write_volatile(address as *mut u32, val);
}
Ok(())
}
// TODO: remove Result and use an enum instead of usize
/// Set the state of an output Pin.
///
/// # Result
///
/// Return an error if the PIN does not exist.
pub fn set_pin_output_state(n: usize, state: PinOutputState) -> Result<(), &'static str> {
if n >= NUMBER_PIN {
return Err("The pin does not exist.");
}
let field = match state {
PinOutputState::High => get_set(n),
PinOutputState::Low => get_clr(n),
};
let val = field.get_mask();
let address = field.get_address();
// 0 has no effect on this field: no nead to read-modify-write
unsafe {
core::ptr::write_volatile(address as *mut u32, val);
}
Ok(())
}