mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-17 10:33:49 +01:00
688 lines
28 KiB
C
688 lines
28 KiB
C
/*
|
|
* Copyright (C) 2021 Gunar Schorcht
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
/**
|
|
* @defgroup drivers_mcp23x17 MCP23x17 I/O Expander
|
|
* @ingroup drivers_misc
|
|
* @ingroup drivers_saul
|
|
* @brief Device driver for Microchip MCP23x17 I/O expanders
|
|
*
|
|
* \section mcp23x17_driver Device driver for Microchip MCP23x17 I/O expanders
|
|
*
|
|
* ## Overview
|
|
*
|
|
* Microchip MCP23x17 I/O expanders provide general purpose I/O extension over
|
|
* I2C or SPI. The driver supports the following MCP23x17 I/O expander and
|
|
* interface variants:
|
|
*
|
|
* <center>
|
|
* Expander | Type | Interface | Pseudomodule to be used
|
|
* :--------|:--------------------|:----------|:----------------------------
|
|
* MCP23017 | 16-bit I/O expander | I2C | `mcp23017` or `mcp23x17_i2c`
|
|
* MCP23S17 | 16-bit I/O expander | SPI | `mcp23s17` or `mcp23x17_spi`
|
|
* </center>
|
|
*
|
|
* For each of the MCP23x17 interface variant, the driver defines a separate
|
|
* pseudomodule. Multiple MCP23x17 I/O expanders and different interface
|
|
* variants can be used simultaneously. The application has to specify used
|
|
* MCP23x17 I/O expander or interface variants as a list of used pseudomodules.
|
|
* For example, to use a MCP23017 with I2C interface and a MCP23S17 with SPI
|
|
* interface at the same time, the make command would be:
|
|
*
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
* USEMODULE="mcp23x17_i2c mcp23x17_spi" BOARD=... make -C tests/driver_mcp23x17
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
*
|
|
* At least one MCP23x17 I/O expander or interface variant has to be specified.
|
|
* The driver module `mcp23x17` is then enabled implicitly.
|
|
*
|
|
* ## Driver Interface
|
|
*
|
|
* The driver interface is kept as compatible as possible with the peripheral
|
|
* GPIO interface. The only differences are that
|
|
*
|
|
* - functions have the prefix `mcp23x17_` and
|
|
* - functions require an additional parameter, the pointer to the expander
|
|
* device of type #mcp23x17_t.
|
|
*
|
|
* ## Defined pseudomodules
|
|
*
|
|
* The functionality of the driver is controlled by the use of pseudomodules.
|
|
* The following pseudomodules are defined:
|
|
* <center>
|
|
* Pseudomoule | Functionality
|
|
* :---------------------|:---------------------
|
|
* `mcp23017` | support of MCP23017 with I2C interface
|
|
* `mcp23x17_i2c` | support of MCP23017 with I2C interface
|
|
* `mcp23s17` | support of MCP23S17 with SPI interface
|
|
* `mcp23x17_spi` | support of MCP23S17 with SPI interface
|
|
* `mcp23x17_irq` | support of interrupts enabled with medium event priority
|
|
* `mcp23x17_irq_medium` | support of interrupts enabled with medium event priority
|
|
* `mcp23x17_irq_highest`| support of interrupts enabled with highest event priority
|
|
* `mcp23x17_reset` | support of hardware reset (RESET pin is used)
|
|
* </center><br>
|
|
*
|
|
* @note
|
|
* - At least one of the modules `mcp23017`, `mcp23x17_i2c`, `mcp23s17` or
|
|
* `mcp23x17_spi` has to be used.
|
|
* - Module `mcp23017` enables the `mcp23x17_i2c` module automatically.
|
|
* - Module `mcp23s17` enables the `mcp23x17_spi` module automatically.
|
|
* - Module `mcp23x17_irq` enables the `mcp23x17_irq_medium` module
|
|
* automatically if no other ``mcp23x17_irq_*` module is enabled.
|
|
*
|
|
* ## Expander GPIOs
|
|
*
|
|
* The MCP23x17 expander devices provide 16 bidirectional input/output (I/O)
|
|
* pins. These pins are arranged in two ports A and B with 8 pins each.
|
|
* Each expander I/O pin can be used as input or output. Weak pull-up resistors
|
|
* can be enabled for input pins. Output pins are latched.
|
|
*
|
|
* The driver supports the following GPIO modes:
|
|
*
|
|
* <center>
|
|
* GPIO mode | Remarks
|
|
* :---------- |:--------
|
|
* #GPIO_IN | supported by the MCP27x17 expander device
|
|
* #GPIO_IN_PU | supported by the MCP27x17 expander device
|
|
* #GPIO_IN_PD | not supported
|
|
* #GPIO_OUT | supported by the MCP27x17 expander device
|
|
* #GPIO_OD | emulated by the driver
|
|
* #GPIO_OD_PU | emulated by the driver
|
|
* </center><br>
|
|
*
|
|
* After the initialization with function #mcp23x17_init, all
|
|
* MCP23x17 expander I/O pins are in #GPIO_IN mode.
|
|
*
|
|
* The MCP23x17 expander I/O pins for each device can be addressed either
|
|
* consecutively in the range of 0 ... 15 or by using the macro
|
|
* #MCP23X17_GPIO_PIN with the tuple (port, pin) according to the
|
|
* following scheme:
|
|
*
|
|
* <center>
|
|
* MCP23x17 pin label | Expander Port | Expander Pin | RIOT symbol
|
|
* ------------------ |:-------------:|:------------:|:-------------------------
|
|
* GPA0 | 0 | 0 | `MCP23X17_GPIO_PIN(0, 0)`
|
|
* GPA1 | 0 | 1 | `MCP23X17_GPIO_PIN(0, 1)`
|
|
* ... | ... | ... | ...
|
|
* GPA7 | 0 | 7 | `MCP23X17_GPIO_PIN(0, 7)`
|
|
* GPB0 | 1 | 0 | `MCP23X17_GPIO_PIN(1, 0)`
|
|
* GPB1 | 1 | 1 | `MCP23X17_GPIO_PIN(1, 1)`
|
|
* ... | ... | ... | ...
|
|
* GPB7 | 1 | 7 | `MCP23X17_GPIO_PIN(1, 7)`
|
|
* </center>
|
|
*
|
|
* ## Expander Interfaces
|
|
*
|
|
* MCP23x17 I/O expanders can be connected either via I2C or via SPI. The
|
|
* interface of the respective device is defined by the configuration
|
|
* parameter mcp23x17_if_params_t::type, which can be either
|
|
* #MCP23X17_SPI or #MCP23X17_I2C. To use these interface types, the
|
|
* corresponding modules `mcp23x17_spi` and/or `mcp23x17_i2c` have to be
|
|
* enabled.
|
|
*
|
|
* Each MCP23x17 device requires an address which is configured via the
|
|
* hardware address pins A0 ... A2 of the MCP23x17 device. The address is in
|
|
* the range from 0 to 7 and is used internally by the driver as an offset
|
|
* to the base address #MCP23X17_BASE_ADDR to derive the full device address.
|
|
*
|
|
* @note The driver uses hardware addressing with MCP23x17 pins A0 ... A2
|
|
* also for MCP23x17 SPI devices. This allows the use of up to eight SPI
|
|
* devices with the same CS signal.
|
|
*
|
|
* In addition to the type and the address of the interface, a number of
|
|
* interface specific parameters have to be configured for each device:
|
|
*
|
|
* <center>
|
|
* |Interface | Parameter | Parameter |
|
|
* |:--------:|:-------------------|:---------------------------------------|
|
|
* | SPI | Device Identifier | \ref mcp23x17_spi_params_t::dev "mcp23x17_if_params_t::if_params.spi.dev" |
|
|
* | SPI | Chip Select GPIO | \ref mcp23x17_spi_params_t::cs "mcp23x17_if_params_t::if_params.spi.cs" |
|
|
* | SPI | Clock Rate | \ref mcp23x17_spi_params_t::clk "mcp23x17_if_params_t::if_params.spi.clk" |
|
|
* | SPI | Address Offset | \ref mcp23x17_params_t::addr "mcp23x17_params_t::addr" |
|
|
* | | | |
|
|
* | I2C | Device Identifier | \ref mcp23x17_i2c_params_t::dev "mcp23x17_if_params_t::if_params.i2c.dev" |
|
|
* | I2C | Address Offset | \ref mcp23x17_params_t::addr "mcp23x17_params_t::addr" |
|
|
* </center>
|
|
*
|
|
* ## Hardware Reset
|
|
*
|
|
* MCP23x17 I/O expanders have a low-active `RESET` pin. If module
|
|
* `mcp23x17_reset` is used, a hardware reset is executed when the expander
|
|
* device is initialized with function #mcp23x17_init. Otherwise, only power
|
|
* on reset configuration is restored.
|
|
*
|
|
* If the hardware reset is used by enabling module `mcp23x17_reset`, the
|
|
* configuration parameter mcp23x17_params_t::reset_pin has to define the
|
|
* MCU GPIO pin that is connected to the `RESET` pin of MCP23x17 devices.
|
|
*
|
|
* ## Interrupts
|
|
*
|
|
* MCP23x17 expanders have two interrupt pins `INTA` and `INTB`, one for each
|
|
* port. These interrupt pins are internally connected (mirrored) by the driver
|
|
* so that an interrupt on either port will cause both pins to activate. Thus,
|
|
* interrupts on either port can be handled using a single interrupt pin
|
|
* connected to the MCU.
|
|
*
|
|
* The configuration parameter mcp23x17_params_t::int_pin is used to
|
|
* configure the MCU pin that is connected to one of the interrupt pins
|
|
* `INTA` or `INTB`. Each MCP23x17 expander device must use its own GPIO pin
|
|
* for its combined `INTA`/`INTB` signal.
|
|
*
|
|
* An interrupt callback function can be attached to an expander input pin with
|
|
* the #mcp23x17_gpio_init_int function. This interrupt callback function is
|
|
* then called on any rising and/or falling edge of the expander input pin.
|
|
*
|
|
* @note The interrupt callback function is called in the thread context,
|
|
* so there are no restrictions on execution time or bus access.
|
|
*
|
|
* To be able to handle interrupts in thread context, a separate event
|
|
* thread is used, see section [The Interrupt Context Problem]
|
|
* (#mcp23x17_interrupt_context_problem).
|
|
* Therefore, enabling interrupts requires more RAM and interrupts have to
|
|
* be explicitly enabled with the module `mcp23x17_irq_<priority>`.
|
|
* `priority` can be one `medium` or `highest`, which correspond
|
|
* to the priority of the event thread that processes the interrupts.
|
|
* For more information on the priorities check @ref sys_event module.
|
|
*
|
|
* @note Interrupt support can also be enabled by using module `mxp23x17_irq`
|
|
* without specifying the priority. In this case, module `mcp23x17_irq_medium`
|
|
* is enabled automatically and the interrupt support is enabled with a
|
|
* medium priority of the event thread.
|
|
*
|
|
* Furthermore, the GPIO pin to which the combined MCP23x17 `INTA`/`INTB` signal
|
|
* is connected has to be defined by the parameter mcp23x17_params_t::int_pin.
|
|
* The default hardware configuration as defined in `mcp23x17_params.h`
|
|
* defines by
|
|
*
|
|
* - #MCP23X17_PARAM_I2C_INT the GPIO pin for the interrupt signal of the
|
|
* default MCP23017 device, and
|
|
* - #MCP23X17_PARAM_SPI_INT he GPIO pin for the interrupt signal of the
|
|
* default MCP23S17 device.
|
|
*
|
|
* For more information about the default hardware configuration, see section
|
|
* [Default Hardware Configuration](#mcp23x17_default_hardware_configuration).
|
|
*
|
|
* This default configuration could be overridden at make command line,
|
|
* for example to use a MCP23017 with I2C interface and interrupt support with
|
|
* high priority:
|
|
*
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
* CFLAGS="-DMCP23X17_PARAM_I2C_INT=GPIO_PIN\(0,6\)" \
|
|
* USEMODULE="mcp23x17_i2c mcp23x17_irq_highest" BOARD=... make -C tests/driver_mcp23x17
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
*
|
|
* ## The Interrupt Context Problem {#mcp23x17_interrupt_context_problem}
|
|
*
|
|
* Handling an interrupt of a MCP23x17 expander requires the driver to access
|
|
* the device directly via I2Cor SPI. However, the mutex-based synchronization
|
|
* of I2C and SPI accesses do not work in the interrupt context. Therefore the
|
|
* ISR must not access the MCP23x17 expander device directly. Rather, the ISR
|
|
* must only indicate the occurrence of the interrupt which has to be handled
|
|
* asynchronously in the thread context.
|
|
*
|
|
* For this purpose an event thread module is used when interrupts are
|
|
* enabled by the module `mcp23x17_irq_<priority>`. The driver then
|
|
* handles the interrupts in the context of the event thread with given
|
|
* `priority`. For more information on the priorities check
|
|
* the @ref sys_event module.
|
|
*
|
|
* ## SAUL Capabilities
|
|
*
|
|
* The driver provides SAUL capabilities that are compatible to the
|
|
* SAUL capabilities of MCU GPIOs. Each MCP23x17 expander I/O pin can
|
|
* be mapped directly to SAUL by defining an according entry in
|
|
* #MCP23X17_SAUL_GPIO_PARAMS. Please refer file `mcp23x17_params.h` for
|
|
* an example.
|
|
*
|
|
* @note Module `saul_gpio` has to be added to the
|
|
* project to enable SAUL capabilities of the MCP23x17 driver, e.g.,
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
* USEMODULE="mcp23x17_i2c saul_gpio" BOARD=... make -C tests/saul
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
*
|
|
* ## Using Multiple Devices
|
|
*
|
|
* It is possible to use multiple devices and different interface variants of
|
|
* MCP23x17 I/O expanders simultaneously. The application has to specify used
|
|
* interface variants by a list of pseudomodules. For example, to use MCP23017
|
|
* and MCP23S17 I/O expanders simultaneously, the make command would be:
|
|
*
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
* USEMODULE="mcp23x17_i2c mcp23x17_spi" BOARD=... make -C tests/driver_mcp23x17
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
*
|
|
* Furthermore, used devices have to be configured by defining the hardware
|
|
* configuration parameter array `mcp23x17_params` of type #mcp23x17_params_t.
|
|
* A default hardware configuration for one device of each interface variant is
|
|
* already defined in `mcp23x17_params.h`.
|
|
*
|
|
* The application can override it by placing a `mcp23x17_params.h` *
|
|
* in the application directory `$(APPDIR)`. For example, the definition
|
|
* of the hardware configuration parameter array for two devices with SPI
|
|
* interface and two devices with I2C interface could be:
|
|
*
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.c}
|
|
* static const mcp23x17_params_t mcp23x17_params[] = {
|
|
* {
|
|
* .addr = 0,
|
|
* .int_pin = GPIO_PIN(0,1),
|
|
* .reset_pin = GPIO_UNDEF,
|
|
* .if_params.type = MCP23X17_SPI,
|
|
* .if_params.spi.dev = SPI_DEV(0),
|
|
* .if_params.spi.cs = GPIO_PIN(0,0),
|
|
* .if_params.spi.clk = SPI_CLK_10MHZ,
|
|
* },
|
|
* {
|
|
* .addr = 1,
|
|
* .int_pin = GPIO_PIN(0,2),
|
|
* .reset_pin = GPIO_UNDEF,
|
|
* .if_params.type = MCP23X17_SPI,
|
|
* .if_params.spi.dev = SPI_DEV(0),
|
|
* .if_params.spi.cs = GPIO_PIN(0,0),
|
|
* .if_params.spi.clk = SPI_CLK_10MHZ,
|
|
* },
|
|
* {
|
|
* .addr = 0,
|
|
* .int_pin = GPIO_PIN(0,3),
|
|
* .reset_pin = GPIO_UNDEF,
|
|
* .if_params.type = MCP23X17_I2C,
|
|
* .if_params.i2c.dev = I2C_DEV(0),
|
|
* },
|
|
* {
|
|
* .addr = 1,
|
|
* .int_pin = GPIO_PIN(0,4),
|
|
* .reset_pin = GPIO_UNDEF,
|
|
* .if_params.type = MCP23X17_I2C,
|
|
* .if_params.i2c.dev = SPI_DEV(0),
|
|
* }
|
|
* };
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
*
|
|
* ## Default Hardware Configuration {#mcp23x17_default_hardware_configuration}
|
|
*
|
|
* The default hardware configuration is defined in file `mcp23x17_params.h`
|
|
* using the following defines:
|
|
*
|
|
* <center>
|
|
* | Hardware configuration | Driver name | Default Value |
|
|
* |:------------------------------|:--------------------------|:--------------|
|
|
* | SPI Address Offset | #MCP23X17_PARAM_SPI_ADDR | 0 |
|
|
* | SPI Device Identifier | #MCP23X17_PARAM_SPI_DEV | SPI_DEV(0) |
|
|
* | SPI Clock rRate | #MCP23X17_PARAM_SPI_CLK | SPI_CLK_10MHZ |
|
|
* | SPI Chip Select GPIO | #MCP23X17_PARAM_SPI_CS | GPIO_PIN(0,0) |
|
|
* | SPI Device `INTA`/`INTB` GPIO | #MCP23X17_PARAM_SPI_INT | GPIO_PIN(0,1) |
|
|
* | | | |
|
|
* | I2C Address Offset | #MCP23X17_PARAM_I2C_ADDR | 0 |
|
|
* | I2C Device Identifier | #MCP23X17_PARAM_I2C_DEV | I2C_DEV(0) |
|
|
* | I2C Device `INTA`/`INTB` GPIO | #MCP23X17_PARAM_I2C_INT | GPIO_PIN(0,2) |
|
|
* | | | |
|
|
* | `RESET` GPIO for all devices | #MCP23X17_PARAM_RESET_PIN | GPIO_UNDEF |
|
|
* </center><br>
|
|
*
|
|
* These default hardware configuration parameters can be overridden either by
|
|
* the board definition or by defining them in the `CFLAGS` variable in the make
|
|
* command, for example:
|
|
*
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
* CFLAGS="-DMCP23X17_PARAM_I2C_ADDR=2 -DMCP23X17_PARAM_RESET_PIN=GPIO_PIN\(0,7\)" \
|
|
* USEMODULE='mcp23x17_i2c mcp23x17_reset' BOARD=... make -C tests/driver_mcp23x17
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
*
|
|
* @author Gunar Schorcht <gunar@schorcht.net>
|
|
*
|
|
* @{
|
|
* @file
|
|
* @brief Device driver interface for Microchip MCP23x17 I/O expanders
|
|
*/
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#include "periph/gpio.h"
|
|
#include "periph/i2c.h"
|
|
#include "periph/spi.h"
|
|
|
|
#if IS_USED(MODULE_SAUL_GPIO) || DOXYGEN
|
|
#include "saul/periph.h"
|
|
#endif /* MODULE_SAUL_GPIO */
|
|
|
|
#if !IS_USED(MODULE_MCP23X17_I2C) && !IS_USED(MODULE_MCP23X17_SPI)
|
|
#error "Please provide the MCP23x17 variants used by the application."
|
|
#error "At least one variant has to be specified (mcp23017 and/or mcp23s17)."
|
|
#endif
|
|
|
|
#if IS_USED(MODULE_MCP23X17_IRQ) || DOXYGEN
|
|
|
|
#include "event.h"
|
|
|
|
#endif /* MODULE_MCP23X17_IRQ */
|
|
|
|
/**
|
|
* @brief MCP23x17 device base address
|
|
*
|
|
* The address of a MCP23x17 device, both for devices with I2C interface and
|
|
* for devices with SPI interface, is defined as the offset to a base address.
|
|
* The address is in the range from 0 to 7 and is defined for the respective
|
|
* MCP23x17 device by its hardware address pins A0 ... A2.
|
|
*
|
|
* @note The base address MCP23X17_BASE_ADDR is for internal use only. In the
|
|
* device parameters only the offset to the base address is used as address.
|
|
*/
|
|
#define MCP23X17_BASE_ADDR (0x20)
|
|
|
|
/**
|
|
* @brief MCP23x17 has 16 I/O pins
|
|
*/
|
|
#define MCP23X17_GPIO_PIN_NUM (16)
|
|
|
|
/**
|
|
* @brief Conversion of (port x : pin y) to a pin number
|
|
*
|
|
* MCP23x17 expanders have 16 pins arranged in 2 ports with 8 pins each.
|
|
* #MCP23X17_GPIO_PIN can either be used
|
|
*
|
|
* - #MCP23X17_GPIO_PIN(0, 0...15) or
|
|
* - #MCP23X17_GPIO_PIN(0, 0...7) and MCP23X17_GPIO_PIN(1, 0...7)
|
|
*
|
|
* to address the 16 expander pins.
|
|
*/
|
|
#define MCP23X17_GPIO_PIN(port, pin) ((gpio_t)((port << 3) | pin))
|
|
|
|
/**
|
|
* @brief Named MCP23x17 driver error codes
|
|
*/
|
|
typedef enum {
|
|
MCP23X17_OK, /**< success */
|
|
MCP23X17_ERROR_I2C, /**< I2C communication error */
|
|
MCP23X17_ERROR_SPI, /**< SPI communication error */
|
|
MCP23X17_ERROR_NO_DEV, /**< no MCP23x17 I/O expander device */
|
|
MCP23X17_ERROR_INV_MODE, /**< invalid pin mode */
|
|
MCP23X17_ERROR_INV_FLANK, /**< invalid interrupt flank */
|
|
MCP23X17_ERROR_GPIO, /**< GPIO pin error */
|
|
MCP23X17_ERROR_INT_PIN, /**< `INTA`/`INTB` pin error */
|
|
MCP23X17_ERROR_RESET_PIN, /**< `RESET` pin error */
|
|
} mcp23x17_error_codes_t;
|
|
|
|
/**
|
|
* @brief MCP23x17 interface types
|
|
*/
|
|
typedef enum {
|
|
#if IS_USED(MODULE_MCP23X17_I2C) || DOXYGEN
|
|
MCP23X17_I2C, /**< I2C interface used */
|
|
#endif
|
|
#if IS_USED(MODULE_MCP23X17_SPI) || DOXYGEN
|
|
MCP23X17_SPI, /**< SPI interface used */
|
|
#endif
|
|
} mcp23x17_if_t;
|
|
|
|
/**
|
|
* @brief MCP23017 I2C parameters
|
|
*/
|
|
#if IS_USED(MODULE_MCP23X17_I2C) || DOXYGEN
|
|
typedef struct {
|
|
i2c_t dev; /**< I2C device used */
|
|
} mcp23x17_i2c_params_t;
|
|
#endif
|
|
|
|
/**
|
|
* @brief MCP23S17 SPI parameters
|
|
*/
|
|
#if IS_USED(MODULE_MCP23X17_SPI) || DOXYGEN
|
|
typedef struct {
|
|
spi_t dev; /**< SPI device used */
|
|
spi_clk_t clk; /**< SPI clock speed */
|
|
gpio_t cs; /**< SPI chip Select pin */
|
|
} mcp23x17_spi_params_t;
|
|
#endif
|
|
|
|
/**
|
|
* @brief MCP23x17 Hardware interface parameters union
|
|
*/
|
|
typedef struct {
|
|
mcp23x17_if_t type; /**< I2C/SPI interface type selector */
|
|
union {
|
|
#if IS_USED(MODULE_MCP23X17_I2C) || DOXYGEN
|
|
mcp23x17_i2c_params_t i2c; /**< I2C specific interface parameters */
|
|
#endif
|
|
#if IS_USED(MODULE_MCP23X17_SPI) || DOXYGEN
|
|
mcp23x17_spi_params_t spi; /**< SPI specific interface parameters */
|
|
#endif
|
|
};
|
|
} mcp23x17_if_params_t;
|
|
|
|
/**
|
|
* @brief Struct containing the peripheral configuration
|
|
*/
|
|
typedef struct {
|
|
/**
|
|
* @brief MCP2317 device address.
|
|
*
|
|
* The MCP2317 device address is the address configured via the hardware
|
|
* address pins A0 ... A2 of the MCP23x17 device. It is in the range
|
|
* from 0 to 7. The address is used internally by the driver as an offset
|
|
* to the base address MCP23X17_BASE_ADDR to derive the complete device
|
|
* address.
|
|
*
|
|
* @note The driver uses hardware addressing with MCP23x17
|
|
* pins A0 ... A2 also for MCP23x17 SPI devices. The use of hardware
|
|
* addressing also for SPI devices allows the use of up to eight
|
|
* SPI devices with the same CS signal.
|
|
*/
|
|
uint8_t addr;
|
|
gpio_t int_pin; /**< GPIO pin used for combined `INTA`/`INTB` signal.
|
|
Each device must use its own GPIO pin for its
|
|
combined `INTA`/`INTB` signal. */
|
|
gpio_t reset_pin; /**< GPIO pin used for `RESET` signal */
|
|
mcp23x17_if_params_t if_params; /**< specific I2C/SPI interface parameters */
|
|
} mcp23x17_params_t;
|
|
|
|
#if IS_USED(MODULE_MCP23X17_IRQ) || DOXYGEN
|
|
/**
|
|
* @brief IRQ event type
|
|
*
|
|
* Handling an interrupt of a MCP23x17 expander requires direct access to the
|
|
* device by the driver over I2C/SPI within the ISR. However, the mutex
|
|
* based synchronization of I2C/SPI accesses does not work in the interrupt
|
|
* context. Accessing I2C/SPI within an ISR could therefore interfere with an
|
|
* existing I2C/SPI access. Therefore, the ISR must not access the MCP23x17
|
|
* expander device. Rather, the ISR has only to indicate the occurrence
|
|
* of the interrupt. The interrupt is then handled asynchronously by a thread.
|
|
*
|
|
* The type defines the data structure which is part of each device data
|
|
* structure to indicate that an interrupt for the device occurred. Since there
|
|
* is only one interrupt source, only one interrupt can be pending per device.
|
|
* Thus, only one object of this type per device is required.
|
|
*/
|
|
typedef struct {
|
|
event_t event; /**< Super event data structure */
|
|
void *dev; /**< MCP23x17 device reference */
|
|
} mcp23x17_irq_event_t;
|
|
|
|
#endif /* MODULE_MCP23X17_IRQ */
|
|
|
|
/**
|
|
* @brief Device descriptor for MCP23x17 I/O expanders
|
|
*/
|
|
typedef struct {
|
|
mcp23x17_params_t params; /**< Device initialization parameters */
|
|
|
|
uint16_t od_pins; /**< Pins defined as GPIO_OD or GPIO_OD_PU */
|
|
|
|
#if IS_USED(MODULE_MCP23X17_IRQ) || DOXYGEN
|
|
gpio_isr_ctx_t isr[MCP23X17_GPIO_PIN_NUM]; /**< ISR with arg for each expander pin */
|
|
gpio_flank_t flank[MCP23X17_GPIO_PIN_NUM]; /**< interrupt flank for each expander pin */
|
|
|
|
mcp23x17_irq_event_t irq_event; /**< IRQ event object used for the device */
|
|
#endif /* MODULE_MCP23X17_IRQ */
|
|
|
|
} mcp23x17_t;
|
|
|
|
#if IS_USED(MODULE_SAUL_GPIO) || DOXYGEN
|
|
/**
|
|
* @brief MCP23x17 configuration structure for mapping expander pins to SAUL
|
|
*
|
|
* This data structure is an extension of the GPIO configuration structure for
|
|
* mapping GPIOs to SAUL. The only additional information required is a
|
|
* reference to the according MCP23x17 device.
|
|
*
|
|
* @note To use MCP23x17 with SAUL, module `saul_gpio` has to be added to the
|
|
* project.
|
|
*/
|
|
typedef struct {
|
|
uint8_t dev; /**< MCP23x17 device index */
|
|
saul_gpio_params_t gpio; /**< GPIO configuration for mapping to SAUL */
|
|
} mcp23x17_saul_gpio_params_t;
|
|
#endif
|
|
|
|
/**
|
|
* @brief Initialize the MCP23x17 I/O expander
|
|
*
|
|
* All expander pins are set to be input and are pulled up.
|
|
*
|
|
* @param[in] dev Descriptor of MCP23x17 I/O expander device
|
|
* @param[in] params Configuration parameters, see #mcp23x17_params_t
|
|
*
|
|
* @retval MCP23X17_OK on success
|
|
* @retval MCP23X17_ERROR_* on error, a negative error code,
|
|
* see #mcp23x17_error_codes_t
|
|
*/
|
|
int mcp23x17_init(mcp23x17_t *dev, const mcp23x17_params_t *params);
|
|
|
|
/**
|
|
* @brief Initialize a MCP23x17 pin
|
|
*
|
|
* @param[in] dev Descriptor of MCP23x17 I/O expander device
|
|
* @param[in] pin Pin to initialize, use MCP23X17_GPIO_PIN(x,y) to specify
|
|
* @param[in] mode Mode of the pin, see #gpio_t
|
|
*
|
|
* @retval MCP23X17_OK on success
|
|
* @retval MCP23X17_ERROR_* on error, a negative error code,
|
|
* see #mcp23x17_error_codes_t
|
|
*/
|
|
int mcp23x17_gpio_init(mcp23x17_t *dev, gpio_t pin, gpio_mode_t mode);
|
|
|
|
#if IS_USED(MODULE_MCP23X17_IRQ) || DOXYGEN
|
|
/**
|
|
* @brief Initialize a MCP23x17 pin for external interrupt usage
|
|
*
|
|
* The registered callback function will be called in interrupt context every
|
|
* time the defined flank(s) are detected. Therefore, it MUST NOT be blocking
|
|
* or time-consuming.
|
|
*
|
|
* The interrupt is activated automatically after the initialization.
|
|
*
|
|
* @note
|
|
* - Module `mcp23x17_irq` has to be added to the project to enable this
|
|
* function.
|
|
* - The GPIO pin connected to the MCP23x17 combined `INTA`/`INTB` signal has
|
|
* to be defined by parameter mcp23x17_params_t::int_pin.
|
|
*
|
|
* @param[in] dev Descriptor of MCP23x17 I/O expander device
|
|
* @param[in] pin pin to initialize, use MCP23X17_GPIO_PIN(x,y) to specify
|
|
* @param[in] mode mode of the pin, see #gpio_t
|
|
* @param[in] flank define the active flanks, see #gpio_flank_t
|
|
* @param[in] isr ISR that is called back from interrupt context
|
|
* @param[in] arg optional argument passed to the callback
|
|
*
|
|
* @retval MCP23X17_OK on success
|
|
* @retval MCP23X17_ERROR_* on error, a negative error code,
|
|
* see #mcp23x17_error_codes_t
|
|
*/
|
|
int mcp23x17_gpio_init_int(mcp23x17_t *dev, gpio_t pin,
|
|
gpio_mode_t mode,
|
|
gpio_flank_t flank,
|
|
gpio_cb_t isr,
|
|
void *arg);
|
|
#endif /* MODULE_MCP23X17_IRQ || DOXYGEN */
|
|
|
|
/**
|
|
* @brief Get the value from MCP23x17 input pin
|
|
*
|
|
* @param[in] dev Descriptor of MCP23x17 I/O expander device
|
|
* @param[in] pin pin to read, use MCP23X17_GPIO_PIN(x,y) to specify
|
|
*
|
|
* @retval 0 on LOW signal
|
|
* @retval 1 on HIGH signal
|
|
* @retval MCP23X17_ERROR_* on error, a negative error code,
|
|
* see #mcp23x17_error_codes_t
|
|
*/
|
|
int mcp23x17_gpio_read(mcp23x17_t *dev, gpio_t pin);
|
|
|
|
/**
|
|
* @brief Write the value to MCP23x17 input pin
|
|
*
|
|
* @param[in] dev Descriptor of MCP23x17 I/O expander device
|
|
* @param[in] pin pin to write, use MCP23X17_GPIO_PIN(x,y) to specify
|
|
* @param[in] value value to write
|
|
*/
|
|
void mcp23x17_gpio_write(mcp23x17_t *dev, gpio_t pin, int value);
|
|
|
|
/**
|
|
* @brief Clear the MCP23x17 output pin
|
|
*
|
|
* @param[in] dev Descriptor of MCP23x17 I/O expander device
|
|
* @param[in] pin pin to clear, use MCP23X17_GPIO_PIN(x,y) to specify
|
|
*/
|
|
void mcp23x17_gpio_clear(mcp23x17_t *dev, gpio_t pin);
|
|
|
|
/**
|
|
* @brief Set the MCP23x17 output pin
|
|
*
|
|
* @param[in] dev Descriptor of MCP23x17 I/O expander device
|
|
* @param[in] pin pin to set, use MCP23X17_GPIO_PIN(x,y) to specify
|
|
*/
|
|
void mcp23x17_gpio_set(mcp23x17_t *dev, gpio_t pin);
|
|
|
|
/**
|
|
* @brief Toggle the value of the MCP23x17 output pin
|
|
*
|
|
* @param[in] dev Descriptor of MCP23x17 I/O expander device
|
|
* @param[in] pin pin to toggle, use MCP23X17_GPIO_PIN(x,y) to specify
|
|
*/
|
|
void mcp23x17_gpio_toggle(mcp23x17_t *dev, gpio_t pin);
|
|
|
|
#if IS_USED(MODULE_MCP23X17_IRQ) || DOXYGEN
|
|
/**
|
|
* @brief Enable pin interrupt
|
|
*
|
|
* @note
|
|
* - Module `mcp23x17_irq` has to be added to the project to enable this
|
|
* function.
|
|
* - The GPIO pin connected to the MCP23x17 combined `INTA`/`INTB` signal has
|
|
* to be defined by parameter mcp23x17_params_t::int_pin.
|
|
*
|
|
* @param[in] dev Descriptor of MCP23x17 I/O expander device
|
|
* @param[in] pin pin to enable the interrupt for
|
|
*/
|
|
void mcp23x17_gpio_irq_enable(mcp23x17_t *dev, gpio_t pin);
|
|
|
|
/**
|
|
* @brief Disable pin interrupt
|
|
*
|
|
* @note
|
|
* - Module `mcp23x17_irq` has to be added to the project to enable this
|
|
* function.
|
|
* - The GPIO pin connected to the MCP23x17 combined `INTA`/`INTB` signal has
|
|
* to be defined by parameter mcp23x17_params_t::int_pin.
|
|
*
|
|
* @param[in] dev Descriptor of MCP23x17 I/O expander device
|
|
* @param[in] pin pin to enable the interrupt for
|
|
*/
|
|
void mcp23x17_gpio_irq_disable(mcp23x17_t *dev, gpio_t pin);
|
|
|
|
#endif /* MODULE_MCP23X17_IRQ || DOXYGEN */
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
/** @} */
|