diff --git a/src/blocking/channels.rs b/src/blocking/channels.rs new file mode 100644 index 0000000..112c941 --- /dev/null +++ b/src/blocking/channels.rs @@ -0,0 +1,97 @@ +use crate::{hal, Channel, Error, Pca9685, Register, channels::{get_register_on, get_register_off}}; + +impl Pca9685 +where + I2C: hal::blocking::i2c::Write + hal::blocking::i2c::WriteRead, +{ + /// Set the `ON` counter for the selected channel. + /// + /// Note that the full off setting takes precedence over the `on` settings. + /// See section 7.3.3 "LED output and PWM control" of the datasheet for + /// further details. + pub fn set_channel_on(&mut self, channel: Channel, value: u16) -> Result<(), Error> { + if value > 4095 { + return Err(Error::InvalidInputData); + } + let reg = get_register_on(channel); + self.write_double_register(reg, value) + } + + /// Set the `OFF` counter for the selected channel. + pub fn set_channel_off(&mut self, channel: Channel, value: u16) -> Result<(), Error> { + if value > 4095 { + return Err(Error::InvalidInputData); + } + let reg = get_register_off(channel); + self.write_double_register(reg, value) + } + + /// Set the `ON` and `OFF` counters for the selected channel. + /// + /// Note that the full off setting takes precedence over the `on` settings. + /// See section 7.3.3 "LED output and PWM control" of the datasheet for + /// further details. + pub fn set_channel_on_off( + &mut self, + channel: Channel, + on: u16, + off: u16, + ) -> Result<(), Error> { + if on > 4095 || off > 4095 { + return Err(Error::InvalidInputData); + } + let reg = get_register_on(channel); + self.write_two_double_registers(reg, on, off) + } + + /// Set the channel always on. + /// + /// The turning on is delayed by the value argument. + /// Note that the full off setting takes precedence over the `on` settings. + /// + /// See section 7.3.3 "LED output and PWM control" of the datasheet for + /// further details. + pub fn set_channel_full_on(&mut self, channel: Channel, value: u16) -> Result<(), Error> { + if value > 4095 { + return Err(Error::InvalidInputData); + } + let reg = get_register_on(channel); + let value = value | 0b0001_0000_0000_0000; + self.write_double_register(reg, value) + } + + /// Set the channel always off. + /// + /// This takes precedence over the `on` settings and can be cleared by setting + /// the `off` counter with [`set_channel_off`](struct.Pca9685.html#method.set_channel_off). + /// + /// See section 7.3.3 "LED output and PWM control" of the datasheet for + /// further details. + pub fn set_channel_full_off(&mut self, channel: Channel) -> Result<(), Error> { + let reg = get_register_off(channel); + let value = 0b0001_0000_0000_0000; + self.write_double_register(reg, value) + } + + /// Set the `ON` and `OFF` counter for each channel at once. + /// + /// The index of the value in the arrays corresponds to the channel: 0-15. + /// Note that the full off setting takes precedence over the `on` settings. + /// See section 7.3.3 "LED output and PWM control" of the datasheet for + /// further details. + pub fn set_all_on_off(&mut self, on: &[u16; 16], off: &[u16; 16]) -> Result<(), Error> { + let mut data = [0; 65]; + data[0] = Register::C0_ON_L; + for (i, (on, off)) in on.iter().zip(off).enumerate() { + if *on > 4095 || *off > 4095 { + return Err(Error::InvalidInputData); + } + data[i * 4 + 1] = *on as u8; + data[i * 4 + 2] = (*on >> 8) as u8; + data[i * 4 + 3] = *off as u8; + data[i * 4 + 4] = (*off >> 8) as u8; + } + self.enable_auto_increment()?; + self.i2c.write(self.address, &data).map_err(Error::I2C) + } +} diff --git a/src/blocking/device_impl.rs b/src/blocking/device_impl.rs new file mode 100644 index 0000000..7bdeed0 --- /dev/null +++ b/src/blocking/device_impl.rs @@ -0,0 +1,272 @@ +use crate::{ + config::{BitFlagMode1, BitFlagMode2, Config}, + Pca9685, ProgrammableAddress, + hal::blocking::{i2c, delay::DelayUs}, + Address, DisabledOutputValue, Error, OutputDriver, OutputLogicState, OutputStateChange, + Register, +}; + + +impl Pca9685 +where + I2C: i2c::Write + i2c::WriteRead, +{ + /// Create a new instance of the device. + pub fn new>(i2c: I2C, address: A) -> Result> { + let a = address.into(); + + Self::check_address(a.0)?; + + Ok(Pca9685 { + i2c, + address: a.0, + config: Config::default(), + }) + } + + /// Destroy driver instance, return I²C bus instance. + pub fn destroy(self) -> I2C { + self.i2c + } + + /// Enable the controller. + pub fn enable(&mut self) -> Result<(), Error> { + let config = self.config; + self.write_mode1(config.with_low(BitFlagMode1::Sleep)) + } + + /// Disable the controller (sleep). + pub fn disable(&mut self) -> Result<(), Error> { + let config = self.config; + self.write_mode1(config.with_high(BitFlagMode1::Sleep)) + } + + /// Put the controller to sleep while keeping the PWM register + /// contents in preparation for a future restart. + pub fn enable_restart_and_disable(&mut self) -> Result<(), Error> { + let config = self.config.with_high(BitFlagMode1::Sleep); + self.write_mode1(config.with_high(BitFlagMode1::Restart))?; + // Do not store restart bit high as writing this bit high again + // would internally clear it to 0. Writing 0 has no effect. + self.config = config; + Ok(()) + } + + /// Re-enable the controller after a sleep with restart enabled so that + /// previously active PWM channels are restarted. + /// + /// This includes a delay of 500us in order for the oscillator to stabilize. + /// If you cannot afford a 500us delay you can use `restart_nonblocking()`. + pub fn restart(&mut self, delay: &mut impl DelayUs) -> Result<(), Error> { + let mode1 = self.read_register(Register::MODE1)?; + if (mode1 & BitFlagMode1::Restart as u8) != 0 { + self.enable()?; + delay.delay_us(500_u16); + let previous = self.config; + let config = previous.with_high(BitFlagMode1::Restart); + self.write_mode1(config)?; + self.config = previous; + } + Ok(()) + } + + /// Re-enable the controller after a sleep with restart enabled so that + /// previously active PWM channels are restarted (non-blocking version). + /// + /// This is a nonblocking version where you are responsible for waiting at + /// least 500us after the receiving the first `WouldBlock` error before + /// calling again to continue. + pub fn restart_nonblocking(&mut self) -> nb::Result<(), Error> { + let mode1 = self + .read_register(Register::MODE1) + .map_err(nb::Error::Other)?; + let restart_high = (mode1 & BitFlagMode1::Restart as u8) != 0; + let sleep_high = (mode1 & BitFlagMode1::Sleep as u8) != 0; + if restart_high { + if sleep_high { + self.enable().map_err(nb::Error::Other)?; + return Err(nb::Error::WouldBlock); + } else { + let previous = self.config; + let config = previous.with_high(BitFlagMode1::Restart); + self.write_mode1(config).map_err(nb::Error::Other)?; + self.config = previous; + } + } + Ok(()) + } + + /// Set one of the programmable addresses. + /// + /// Initially these are not enabled. Once you set this, you can call + /// `enable_programmable_address()` and then use `set_address()` to configure + /// the driver to use the new address. + pub fn set_programmable_address>( + &mut self, + address_type: ProgrammableAddress, + address: A, + ) -> Result<(), Error> { + let a = address.into(); + + Self::check_address(a.0)?; + let reg = match address_type { + ProgrammableAddress::Subaddress1 => Register::SUBADDR1, + ProgrammableAddress::Subaddress2 => Register::SUBADDR2, + ProgrammableAddress::Subaddress3 => Register::SUBADDR3, + ProgrammableAddress::AllCall => Register::ALL_CALL_ADDR, + }; + self.i2c + .write(self.address, &[reg, a.0]) + .map_err(Error::I2C) + } + + /// Enable responding to programmable address + pub fn enable_programmable_address( + &mut self, + address_type: ProgrammableAddress, + ) -> Result<(), Error> { + let flag = Self::get_subaddr_bitflag(address_type); + let config = self.config; + self.write_mode1(config.with_high(flag)) + } + + /// Disable responding to programmable address + pub fn disable_programmable_address( + &mut self, + address_type: ProgrammableAddress, + ) -> Result<(), Error> { + let flag = Self::get_subaddr_bitflag(address_type); + let config = self.config; + self.write_mode1(config.with_low(flag)) + } + + /// Sets the address used by the driver for communication. + /// + /// This does not have any effect on the hardware and is useful when + /// switching between programmable addresses and the fixed hardware address + /// for communication. + pub fn set_address>(&mut self, address: A) -> Result<(), Error> { + let a = address.into(); + + Self::check_address(a.0)?; + self.address = a.0; + + Ok(()) + } + + fn check_address(address: u8) -> Result<(), Error> { + const LED_ALL_CALL: u8 = 0b111_0000; + // const SW_RESET: u8 = 0b000_0011; this gets absorbed by the high speed mode test + const HIGH_SPEED_MODE: u8 = 0b00_0111; + if address == 0 || address > 0x7F || address == LED_ALL_CALL || address <= HIGH_SPEED_MODE { + Err(Error::InvalidInputData) + } else { + Ok(()) + } + } + + /// Set the output change behavior. Either byte-by-byte or all at the same time. + /// + /// Note that update on ACK requires all 4 PWM channel registers to be loaded before + /// outputs are changed on the last ACK. + pub fn set_output_change_behavior( + &mut self, + change_behavior: OutputStateChange, + ) -> Result<(), Error> { + let config = match change_behavior { + OutputStateChange::OnStop => self.config.with_low(BitFlagMode2::Och), + OutputStateChange::OnAck => self.config.with_high(BitFlagMode2::Och), + }; + self.write_mode2(config) + } + + /// Set the output driver configuration. + pub fn set_output_driver(&mut self, driver: OutputDriver) -> Result<(), Error> { + let config = match driver { + OutputDriver::TotemPole => self.config.with_high(BitFlagMode2::OutDrv), + OutputDriver::OpenDrain => self.config.with_low(BitFlagMode2::OutDrv), + }; + self.write_mode2(config) + } + + /// Set the output value when outputs are disabled (`OE` = 1). + pub fn set_disabled_output_value( + &mut self, + value: DisabledOutputValue, + ) -> Result<(), Error> { + let config = match value { + DisabledOutputValue::Zero => self + .config + .with_low(BitFlagMode2::OutNe0) + .with_low(BitFlagMode2::OutNe1), + DisabledOutputValue::OutputDriver => self + .config + .with_high(BitFlagMode2::OutNe0) + .with_low(BitFlagMode2::OutNe1), + DisabledOutputValue::HighImpedance => self + .config + .with_low(BitFlagMode2::OutNe0) + .with_high(BitFlagMode2::OutNe1), + }; + self.write_mode2(config) + } + + /// Set the output logic state + /// + /// This allows for inversion of the output logic. Applicable when `OE = 0`. + pub fn set_output_logic_state(&mut self, state: OutputLogicState) -> Result<(), Error> { + let config = self.config; + match state { + OutputLogicState::Direct => self.write_mode2(config.with_low(BitFlagMode2::Invrt)), + OutputLogicState::Inverted => self.write_mode2(config.with_high(BitFlagMode2::Invrt)), + } + } + + /// Enable using the EXTCLK pin as clock source input. + /// + /// This setting is _sticky_. It can only be cleared by a power cycle or + /// a software reset. + pub fn use_external_clock(&mut self) -> Result<(), Error> { + let config = self.config; + self.write_mode1(config.with_high(BitFlagMode1::Sleep))?; + let config = self.config; + self.write_mode1(config.with_high(BitFlagMode1::ExtClk)) + } + + /// Set the prescale value. + /// + /// The prescale value can be calculated for an update rate with the formula: + /// `prescale_value = round(osc_value / (4096 * update_rate)) - 1` + /// + /// The minimum prescale value is 3, which corresonds to an update rate of + /// 1526 Hz. The maximum prescale value is 255, which corresponds to an + /// update rate of 24 Hz. + /// + /// If you want to control a servo, set a prescale value of 100. This will + /// correspond to a frequency of about 60 Hz, which is the frequency at + /// which servos work. + /// + /// Internally this function stops the oscillator and restarts it after + /// setting the prescale value if it was running. + pub fn set_prescale(&mut self, prescale: u8) -> Result<(), Error> { + if prescale < 3 { + return Err(Error::InvalidInputData); + } + let config = self.config; + let was_oscillator_running = config.is_low(BitFlagMode1::Sleep); + if was_oscillator_running { + // stop the oscillator + self.write_mode1(config.with_high(BitFlagMode1::Sleep))?; + } + + self.i2c + .write(self.address, &[Register::PRE_SCALE, prescale]) + .map_err(Error::I2C)?; + + if was_oscillator_running { + // restart the oscillator + self.write_mode1(config)?; + } + Ok(()) + } +} diff --git a/src/blocking/mod.rs b/src/blocking/mod.rs new file mode 100644 index 0000000..09c89af --- /dev/null +++ b/src/blocking/mod.rs @@ -0,0 +1,3 @@ +mod device_impl; +mod register_access; +mod channels; diff --git a/src/blocking/register_access.rs b/src/blocking/register_access.rs new file mode 100644 index 0000000..ad52d92 --- /dev/null +++ b/src/blocking/register_access.rs @@ -0,0 +1,75 @@ +use crate::{ + config::{BitFlagMode1, Config}, + hal::blocking::i2c, + Error, Pca9685, Register +}; + +impl Pca9685 +where + I2C: i2c::Write + i2c::WriteRead, +{ + pub(crate) fn write_mode2(&mut self, config: Config) -> Result<(), Error> { + self.i2c + .write(self.address, &[Register::MODE2, config.mode2]) + .map_err(Error::I2C)?; + self.config.mode2 = config.mode2; + Ok(()) + } + + pub(crate) fn write_mode1(&mut self, config: Config) -> Result<(), Error> { + self.i2c + .write(self.address, &[Register::MODE1, config.mode1]) + .map_err(Error::I2C)?; + self.config.mode1 = config.mode1; + Ok(()) + } + + pub(crate) fn enable_auto_increment(&mut self) -> Result<(), Error> { + if self.config.is_low(BitFlagMode1::AutoInc) { + let config = self.config; + self.write_mode1(config.with_high(BitFlagMode1::AutoInc)) + } else { + Ok(()) + } + } + + pub(crate) fn write_two_double_registers( + &mut self, + address: u8, + value0: u16, + value1: u16, + ) -> Result<(), Error> { + self.enable_auto_increment()?; + self.i2c + .write( + self.address, + &[ + address, + value0 as u8, + (value0 >> 8) as u8, + value1 as u8, + (value1 >> 8) as u8, + ], + ) + .map_err(Error::I2C) + } + + pub(crate) fn write_double_register( + &mut self, + address: u8, + value: u16, + ) -> Result<(), Error> { + self.enable_auto_increment()?; + self.i2c + .write(self.address, &[address, value as u8, (value >> 8) as u8]) + .map_err(Error::I2C) + } + + pub(crate) fn read_register(&mut self, address: u8) -> Result> { + let mut data = [0]; + self.i2c + .write_read(self.address, &[address], &mut data) + .map_err(Error::I2C) + .and(Ok(data[0])) + } +} diff --git a/src/channels.rs b/src/channels.rs index 48386f9..bf15698 100644 --- a/src/channels.rs +++ b/src/channels.rs @@ -1,100 +1,4 @@ -use crate::{hal, Channel, Error, Pca9685, Register}; - -impl Pca9685 -where - I2C: hal::blocking::i2c::Write + hal::blocking::i2c::WriteRead, -{ - /// Set the `ON` counter for the selected channel. - /// - /// Note that the full off setting takes precedence over the `on` settings. - /// See section 7.3.3 "LED output and PWM control" of the datasheet for - /// further details. - pub fn set_channel_on(&mut self, channel: Channel, value: u16) -> Result<(), Error> { - if value > 4095 { - return Err(Error::InvalidInputData); - } - let reg = get_register_on(channel); - self.write_double_register(reg, value) - } - - /// Set the `OFF` counter for the selected channel. - pub fn set_channel_off(&mut self, channel: Channel, value: u16) -> Result<(), Error> { - if value > 4095 { - return Err(Error::InvalidInputData); - } - let reg = get_register_off(channel); - self.write_double_register(reg, value) - } - - /// Set the `ON` and `OFF` counters for the selected channel. - /// - /// Note that the full off setting takes precedence over the `on` settings. - /// See section 7.3.3 "LED output and PWM control" of the datasheet for - /// further details. - pub fn set_channel_on_off( - &mut self, - channel: Channel, - on: u16, - off: u16, - ) -> Result<(), Error> { - if on > 4095 || off > 4095 { - return Err(Error::InvalidInputData); - } - let reg = get_register_on(channel); - self.write_two_double_registers(reg, on, off) - } - - /// Set the channel always on. - /// - /// The turning on is delayed by the value argument. - /// Note that the full off setting takes precedence over the `on` settings. - /// - /// See section 7.3.3 "LED output and PWM control" of the datasheet for - /// further details. - pub fn set_channel_full_on(&mut self, channel: Channel, value: u16) -> Result<(), Error> { - if value > 4095 { - return Err(Error::InvalidInputData); - } - let reg = get_register_on(channel); - let value = value | 0b0001_0000_0000_0000; - self.write_double_register(reg, value) - } - - /// Set the channel always off. - /// - /// This takes precedence over the `on` settings and can be cleared by setting - /// the `off` counter with [`set_channel_off`](struct.Pca9685.html#method.set_channel_off). - /// - /// See section 7.3.3 "LED output and PWM control" of the datasheet for - /// further details. - pub fn set_channel_full_off(&mut self, channel: Channel) -> Result<(), Error> { - let reg = get_register_off(channel); - let value = 0b0001_0000_0000_0000; - self.write_double_register(reg, value) - } - - /// Set the `ON` and `OFF` counter for each channel at once. - /// - /// The index of the value in the arrays corresponds to the channel: 0-15. - /// Note that the full off setting takes precedence over the `on` settings. - /// See section 7.3.3 "LED output and PWM control" of the datasheet for - /// further details. - pub fn set_all_on_off(&mut self, on: &[u16; 16], off: &[u16; 16]) -> Result<(), Error> { - let mut data = [0; 65]; - data[0] = Register::C0_ON_L; - for (i, (on, off)) in on.iter().zip(off).enumerate() { - if *on > 4095 || *off > 4095 { - return Err(Error::InvalidInputData); - } - data[i * 4 + 1] = *on as u8; - data[i * 4 + 2] = (*on >> 8) as u8; - data[i * 4 + 3] = *off as u8; - data[i * 4 + 4] = (*off >> 8) as u8; - } - self.enable_auto_increment()?; - self.i2c.write(self.address, &data).map_err(Error::I2C) - } -} +use crate::{Channel, Register}; macro_rules! get_register { ($channel:expr, $($C:ident, $reg:ident),*) => { @@ -106,7 +10,7 @@ macro_rules! get_register { }; } -fn get_register_on(channel: Channel) -> u8 { +pub(crate) fn get_register_on(channel: Channel) -> u8 { get_register!( channel, C0, C0_ON_L, C1, C1_ON_L, C2, C2_ON_L, C3, C3_ON_L, C4, C4_ON_L, C5, C5_ON_L, C6, C6_ON_L, C7, C7_ON_L, C8, C8_ON_L, C9, C9_ON_L, C10, C10_ON_L, C11, C11_ON_L, C12, @@ -114,7 +18,7 @@ fn get_register_on(channel: Channel) -> u8 { ) } -fn get_register_off(channel: Channel) -> u8 { +pub(crate) fn get_register_off(channel: Channel) -> u8 { get_register!( channel, C0, diff --git a/src/device_impl.rs b/src/device_impl.rs index 82b331d..32fa118 100644 --- a/src/device_impl.rs +++ b/src/device_impl.rs @@ -1,124 +1,12 @@ use crate::{ - config::{BitFlagMode1, BitFlagMode2, Config}, - hal::{blocking::delay::DelayUs, blocking::i2c}, - Address, DisabledOutputValue, Error, OutputDriver, OutputLogicState, OutputStateChange, - Pca9685, ProgrammableAddress, Register, + config::{BitFlagMode1, Config}, + Pca9685, ProgrammableAddress, }; -impl Pca9685 -where - I2C: i2c::Write + i2c::WriteRead, -{ - /// Create a new instance of the device. - pub fn new>(i2c: I2C, address: A) -> Result> { - let a = address.into(); - - Self::check_address(a.0)?; - - Ok(Pca9685 { - i2c, - address: a.0, - config: Config::default(), - }) - } - - /// Destroy driver instance, return I²C bus instance. - pub fn destroy(self) -> I2C { - self.i2c - } - - /// Enable the controller. - pub fn enable(&mut self) -> Result<(), Error> { - let config = self.config; - self.write_mode1(config.with_low(BitFlagMode1::Sleep)) - } - - /// Disable the controller (sleep). - pub fn disable(&mut self) -> Result<(), Error> { - let config = self.config; - self.write_mode1(config.with_high(BitFlagMode1::Sleep)) - } - - /// Put the controller to sleep while keeping the PWM register - /// contents in preparation for a future restart. - pub fn enable_restart_and_disable(&mut self) -> Result<(), Error> { - let config = self.config.with_high(BitFlagMode1::Sleep); - self.write_mode1(config.with_high(BitFlagMode1::Restart))?; - // Do not store restart bit high as writing this bit high again - // would internally clear it to 0. Writing 0 has no effect. - self.config = config; - Ok(()) - } - - /// Re-enable the controller after a sleep with restart enabled so that - /// previously active PWM channels are restarted. - /// - /// This includes a delay of 500us in order for the oscillator to stabilize. - /// If you cannot afford a 500us delay you can use `restart_nonblocking()`. - pub fn restart(&mut self, delay: &mut impl DelayUs) -> Result<(), Error> { - let mode1 = self.read_register(Register::MODE1)?; - if (mode1 & BitFlagMode1::Restart as u8) != 0 { - self.enable()?; - delay.delay_us(500_u16); - let previous = self.config; - let config = previous.with_high(BitFlagMode1::Restart); - self.write_mode1(config)?; - self.config = previous; - } - Ok(()) - } - /// Re-enable the controller after a sleep with restart enabled so that - /// previously active PWM channels are restarted (non-blocking version). - /// - /// This is a nonblocking version where you are responsible for waiting at - /// least 500us after the receiving the first `WouldBlock` error before - /// calling again to continue. - pub fn restart_nonblocking(&mut self) -> nb::Result<(), Error> { - let mode1 = self - .read_register(Register::MODE1) - .map_err(nb::Error::Other)?; - let restart_high = (mode1 & BitFlagMode1::Restart as u8) != 0; - let sleep_high = (mode1 & BitFlagMode1::Sleep as u8) != 0; - if restart_high { - if sleep_high { - self.enable().map_err(nb::Error::Other)?; - return Err(nb::Error::WouldBlock); - } else { - let previous = self.config; - let config = previous.with_high(BitFlagMode1::Restart); - self.write_mode1(config).map_err(nb::Error::Other)?; - self.config = previous; - } - } - Ok(()) - } - - /// Set one of the programmable addresses. - /// - /// Initially these are not enabled. Once you set this, you can call - /// `enable_programmable_address()` and then use `set_address()` to configure - /// the driver to use the new address. - pub fn set_programmable_address>( - &mut self, - address_type: ProgrammableAddress, - address: A, - ) -> Result<(), Error> { - let a = address.into(); - - Self::check_address(a.0)?; - let reg = match address_type { - ProgrammableAddress::Subaddress1 => Register::SUBADDR1, - ProgrammableAddress::Subaddress2 => Register::SUBADDR2, - ProgrammableAddress::Subaddress3 => Register::SUBADDR3, - ProgrammableAddress::AllCall => Register::ALL_CALL_ADDR, - }; - self.i2c - .write(self.address, &[reg, a.0]) - .map_err(Error::I2C) - } - - fn get_subaddr_bitflag(address_type: ProgrammableAddress) -> BitFlagMode1 { +impl Pca9685 +{ + pub(crate) fn get_subaddr_bitflag(address_type: ProgrammableAddress) -> BitFlagMode1 { match address_type { ProgrammableAddress::Subaddress1 => BitFlagMode1::Subaddr1, ProgrammableAddress::Subaddress2 => BitFlagMode1::Subaddr2, @@ -127,156 +15,6 @@ where } } - /// Enable responding to programmable address - pub fn enable_programmable_address( - &mut self, - address_type: ProgrammableAddress, - ) -> Result<(), Error> { - let flag = Self::get_subaddr_bitflag(address_type); - let config = self.config; - self.write_mode1(config.with_high(flag)) - } - - /// Disable responding to programmable address - pub fn disable_programmable_address( - &mut self, - address_type: ProgrammableAddress, - ) -> Result<(), Error> { - let flag = Self::get_subaddr_bitflag(address_type); - let config = self.config; - self.write_mode1(config.with_low(flag)) - } - - /// Sets the address used by the driver for communication. - /// - /// This does not have any effect on the hardware and is useful when - /// switching between programmable addresses and the fixed hardware address - /// for communication. - pub fn set_address>(&mut self, address: A) -> Result<(), Error> { - let a = address.into(); - - Self::check_address(a.0)?; - self.address = a.0; - - Ok(()) - } - - fn check_address(address: u8) -> Result<(), Error> { - const LED_ALL_CALL: u8 = 0b111_0000; - // const SW_RESET: u8 = 0b000_0011; this gets absorbed by the high speed mode test - const HIGH_SPEED_MODE: u8 = 0b00_0111; - if address == 0 || address > 0x7F || address == LED_ALL_CALL || address <= HIGH_SPEED_MODE { - Err(Error::InvalidInputData) - } else { - Ok(()) - } - } - - /// Set the output change behavior. Either byte-by-byte or all at the same time. - /// - /// Note that update on ACK requires all 4 PWM channel registers to be loaded before - /// outputs are changed on the last ACK. - pub fn set_output_change_behavior( - &mut self, - change_behavior: OutputStateChange, - ) -> Result<(), Error> { - let config = match change_behavior { - OutputStateChange::OnStop => self.config.with_low(BitFlagMode2::Och), - OutputStateChange::OnAck => self.config.with_high(BitFlagMode2::Och), - }; - self.write_mode2(config) - } - - /// Set the output driver configuration. - pub fn set_output_driver(&mut self, driver: OutputDriver) -> Result<(), Error> { - let config = match driver { - OutputDriver::TotemPole => self.config.with_high(BitFlagMode2::OutDrv), - OutputDriver::OpenDrain => self.config.with_low(BitFlagMode2::OutDrv), - }; - self.write_mode2(config) - } - - /// Set the output value when outputs are disabled (`OE` = 1). - pub fn set_disabled_output_value( - &mut self, - value: DisabledOutputValue, - ) -> Result<(), Error> { - let config = match value { - DisabledOutputValue::Zero => self - .config - .with_low(BitFlagMode2::OutNe0) - .with_low(BitFlagMode2::OutNe1), - DisabledOutputValue::OutputDriver => self - .config - .with_high(BitFlagMode2::OutNe0) - .with_low(BitFlagMode2::OutNe1), - DisabledOutputValue::HighImpedance => self - .config - .with_low(BitFlagMode2::OutNe0) - .with_high(BitFlagMode2::OutNe1), - }; - self.write_mode2(config) - } - - /// Set the output logic state - /// - /// This allows for inversion of the output logic. Applicable when `OE = 0`. - pub fn set_output_logic_state(&mut self, state: OutputLogicState) -> Result<(), Error> { - let config = self.config; - match state { - OutputLogicState::Direct => self.write_mode2(config.with_low(BitFlagMode2::Invrt)), - OutputLogicState::Inverted => self.write_mode2(config.with_high(BitFlagMode2::Invrt)), - } - } - - /// Enable using the EXTCLK pin as clock source input. - /// - /// This setting is _sticky_. It can only be cleared by a power cycle or - /// a software reset. - pub fn use_external_clock(&mut self) -> Result<(), Error> { - let config = self.config; - self.write_mode1(config.with_high(BitFlagMode1::Sleep))?; - let config = self.config; - self.write_mode1(config.with_high(BitFlagMode1::ExtClk)) - } - - /// Set the prescale value. - /// - /// The prescale value can be calculated for an update rate with the formula: - /// `prescale_value = round(osc_value / (4096 * update_rate)) - 1` - /// - /// The minimum prescale value is 3, which corresonds to an update rate of - /// 1526 Hz. The maximum prescale value is 255, which corresponds to an - /// update rate of 24 Hz. - /// - /// If you want to control a servo, set a prescale value of 100. This will - /// correspond to a frequency of about 60 Hz, which is the frequency at - /// which servos work. - /// - /// Internally this function stops the oscillator and restarts it after - /// setting the prescale value if it was running. - pub fn set_prescale(&mut self, prescale: u8) -> Result<(), Error> { - if prescale < 3 { - return Err(Error::InvalidInputData); - } - let config = self.config; - let was_oscillator_running = config.is_low(BitFlagMode1::Sleep); - if was_oscillator_running { - // stop the oscillator - self.write_mode1(config.with_high(BitFlagMode1::Sleep))?; - } - - self.i2c - .write(self.address, &[Register::PRE_SCALE, prescale]) - .map_err(Error::I2C)?; - - if was_oscillator_running { - // restart the oscillator - self.write_mode1(config)?; - } - Ok(()) - } - /// Reset the internal state of this driver to the default values. /// /// *Note:* This does not alter the state or configuration of the device. diff --git a/src/lib.rs b/src/lib.rs index de0b8ea..a6cdadd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -255,3 +255,6 @@ pub use crate::types::{ OutputStateChange, Pca9685, ProgrammableAddress, }; pub use nb; + +/// Implementation of sync functionality +mod blocking; diff --git a/src/register_access.rs b/src/register_access.rs index 5bea229..9cfa19c 100644 --- a/src/register_access.rs +++ b/src/register_access.rs @@ -1,9 +1,3 @@ -use crate::{ - config::{BitFlagMode1, Config}, - hal::blocking::i2c, - Error, Pca9685, -}; - pub struct Register; impl Register { pub const MODE1: u8 = 0x00; @@ -48,73 +42,3 @@ impl Register { pub const ALL_C_OFF_L: u8 = 0xFC; pub const PRE_SCALE: u8 = 0xFE; } - -impl Pca9685 -where - I2C: i2c::Write + i2c::WriteRead, -{ - pub(crate) fn write_mode2(&mut self, config: Config) -> Result<(), Error> { - self.i2c - .write(self.address, &[Register::MODE2, config.mode2]) - .map_err(Error::I2C)?; - self.config.mode2 = config.mode2; - Ok(()) - } - - pub(crate) fn write_mode1(&mut self, config: Config) -> Result<(), Error> { - self.i2c - .write(self.address, &[Register::MODE1, config.mode1]) - .map_err(Error::I2C)?; - self.config.mode1 = config.mode1; - Ok(()) - } - - pub(crate) fn enable_auto_increment(&mut self) -> Result<(), Error> { - if self.config.is_low(BitFlagMode1::AutoInc) { - let config = self.config; - self.write_mode1(config.with_high(BitFlagMode1::AutoInc)) - } else { - Ok(()) - } - } - - pub(crate) fn write_two_double_registers( - &mut self, - address: u8, - value0: u16, - value1: u16, - ) -> Result<(), Error> { - self.enable_auto_increment()?; - self.i2c - .write( - self.address, - &[ - address, - value0 as u8, - (value0 >> 8) as u8, - value1 as u8, - (value1 >> 8) as u8, - ], - ) - .map_err(Error::I2C) - } - - pub(crate) fn write_double_register( - &mut self, - address: u8, - value: u16, - ) -> Result<(), Error> { - self.enable_auto_increment()?; - self.i2c - .write(self.address, &[address, value as u8, (value >> 8) as u8]) - .map_err(Error::I2C) - } - - pub(crate) fn read_register(&mut self, address: u8) -> Result> { - let mut data = [0]; - self.i2c - .write_read(self.address, &[address], &mut data) - .map_err(Error::I2C) - .and(Ok(data[0])) - } -}