Are we there yet?
pub fn read<P: AsRef<Path>>(path: P)
-> io::Result<Vec<u8>> {
fn inner(path: &Path) -> io::Result<Vec<u8>> {
let mut file = File::open(path)?;
let mut bytes = Vec::new();
file.read_to_end(&mut bytes)?;
Ok(bytes)
}
inner(path.as_ref())
}
(Pic unrelated.)
rustc
== language standardHypothetical memory layout
Port A
0x10000000 | Output enable |
0x10000001 | Output value |
0x10000002 | Pull-up enable |
0x10000003 | Pull-down enable |
0x10000010 | Input value |
Port B
0x10100000 | Output enable |
0x10100001 | Output value |
0x10100002 | Pull-up enable |
0x10100003 | Pull-down enable |
0x10100010 | Input value |
typedef struct
__attribute__((__packed__))
{
unsigned char output_enable;
unsigned char output_value;
unsigned char pull_up_enable;
unsigned char pull_down_enable;
unsigned char _reserved[12];
unsigned char input_value;
} gpio_port_t;
gpio_port_t* const PORT_A = 0x10000000;
gpio_port_t* const PORT_B = 0x10100000;
void main() {
PORT_A->pull_up_enable = 1;
PORT_B->output_enable = 1;
}
#[repr(C, packed)]
struct GpioPort {
output_enable: u8,
output_value: u8,
pull_up_enable: u8,
pull_down_enable: u8,
_reserved: [u8; 12],
input_value: u8,
}
const PORT_A: *mut GpioPort =
0x10000000 as *mut GpioPort;
const PORT_B: *mut GpioPort =
0x10100000 as *mut GpioPort;
fn main() {
unsafe { (*PORT_A).pull_up_enable = 1 };
unsafe { (*PORT_B).output_enable = 1 };
}
volatile gpio_port_t* const PORT_A = 0x10000000;
void spike() {
PORT_A->output_value = 1;
PORT_A->output_value = 0;
}
use core::ptr::{addr_of_mut, write_volatile};
const PORT_A: *mut GpioPort =
0x10000000 as *mut GpioPort;
fn spike() {
unsafe {
write_volatile(
addr_of_mut!((*PORT_A).output_value),
1
);
write_volatile(
addr_of_mut!((*PORT_A).output_value),
0
)
};
}
pub enum Direction {
Input,
Output,
}
pub enum Enabled {
Enabled,
Disabled,
}
pub enum SignalLevel {
High,
Low,
}
pub struct GpioPort {
raw: *mut GpioPortRaw,
}
impl GpioPort {
pub fn set_direction(&self, direction: Direction) {
unsafe { write_volatile(
addr_of_mut!((*self.raw).output_enable),
match direction {
Direction::Input => 0,
Direction::Output => 1,
},
)};
}
pub fn set_pull_up(&self, enabled: Enabled) { /* ... */ }
pub fn set_pull_down(&self, enabled: Enabled) { /* ... */ }
pub fn set_output(&self, level: SignalLevel) { /* ... */ }
pub fn get_input(&self) -> SignalLevel { /* ... */ }
}
impl GpioPort {
pub fn set_direction(&mut self, direction: Direction) { /* ... */ }
pub fn set_pull_up(&mut self, enabled: Enabled) { /* ... */ }
pub fn set_pull_down(&mut self, enabled: Enabled) { /* ... */ }
pub fn set_output(&mut self, level: SignalLevel) { /* ... */ }
pub fn get_input(&self) -> SignalLevel { /* ... */ }
}
pub enum PullState {
Float,
PullUp,
PullDown,
}
impl GpioPort {
/* ... */
pub fn set_pull_state(&mut self, state: PullState) {
/* Set both pull up and pull down registers */
}
/* ... */
}
pub struct InputPort {
raw: *mut GpioPortRaw,
}
impl InputPort {
pub fn to_output(self) -> OutputPort{
self.set_pull_state(Float);
/* ... set direction register ... */
OutputPort{
raw: self.raw
}
}
pub fn get_level(&self) -> SignalLevel
{ /*...*/ }
pub fn set_pull_state(
&mut self, state: PullState
) { /*...*/}
}
pub struct OutputPort {
raw: *mut GpioPortRaw,
}
impl OutputPort {
pub fn to_input(self) -> InputPort{
/* ... set direction register ... */
InputPort{
raw: self.raw
}
}
pub fn set_level(
&mut self, level: SignalLevel
) { /*...*/ }
}
pub trait PullState {
fn set_registers(raw: *mut GpioPortRaw);
}
pub struct Float;
pub struct PullUp;
pub struct PullDown;
impl PullState for Float { /*...*/ }
impl PullState for PullUp { /*...*/ }
impl PullState for PullDown { /*...*/ }
pub struct InputPort<PS: PullState> {
raw: *mut GpioPortRaw,
_ps: std::marker::PhantomData<PS>,
}
impl<PS: PullState> InputPort<PS> {
pub fn get_level(&self) -> SignalLevel { /*...*/ }
pub fn set_pull_state<PSN:PullState>(self)
-> InputPort::<PSN>
{
PSN::set_registers(self.raw);
InputPort::<PSN> {
raw: self.raw,
_ps: std::marker::PhantomData::<PSN>{},
}
}
pub fn to_output(self) -> OutputPort{
let new_self = self.set_pull_state::<Float>();
/* ... */
}
}
pub fn get_smooth<PS:PullState>(port: InputPort<PS>)
-> SignalLevel
{
const SAMPLES:u8 = 16;
let mut highs = 0;
for _ in 0..SAMPLES {
if port.get_level() == SignalLevel::High {
highs += 1;
}
}
if highs > SAMPLES/2 {
SignalLevel::High
} else {
SignalLevel::Low
}
}
enum
erase()
method to the specific structsrustc
use heapless::Vec;
let mut vec = Vec::<_, 8>::new();
vec.push(1);
vec.push(2);
assert_eq!(vec.len(), 2);
assert_eq!(vec[0], 1);
assert_eq!(vec.pop(), Some(2));
assert_eq!(vec.len(), 1);
vec.extend(
[1, 2, 3].iter().cloned()
);
Vec
, String
Map
, Set
Arc
, Box
Queue
<register>
<name>CR</name>
<description>Control Register</description>
<addressOffset>0x00</addressOffset>
<size>32</size>
<access>read-write</access>
<resetValue>0x00000000</resetValue>
<resetMask>0x1337F7F</resetMask>
<fields>
<!-- EN: Enable -->
<field>
<name>EN</name>
<description>Enable</description>
<bitRange>[0:0]</bitRange>
<access>read-write</access>
<enumeratedValues>
let peripherals = stm32f407::Peripherals::take().unwrap();
cortex_m::interrupt::free(|_cs| {
// Power up the relevant peripherals
peripherals.RCC.ahb1enr.write(|w| w.gpioden().set_bit());
peripherals.RCC.apb1enr.write(| w| w.tim6en().set_bit());
// Configure the pin PD12 as a pullup output pin
peripherals.GPIOD.otyper.write(|w| w.ot12().clear_bit());
peripherals.GPIOD.moder.write(|w| w.moder12().output());
peripherals.GPIOD.pupdr.write(|w| w.pupdr12().pull_up());
// Configure TIM6 for periodic timeouts
let ratio = frequency::APB1 / FREQUENCY;
let psc = u16((ratio - 1) / u32(U16_MAX)).unwrap();
let arr = u16(ratio / u32(psc + 1)).unwrap();
unsafe {
peripherals.TIM6.psc.write(|w| w.psc().bits(psc));
peripherals.TIM6.arr.write(|w| w.arr().bits(arr));
};
peripherals.TIM6.cr1.write(|w| w.opm().clear_bit());
}
defmt::error!("The answer is {=i16}!", 300);
// on the wire: [3, 44, 1]
// string index ^ ^^^^^ `300.to_le_bytes()`
// ^ = intern("The answer is {=i16}!")
defmt::error!("The answer is {=u32}!", 131000);
// on the wire: [4, 184, 255, 1, 0]
// ^^^^^^^^^^^^^^^ 131000.to_le_bytes()
defmt::error!("Data: {=[u8]}!", [0, 1, 2]);
// on the wire: [1, 3, 0, 1, 2]
// string index ^ ^ ^^^^^^^ the slice data
// LEB128(length) ^
$ cargo run --release
Compiling microbit v0.1.0 (/microbit/)
Finished release [optimized + debuginfo] target(s) in 0.17s
Running `probe-rs run --chip nRF51822_xxAA target/thumbv6m-none-eabi/release/microbit`
Erasing sectors ✔ [00:00:00] [############] 5.00 KiB/5.00 KiB @ 8.09 KiB/s (eta 0s )
Programming pages ✔ [00:00:00] [############] 5.00 KiB/5.00 KiB @ 5.29 KiB/s (eta 0s )
Hello from the microbit!
Going to udf to print a stacktrace on the host ...
Frame 0: exp_u128 @ 0x00000fa2
Frame 1: __udf @ 0x000000f2 inline
/.cargo/registry/src/index.crates.io-6f17d22bba15001f/cortex-m-0.7.7/src/../asm/inline.rs:181:5
Frame 2: udf @ 0x00000000000000f2 inline
/.cargo/registry/src/index.crates.io-6f17d22bba15001f/cortex-m-0.7.7/src/call_asm.rs:11:43
Frame 3: panic @ 0x00000000000000f2
/repos/microbit/examples/gpio-hal-blinky/src/main.rs:36:9
Frame 4: exp_u128 @ 0x000006be
/rustc/5680fa18feaa87f3ff04063800aec256c3d4b4be/library/core/src/ptr/const_ptr.rs:921:18
Frame 5: exp_u128 @ 0x000006ec
/rustc/5680fa18feaa87f3ff04063800aec256c3d4b4be/library/core/src/num/bignum.rs:299:60
Frame 6: b @ 0x0000015e inline
cargo run
runs on hardwareBut only if you find good crates first!
#[task(local = [led, state])]
async fn blink(cx: blink::Context) {
loop {
rprintln!("blink");
if *cx.local.state {
cx.local.led.set_high().unwrap();
*cx.local.state = false;
} else {
cx.local.led.set_low().unwrap();
*cx.local.state = true;
}
Mono::delay(1000.millis()).await;
}
}
#[embassy_executor::task]
async fn blink(pin: AnyPin) {
let mut led = Output::new(pin, Level::Low, OutputDrive::Standard);
loop {
led.set_high();
Timer::after_millis(150).await;
led.set_low();
Timer::after_millis(150).await;
}
}
#[embassy_executor::main]
async fn main(spawner: Spawner) {
let p = embassy_nrf::init(Default::default());
spawner.spawn(blink(p.P0_13.degrade())).unwrap();
let mut button = Input::new(p.P0_11, Pull::Up);
loop {
button.wait_for_low().await;
info!("Button pressed!");
button.wait_for_high().await;
info!("Button released!");
}
}