Mapper tool for decoding charlieplex

This commit is contained in:
2025-06-27 21:19:59 +02:00
parent 9510ba04be
commit 6eb15fbd12
11 changed files with 1547 additions and 80 deletions

View File

@@ -5,6 +5,7 @@ target = "thumbv6m-none-eabi"
runner = "probe-rs run --chip STM32F042C4Tx"
rustflags = [
"-C", "link-arg=-Tlink.x",
"-C", "link-arg=-Tdefmt.x",
"-C", "link-arg=--nmagic",
]

35
firmware/Cargo.lock generated
View File

@@ -88,15 +88,6 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
[[package]]
name = "defmt"
version = "0.3.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0963443817029b2024136fc4dd07a5107eb8f977eaf18fcd1fdeb11306b64ad"
dependencies = [
"defmt 1.0.1",
]
[[package]]
name = "defmt"
version = "1.0.1"
@@ -131,12 +122,12 @@ dependencies = [
[[package]]
name = "defmt-rtt"
version = "0.4.2"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6eca0aae8aa2cf8333200ecbd236274697bc0a394765c858b3d9372eb1abcfa"
checksum = "b2cac3b8a5644a9e02b75085ebad3b6deafdbdbdec04bb25086523828aa4dfd1"
dependencies = [
"critical-section",
"defmt 0.3.100",
"defmt",
]
[[package]]
@@ -149,6 +140,23 @@ dependencies = [
"void",
]
[[package]]
name = "embedded-midi"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26119337828c4c6a29d9c1661962eeec2a3f884b859d5713a70c6c4143988497"
dependencies = [
"embedded-hal",
"midi-types",
"nb 1.1.0",
]
[[package]]
name = "midi-types"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef0bbe5256e5c434947d790788426bb65773502784aed7b23408f7e7fb4d8eb5"
[[package]]
name = "nb"
version = "0.1.3"
@@ -268,9 +276,10 @@ dependencies = [
"cortex-m",
"cortex-m-rt",
"critical-section",
"defmt 0.3.100",
"defmt",
"defmt-rtt",
"embedded-hal",
"embedded-midi",
"nb 1.1.0",
"panic-halt",
"stm32f0xx-hal",

9
firmware/Cargo.toml Normal file → Executable file
View File

@@ -8,13 +8,18 @@ cortex-m = { version = "0.7", features = ["inline-asm", "critical-section-single
cortex-m-rt = "0.7"
critical-section = "1"
embedded-hal = "0.2"
embedded-midi = "0.1.2"
nb = "1"
panic-halt = "0.2"
stm32f0xx-hal = { version = "0.18", features = ["stm32f042", "rt"] }
# For debugging and logging
defmt = "0.3"
defmt-rtt = "0.4"
defmt = "1"
defmt-rtt = "1"
# Add defmt feature to make sure metadata is included
[package.metadata.defmt]
linker_args = ["-C", "link-arg=-Tdefmt.x"]
[profile.release]
debug = true # Keep debug info for better debugging

View File

@@ -13,4 +13,4 @@ fn main() {
println!("cargo:rustc-link-search={}", out.display());
println!("cargo:rerun-if-changed=memory.x");
println!("cargo:rustc-link-arg=--nmagic");
}
}

185
firmware/src/main.rs Normal file → Executable file
View File

@@ -1,28 +1,48 @@
#![no_std]
#![no_main]
use panic_halt as _;
use cortex_m_rt::entry;
use stm32f0xx_hal::serial::Error;
use stm32f0xx_hal as hal;
use hal::prelude::*;
use hal::stm32;
use hal::{
delay::Delay,
serial::Serial,
};
use panic_halt as _;
use stm32f0xx_hal as hal;
use defmt::info;
use defmt_rtt as _;
use embedded_midi::Channel;
use hal::{delay::Delay, serial::Serial};
defmt::timestamp!("{=u32}", {
static mut COUNTER: u32 = 0;
unsafe {
COUNTER = COUNTER.wrapping_add(1);
COUNTER
}
});
struct Bus {
latch_en: stm32f0xx_hal::gpio::gpioa::PA0<stm32f0xx_hal::gpio::Output<stm32f0xx_hal::gpio::PushPull>>,
select_en: stm32f0xx_hal::gpio::gpiob::PB8<stm32f0xx_hal::gpio::Output<stm32f0xx_hal::gpio::OpenDrain>>,
pb0: stm32f0xx_hal::gpio::gpiob::PB0<stm32f0xx_hal::gpio::Output<stm32f0xx_hal::gpio::PushPull>>,
pb1: stm32f0xx_hal::gpio::gpiob::PB1<stm32f0xx_hal::gpio::Output<stm32f0xx_hal::gpio::PushPull>>,
pb2: stm32f0xx_hal::gpio::gpiob::PB2<stm32f0xx_hal::gpio::Output<stm32f0xx_hal::gpio::PushPull>>,
pb3: stm32f0xx_hal::gpio::gpiob::PB3<stm32f0xx_hal::gpio::Output<stm32f0xx_hal::gpio::PushPull>>,
pb4: stm32f0xx_hal::gpio::gpiob::PB4<stm32f0xx_hal::gpio::Output<stm32f0xx_hal::gpio::PushPull>>,
pb5: stm32f0xx_hal::gpio::gpiob::PB5<stm32f0xx_hal::gpio::Output<stm32f0xx_hal::gpio::PushPull>>,
pb6: stm32f0xx_hal::gpio::gpiob::PB6<stm32f0xx_hal::gpio::Output<stm32f0xx_hal::gpio::PushPull>>,
pb7: stm32f0xx_hal::gpio::gpiob::PB7<stm32f0xx_hal::gpio::Output<stm32f0xx_hal::gpio::PushPull>>,
latch_en:
stm32f0xx_hal::gpio::gpioa::PA0<stm32f0xx_hal::gpio::Output<stm32f0xx_hal::gpio::PushPull>>,
select_en: stm32f0xx_hal::gpio::gpiob::PB8<
stm32f0xx_hal::gpio::Output<stm32f0xx_hal::gpio::OpenDrain>,
>,
pb0:
stm32f0xx_hal::gpio::gpiob::PB0<stm32f0xx_hal::gpio::Output<stm32f0xx_hal::gpio::PushPull>>,
pb1:
stm32f0xx_hal::gpio::gpiob::PB1<stm32f0xx_hal::gpio::Output<stm32f0xx_hal::gpio::PushPull>>,
pb2:
stm32f0xx_hal::gpio::gpiob::PB2<stm32f0xx_hal::gpio::Output<stm32f0xx_hal::gpio::PushPull>>,
pb3:
stm32f0xx_hal::gpio::gpiob::PB3<stm32f0xx_hal::gpio::Output<stm32f0xx_hal::gpio::PushPull>>,
pb4:
stm32f0xx_hal::gpio::gpiob::PB4<stm32f0xx_hal::gpio::Output<stm32f0xx_hal::gpio::PushPull>>,
pb5:
stm32f0xx_hal::gpio::gpiob::PB5<stm32f0xx_hal::gpio::Output<stm32f0xx_hal::gpio::PushPull>>,
pb6:
stm32f0xx_hal::gpio::gpiob::PB6<stm32f0xx_hal::gpio::Output<stm32f0xx_hal::gpio::PushPull>>,
pb7:
stm32f0xx_hal::gpio::gpiob::PB7<stm32f0xx_hal::gpio::Output<stm32f0xx_hal::gpio::PushPull>>,
}
#[entry]
@@ -30,9 +50,11 @@ fn main() -> ! {
// Get device peripherals
let mut dp = stm32::Peripherals::take().unwrap();
let cp = cortex_m::Peripherals::take().unwrap();
// Configure the clock to 48 MHz
let mut rcc = dp.RCC.configure()
let mut rcc = dp
.RCC
.configure()
.hsi48()
.enable_crs(dp.CRS)
.sysclk(48.mhz())
@@ -41,56 +63,105 @@ fn main() -> ! {
// Set up delay provider
let mut delay = Delay::new(cp.SYST, &rcc);
// Configure GPIO
let gpioa = dp.GPIOA.split(&mut rcc);
let gpiob = dp.GPIOB.split(&mut rcc);
let mut bus = cortex_m::interrupt::free(|cs| {
Bus {
latch_en: gpioa.pa0.into_push_pull_output(cs),
select_en: gpiob.pb8.into_open_drain_output(cs),
pb0: gpiob.pb0.into_push_pull_output(cs),
pb1: gpiob.pb1.into_push_pull_output(cs),
pb2: gpiob.pb2.into_push_pull_output(cs),
pb3: gpiob.pb3.into_push_pull_output(cs),
pb4: gpiob.pb4.into_push_pull_output(cs),
pb5: gpiob.pb5.into_push_pull_output(cs),
pb6: gpiob.pb6.into_push_pull_output(cs),
pb7: gpiob.pb7.into_push_pull_output(cs),
}
let button_1_5 = cortex_m::interrupt::free(|cs| gpiob.pb11.into_floating_input(cs));
let button_6_10 = cortex_m::interrupt::free(|cs| gpiob.pb13.into_floating_input(cs));
let mut bus = cortex_m::interrupt::free(|cs| Bus {
latch_en: gpioa.pa0.into_push_pull_output(cs),
select_en: gpiob.pb8.into_open_drain_output(cs),
pb0: gpiob.pb0.into_push_pull_output(cs),
pb1: gpiob.pb1.into_push_pull_output(cs),
pb2: gpiob.pb2.into_push_pull_output(cs),
pb3: gpiob.pb3.into_push_pull_output(cs),
pb4: gpiob.pb4.into_push_pull_output(cs),
pb5: gpiob.pb5.into_push_pull_output(cs),
pb6: gpiob.pb6.into_push_pull_output(cs),
pb7: gpiob.pb7.into_push_pull_output(cs),
});
let mut serial = cortex_m::interrupt::free(|cs| {
// Configure serial port
let serial = cortex_m::interrupt::free(|cs| {
let tx = gpioa.pa9.into_alternate_af1(cs);
let rx = gpioa.pa10.into_alternate_af1(cs);
//dp.USART1.cr1.write(|w| w.uesm().enabled());
Serial::usart1(dp.USART1, (tx, rx), 31_250.bps(), &mut rcc)
});
// Loop
let (_tx, rx) = serial.split();
let mut midi = embedded_midi::MidiIn::new(rx);
// Main loop
let mut ic_03: u8 = 0;
let mut ic_10: u8 = 0;
let mut ic_11: u8 = 0;
loop {
use stm32f0xx_hal::serial::Error;
//type Error = nb::Error<stm32f0xx_hal::serial::Error>;
//use embedded_hal::serial::nb::Error;
match serial.read() {
Ok(_) => {
let message = midi.read();
match message {
Ok(embedded_midi::MidiMessage::ControlChange(channel, control, value))
if channel == Channel::new(0) =>
{
bus.led_button_1(&mut delay);
if control == embedded_midi::Control::new(20) {
bus.led_button_2(&mut delay);
ic_03 = value.into();
} else if control == embedded_midi::Control::new(21) {
bus.led_button_2(&mut delay);
let value: u8 = value.into();
ic_03 = 128_u8 + value;
} else if control == embedded_midi::Control::new(22) {
bus.led_button_2(&mut delay);
ic_10 = value.into();
} else if control == embedded_midi::Control::new(23) {
bus.led_button_2(&mut delay);
let value: u8 = value.into();
ic_10 = 128_u8 + value;
} else if control == embedded_midi::Control::new(24) {
bus.led_button_2(&mut delay);
ic_11 = value.into();
} else if control == embedded_midi::Control::new(25) {
bus.led_button_2(&mut delay);
let value: u8 = value.into();
ic_11 = 128_u8 + value;
}
bus.output(03, ic_03, &mut delay);
bus.output(10, ic_10, &mut delay);
bus.output(11, ic_11, &mut delay);
}
Err(nb::Error::WouldBlock) => {
bus.led_button_3(&mut delay);
Ok(_) => {
info!("unhandled midi message");
}
Err(nb::Error::Other(Error::Framing)) => {
bus.led_button_2(&mut delay);
Err(nb::Error::WouldBlock) => {}
Err(nb::Error::Other(hal::serial::Error::Framing)) => {
info!("Error::Framing");
}
Err(nb::Error::Other(Error::Noise)) => {
bus.led_button_9(&mut delay);
Err(nb::Error::Other(hal::serial::Error::Noise)) => {
info!("Error::Noise");
}
Err(nb::Error::Other(hal::serial::Error::Overrun)) => {
info!("Error::Overrun");
}
Err(nb::Error::Other(hal::serial::Error::Parity)) => {
info!("Error::Parity");
}
Err(nb::Error::Other(_)) => {
bus.led_button_10(&mut delay);
info!("Error::Other");
}
}
delay.delay_ms(1000u16);
if button_1_5.is_high().unwrap_or(false) {
info!("Button 1-5 pressed");
delay.delay_ms(500u16);
}
if button_6_10.is_high().unwrap_or(false) {
info!("Button 6-10 pressed");
delay.delay_ms(500u16);
}
}
}
@@ -103,11 +174,11 @@ impl Bus {
_ => self.select(2, delay),
}
delay.delay_ms(10u16);
delay.delay_us(1u16);
self.select_en(true);
delay.delay_ms(10u16);
delay.delay_us(1u16);
self.write(data);
delay.delay_ms(10u16);
delay.delay_us(1u16);
self.select_en(false);
}
@@ -128,7 +199,7 @@ impl Bus {
fn select(&mut self, line: u8, delay: &mut Delay) {
self.select_en.set_low().ok();
delay.delay_ms(10u16);
delay.delay_us(1u16);
match line {
0 => {
self.pb0.set_low().ok();
@@ -212,11 +283,11 @@ impl Bus {
}
_ => {}
}
delay.delay_ms(10u16);
delay.delay_us(1u16);
self.latch_en.set_high().ok();
delay.delay_ms(10u16);
delay.delay_us(1u16);
self.latch_en.set_low().ok();
delay.delay_ms(10u16);
delay.delay_us(1u16);
self.select_en.set_high().ok();
}
@@ -249,4 +320,4 @@ impl Bus {
self.output(10, 0b0001_0000, delay);
self.output(11, 0b0000_0000, delay);
}
}
}