Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions drivers/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ ifneq (,$(filter lpd8808,$(USEMODULE)))
FEATURES_REQUIRED += periph_gpio
endif

ifneq (,$(filter mcp23017,$(USEMODULE)))
FEATURES_REQUIRED += periph_i2c

Copy link
Copy Markdown
Contributor

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

endif

ifneq (,$(filter mpu9150,$(USEMODULE)))
USEMODULE += xtimer
endif
Expand Down
3 changes: 3 additions & 0 deletions drivers/Makefile.include
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,6 @@ endif
ifneq (,$(filter apa102,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/apa102/include
endif
ifneq (,$(filter mcp23017,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/mcp23017/include
endif
175 changes: 175 additions & 0 deletions drivers/include/mcp23017.h
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 */
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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 periph/gpio.h driver. As a first step, I think it would make sense to go with the following:

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 pin parameter as used above is used as abstraction for the 16 internal pins, so we simply map it A0 -> 0, A1 -> 1, ..., B0 -> 8, B7 -> 15. This needs of course to be documented in the module and API description for this driver...

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 */
/** @} */
1 change: 1 addition & 0 deletions drivers/mcp23017/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base
58 changes: 58 additions & 0 deletions drivers/mcp23017/include/mcp23017_params.h
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 */
/** @} */
113 changes: 113 additions & 0 deletions drivers/mcp23017/include/mcp23017_regs.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 */
/** @} */
Loading