ADC scaling and fixes

This commit is contained in:
2025-07-16 16:02:59 +02:00
parent 14143cfe60
commit 3fd35d723a
4 changed files with 415 additions and 34 deletions

View File

@@ -5,10 +5,10 @@ use hal::gpio::{Output, PushPull, Alternate, AF0, AF5};
use embedded_hal::blocking::spi::Transfer;
use defmt::*;
pub const PEDAL_A_MIN: u8 = 10;
pub const PEDAL_A_MAX: u8 = 245;
pub const PEDAL_B_MIN: u8 = 10;
pub const PEDAL_B_MAX: u8 = 245;
pub const PEDAL_A_MIN: u8 = 71;
pub const PEDAL_A_MAX: u8 = 248;
pub const PEDAL_B_MIN: u8 = 83;
pub const PEDAL_B_MAX: u8 = 250;
const IIR_ALPHA: u16 = 51;
@@ -38,7 +38,8 @@ impl Tlc0832 {
let sck = sck.into_alternate_af5(critical_section);
let miso = miso.into_alternate_af0(critical_section);
let mosi = mosi.into_alternate_af0(critical_section);
let cs = cs.into_push_pull_output(critical_section);
let mut cs = cs.into_push_pull_output(critical_section);
cs.set_high().ok();
let spi_mode = Mode {
polarity: Polarity::IdleLow,
@@ -53,21 +54,14 @@ impl Tlc0832 {
rcc,
);
let adc = Self {
Self {
spi,
cs,
pedal_a_filtered: 128 << 8,
pedal_b_filtered: 128 << 8,
last_midi_a: 64,
last_midi_b: 64,
};
// Small delay to ensure SPI peripheral is ready
for _ in 0..1000 {
cortex_m::asm::nop();
}
adc
})
}
@@ -75,34 +69,35 @@ impl Tlc0832 {
if channel > 1 {
return Err("Invalid channel");
}
self.cs.set_high().ok();
// Small delay before starting transaction
for _ in 0..100 {
cortex_m::asm::nop();
}
self.cs.set_low().ok();
// Small delay after CS low
for _ in 0..100 {
cortex_m::asm::nop();
}
let start_bit = 1u8 << 7;
let channel_bit = if channel == 0 { 0x00 } else { 1u8 << 6 };
let command = start_bit | channel_bit;
info!("Reading channel {} with command 0x{:02x}", channel, command);
// TLC0832 protocol:
// Send 3 bits: Start(1) + SGL/DIF(1 for single-ended) + ODD/EVEN(channel)
// Then 1 clock cycle of MUX settling (DO goes low)
// Then 8 clock cycles of MSB-first data
// Use HAL SPI transfer - much simpler and more reliable
let mut data = [command, 0x00, 0x00]; // TLC0832 needs 3 bytes
let result = match self.spi.transfer(&mut data) {
Ok(response) => {
info!("SPI transfer successful: [{:02x}, {:02x}, {:02x}]",
response[0], response[1], response[2]);
// TLC0832 returns data in the 3rd byte for 8-bit mode
response[2]
},
// For single-ended mode:
// Channel 0: 110 (Start=1, SGL/DIF=1, ODD/EVEN=0)
// Channel 1: 111 (Start=1, SGL/DIF=1, ODD/EVEN=1)
let command_bits = 0x06 | channel; // 110 or 111 in the top 3 bits
let command_byte = command_bits << 5; // Shift to MSB position: 11000000 or 11100000
info!("Reading channel {} with command bits {:03b} (0x{:02x})", channel, command_bits, command_byte);
// Send command byte + 2 dummy bytes to clock out the full response
// The TLC0832 needs 11 total clock cycles:
// 3 for command + 1 for MUX settling + 8 for data = 12 bits total
let mut data = [command_byte, 0x00];
let response = match self.spi.transfer(&mut data) {
Ok(resp) => resp,
Err(_) => {
self.cs.set_high().ok();
error!("SPI transfer error");
@@ -110,12 +105,26 @@ impl Tlc0832 {
}
};
info!("SPI response: [{:02x}, {:02x}]", response[0], response[1]);
// The result spans across the response bytes
// After the 3 command bits + 1 MUX settling bit (4 bits total),
// the next 8 bits are the conversion result
// So we need to extract bits from both response bytes
// response[0] contains the first 8 bits (3 command + 1 settling + 4 data MSBs)
// response[1] contains the remaining 4 data LSBs
let result = ((response[0] & 0x0F) << 4) | ((response[1] & 0xF0) >> 4);
// Small delay before CS high
for _ in 0..100 {
cortex_m::asm::nop();
}
self.cs.set_high().ok();
info!("Read channel {} = {}", channel, result);
info!("Channel {} result: {}", channel, result);
Ok(result)
}
@@ -154,13 +163,16 @@ impl Tlc0832 {
let mut midi_a_change = None;
let mut midi_b_change = None;
// Read channel 0 (pedal A)
match self.read_channel(0) {
Ok(raw_a) => {
info!("Raw channel 0 value: {}", raw_a);
self.apply_iir_filter(0, raw_a);
let filtered_a = (self.pedal_a_filtered >> 8) as u8;
let midi_a = self.adc_to_midi(filtered_a, PEDAL_A_MIN, PEDAL_A_MAX);
if midi_a != self.last_midi_a {
info!("Channel 0 MIDI change: {} -> {}", self.last_midi_a, midi_a);
self.last_midi_a = midi_a;
midi_a_change = Some(midi_a);
}
@@ -170,13 +182,16 @@ impl Tlc0832 {
}
}
// Read channel 1 (pedal B)
match self.read_channel(1) {
Ok(raw_b) => {
info!("Raw channel 1 value: {}", raw_b);
self.apply_iir_filter(1, raw_b);
let filtered_b = (self.pedal_b_filtered >> 8) as u8;
let midi_b = self.adc_to_midi(filtered_b, PEDAL_B_MIN, PEDAL_B_MAX);
if midi_b != self.last_midi_b {
info!("Channel 1 MIDI change: {} -> {}", self.last_midi_b, midi_b);
self.last_midi_b = midi_b;
midi_b_change = Some(midi_b);
}