Implement keypad support with sx1509

This commit is contained in:
Sofia 2026-05-29 19:23:45 +03:00
parent 03f560b2c1
commit 4a3a88f0c0
2 changed files with 167 additions and 14 deletions

View File

@ -141,25 +141,25 @@ fn main() -> ! {
);
sx1509.init().unwrap();
sx1509.set_pin_dir(0, sx1509::PinDirection::Output, false);
sx1509.set_pin_dir(1, sx1509::PinDirection::InputPullUp, false);
sx1509.set_pin_dir(2, sx1509::PinDirection::Output, false);
sx1509.set_pin_dir(3, sx1509::PinDirection::InputPullUp, false);
sx1509.set_pin_dir(4, sx1509::PinDirection::Output, false);
sx1509.set_pin_dir(5, sx1509::PinDirection::InputPullUp, false);
sx1509.set_pin_dir(6, sx1509::PinDirection::InputPullUp, false);
sx1509.keypad(3, 4, 256, 2, 1);
let delay = Delay::new();
let keypad = [
['2', '1', '3'],
['0', '*', '#'],
['8', '7', '9'],
['5', '4', '6'],
];
loop {
delay.delay_millis(500);
sx1509.write_pin(0, true);
log::info!("Pin 1: {:?}", sx1509.read_pin(1));
log::info!("Pin 3: {:?}", sx1509.read_pin(3));
log::info!("Pin 5: {:?}", sx1509.read_pin(5));
log::info!("Pin 6: {:?}", sx1509.read_pin(6));
sx1509.write_pin(0, false);
let keypad_data = sx1509.read_keypad();
let row = bit_representation_to_number(((keypad_data & 0xFF00) >> 8) as u8) as usize;
let col = bit_representation_to_number((keypad_data & 0xFF) as u8) as usize;
if row > 0 && col > 0 {
log::info!("Key data: {}", keypad[row - 1][col - 1]);
}
}
// let mut at_commands = ATCommands::new(sim_rst, sim_pwr_key, uart);
@ -230,3 +230,18 @@ fn thread_2_main(async_io: AsyncIO, mut at_commands: ATCommands<'static, 'static
}
}
}
fn bit_representation_to_number(byte: u8) -> u8 {
match byte {
0b00000000 => 0,
0b00000001 => 1,
0b00000010 => 2,
0b00000100 => 3,
0b00001000 => 4,
0b00010000 => 5,
0b00100000 => 6,
0b01000000 => 7,
0b10000000 => 8,
_ => 255,
}
}

View File

@ -1,14 +1,36 @@
use esp_hal::{Blocking, delay::Delay, gpio::Output, i2c::master::I2c};
pub enum Register {
/// RegPullUpB Pull_up register _ I/O[15_8] (Bank B) 0000 0000
RegPullUpB = 0x6,
/// RegPullDownB Pull_down register _ I/O[15_8] (Bank B) 0000 0000
RegPullDownB = 0x8,
/// RegOpenDrainA Open drain register _ I/O[7_0] (Bank A) 0000 0000
RegOpenDrainA = 0x0B,
/// RegDirB Direction register _ I/O[15_8] (Bank B) 1111 1111
RegDirB = 0x0E,
/// RegDataB Data register _ I/O[15_8] (Bank B) 1111 1111*
RegDataB = 0x10,
/// RegInterruptMaskA Interrupt mask register _ I/O[7_0] (Bank A) 1111 1111
RegInterruptMaskA = 0x13,
/// RegClock Clock management register 0000 0000
RegClock = 0x1E,
/// RegMisc Miscellaneous device settings register 0000 0000
RegMisc = 0x1F,
/// RegDebounceEnableB Debounce enable register _ I/O[15_8] (Bank B) 0000 0000
RegDebounceEnableB = 0x23,
/// RegDebounceConfig Debounce configuration register 0000 0000
RegDebounceConfig = 0x22,
/// RegKeyConfig1 Key scan configuration register 0000 0000
RegKeyConfig1 = 0x25,
/// RegKeyConfig2 Key scan configuration register 0000 0000
RegKeyConfig2 = 0x26,
/// RegKeyData1 Key value (column) 1111 1111
RegKeyData1 = 0x27,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
@ -168,5 +190,121 @@ impl<'d> Sx1509<'d> {
scan_time: u16,
debounce_time: u8,
) {
// Set regDir 0:7 outputs, 8:15 inputs:
let mut temp_dir = self.read_16(Register::RegDirB);
for i in 0..rows {
temp_dir &= !(1 << i);
}
for i in 8..(columns * 2) {
temp_dir |= 1 << i;
}
self.write_16(Register::RegDirB, temp_dir);
// Set regOpenDrain on 0:7:
let mut temp_open_drain = self.read_8(Register::RegOpenDrainA);
for i in 0..rows {
temp_open_drain |= 1 << i;
}
self.write_8(Register::RegOpenDrainA, temp_open_drain);
// Set regPullUp on 8:15:
let mut temp_pull_up = self.read_8(Register::RegPullUpB);
for i in 0..columns {
temp_pull_up |= 1 << i;
}
self.write_8(Register::RegPullUpB, temp_pull_up);
let mut debounce_time = debounce_time.clamp(1, 64);
let scan_time = scan_time.clamp(1, 128);
if debounce_time as u16 >= scan_time {
debounce_time = (scan_time >> 1) as u8;
}
self.debounce_keypad(debounce_time, rows, columns);
let mut scan_time_bits = 0u8;
for i in 7..0 {
if (scan_time & (1 << i)) > 0 {
scan_time_bits = i;
break;
}
}
let mut sleep_time_bits = 0u8;
if sleep_time != 0 {
for i in 7..0 {
if (sleep_time & (1u16 << i + 6)) > 0 {
sleep_time_bits = i;
break;
}
}
// If sleepTime was non-zero, but less than 128,
// assume we wanted to turn sleep on, set it to minimum:
if sleep_time_bits == 0 {
sleep_time_bits = 1;
}
}
// RegKeyConfig1 sets the auto sleep time and scan time per row
let sleep_time_bits = (sleep_time_bits & 0b111) << 4;
scan_time_bits &= 0b111; // Scan time is bits 2:0
self.write_8(
Register::RegKeyConfig1,
// TODO: Was incorrectly sleep_time
sleep_time_bits as u8 | scan_time_bits,
);
let rows = (rows - 1) & 0b111;
let columns = (columns - 1) & 0b111;
self.write_8(Register::RegKeyConfig2, (rows << 3) | columns);
}
fn debounce_keypad(&mut self, debounce_time: u8, rows: u8, columns: u8) {
self.debounce_time(debounce_time);
for i in 0..rows {
self.debounce_pin(i);
}
for i in 0..(8 + columns) {
self.debounce_pin(i);
}
}
fn debounce_time(&mut self, debounce_time: u8) {
let mut config_value = 0u8;
for i in 7..0 {
if (debounce_time & (1 << i)) > 0 {
config_value = i + 1;
break;
}
}
config_value = config_value.clamp(0, 7);
self.debounce_config(config_value);
}
fn debounce_pin(&mut self, pin: u8) {
let mut debounce_enable = self.read_16(Register::RegDebounceEnableB);
debounce_enable |= 1 << pin;
self.write_16(Register::RegDebounceEnableB, debounce_enable);
}
fn debounce_config(&mut self, config: u8) {
let mut temp_reg_misc = self.read_8(Register::RegMisc);
if (temp_reg_misc & 0x70) == 0 {
temp_reg_misc |= 1 << 4;
self.write_8(Register::RegMisc, temp_reg_misc);
}
let mut temp_clock = self.read_8(Register::RegClock);
if (temp_clock & 0x60) == 0 {
temp_clock |= 1 << 6;
self.write_8(Register::RegClock, temp_clock);
}
let config_value = config & 0b111;
self.write_8(Register::RegDebounceConfig, config_value);
}
pub fn read_keypad(&mut self) -> u16 {
0xFFFF ^ self.read_16(Register::RegKeyData1)
}
}