A step sequencer for Adafruit's RP2040-based macropad

hold keys to limit steps

+19 -19
+3 -4
src/main.rs
··· 1 1 #![no_std] 2 2 #![no_main] 3 3 4 - use core::sync::atomic::{AtomicBool, AtomicU8, AtomicU32}; 5 - 6 4 use embassy_executor::Spawner; 7 5 use embassy_rp::{ 8 6 Peri, bind_interrupts, ··· 40 38 PIO0_IRQ_0 => PioInterruptHandler<PIO0>; 41 39 }); 42 40 43 - const COLS: usize = 3; 44 - const ROWS: usize = 4; 41 + static COLS: usize = 3; 42 + static ROWS: usize = 4; 43 + static NUM_KEYS: usize = ROWS * COLS; 45 44 type KeyGrid<T> = [[T; COLS]; ROWS]; 46 45 47 46 #[embassy_executor::main]
+15 -5
src/tasks/controls.rs
··· 2 2 use smart_leds::RGB; 3 3 4 4 use crate::{ 5 - COLS, KeyGrid, ROWS, 5 + COLS, KeyGrid, NUM_KEYS, ROWS, 6 6 key_leds::Coord, 7 7 menus::{SEQUENCER_MENU, SequencerMenuValue, StepMenuValue}, 8 8 tasks::{ ··· 16 16 pub enum ControlEvent { 17 17 Key { pressed: bool, coord: Coord }, 18 18 RotaryButton { pressed: bool }, 19 - SequencerStep { coord: Coord }, 19 + SequencerStep, 20 20 RotaryEncoder { increment: i32 }, 21 21 SequencerMenuChange { value: SequencerMenuValue }, 22 22 StepMenuChange { value: StepMenuValue }, ··· 39 39 40 40 let mut num_keys_pressed = 0; 41 41 let mut selected_step: Option<Coord> = None; 42 + let mut step_index: usize = 0; 42 43 let mut step: Coord = (0, 0); 43 44 44 45 loop { ··· 78 79 rotary_press().await; 79 80 } 80 81 ControlEvent::RotaryEncoder { increment } => rotary_change(increment).await, 81 - ControlEvent::SequencerStep { coord } => { 82 + ControlEvent::SequencerStep => { 82 83 let prev_color = if step_state[step.1 as usize][step.0 as usize].active { 83 84 active 84 85 } else { 85 86 off 86 87 }; 87 88 89 + step_index = (step_index + 1).rem_euclid(NUM_KEYS); 90 + let mut next_step = ((step_index % COLS) as u8, (step_index / COLS) as u8); 91 + if num_keys_pressed > 0 { 92 + while !step_state[next_step.1 as usize][next_step.0 as usize].pressed { 93 + step_index = (step_index + 1).rem_euclid(NUM_KEYS); 94 + next_step = ((step_index % COLS) as u8, (step_index / COLS) as u8); 95 + } 96 + } 97 + 88 98 update_key_light(step, prev_color).await; 89 - update_key_light(coord, current).await; 90 - step = coord; 99 + update_key_light(next_step, current).await; 100 + step = next_step; 91 101 } 92 102 ControlEvent::SequencerMenuChange { value } => unsafe { 93 103 SEQUENCER_MENU.lock_mut(|inner| *inner = Some(value));
+1 -10
src/tasks/sequencer.rs
··· 1 1 use crate::{ 2 - COLS, 3 2 menus::{SEQUENCER_MENU, SequencerMenuValue}, 4 3 sequencer_timer::{SequencerConfig, SequencerTimer}, 5 4 tasks::{CONTROLS_CHANNEL, controls::ControlEvent}, ··· 7 6 8 7 #[embassy_executor::task] 9 8 pub async fn sequencer() { 10 - let mut step: u8 = 0; 11 - let cols = COLS as u8; 12 - 13 9 let mut timer = SequencerTimer::new(); 14 10 let mut play = false; 15 11 loop { ··· 25 21 }); 26 22 27 23 if play { 28 - let coord = (step % cols, step / cols); 29 - CONTROLS_CHANNEL 30 - .send(ControlEvent::SequencerStep { coord }) 31 - .await; 32 - 33 - step = (step + 1).rem_euclid(12); 24 + CONTROLS_CHANNEL.send(ControlEvent::SequencerStep).await; 34 25 } 35 26 36 27 timer.next_step().await;