Skip to main content

gb_pak/
tilt.rs

1//! The MBC7 accelerometer.
2//!
3//! Two axes of tilt, the only analogue input the console can read. The sensor
4//! measures gravity, so it reports which way the cartridge is leaning rather than
5//! how fast it is moving, and shaking it reads as noise.
6//!
7//! A reading is latched before it can be read, the same way `rtc` does: write
8//! `0x55` to clear, then `0xAA` to sample.
9//!
10//! ```ignore
11//! let t = gb_pak::tilt::read();
12//! let lean = t.x.wrapping_sub(gb_pak::tilt::CENTRE) as i16;
13//! ```
14
15use core::ptr::{read_volatile, write_volatile};
16
17use crate::{WINDOW, reg};
18
19const CLEAR: *mut u8 = WINDOW as *mut u8;
20const SAMPLE: *mut u8 = (WINDOW + 0x10) as *mut u8;
21const X_LOW: *const u8 = (WINDOW + 0x20) as *const u8;
22const X_HIGH: *const u8 = (WINDOW + 0x30) as *const u8;
23const Y_LOW: *const u8 = (WINDOW + 0x40) as *const u8;
24const Y_HIGH: *const u8 = (WINDOW + 0x50) as *const u8;
25
26/// What each axis reads when the cartridge is level.
27pub const CENTRE: u16 = 0x8000;
28
29/// One latched pair of axes, as the sensor reports them.
30///
31/// Subtract [`CENTRE`] for a signed lean. `x` grows leftward and `y` upward, and
32/// one g moves either by about `0x70`.
33#[derive(Clone, Copy, PartialEq, Eq, Debug)]
34pub struct Tilt {
35    pub x: u16,
36    pub y: u16,
37}
38
39/// Sample both axes.
40pub fn read() -> Tilt {
41    reg::enable();
42    reg::select_raw(0x40);
43
44    unsafe { write_volatile(CLEAR, 0x55) };
45    unsafe { write_volatile(SAMPLE, 0xAA) };
46
47    let x = unsafe { read_volatile(X_LOW) } as u16
48        | (unsafe { read_volatile(X_HIGH) } as u16) << 8;
49    let y = unsafe { read_volatile(Y_LOW) } as u16
50        | (unsafe { read_volatile(Y_HIGH) } as u16) << 8;
51
52    reg::disable();
53    Tilt { x, y }
54}