• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

eldruin / pwm-pca9685-rs / 9962393144

16 Jul 2024 06:43PM UTC coverage: 97.517% (+14.4%) from 83.103%
9962393144

push

github

eldruin
Use cargo-llvm-cov for coverage

432 of 443 relevant lines covered (97.52%)

34.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.81
/src/device_impl.rs
1
use crate::{
2
    config::{BitFlagMode1, BitFlagMode2, Config},
3
    Address, DisabledOutputValue, Error, OutputDriver, OutputLogicState, OutputStateChange,
4
    Pca9685, ProgrammableAddress, Register,
5
};
6

7
#[cfg(not(feature = "async"))]
8
use embedded_hal::{delay::DelayNs, i2c::I2c};
9
#[cfg(feature = "async")]
10
use embedded_hal_async::{delay::DelayNs as AsyncDelayNs, i2c::I2c as AsyncI2c};
11

12
#[maybe_async_cfg::maybe(
13
    sync(
14
        cfg(not(feature = "async")),
15
        self = "Pca9685",
16
        idents(AsyncI2c(sync = "I2c")),
17
        idents(AsyncDelayNs(sync = "DelayNs"))
18
    ),
19
    async(feature = "async", keep_self)
20
)]
21
impl<I2C, E> Pca9685<I2C>
22
where
23
    I2C: AsyncI2c<Error = E>,
24
{
25
    /// Create a new instance of the device.
26
    pub fn new<A: Into<Address>>(i2c: I2C, address: A) -> Result<Self, Error<E>> {
192✔
27
        let a = address.into();
192✔
28

192✔
29
        Self::check_address(a.0)?;
192✔
30

31
        Ok(Pca9685 {
192✔
32
            i2c,
192✔
33
            address: a.0,
192✔
34
            config: Config::default(),
192✔
35
        })
192✔
36
    }
192✔
37

38
    /// Destroy driver instance, return I²C bus instance.
39
    pub fn destroy(self) -> I2C {
192✔
40
        self.i2c
192✔
41
    }
192✔
42

43
    /// Enable the controller.
44
    pub async fn enable(&mut self) -> Result<(), Error<E>> {
4✔
45
        let config = self.config;
4✔
46
        self.write_mode1(config.with_low(BitFlagMode1::Sleep)).await
4✔
47
    }
4✔
48

49
    /// Disable the controller (sleep).
50
    pub async fn disable(&mut self) -> Result<(), Error<E>> {
1✔
51
        let config = self.config;
1✔
52
        self.write_mode1(config.with_high(BitFlagMode1::Sleep))
1✔
53
            .await
1✔
54
    }
1✔
55

56
    /// Put the controller to sleep while keeping the PWM register
57
    /// contents in preparation for a future restart.
58
    pub async fn enable_restart_and_disable(&mut self) -> Result<(), Error<E>> {
4✔
59
        let config = self.config.with_high(BitFlagMode1::Sleep);
4✔
60
        self.write_mode1(config.with_high(BitFlagMode1::Restart))
4✔
61
            .await?;
×
62
        // Do not store restart bit high as writing this bit high again
63
        // would internally clear it to 0. Writing 0 has no effect.
64
        self.config = config;
4✔
65
        Ok(())
4✔
66
    }
4✔
67

68
    /// Re-enable the controller after a sleep with restart enabled so that
69
    /// previously active PWM channels are restarted.
70
    ///
71
    /// This includes a delay of 500us in order for the oscillator to stabilize.
72
    /// If you cannot afford a 500us delay you can use `restart_nonblocking()`.
73
    pub async fn restart(&mut self, delay: &mut impl AsyncDelayNs) -> Result<(), Error<E>> {
2✔
74
        let mode1 = self.read_register(Register::MODE1).await?;
2✔
75
        if (mode1 & BitFlagMode1::Restart as u8) != 0 {
2✔
76
            self.enable().await?;
1✔
77
            delay.delay_us(500).await;
1✔
78
            let previous = self.config;
1✔
79
            let config = previous.with_high(BitFlagMode1::Restart);
1✔
80
            self.write_mode1(config).await?;
1✔
81
            self.config = previous;
1✔
82
        }
1✔
83
        Ok(())
2✔
84
    }
2✔
85

86
    /// Re-enable the controller after a sleep with restart enabled so that
87
    /// previously active PWM channels are restarted (non-blocking version).
88
    ///
89
    /// This is a nonblocking version where you are responsible for waiting at
90
    /// least 500us after the receiving the first `WouldBlock` error before
91
    /// calling again to continue.
92
    pub async fn restart_nonblocking(&mut self) -> nb::Result<(), Error<E>> {
3✔
93
        let mode1 = self
3✔
94
            .read_register(Register::MODE1)
3✔
95
            .await
3✔
96
            .map_err(nb::Error::Other)?;
3✔
97
        let restart_high = (mode1 & BitFlagMode1::Restart as u8) != 0;
3✔
98
        let sleep_high = (mode1 & BitFlagMode1::Sleep as u8) != 0;
3✔
99
        if restart_high {
3✔
100
            if sleep_high {
2✔
101
                self.enable().await.map_err(nb::Error::Other)?;
1✔
102
                return Err(nb::Error::WouldBlock);
1✔
103
            } else {
104
                let previous = self.config;
1✔
105
                let config = previous.with_high(BitFlagMode1::Restart);
1✔
106
                self.write_mode1(config).await.map_err(nb::Error::Other)?;
1✔
107
                self.config = previous;
1✔
108
            }
109
        }
1✔
110
        Ok(())
2✔
111
    }
3✔
112

113
    /// Set one of the programmable addresses.
114
    ///
115
    /// Initially these are not enabled. Once you set this, you can call
116
    /// `enable_programmable_address()` and then use `set_address()` to configure
117
    /// the driver to use the new address.
118
    pub async fn set_programmable_address<A: Into<Address>>(
8✔
119
        &mut self,
8✔
120
        address_type: ProgrammableAddress,
8✔
121
        address: A,
8✔
122
    ) -> Result<(), Error<E>> {
8✔
123
        let a = address.into();
8✔
124

8✔
125
        Self::check_address(a.0)?;
8✔
126
        let reg = match address_type {
4✔
127
            ProgrammableAddress::Subaddress1 => Register::SUBADDR1,
1✔
128
            ProgrammableAddress::Subaddress2 => Register::SUBADDR2,
1✔
129
            ProgrammableAddress::Subaddress3 => Register::SUBADDR3,
1✔
130
            ProgrammableAddress::AllCall => Register::ALL_CALL_ADDR,
1✔
131
        };
132
        self.i2c
4✔
133
            .write(self.address, &[reg, a.0])
4✔
134
            .await
4✔
135
            .map_err(Error::I2C)
4✔
136
    }
8✔
137

138
    fn get_subaddr_bitflag(address_type: ProgrammableAddress) -> BitFlagMode1 {
9✔
139
        match address_type {
9✔
140
            ProgrammableAddress::Subaddress1 => BitFlagMode1::Subaddr1,
3✔
141
            ProgrammableAddress::Subaddress2 => BitFlagMode1::Subaddr2,
2✔
142
            ProgrammableAddress::Subaddress3 => BitFlagMode1::Subaddr3,
2✔
143
            ProgrammableAddress::AllCall => BitFlagMode1::AllCall,
2✔
144
        }
145
    }
9✔
146

147
    /// Enable responding to programmable address
148
    pub async fn enable_programmable_address(
5✔
149
        &mut self,
5✔
150
        address_type: ProgrammableAddress,
5✔
151
    ) -> Result<(), Error<E>> {
5✔
152
        let flag = Self::get_subaddr_bitflag(address_type);
5✔
153
        let config = self.config;
5✔
154
        self.write_mode1(config.with_high(flag)).await
5✔
155
    }
5✔
156

157
    /// Disable responding to programmable address
158
    pub async fn disable_programmable_address(
4✔
159
        &mut self,
4✔
160
        address_type: ProgrammableAddress,
4✔
161
    ) -> Result<(), Error<E>> {
4✔
162
        let flag = Self::get_subaddr_bitflag(address_type);
4✔
163
        let config = self.config;
4✔
164
        self.write_mode1(config.with_low(flag)).await
4✔
165
    }
4✔
166

167
    /// Sets the address used by the driver for communication.
168
    ///
169
    /// This does not have any effect on the hardware and is useful when
170
    /// switching between programmable addresses and the fixed hardware address
171
    /// for communication.
172
    pub fn set_address<A: Into<Address>>(&mut self, address: A) -> Result<(), Error<E>> {
6✔
173
        let a = address.into();
6✔
174

6✔
175
        Self::check_address(a.0)?;
6✔
176
        self.address = a.0;
1✔
177

1✔
178
        Ok(())
1✔
179
    }
6✔
180

181
    fn check_address(address: u8) -> Result<(), Error<E>> {
206✔
182
        const LED_ALL_CALL: u8 = 0b111_0000;
206✔
183
        // const SW_RESET: u8 = 0b000_0011; this gets absorbed by the high speed mode test
206✔
184
        const HIGH_SPEED_MODE: u8 = 0b00_0111;
206✔
185
        if address == 0 || address > 0x7F || address == LED_ALL_CALL || address <= HIGH_SPEED_MODE {
206✔
186
            Err(Error::InvalidInputData)
9✔
187
        } else {
188
            Ok(())
197✔
189
        }
190
    }
206✔
191

192
    /// Set the output change behavior. Either byte-by-byte or all at the same time.
193
    ///
194
    /// Note that update on ACK requires all 4 PWM channel registers to be loaded before
195
    /// outputs are changed on the last ACK.
196
    pub async fn set_output_change_behavior(
2✔
197
        &mut self,
2✔
198
        change_behavior: OutputStateChange,
2✔
199
    ) -> Result<(), Error<E>> {
2✔
200
        let config = match change_behavior {
2✔
201
            OutputStateChange::OnStop => self.config.with_low(BitFlagMode2::Och),
1✔
202
            OutputStateChange::OnAck => self.config.with_high(BitFlagMode2::Och),
1✔
203
        };
204
        self.write_mode2(config).await
2✔
205
    }
2✔
206

207
    /// Set the output driver configuration.
208
    pub async fn set_output_driver(&mut self, driver: OutputDriver) -> Result<(), Error<E>> {
2✔
209
        let config = match driver {
2✔
210
            OutputDriver::TotemPole => self.config.with_high(BitFlagMode2::OutDrv),
1✔
211
            OutputDriver::OpenDrain => self.config.with_low(BitFlagMode2::OutDrv),
1✔
212
        };
213
        self.write_mode2(config).await
2✔
214
    }
2✔
215

216
    /// Set the output value when outputs are disabled (`OE` = 1).
217
    pub async fn set_disabled_output_value(
3✔
218
        &mut self,
3✔
219
        value: DisabledOutputValue,
3✔
220
    ) -> Result<(), Error<E>> {
3✔
221
        let config = match value {
3✔
222
            DisabledOutputValue::Zero => self
1✔
223
                .config
1✔
224
                .with_low(BitFlagMode2::OutNe0)
1✔
225
                .with_low(BitFlagMode2::OutNe1),
1✔
226
            DisabledOutputValue::OutputDriver => self
1✔
227
                .config
1✔
228
                .with_high(BitFlagMode2::OutNe0)
1✔
229
                .with_low(BitFlagMode2::OutNe1),
1✔
230
            DisabledOutputValue::HighImpedance => self
1✔
231
                .config
1✔
232
                .with_low(BitFlagMode2::OutNe0)
1✔
233
                .with_high(BitFlagMode2::OutNe1),
1✔
234
        };
235
        self.write_mode2(config).await
3✔
236
    }
3✔
237

238
    /// Set the output logic state
239
    ///
240
    /// This allows for inversion of the output logic. Applicable when `OE = 0`.
241
    pub async fn set_output_logic_state(
2✔
242
        &mut self,
2✔
243
        state: OutputLogicState,
2✔
244
    ) -> Result<(), Error<E>> {
2✔
245
        let config = self.config;
2✔
246
        match state {
2✔
247
            OutputLogicState::Direct => {
248
                self.write_mode2(config.with_low(BitFlagMode2::Invrt)).await
1✔
249
            }
250
            OutputLogicState::Inverted => {
251
                self.write_mode2(config.with_high(BitFlagMode2::Invrt))
1✔
252
                    .await
253
            }
254
        }
255
    }
2✔
256

257
    /// Enable using the EXTCLK pin as clock source input.
258
    ///
259
    /// This setting is _sticky_. It can only be cleared by a power cycle or
260
    /// a software reset.
261
    pub async fn use_external_clock(&mut self) -> Result<(), Error<E>> {
1✔
262
        let config = self.config;
1✔
263
        self.write_mode1(config.with_high(BitFlagMode1::Sleep))
1✔
264
            .await?;
×
265
        let config = self.config;
1✔
266
        self.write_mode1(config.with_high(BitFlagMode1::ExtClk))
1✔
267
            .await
268
    }
1✔
269

270
    /// Set the prescale value.
271
    ///
272
    /// The prescale value can be calculated for an update rate with the formula:
273
    /// `prescale_value = round(osc_value / (4096 * update_rate)) - 1`
274
    ///
275
    /// The minimum prescale value is 3, which corresonds to an update rate of
276
    /// 1526 Hz. The maximum prescale value is 255, which corresponds to an
277
    /// update rate of 24 Hz.
278
    ///
279
    /// If you want to control a servo, set a prescale value of 100. This will
280
    /// correspond to a frequency of about 60 Hz, which is the frequency at
281
    /// which servos work.
282
    ///
283
    /// Internally this function stops the oscillator and restarts it after
284
    /// setting the prescale value if it was running.
285
    pub async fn set_prescale(&mut self, prescale: u8) -> Result<(), Error<E>> {
4✔
286
        if prescale < 3 {
4✔
287
            return Err(Error::InvalidInputData);
1✔
288
        }
3✔
289
        let config = self.config;
3✔
290
        let was_oscillator_running = config.is_low(BitFlagMode1::Sleep);
3✔
291
        if was_oscillator_running {
3✔
292
            // stop the oscillator
293
            self.write_mode1(config.with_high(BitFlagMode1::Sleep))
1✔
294
                .await?;
×
295
        }
2✔
296

297
        self.i2c
3✔
298
            .write(self.address, &[Register::PRE_SCALE, prescale])
3✔
299
            .await
3✔
300
            .map_err(Error::I2C)?;
3✔
301

302
        if was_oscillator_running {
3✔
303
            // restart the oscillator
304
            self.write_mode1(config).await?;
1✔
305
        }
2✔
306
        Ok(())
3✔
307
    }
4✔
308

309
    /// Reset the internal state of this driver to the default values.
310
    ///
311
    /// *Note:* This does not alter the state or configuration of the device.
312
    ///
313
    /// This resets the cached configuration register value in this driver to
314
    /// the power-up (reset) configuration of the device.
315
    ///
316
    /// This needs to be called after performing a reset on the device, for
317
    /// example through an I2C general-call Reset command, which was not done
318
    /// through this driver to ensure that the configurations in the device
319
    /// and in the driver match.
320
    pub fn reset_internal_driver_state(&mut self) {
×
321
        self.config = Config::default();
×
322
    }
×
323
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc