Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
{
"recommendations": [
"rust-lang.rust-analyzer",
"tamasfe.even-better-toml",
]
"recommendations": ["rust-lang.rust-analyzer", "tamasfe.even-better-toml"]
}
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
},
"rust-analyzer.cargo.extraEnv": {
"RUSTUP_TOOLCHAIN": "esp"
},
}
}
17 changes: 10 additions & 7 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@
"type": "shell",
"command": "cargo",
"args": [
"+stable", // needed to use the host toolchain and not conflict with the esp toolchain
"test",
"--workspace",
"--exclude",
"focus",
"--features",
"unit-tests"
],
"group": "build",
"group":{
"kind":"test",
"isDefault": true
},
"label": "unit-tests",
"problemMatcher": []
},
Expand Down Expand Up @@ -43,18 +47,17 @@
"problemMatcher": []
},
{
"type": "cargo",
"command": "run",
"type": "shell",
"command": "sh",
"args": [
"--target",
"xtensa-esp32s3-none-elf"
"${cwd}/scripts/build_flash_monitor.sh"
],
"group": {
"kind": "build",
"isDefault": true
"isDefault": false
},
"label": "Build, Flash, Monitor",
"problemMatcher": []
}
},
]
}
44 changes: 44 additions & 0 deletions .zed/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Project tasks configuration. See https://zed.dev/docs/tasks for documentation.
[
{
"label": "Test",
"command": "cargo",
"args": [
"+stable",
"test",
"--workspace",
"--exclude",
"focus",
"--features",
"unit-tests"
],
"use_new_terminal": false,
"allow_concurrent_runs": false,
"reveal": "always",
"reveal_target": "dock",
"hide": "never",
"shell": "system"
},
{
"label": "Run",
"command": "sh",
"args": ["./scripts/build_flash_monitor.sh"],
"use_new_terminal": false,
"allow_concurrent_runs": false,
"reveal": "always",
"reveal_target": "dock",
"hide": "never",
"shell": "system"
},
{
"label": "Clean",
"command": "cargo",
"args": ["clean"],
"use_new_terminal": false,
"allow_concurrent_runs": false,
"reveal": "always",
"reveal_target": "dock",
"hide": "never",
"shell": "system"
}
]
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[workspace]
resolver = "3"
members = [ "focus", "hl_driver"]
members = ["focus", "hl_driver"]


[profile.dev]
Expand All @@ -17,3 +17,9 @@ incremental = false
lto = 'fat'
opt-level = 's'
overflow-checks = false

[profile.test]
# Rust debug is too slow.
# For debug builds always builds with some optimization
opt-level = 0
overflow-checks = true
1 change: 1 addition & 0 deletions focus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ embedded-hal = "1.0.0"
esp-hal = { version = "1.0.0-beta.1", features = ["esp32s3", "unstable"] }
esp-println = { version = "0.13.1", features = ["esp32s3"] }
gc9a01-rs = "0.4.2"
hl_driver = { path = "../hl_driver" }
87 changes: 41 additions & 46 deletions focus/src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,30 @@ use embedded_graphics::{
primitives::{Circle, PrimitiveStyle},
Drawable,
};
use embedded_hal::digital::PinState;
use esp_hal::{
clock::CpuClock,
delay::Delay,
gpio::{Input, Io, Level, Output, OutputConfig},
handler, main, ram,
gpio::{Input, InputConfig, Level, Output, OutputConfig, Pull},
main,
spi::master::Spi,
time::{Duration, Instant},
time::Instant,
Blocking,
};
use esp_println::println;
use focus::hardware::{button, screen, spi_bus};
use focus::hardware::{screen, spi_bus};
use hl_driver::{
debounce,
switch::{self, Pressable},
};

#[panic_handler]
fn panic(e: &core::panic::PanicInfo) -> ! {
println!("Panic: {}", e);
loop {}
}

static BUTTON: Mutex<RefCell<Option<Input>>> = Mutex::new(RefCell::new(None));
// static BUTTON: Mutex<RefCell<Option<Input>>> = Mutex::new(RefCell::new(None));
static SPI_BUS: Mutex<RefCell<Option<Spi<'static, Blocking>>>> = Mutex::new(RefCell::new(None));

#[main]
Expand All @@ -38,18 +43,24 @@ fn main() -> ! {
let peripherals = esp_hal::init(config);
let mut delay = Delay::new();

//IO mulitplexer for gpio interrupt
let mut io = Io::new(peripherals.IO_MUX);
io.set_interrupt_handler(button_handler);

// Button
// let config = InputConfig::default().with_pull(Pull::Up);
// let mut boot_button = Input::new(peripherals.GPIO0, config);
let mut boot_button = button::init_boot_button(peripherals.GPIO0);
critical_section::with(|cs| {
boot_button.listen(esp_hal::gpio::Event::FallingEdge);
BUTTON.borrow_ref_mut(cs).replace(boot_button);
});
// Switches
let mut boot_button = switch::Switch::new(
Input::new(
peripherals.GPIO0,
InputConfig::default().with_pull(Pull::Up),
),
PinState::Low,
)
.with_debounce(debounce::Debouncer::default());

let mut hy040_switch = switch::Switch::new(
Input::new(
peripherals.GPIO6,
InputConfig::default().with_pull(esp_hal::gpio::Pull::Up),
),
PinState::Low,
)
.with_debounce(debounce::Debouncer::default());

// SPI Bus
let spi = spi_bus::init_spi_bus(peripherals.SPI2, peripherals.GPIO12, peripherals.GPIO13);
Expand Down Expand Up @@ -87,12 +98,22 @@ fn main() -> ! {
let mut iter = COLOR_LIST.iter().cycle();

loop {
let delay_start = Instant::now();
let _delay_start = Instant::now();

if radius == 0 {
if boot_button.has_been_pressed().unwrap() {
println!("Reset radius");
radius = 0;
display_driver.fill(0);
}

if hy040_switch.has_been_pressed().unwrap() {
if let Some(color) = iter.next() {
println!("Change color");
circle.style.fill_color = Some(*color);
}
}

if radius == 0 {
decrease = false;
} else if radius == center.y as u32 {
decrease = true;
Expand All @@ -111,34 +132,8 @@ fn main() -> ! {
circle.draw(&mut display_driver).unwrap();
display_driver.flush().unwrap();

while delay_start.elapsed() < Duration::from_millis(20) {}
// while delay_start.elapsed() < Duration::from_millis(200) {}
}

// for inspiration have a look at the examples at https://github.com/esp-rs/esp-hal/tree/esp-hal-v1.0.0-beta.0/examples/src/bin
}

#[handler]
#[ram]
fn button_handler() {
println!("GPIO interrupt");

if critical_section::with(|cs| {
BUTTON
.borrow_ref_mut(cs)
.as_mut()
.unwrap()
.is_interrupt_set()
}) {
println!("Button was source of interrupt");
} else {
println!("Button was not source of interrupt");
}

critical_section::with(|cs| {
BUTTON
.borrow_ref_mut(cs)
.as_mut()
.unwrap()
.clear_interrupt();
})
}
2 changes: 2 additions & 0 deletions hl_driver/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ version = "0.1.0"
edition = "2024"

[dependencies]
embedded-hal = "1.0.0"


[features]
unit-tests = []
98 changes: 98 additions & 0 deletions hl_driver/src/debounce.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
const DEBOUNCE_MASK: u8 = 0x07;
const RELEASED_MASK: u8 = 0x00;

/// ## Description
///
/// Trait defining debouncing behaviours
pub trait Debounce {
fn get_state(&self) -> DebounceState;
fn debounce(&mut self, state: bool);
}

/// ## Description
///
/// Possible state for a debouncer
#[derive(Debug, PartialEq)]
pub enum DebounceState {
Loaded,
Unloaded,
Transition,
}

/// ## Description
///
/// Allow rapid conversion between u8 and the Debounce state.
/// Useful for converting the state of a register.
impl From<u8> for DebounceState {
fn from(value: u8) -> Self {
match value {
DEBOUNCE_MASK => DebounceState::Loaded,
RELEASED_MASK => DebounceState::Unloaded,
_ => DebounceState::Transition,
}
}
}

#[allow(dead_code)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
/// ## Description
///
/// Debouncer struct implementing the debouncing trait based on a u8 register
///
/// ## Example
///
/// ```rust
/// use hl_driver::debounce::{Debouncer, DebounceState, Debounce};
/// // Create a debouncer with en empty register
/// let mut debouncer = Debouncer::default();
/// // Perform one register manipulation based on the provided boolean. For instance a gpio state.
/// debouncer.debounce(true);
/// // Retrieve the DebounceState. When the register is full (3 ticks), the state will be Loaded.
/// let state = debouncer.get_state();
/// assert_eq!(DebounceState::Transition, state);
/// ```
#[derive(Default)]
pub struct Debouncer {
register: u8,
}

impl Debounce for Debouncer {
fn debounce(&mut self, state: bool) {
self.register = (self.register << 1) | state as u8;
}

fn get_state(&self) -> DebounceState {
DebounceState::from(self.register)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[inline(never)]
#[test]
fn test_debouncer() {
let mut debouncer = Debouncer::default();

// 3 first ticks filling the register
for _ in 0..2 {
debouncer.debounce(true);
assert_eq!(DebounceState::Transition, debouncer.get_state());
}

// 3th tick should fill register and reach loaded state
debouncer.debounce(true);
assert_eq!(DebounceState::Loaded, debouncer.get_state());

// 7 more ticks emptying the register
for _ in 0..7 {
debouncer.debounce(false);
assert_eq!(DebounceState::Transition, debouncer.get_state());
}

// 8th tick should empty the register and reach unloaded state
debouncer.debounce(false);
assert_eq!(DebounceState::Unloaded, debouncer.get_state());
}
}
4 changes: 4 additions & 0 deletions hl_driver/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
#![cfg_attr(not(feature = "unit-tests"), no_std)]

pub mod debounce;
pub mod switch;

#[cfg(test)]
pub mod test_utils;
Loading