pamoja_actuators/pca9685.rs
1//! NXP PCA9685 16-channel, 12-bit PWM controller.
2//!
3//! The PCA9685 drives sixteen independent PWM outputs at one shared frequency, which
4//! is what makes it the usual way to run a bank of servos, dimmable LEDs, or the
5//! speed and direction inputs of motor drivers from a single I2C device. This module
6//! builds the values that program it: the prescaler that sets the output frequency,
7//! the address of each channel's registers, and the 12-bit on/off word that sets a
8//! channel's phase and duty, with the full-on and full-off encodings the datasheet
9//! defines.
10//!
11//! It is pure logic: a caller writes the bytes to the device over whatever performs
12//! the I2C transfers.
13
14#[cfg(feature = "embedded-hal")]
15mod driver;
16#[cfg(feature = "embedded-hal")]
17pub mod sim;
18
19#[cfg(feature = "embedded-hal")]
20pub use driver::{Output, Outputs, Pca9685};
21
22/// The I2C address with the six address pins low.
23pub const DEFAULT_I2C_ADDRESS: u8 = 0x40;
24
25/// The general-call address the software reset is sent to.
26pub const SOFTWARE_RESET_ADDRESS: u8 = 0x00;
27
28/// The one data byte the software reset carries; any other byte is not acknowledged.
29pub const SOFTWARE_RESET_BYTE: u8 = 0x06;
30
31/// How long the oscillator takes to run after the SLEEP bit is cleared, in
32/// microseconds; channel timing is not guaranteed inside this window and the
33/// RESTART bit must not be written before it has passed.
34pub const OSCILLATOR_STARTUP_MICROS: u32 = 500;
35
36/// The reset value of MODE2: totem-pole outputs, not inverted, change on STOP.
37pub const MODE2_RESET: u8 = 0x04;
38
39/// The PCA9685 register addresses.
40pub mod register {
41 /// Mode register 1.
42 pub const MODE1: u8 = 0x00;
43 /// Mode register 2.
44 pub const MODE2: u8 = 0x01;
45 /// I2C-bus subaddress 1.
46 pub const SUBADR1: u8 = 0x02;
47 /// I2C-bus subaddress 2.
48 pub const SUBADR2: u8 = 0x03;
49 /// I2C-bus subaddress 3.
50 pub const SUBADR3: u8 = 0x04;
51 /// LED All Call I2C-bus address.
52 pub const ALLCALL_ADDR: u8 = 0x05;
53 /// First register of channel 0 (LED0_ON_L); each channel spans four registers.
54 pub const LED0_ON_L: u8 = 0x06;
55 /// Low byte of the on-count applied to all channels at once.
56 pub const ALL_LED_ON_L: u8 = 0xFA;
57 /// High byte of the on-count applied to all channels at once.
58 pub const ALL_LED_ON_H: u8 = 0xFB;
59 /// Low byte of the off-count applied to all channels at once.
60 pub const ALL_LED_OFF_L: u8 = 0xFC;
61 /// High byte of the off-count applied to all channels at once.
62 pub const ALL_LED_OFF_H: u8 = 0xFD;
63 /// Prescaler that sets the PWM output frequency.
64 pub const PRE_SCALE: u8 = 0xFE;
65}
66
67/// Bit masks for the MODE1 register.
68pub mod mode1 {
69 /// Restart logic.
70 pub const RESTART: u8 = 0x80;
71 /// Use the external clock pin instead of the internal oscillator.
72 pub const EXTCLK: u8 = 0x40;
73 /// Auto-increment the register pointer, needed to write a channel's four bytes in
74 /// one transfer.
75 pub const AUTO_INCREMENT: u8 = 0x20;
76 /// Low-power sleep: the oscillator is off and the prescaler can be written.
77 pub const SLEEP: u8 = 0x10;
78 /// Respond to I2C-bus subaddress 1.
79 pub const SUB1: u8 = 0x08;
80 /// Respond to I2C-bus subaddress 2.
81 pub const SUB2: u8 = 0x04;
82 /// Respond to I2C-bus subaddress 3.
83 pub const SUB3: u8 = 0x02;
84 /// Respond to the LED All Call address.
85 pub const ALLCALL: u8 = 0x01;
86}
87
88/// The MODE2 register bits.
89pub mod mode2 {
90 /// Invert the output logic; for boards with no external driver.
91 pub const INVRT: u8 = 0x10;
92 /// Outputs change on the acknowledge of each register write instead of on STOP.
93 pub const OCH: u8 = 0x08;
94 /// Totem-pole outputs when set, open-drain when clear.
95 pub const OUTDRV: u8 = 0x04;
96 /// With OE high: outputs high when OUTDRV is set, high-impedance otherwise.
97 pub const OUTNE_HIGH: u8 = 0x01;
98 /// With OE high: outputs high-impedance.
99 pub const OUTNE_HIGH_Z: u8 = 0x02;
100}
101
102/// The frequency of the internal oscillator, 25 MHz.
103pub const INTERNAL_OSC_HZ: u32 = 25_000_000;
104/// The number of PWM channels.
105pub const CHANNELS: u8 = 16;
106/// The number of counts in one PWM period (12-bit resolution).
107pub const COUNTS: u16 = 4096;
108/// The power-on value of the PRE_SCALE register (0x1E), about 200 Hz at 25 MHz.
109pub const PRE_SCALE_RESET: u8 = 0x1E;
110/// The power-on value of MODE1 (0x11): sleeping, responding to the All Call address.
111pub const MODE1_RESET: u8 = 0x11;
112/// The smallest value the part loads into PRE_SCALE; a smaller write loads this.
113pub const PRE_SCALE_MIN: u8 = 3;
114/// The power-on value of SUBADR1 (0xE2), the first programmable subaddress.
115pub const SUBADR1_RESET: u8 = 0xE2;
116/// The power-on value of SUBADR2 (0xE4).
117pub const SUBADR2_RESET: u8 = 0xE4;
118/// The power-on value of SUBADR3 (0xE8).
119pub const SUBADR3_RESET: u8 = 0xE8;
120/// The power-on value of ALLCALLADR (0xE0), the LED All Call address.
121pub const ALLCALL_ADDR_RESET: u8 = 0xE0;
122/// The power-on value of every channel's LEDn_OFF_H (0x10): the full-off bit set, so each
123/// output starts off. The channel's other three registers start at zero.
124pub const LED_OFF_H_RESET: u8 = 0x10;
125
126/// Returns the address of a channel's first register (its on-count low byte).
127///
128/// Each channel occupies four consecutive registers (on low, on high, off low, off
129/// high), starting at `0x06` for channel 0, so channel `n` begins at `0x06 + 4 * n`.
130///
131/// # Arguments
132///
133/// * `channel` - the channel number, `0..=15`.
134///
135/// # Returns
136///
137/// The address of `LEDn_ON_L`. Channels past 15 are clamped to 15.
138pub fn channel_register(channel: u8) -> u8 {
139 let channel = if channel >= CHANNELS {
140 CHANNELS - 1
141 } else {
142 channel
143 };
144 register::LED0_ON_L + 4 * channel
145}
146
147/// Computes the PRE_SCALE value for a desired PWM frequency.
148///
149/// This is the datasheet's prescale formula `round(osc_clock / (4096 * update_rate)) - 1`,
150/// clamped to the hardware's `3..=255` range (which bounds the frequency to roughly
151/// 24 Hz to 1.5 kHz at 25 MHz).
152///
153/// # Arguments
154///
155/// * `update_rate_hz` - the desired output frequency in hertz.
156/// * `osc_hz` - the oscillator frequency, [`INTERNAL_OSC_HZ`] unless an external clock
157/// is used.
158///
159/// # Returns
160///
161/// The value to write to the PRE_SCALE register.
162pub fn prescale_for_frequency(update_rate_hz: u32, osc_hz: u32) -> u8 {
163 let divisor = COUNTS as u32 * update_rate_hz.max(1);
164 let rounded = (osc_hz + divisor / 2) / divisor;
165 rounded.saturating_sub(1).clamp(3, 255) as u8
166}
167
168/// Computes the PWM frequency a PRE_SCALE value produces.
169///
170/// # Arguments
171///
172/// * `prescale` - the PRE_SCALE register value.
173/// * `osc_hz` - the oscillator frequency.
174///
175/// # Returns
176///
177/// The output frequency in hertz.
178pub fn frequency_for_prescale(prescale: u8, osc_hz: u32) -> f32 {
179 osc_hz as f32 / (COUNTS as f32 * (prescale as f32 + 1.0))
180}
181
182/// A channel's PWM setting: when in the period it turns on and when it turns off.
183///
184/// The PCA9685 counts from 0 to 4095 each period and lets a channel turn on at one
185/// count and off at another, so duty and phase are both programmable. The special
186/// full-on and full-off states are encoded in a dedicated bit rather than as counts,
187/// and the datasheet rules out loading the same count into both, so 0 % and 100 % are
188/// only ever those flags.
189///
190/// # Examples
191///
192/// ```
193/// use pamoja_actuators::pca9685::Pwm;
194///
195/// // Half brightness with no phase delay: on at count 0, off at the midpoint.
196/// let half = Pwm::duty(2048);
197/// assert_eq!((half.on(), half.off()), (0, 2048));
198///
199/// // What a channel's four registers hold reads back as the same setting.
200/// assert_eq!(Pwm::from_bytes(&half.bytes()), half);
201///
202/// // Fully off is its own encoding, and a zero duty is that encoding.
203/// assert_eq!(Pwm::duty(0), Pwm::full_off());
204/// ```
205#[derive(Clone, Copy, Debug, PartialEq, Eq)]
206pub struct Pwm {
207 on: u16,
208 off: u16,
209}
210
211impl Pwm {
212 /// Builds a setting from explicit on and off counts.
213 ///
214 /// # Arguments
215 ///
216 /// * `on` - the count at which the output goes high, `0..=4095`.
217 /// * `off` - the count at which it goes low, `0..=4095`.
218 ///
219 /// # Returns
220 ///
221 /// The PWM setting; counts are masked to 12 bits.
222 pub fn from_counts(on: u16, off: u16) -> Pwm {
223 Pwm {
224 on: on & 0x0FFF,
225 off: off & 0x0FFF,
226 }
227 }
228
229 /// Builds a setting with no phase delay: on at count 0, off at `off`.
230 ///
231 /// The datasheet says the on and off counts should never hold the same value, which
232 /// a count of 0 would load, so 0 is the full-off setting, and a count of 4096 or more
233 /// the full-on one.
234 ///
235 /// # Arguments
236 ///
237 /// * `off` - the count at which the output goes low, which sets the duty cycle.
238 ///
239 /// # Returns
240 ///
241 /// The PWM setting.
242 pub fn duty(off: u16) -> Pwm {
243 match off {
244 0 => Pwm::full_off(),
245 off if off >= COUNTS => Pwm::full_on(),
246 off => Pwm::from_counts(0, off),
247 }
248 }
249
250 /// Builds the setting that drives a hobby servo to a given pulse width.
251 ///
252 /// A servo reads the high-pulse width each period; the count is that width as a
253 /// fraction of the period, `pulse * 4096 / period`. Typical travel is about 1000
254 /// to 2000 microseconds at a 50 Hz update rate.
255 ///
256 /// # Arguments
257 ///
258 /// * `pulse_micros` - the high-pulse width in microseconds.
259 /// * `update_rate_hz` - the PWM frequency the controller is set to.
260 ///
261 /// # Returns
262 ///
263 /// The PWM setting for that pulse width.
264 pub fn servo(pulse_micros: u32, update_rate_hz: u32) -> Pwm {
265 let counts = (pulse_micros as u64 * COUNTS as u64 * update_rate_hz as u64) / 1_000_000;
266 Pwm::duty(counts.min(COUNTS as u64 - 1) as u16)
267 }
268
269 /// The setting that holds the output continuously high.
270 ///
271 /// # Returns
272 ///
273 /// The full-on setting.
274 pub fn full_on() -> Pwm {
275 Pwm { on: 0x1000, off: 0 }
276 }
277
278 /// The setting that holds the output continuously low.
279 ///
280 /// # Returns
281 ///
282 /// The full-off setting, the power-on state of every channel.
283 pub fn full_off() -> Pwm {
284 Pwm { on: 0, off: 0x1000 }
285 }
286
287 /// Returns the four register bytes for this setting.
288 ///
289 /// The order is on-low, on-high, off-low, off-high, matching the channel's four
290 /// consecutive registers; the full-on and full-off flags ride in bit 4 of the
291 /// high bytes.
292 ///
293 /// # Returns
294 ///
295 /// `[on_low, on_high, off_low, off_high]`.
296 pub fn bytes(self) -> [u8; 4] {
297 [
298 self.on as u8,
299 (self.on >> 8) as u8,
300 self.off as u8,
301 (self.off >> 8) as u8,
302 ]
303 }
304
305 /// Reads a setting back from the four register bytes a channel holds.
306 ///
307 /// The inverse of [`bytes`](Pwm::bytes), so a caller can read a channel back off the
308 /// bus and see what it is set to rather than decoding the registers by hand.
309 ///
310 /// # Arguments
311 ///
312 /// * `bytes` - the four channel registers, `[on_low, on_high, off_low, off_high]`.
313 ///
314 /// # Returns
315 ///
316 /// The PWM setting those registers hold, full-on and full-off flags included.
317 pub fn from_bytes(bytes: &[u8; 4]) -> Pwm {
318 Pwm {
319 on: u16::from_le_bytes([bytes[0], bytes[1]]),
320 off: u16::from_le_bytes([bytes[2], bytes[3]]),
321 }
322 }
323
324 /// Returns the count at which the output goes high.
325 ///
326 /// # Returns
327 ///
328 /// The on count, including the full-on flag in bit 12 when the output is held high.
329 pub fn on(self) -> u16 {
330 self.on
331 }
332
333 /// Returns the count at which the output goes low.
334 ///
335 /// # Returns
336 ///
337 /// The off count, including the full-off flag in bit 12 when the output is held low.
338 pub fn off(self) -> u16 {
339 self.off
340 }
341}
342
343#[cfg(test)]
344mod tests {
345 use super::*;
346
347 #[test]
348 fn prescale_matches_the_datasheet_example() {
349 // The datasheet's worked example: 200 Hz at 25 MHz gives prescale 0x1E.
350 assert_eq!(prescale_for_frequency(200, INTERNAL_OSC_HZ), 0x1E);
351 assert_eq!(
352 prescale_for_frequency(200, INTERNAL_OSC_HZ),
353 PRE_SCALE_RESET
354 );
355 // The documented bounds: 1526 Hz is the fastest (prescale 3), and the value
356 // is clamped to the hardware minimum.
357 assert_eq!(prescale_for_frequency(1526, INTERNAL_OSC_HZ), 3);
358 assert_eq!(prescale_for_frequency(100_000, INTERNAL_OSC_HZ), 3);
359 // A common 50 Hz servo rate.
360 assert_eq!(prescale_for_frequency(50, INTERNAL_OSC_HZ), 0x79);
361 }
362
363 #[test]
364 fn frequency_and_prescale_round_trip() {
365 for prescale in [3u8, 30, 0x79, 255] {
366 let freq = frequency_for_prescale(prescale, INTERNAL_OSC_HZ);
367 assert_eq!(
368 prescale_for_frequency(freq as u32, INTERNAL_OSC_HZ),
369 prescale
370 );
371 }
372 }
373
374 #[test]
375 fn channel_registers_are_four_apart() {
376 assert_eq!(channel_register(0), 0x06);
377 assert_eq!(channel_register(1), 0x0A);
378 assert_eq!(channel_register(15), 0x42);
379 // Past the last channel clamps rather than running into the prescaler.
380 assert_eq!(channel_register(20), 0x42);
381 }
382
383 #[test]
384 fn pwm_bytes_pack_counts_little_endian() {
385 // On at 0x199 (409), off at 0xCCC (3276): the 10 %/90 % example shape.
386 let pwm = Pwm::from_counts(0x199, 0xCCC);
387 assert_eq!(pwm.bytes(), [0x99, 0x01, 0xCC, 0x0C]);
388 }
389
390 #[test]
391 fn full_on_and_full_off_set_the_flag_bit() {
392 assert_eq!(Pwm::full_on().bytes(), [0x00, 0x10, 0x00, 0x00]);
393 assert_eq!(Pwm::full_off().bytes(), [0x00, 0x00, 0x00, 0x10]);
394 }
395
396 #[test]
397 fn a_duty_never_loads_the_same_count_into_on_and_off() {
398 // Section 7.3.4: "The LEDn_ON and LEDn_OFF count registers should never be
399 // programmed with the same values." A duty starts on at count 0, so its ends are
400 // the flags.
401 assert_eq!(Pwm::duty(0), Pwm::full_off());
402 assert_eq!(Pwm::duty(COUNTS), Pwm::full_on());
403 assert_eq!(Pwm::duty(u16::MAX), Pwm::full_on());
404 assert_eq!(Pwm::duty(1).bytes(), [0x00, 0x00, 0x01, 0x00]);
405 assert_eq!(Pwm::duty(COUNTS - 1).bytes(), [0x00, 0x00, 0xFF, 0x0F]);
406 assert_eq!(Pwm::servo(0, 50), Pwm::full_off(), "no pulse at all");
407 }
408
409 #[test]
410 fn servo_midpoint_is_a_centered_pulse() {
411 // 1500 µs at 50 Hz is 7.5 % of the 20 ms period: 0.075 * 4096 = 307 counts.
412 assert_eq!(Pwm::servo(1500, 50), Pwm::duty(307));
413 // The travel extremes.
414 assert_eq!(Pwm::servo(1000, 50), Pwm::duty(204));
415 assert_eq!(Pwm::servo(2000, 50), Pwm::duty(409));
416 }
417 #[test]
418 fn a_setting_reads_back_from_the_registers_it_writes() {
419 for setting in [
420 Pwm::servo(1500, 50),
421 Pwm::duty(0),
422 Pwm::duty(2048),
423 Pwm::full_on(),
424 Pwm::full_off(),
425 Pwm::from_counts(410, 1229),
426 ] {
427 assert_eq!(Pwm::from_bytes(&setting.bytes()), setting);
428 }
429
430 // A centered servo holds its output high for 1500 us of a 20 ms period, which is
431 // 307 of the part's 4096 counts.
432 assert_eq!(Pwm::servo(1500, 50).off(), 307);
433 assert_eq!(Pwm::servo(1500, 50).on(), 0);
434 }
435}