-
Notifications
You must be signed in to change notification settings - Fork 2.1k
drivers: add driver mcp23017 #7652
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,175 @@ | ||
| /* | ||
| * Copyright (C) 2017 HAW Hamburg | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @defgroup drivers_mcp23017 | ||
| * @ingroup drivers_actuators | ||
| * @brief Device driver interface for the MCP23017 | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Interface definition for the MCP23017 | ||
| * | ||
| * @author Dimitri Nahm <dimitri.nahm@haw-hamburg.de> | ||
| */ | ||
|
|
||
| #ifndef MCP23017_H | ||
| #define MCP23017_H | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| #include "periph/i2c.h" | ||
| #include "periph/gpio.h" | ||
|
|
||
| /** | ||
| * @brief Possible MCP23017 hardware addresses (wiring specific) | ||
| */ | ||
| enum { | ||
| MCP23017_ADDR_20 = 0x20, /**< I2C device address: A2=0, A1=0, A0=0 */ | ||
| MCP23017_ADDR_21 = 0x21, /**< I2C device address: A2=0, A1=0, A0=1 */ | ||
| MCP23017_ADDR_22 = 0x22, /**< I2C device address: A2=0, A1=1, A0=0 */ | ||
| MCP23017_ADDR_23 = 0x23, /**< I2C device address: A2=0, A1=1, A0=1 */ | ||
| MCP23017_ADDR_24 = 0x24, /**< I2C device address: A2=1, A1=0, A0=0 */ | ||
| MCP23017_ADDR_25 = 0x25, /**< I2C device address: A2=1, A1=0, A0=1 */ | ||
| MCP23017_ADDR_26 = 0x26, /**< I2C device address: A2=1, A1=1, A0=0 */ | ||
| MCP23017_ADDR_27 = 0x27, /**< I2C device address: A2=1, A1=1, A0=1 */ | ||
| }; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need to list all these addresses explicitly I'd say. Having these in a comment somewhere should suffice. |
||
|
|
||
| /** | ||
| * @brief Output Interrupt selection | ||
| */ | ||
| enum { | ||
| INTA, /**< Output interrupt on INTA pin */ | ||
| INTB /**< Output interrupt on INTB pin */ | ||
| }; | ||
|
|
||
| /** | ||
| * @brief Named return values | ||
| */ | ||
| enum { | ||
| MCP23017_OK = 0, /**< everything was fine */ | ||
| MCP23017_NOI2C = -1, /**< I2C communication failed */ | ||
| MCP23017_NODEV = -2 /**< no MCP23017 device found on the bus */ | ||
| }; | ||
|
|
||
| /** | ||
| * @brief Device descriptor for the MCP23017 sensor | ||
| */ | ||
| typedef struct { | ||
| i2c_t i2c; /**< I2C device which is used */ | ||
| uint8_t addr; /**< I2C address */ | ||
| uint8_t port_a_dir; | ||
| uint8_t port_b_dir; | ||
| uint8_t port_a_pull_up; | ||
| uint8_t port_b_pull_up; | ||
| uint8_t port_a_value; | ||
| uint8_t port_b_value; | ||
| uint8_t port_a_inten; | ||
| uint8_t port_b_inten; | ||
| } mcp23017_t; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems like a lot of wasted RAM. There is no need to keep all these configuration data in RAM. But instead, you should add an array for storing callback functions and arguments, so we allow for registering user defined functions for pin interrupts. The simplest (though also the most resource intensive option) would be to allow for storage of 16 callback functions and 16 arguments, so one tuple for each provided pin. Or maybe better: we only save 2 callbacks and 2 args, and allow only a single active interrupt on port A and one active one on port B. |
||
|
|
||
| /** | ||
| * @brief Struct containing the needed peripheral configuration | ||
| */ | ||
| typedef struct { | ||
| gpio_t int_a_pin; /**< interrupt a pin */ | ||
| gpio_t int_b_pin; /**< interrupt b pin */ | ||
| } mcp23017_params_t; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This struct is incomplete and inconsistent with the actual usage below. As I see it, it should contain: typedef struct {
i2c_t i2c_dev;
uint8_t i2c_addr;
gpio_t int_a_pin;
gpio_t int_b_pin;
} mcp23017_params_t; |
||
|
|
||
| /** | ||
| * @brief Initialize the MCP23017 driver. | ||
| * | ||
| * @param[out] dev device descriptor of MCP23017 to initialize | ||
| * | ||
| * @return MCP23017_OK on success | ||
| * @return MCP23017_NOI2C if initialization of I2C bus failed | ||
| */ | ||
| int mcp23017_init(mcp23017_t *dev, const mcp23017_params_t* params); | ||
|
|
||
| /** | ||
| * @brief Read port of MCP23017 | ||
| * | ||
| * @param[in] dev device descriptor of MCP23017 | ||
| * @param[in] port device port | ||
| * | ||
| * @return value of port | ||
| * @return MCP23017_NODEV no device found | ||
| */ | ||
| int mcp23017_read_port(mcp23017_t *dev, uint8_t port); | ||
|
|
||
| /** | ||
| * @brief Set pin direction of MCP23017 | ||
| * | ||
| * @param[in] dev device descriptor of MCP23017 | ||
| * @param[in] port device port | ||
| * @param[in] pin device pin | ||
| * @param[in] direction pin direction | ||
| * | ||
| * @return MCP23017_OK on success | ||
| * @return MCP23017_NODEV no device found | ||
| */ | ||
| int mcp23017_set_dir(mcp23017_t *dev, uint8_t port, uint8_t pin, uint8_t dir); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would strongly suggest to rework the interface with the goal to make it more similar to the int mcp23017_pin_init(mcp23017_t *dev, uint8_t pin, gpio_mode_t mode);
int mcp23017_pin_init_int(mcp_23017_t *dev, uint8_t pin, gpio_mode_t mode, gpio_flank_t flank, gpio_cb_t cb, void *arg);
int mcp23017_pin_read(mcp23017_t *dev, uint8_t pin);
int mcp23017_pin_set(mcp23017_t *dev, uint8_t pin);
...The As of now, we are not really able to map the gpio interface 1-on-1, so we have to live with some differences (e.g. set/clear/toggle have return values, as the i2c driver could fail). |
||
|
|
||
| /** | ||
| * @brief Set pull-up for pin of MCP23017 | ||
| * | ||
| * @param[in] dev device descriptor of MCP23017 | ||
| * @param[in] port device port | ||
| * @param[in] pin device pin | ||
| * @param[in] pull_up pin pull-up | ||
| * | ||
| * @return MCP23017_OK on success | ||
| * @return MCP23017_NODEV no device found | ||
| */ | ||
| int mcp23017_set_pull_up(mcp23017_t *dev, uint8_t port, uint8_t pin, uint8_t pull_up); | ||
|
|
||
| /** | ||
| * @brief Set pin value of MCP23017 | ||
| * | ||
| * @param[in] dev device descriptor of MCP23017 | ||
| * @param[in] port device port | ||
| * @param[in] pin device pin | ||
| * @param[in] value pin value | ||
| * | ||
| * @return MCP23017_OK on success | ||
| * @return MCP23017_NODEV no device found | ||
| */ | ||
| int mcp23017_set_pin_value(mcp23017_t *dev, uint8_t port, uint8_t pin, uint8_t value); | ||
|
|
||
| /** | ||
| * @brief Set pin interrupt of MCP23017 | ||
| * | ||
| * @param[in] dev device descriptor of MCP23017 | ||
| * @param[in] port device port | ||
| * @param[in] pin device pin | ||
| * @param[in] status pin interrupt status | ||
| * | ||
| * @return MCP23017_OK on success | ||
| * @return MCP23017_NODEV no device found | ||
| */ | ||
| int mcp23017_set_int(mcp23017_t *dev, uint8_t port, uint8_t pin, uint8_t status); | ||
|
|
||
| /** | ||
| * @brief Capture interrupt of MCP23017 | ||
| * | ||
| * @param[in] dev device descriptor of MCP23017 | ||
| * @param[in] port device port | ||
| * | ||
| * @return value of port | ||
| * @return MCP23017_NODEV no device found | ||
| */ | ||
| int mcp23017_capture_interrupt(mcp23017_t *dev, uint8_t port); | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* MCP23017_H */ | ||
| /** @} */ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| include $(RIOTBASE)/Makefile.base |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| /* | ||
| * Copyright (C) 2017 HAW HAmburg | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @ingroup drivers_mcp23017 | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Default configuration for MCP23017 devices | ||
| * | ||
| * @author Dimitri Nahm <dimitri.nahm@haw-hamburg.de> | ||
| */ | ||
|
|
||
| #ifndef MCP23017_PARAMS_H | ||
| #define MCP23017_PARAMS_H | ||
|
|
||
| #include "board.h" | ||
| #include "saul_reg.h" | ||
| #include "mcp23017.h" | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| /** | ||
| * @brief Set default configuration parameters for the MCP23017 driver | ||
| * @{ | ||
| */ | ||
| #ifndef MCP23017_PARAM_I2C | ||
| #define MCP23017_PARAM_I2C (I2C_DEV(0)) | ||
| #endif | ||
| #ifndef MCP23017_PARAM_ADDR | ||
| #define MCP23017_PARAM_ADDR (MCP23017_ADDR_20) | ||
| #endif | ||
| #ifndef MCP23017_PARAMS | ||
| #define MCP23017_PARAMS { .int_a_pin = 11, \ | ||
| .int_b_pin = 12 } | ||
| #endif | ||
| /**@}*/ | ||
|
|
||
| /** | ||
| * @brief Allocation of MCP23017 configuration | ||
| */ | ||
| static const mcp23017_params_t mcp23017_params[] = { | ||
| MCP23017_PARAMS | ||
| }; | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* MCP23017_PARAMS_H */ | ||
| /** @} */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| /* | ||
| * Copyright (C) 2017 HAW Hamburg | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU Lesser | ||
| * General Public License v2.1. See the file LICENSE in the top level | ||
| * directory for more details. | ||
| */ | ||
|
|
||
| /** | ||
| * @ingroup drivers_mcp23017 | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Register and bit definitions for the MCP23017 | ||
| * | ||
| * @author Dimitri Nahm <dimitri.nahm@haw-hamburg.de> | ||
| */ | ||
|
|
||
| #ifndef MCP23017_REGS_H | ||
| #define MCP23017_REGS_H | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| /** | ||
| * @name Register addresses (IOCON.BANK = 0) | ||
| * @{ | ||
| */ | ||
| #define MCP23017_REG_IODIRA (0x00) | ||
| #define MCP23017_REG_IODIRB (0x01) | ||
| #define MCP23017_REG_IPOLA (0x02) | ||
| #define MCP23017_REG_IPOLB (0x03) | ||
| #define MCP23017_REG_GPINTENA (0x04) | ||
| #define MCP23017_REG_GPINTENB (0x05) | ||
| #define MCP23017_REG_DEFVALA (0x06) | ||
| #define MCP23017_REG_DEFVALB (0x07) | ||
| #define MCP23017_REG_INTCONA (0x08) | ||
| #define MCP23017_REG_INTCONB (0x09) | ||
| #define MCP23017_REG_IOCONA (0x0A) | ||
| #define MCP23017_REG_IOCONB (0x0B) | ||
| #define MCP23017_REG_GPPUA (0x0C) | ||
| #define MCP23017_REG_GPPUB (0x0D) | ||
| #define MCP23017_REG_INTFA (0x0E) | ||
| #define MCP23017_REG_INTFB (0x0F) | ||
| #define MCP23017_REG_INTCAPA (0x10) | ||
| #define MCP23017_REG_INTCAPB (0x11) | ||
| #define MCP23017_REG_GPIOA (0x12) | ||
| #define MCP23017_REG_GPIOB (0x13) | ||
| #define MCP23017_REG_OLATA (0x14) | ||
| #define MCP23017_REG_OLATB (0x15) | ||
| /** @} */ | ||
|
|
||
| /** | ||
| * @name Bit definition for register | ||
| * @{ | ||
| */ | ||
| #define PIN_0 (1 << 0) | ||
| #define PIN_1 (1 << 1) | ||
| #define PIN_2 (1 << 2) | ||
| #define PIN_3 (1 << 3) | ||
| #define PIN_4 (1 << 4) | ||
| #define PIN_5 (1 << 5) | ||
| #define PIN_6 (1 << 6) | ||
| #define PIN_7 (1 << 7) | ||
| /** @} */ | ||
|
|
||
| /** | ||
| * @name Port definition of MCP23017 | ||
| * @{ | ||
| */ | ||
| #define PORT_A (0) | ||
| #define PORT_B (1) | ||
| /** @} */ | ||
|
|
||
| /** | ||
| * @name Pin direction definition of MCP23017 | ||
| * @{ | ||
| */ | ||
| #define INPUT (1) | ||
| #define OUTPUT (0) | ||
| /** @} */ | ||
|
|
||
| /** | ||
| * @name Pin pull-up definition of MCP23017 | ||
| * @{ | ||
| */ | ||
| #define PULL_UP_EN (1) | ||
| #define PULL_UP_DIS (0) | ||
| /** @} */ | ||
|
|
||
| /** | ||
| * @name Pin output definition of MCP23017 | ||
| * @{ | ||
| */ | ||
| #define HIGH (1) | ||
| #define LOW (0) | ||
| /** @} */ | ||
|
|
||
| /** | ||
| * @name Pin interrupt definition of MCP23017 | ||
| * @{ | ||
| */ | ||
| #define ENABLE (1) | ||
| #define DISABLE (0) | ||
| /** @} */ | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* MCP23017_REGS_H */ | ||
| /** @} */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also
FEATURES_REQUIRED += periph_gpio