Skip to content
Snippets Groups Projects

PCA9956 bugfixes, register_print function and better error handling

Merged Leo Springsfeld requested to merge pca9956 into main
+ 83
21
use embedded_hal::digital::OutputPin;
use embedded_hal_async::i2c::I2c;
use heapless::Vec;
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use log::{debug, error};
#[derive(Debug, Copy, Clone)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum PCA9956Error {
I2CError,
InvalidDevice,
@@ -53,61 +52,74 @@ pub struct PCA9956<I2C: I2c, PIN: OutputPin> {
i2c: I2C,
addr: u8,
r_ext: f32,
oe_pin: Option<PIN>,
not_oe_pin: Option<PIN>,
}
#[allow(dead_code)]
impl<I2C: I2c, PIN: OutputPin> PCA9956<I2C, PIN> {
/// "r_ext" in Ohm, `i_max_ma` pro LED in Milliampere.
/// "r_ext" in Ohm, `i_max_ma_array` max current values per LED in milliampere
pub async fn new(
i2c: I2C,
addr: u8,
r_ext: f32,
i_max_ma: f32,
oe_pin: Option<PIN>,
i_max_ma_array: [f32; 24],
not_oe_pin: Option<PIN>,
) -> Result<Self, PCA9956Error> {
let mut pca = Self {
i2c,
addr,
r_ext,
oe_pin,
not_oe_pin,
};
// Check if Chip is present
let mode_1: u8 = pca.i2c_read(Registers::MODE_1).await?;
let mode_2: u8 = pca.i2c_read(Registers::MODE_2).await?;
debug!("PCA9956 Mode 1 register value: {mode_1:#b}");
debug!("PCA9956 Mode 2 register value: {mode_2:#b}");
debug!("PCA9956 Mode 1 register value: {mode_1:#010b}");
debug!("PCA9956 Mode 2 register value: {mode_2:#010b}");
if (mode_2 & 0b111) != 0b101 {
error!("Invalid content of pca9956 mode 2 register!");
error!("Chip probably broken");
return Err(PCA9956Error::InvalidDevice);
}
// Write iref_all in Register
let i_ref_all = calculate_iref(pca.r_ext, i_max_ma);
debug!("PCA9956 new Current Limit register value: {i_ref_all:#b}");
pca.i2c_write(Registers::ALL_IREF, i_ref_all).await?;
// Write irefs in registers and set according LEDOUT-bit to 0 if iref is 0
for i in 0..6 {
let mut reg: u8 = 0;
for j in 0..4 {
let i_ref = calculate_iref(pca.r_ext, i_max_ma_array[i * 4 + j]);
pca.i2c_write_raw(Registers::IREF_0 as u8 + (i * 4 + j) as u8, i_ref)
.await?;
if i_ref != 0 {
reg |= 0b10 << (j * 2);
}
}
pca.i2c_write_raw(Registers::LEDOUT_0 as u8 + i as u8, reg)
.await?;
}
pca.error_check().await?;
// output enable:
if let Some(oe_pin) = pca.oe_pin.as_mut() {
oe_pin.set_high().unwrap();
if let Some(not_oe_pin) = pca.not_oe_pin.as_mut() {
not_oe_pin.set_low().unwrap();
}
Ok(pca)
}
/// Checks for errors and prints error registers if error flag is set (Datasheet section 7.3.14)
async fn error_check(&mut self) -> Result<(), PCA9956Error> {
let mode_2: u8 = self.i2c_read(Registers::MODE_2).await?;
debug!("PCA9956 Mode 2 register value: {mode_2:#b}");
debug!("PCA9956 Mode 2 register value: {mode_2:#010b}");
if (mode_2 & (1 << 6)) != 0 {
error!("PCA9956 Error flag is set");
for i in 0..5 {
for i in 0..6 {
let mut eflags = [0];
self.i2c_read_raw(Registers::ERFLAGS_0 as u8 + i, &mut eflags)
.await?;
error!("EFLAG{i}: {:#b}", eflags[0]);
error!("EFLAG{i}: {:#010b}", eflags[0]);
}
return Err(PCA9956Error::PCAErrorFlag);
}
@@ -115,6 +127,56 @@ impl<I2C: I2c, PIN: OutputPin> PCA9956<I2C, PIN> {
Ok(())
}
/// Prints out all registers for debugging
pub async fn print_registers(&mut self) -> Result<(), PCA9956Error> {
use Registers::*;
let reg = self.i2c_read(MODE_1).await?;
debug!("MODE_1 register: {reg:#010b}");
let reg = self.i2c_read(MODE_2).await?;
debug!("MODE_2 register: {reg:#010b}");
for i in 0..6 {
let mut regs = [0];
self.i2c_read_raw(LEDOUT_0 as u8 + i, &mut regs).await?;
debug!("LEDOUT_{i} register: {:#010b}", regs[0]);
}
let reg = self.i2c_read(GROUP_PWM).await?;
debug!("GROUP_PWM register: {reg:#010b}");
let reg = self.i2c_read(GROUP_FREQ).await?;
debug!("GROUP_FREQ register: {reg:#010b}");
for i in 0..24 {
let mut regs = [0];
self.i2c_read_raw(PWM_0 as u8 + i, &mut regs).await?;
debug!("PWM_{i} register: {:#010b}", regs[0]);
}
for i in 0..24 {
let mut regs = [0];
self.i2c_read_raw(IREF_0 as u8 + i, &mut regs).await?;
debug!("IREF_{i} register: {:#010b}", regs[0]);
}
let reg = self.i2c_read(OFFSET).await?;
debug!("OFFSET register: {reg:#010b}");
let reg = self.i2c_read(SUBADR1).await?;
debug!("SUBADR1 register: {reg:#010b}");
let reg = self.i2c_read(SUBADR2).await?;
debug!("SUBADR2 register: {reg:#010b}");
let reg = self.i2c_read(SUBADR3).await?;
debug!("SUBADR3E_1 register: {reg:#010b}");
let reg = self.i2c_read(ALL_CALLADR).await?;
debug!("ALL_CALLADR register: {reg:#010b}");
let reg = self.i2c_read(ALL_PWM).await?;
debug!("ALL_PWM register: {reg:#010b}");
let reg = self.i2c_read(ALL_IREF).await?;
debug!("ALL_IREF register: {reg:#010b}");
let reg = self.i2c_read(ERFLAGS_0).await?;
debug!("ERFLAGS_0 register: {reg:#010b}");
Ok(())
}
/// Read byte from register adress addr (Register enum)
async fn i2c_read(&mut self, addr: Registers) -> Result<u8, PCA9956Error> {
let mut target = [0];
@@ -124,7 +186,7 @@ impl<I2C: I2c, PIN: OutputPin> PCA9956<I2C, PIN> {
/// Read byte from register adress addr as u8 (not Register enum)
async fn i2c_read_raw(&mut self, addr: u8, target: &mut [u8]) -> Result<(), PCA9956Error> {
if addr + target.len() as u8 > 46 + 1 {
if addr + target.len() as u8 > 0x46 + 1 {
return Err(PCA9956Error::OutOfBound);
}
self.i2c
@@ -146,7 +208,7 @@ impl<I2C: I2c, PIN: OutputPin> PCA9956<I2C, PIN> {
/// Writes data (single byte) to register adress addr as u8 (not Register enum)
async fn i2c_write_raw(&mut self, addr: u8, data: u8) -> Result<(), PCA9956Error> {
if addr > 46 {
if addr > 0x46 {
return Err(PCA9956Error::OutOfBound);
}
let cmd = [addr, data];
Loading