1#![no_std]
2
3#![deny(
13 missing_docs,
14 missing_debug_implementations,
15 missing_copy_implementations,
16 trivial_casts,
17 trivial_numeric_casts,
18 unstable_features,
19 unused_import_braces,
20 unused_qualifications,
21 warnings
22)]
23#![allow(dead_code, non_camel_case_types)]
24#![allow(clippy::uninit_assumed_init, clippy::upper_case_acronyms)]
25
26extern crate embedded_hal as ehal;
27
28use ehal::blocking::i2c::{Write, WriteRead};
29
30const DEFAULT_ADDRESS: u8 = 0x20;
32
33const HIGH: bool = true;
35const LOW: bool = false;
36
37#[derive(Clone, Copy, Debug)]
41pub struct MCP23017<I2C: Write + WriteRead> {
42 com: I2C,
43 pub address: u8,
45}
46
47#[derive(Debug, Copy, Clone)]
49pub enum Error<E> {
50 BusError(E),
52 InterruptPinError,
54}
55
56impl<E> From<E> for Error<E> {
57 fn from(error: E) -> Self {
58 Error::BusError(error)
59 }
60}
61
62impl<I2C, E> MCP23017<I2C>
63where
64 I2C: WriteRead<Error = E> + Write<Error = E>,
65{
66 pub fn default(i2c: I2C) -> Result<MCP23017<I2C>, Error<E>>
68 where
69 I2C: Write<Error = E> + WriteRead<Error = E>,
70 {
71 MCP23017::new(i2c, DEFAULT_ADDRESS)
72 }
73
74 pub fn new(i2c: I2C, address: u8) -> Result<MCP23017<I2C>, Error<E>>
76 where
77 I2C: Write<Error = E> + WriteRead<Error = E>,
78 {
79 let chip = MCP23017 { com: i2c, address };
80
81 Ok(chip)
82 }
83
84 pub fn init_hardware(&mut self) -> Result<(), Error<E>> {
86 self.write_register(Register::IODIRA, 0xff)?;
88 self.write_register(Register::IODIRB, 0xff)?;
89
90 Ok(())
91 }
92
93 fn read_register(&mut self, reg: Register) -> Result<u8, E> {
94 let mut data: [u8; 1] = [0];
95 self.com.write_read(self.address, &[reg as u8], &mut data)?;
96 Ok(data[0])
97 }
98
99 fn read_double_register(&mut self, reg: Register) -> Result<[u8; 2], E> {
100 let mut buffer: [u8; 2] = [0; 2];
101 self.com
102 .write_read(self.address, &[reg as u8], &mut buffer)?;
103 Ok(buffer)
104 }
105
106 fn write_register(&mut self, reg: Register, byte: u8) -> Result<(), E> {
107 self.com.write(self.address, &[reg as u8, byte])
108 }
109
110 fn write_double_register(&mut self, reg: Register, word: u16) -> Result<(), E> {
111 let msb = (word >> 8) as u8;
112 self.com.write(self.address, &[reg as u8, word as u8, msb])
113 }
114
115 fn update_register_bit(
120 &mut self,
121 pin: u8,
122 pin_value: bool,
123 port_a_reg: Register,
124 port_b_reg: Register,
125 ) -> Result<(), E> {
126 let reg = register_for_pin(pin, port_a_reg, port_b_reg);
127 let bit = bit_for_pin(pin);
128 let reg_value = self.read_register(reg)?;
129 let reg_value_mod = write_bit(reg_value, bit, pin_value);
130 self.write_register(reg, reg_value_mod)
131 }
132
133 pub fn pin_mode(&mut self, pin: u8, pin_mode: PinMode) -> Result<(), E> {
135 self.update_register_bit(
136 pin,
137 pin_mode.bit_value(),
138 Register::IODIRA,
139 Register::IODIRB,
140 )
141 }
142
143 pub fn all_pin_mode(&mut self, pin_mode: PinMode) -> Result<(), E> {
145 self.write_register(Register::IODIRA, pin_mode.register_value())?;
146 self.write_register(Register::IODIRB, pin_mode.register_value())
147 }
148
149 pub fn read_gpioab(&mut self) -> Result<u16, E> {
151 let buffer = self.read_double_register(Register::GPIOA)?;
152 Ok((buffer[0] as u16) << 8 | (buffer[1] as u16))
153 }
154
155 pub fn read_gpio(&mut self, port: Port) -> Result<u8, E> {
157 let reg = match port {
158 Port::GPIOA => Register::GPIOA,
159 Port::GPIOB => Register::GPIOB,
160 };
161 self.read_register(reg)
162 }
163
164 pub fn write_gpioab(&mut self, value: u16) -> Result<(), E> {
166 self.write_double_register(Register::GPIOA, value)
167 }
168
169 pub fn write_gpio(&mut self, port: Port, value: u8) -> Result<(), E> {
171 let reg = match port {
172 Port::GPIOA => Register::GPIOA,
173 Port::GPIOB => Register::GPIOB,
174 };
175 self.write_register(reg, value)
176 }
177
178 pub fn digital_write(&mut self, pin: u8, value: bool) -> Result<(), E> {
182 let bit = bit_for_pin(pin);
183 let ol_register = register_for_pin(pin, Register::OLATA, Register::OLATB);
185 let gpio = self.read_register(ol_register)?;
186
187 let gpio_mod = write_bit(gpio, bit, value);
189
190 let reg_gp = register_for_pin(pin, Register::GPIOA, Register::GPIOB);
192 self.write_register(reg_gp, gpio_mod)
193 }
194
195 pub fn digital_read(&mut self, pin: u8) -> Result<bool, E> {
197 let bit = bit_for_pin(pin);
198 let reg = register_for_pin(pin, Register::GPIOA, Register::GPIOB);
199 let value = self.read_register(reg)?;
200 Ok(read_bit(value, bit))
201 }
202
203 pub fn pull_up(&mut self, pin: u8, value: bool) -> Result<(), E> {
205 self.update_register_bit(pin, value, Register::GPPUA, Register::GPPUB)
206 }
207
208 pub fn invert_input_polarity(&mut self, pin: u8, value: bool) -> Result<(), E> {
211 self.update_register_bit(pin, value, Register::IPOLA, Register::IPOLB)
212 }
213
214 pub fn setup_interrupts(
220 &mut self,
221 mirroring: bool,
222 open_drain: bool,
223 polarity: Polarity,
224 ) -> Result<(), E> {
225 self.setup_interrupt_port(Register::IOCONA, mirroring, open_drain, polarity)?;
227
228 self.setup_interrupt_port(Register::IOCONB, mirroring, open_drain, polarity)
230 }
231
232 fn setup_interrupt_port(
233 &mut self,
234 register: Register,
235 mirroring: bool,
236 open_drain: bool,
237 polarity: Polarity,
238 ) -> Result<(), E> {
239 let mut io_conf_value = self.read_register(register)?;
240 io_conf_value = write_bit(io_conf_value, 6, mirroring);
241 io_conf_value = write_bit(io_conf_value, 2, open_drain);
242 io_conf_value = write_bit(io_conf_value, 1, polarity.bit_value());
243 self.write_register(register, io_conf_value)
244 }
245
246 pub fn setup_interrupt_pin(&mut self, pin: u8, int_mode: InterruptMode) -> Result<(), E> {
250 self.update_register_bit(
252 pin,
253 int_mode != InterruptMode::CHANGE,
254 Register::INTCONA,
255 Register::INTCONB,
256 )?;
257
258 self.update_register_bit(
261 pin,
262 int_mode == InterruptMode::FALLING,
263 Register::DEFVALA,
264 Register::DEFVALB,
265 )?;
266
267 self.update_register_bit(pin, HIGH, Register::GPINTENA, Register::GPINTENB)
269 }
270
271 pub fn get_last_interrupt_pin(&mut self) -> Result<u8, Error<E>> {
273 let intf_a = self.read_register(Register::INTFA)?;
275 for x in 0..8 {
276 if read_bit(intf_a, x) {
277 return Ok(x);
278 }
279 }
280
281 let intf_b = self.read_register(Register::INTFB)?;
283 for x in 0..8 {
284 if read_bit(intf_b, x) {
285 return Ok(x + 8);
286 }
287 }
288
289 Err(Error::InterruptPinError)
290 }
291
292 pub fn get_last_interrupt_value(&mut self) -> Result<u8, Error<E>> {
294 match self.get_last_interrupt_pin() {
295 Ok(pin) => {
296 let int_reg = register_for_pin(pin, Register::INTCAPA, Register::INTCAPB);
297 let bit = bit_for_pin(pin);
298 let val = self.read_register(int_reg)?;
299 Ok((val >> bit) & 0x01)
300 }
301 Err(e) => Err(e),
302 }
303 }
304}
305
306fn write_bit(reg: u8, bit: u8, val: bool) -> u8 {
308 let mut res = reg;
309 if val {
310 res |= 1 << bit;
311 } else {
312 res &= !(1 << bit);
313 }
314
315 res
316}
317
318fn read_bit(reg: u8, bit: u8) -> bool {
320 reg & (1 << bit) != 0
321}
322
323fn bit_for_pin(pin: u8) -> u8 {
325 pin % 8
326}
327
328fn register_for_pin(pin: u8, port_a_addr: Register, port_b_addr: Register) -> Register {
330 if pin < 8 {
331 port_a_addr
332 } else {
333 port_b_addr
334 }
335}
336
337#[derive(Debug, Copy, Clone)]
339pub enum PinMode {
340 INPUT = 1,
342 OUTPUT = 0,
344}
345
346impl PinMode {
347 fn bit_value(&self) -> bool {
349 match *self {
350 PinMode::INPUT => true,
351 PinMode::OUTPUT => false,
352 }
353 }
354
355 fn register_value(&self) -> u8 {
357 match *self {
358 PinMode::INPUT => 0xff,
359 PinMode::OUTPUT => 0x00,
360 }
361 }
362}
363
364#[derive(Debug, Copy, Clone, PartialEq)]
366pub enum InterruptMode {
367 CHANGE = 0,
369 FALLING = 1,
371 RISING = 2,
373}
374
375#[derive(Debug, Copy, Clone)]
377pub enum Polarity {
378 LOW = 0,
380 HIGH = 1,
382}
383
384impl Polarity {
385 fn bit_value(&self) -> bool {
387 match self {
388 Polarity::LOW => false,
389 Polarity::HIGH => true,
390 }
391 }
392}
393
394#[derive(Debug, Copy, Clone)]
396pub enum Port {
397 GPIOA,
399 GPIOB,
401}
402
403#[derive(Debug, Copy, Clone)]
404enum Register {
405 IODIRA = 0x00,
406 IPOLA = 0x02,
407 GPINTENA = 0x04,
408 DEFVALA = 0x06,
409 INTCONA = 0x08,
410 IOCONA = 0x0A,
411 GPPUA = 0x0C,
412 INTFA = 0x0E,
413 INTCAPA = 0x10,
414 GPIOA = 0x12,
415 OLATA = 0x14,
416 IODIRB = 0x01,
417 IPOLB = 0x03,
418 GPINTENB = 0x05,
419 DEFVALB = 0x07,
420 INTCONB = 0x09,
421 IOCONB = 0x0B,
422 GPPUB = 0x0D,
423 INTFB = 0x0F,
424 INTCAPB = 0x11,
425 GPIOB = 0x13,
426 OLATB = 0x15,
427}