Device driver for Texas Instruments PCF857X I2C I/O expanders. More...
Device driver for Texas Instruments PCF857X I2C I/O expanders.
Texas Instruments PCF857X I2C I/O expanders provide general purpose I/O extension via I2C bus. The driver supports the following PCF857X I2C I/O expander variants:
Expander | Type | Pseudomodule to be used |
---|---|---|
PCF8574 | 8-bit I2C I/O expander | pcf8574 |
PCF8574A | 8-bit I2C I/O expander | pcf8574a |
PCF8575 | 16-bit I2C I/O expander | pcf8575 |
For each of these PCF857X I2C I/O expanders variants, the driver defines a separate pseudomodule. Multiple PCF857X I2C I/O expanders and different variants can be used at the same time. Either the board definition or the application must specify used PCF857X I/O expander variants by a list of used pseudomodules. For example, to use a PCF8574A and a PCF8575 I/O expander in one application, the make command would be:
USEMODULE="pcf8574a pcf8575" make -C tests/drivers/pcf857x BOARD=...
At least one PCF857X I2C I/O expander variant has to be specified. The driver module pcf857x
is then enabled implicitly.
The driver interface is kept as compatible as possible with the peripheral GPIO interface. The only differences are that
pcf857x_
andThe functionality of the driver is controlled by the use of pseudomodules. The following pseudomodules are defined:
Pseudomoule | Functionality |
---|---|
pcf8574 | support of PCF8574 enabled |
pcf8574a | support of PCF8574A enabled |
pcf8575 | support of PCF8575 enabled |
pcf857x_irq | support of interrupts enabled with medium event priority |
pcf857x_irq_low | support of interrupts enabled with low event priority |
pcf857x_irq_medium | support of interrupts enabled with medium event priority |
pcf857x_irq_low | support of interrupts enabled with high event priority |
pcf8574
, pcf8574a
and pcf8575
has to be used.The PCF857X expander devices provide a GPIO expansion over the I2C interface with either
Each quasi-bidirectional expander I/O pin can be used as an input or output without the use of a data-direction control signal. Output pins are latched and have high-current drive capability for directly driving LEDs. The quasi-bidirectional expander I/O pins without direction control work as follows:
After the initialization with the pcf857x_init function, all expander I/O pins are in input mode and pulled-up to HIGH.
The expander I/O pins can be addressed as GPIO pins using the following scheme:
PCF857X pin label | Port | Pin | RIOT symbol | Remark |
---|---|---|---|---|
P00 | 0 | 0 | PCF857X_GPIO_PIN(0, 0) | PCF8574, PCF8574A and PCF8575 |
P01 | 0 | 1 | PCF857X_GPIO_PIN(0, 1) | PCF8574, PCF8574A and PCF8575 |
... | ... | ... | ... | ... |
P07 | 0 | 7 | PCF857X_GPIO_PIN(0, 7) | PCF8574, PCF8574A and PCF8575 |
P10 | 0 | 8 | PCF857X_GPIO_PIN(0, 8) | PCF8575 only |
P11 | 0 | 9 | PCF857X_GPIO_PIN(0, 9) | PCF8575 only |
... | ... | ... | ... | ... |
P17 | 0 | 15 | PCF857X_GPIO_PIN(0, 15) | PCF8575 only |
PCF857X expanders have an open-drain, low-active interrupt (INT) signal, which generates an interrupt by any rising or falling edge of the expander pins in the input mode. Using this expander interrupt signal, the following features become available:
Since interrupts are handled in the context of a separate event thread (see section The Interrupt Context Problem) enabling interrupts requires more RAM. Therefore interrupts have to be explicitly enabled with the module pcf857x_irq_<priority>
. priority
can be one of low
, medium
or highest
, which correspond to the priority of the event thread that processes the interrupts. If only the module pcf857x_irq
is used without specifying the priority, the interrupt handling is enabled with a medium priority of the event thread. For more information on the priorities check the Event Queue module.
Furthermore, the MCU GPIO pin to which the PCF857X INT
signal is connected has to be defined by the default configuration parameter PCF857X_PARAM_INT_PIN (pcf857x_params_t::int_pin) either in the configuration parameter file or at the command line, for example:
CFLAGS="-DPCF857X_PARAM_INT_PIN=\(GPIO_PIN\(0,6\)\)" \ USEMODULE="pcf8575 pcf857x_irq_medium" make -C tests/drivers/pcf857x BOARD=...
Handling an interrupt of a PCF857x expander requires the driver to access the device directly via I2C. However, the mutex-based synchronization of I2C accesses does not work in the interrupt context. Therefore the ISR must not access the PCF857x expander device directly. Rather, the ISR must only indicate the occurrence of the interrupt which has to be handled asynchronously in thread context.
For this purpose an event thread module is used when interrupts are enabled by the module pcf857x_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 Event Queue module.
The driver provides SAUL capabilities that are compatible to the SAUL capabilities of peripheral GPIOs. Each PCF857X expander I/O pin can be mapped directly to SAUL by defining an according entry in PCF857X_SAUL_GPIO_PARAMS
. Please refer file $RIOTBASE/drivers/pcf857x/include/pcf857x_params.h
for an example.
saul_gpio
has to be added to the project to enable SAUL capabilities of the PCF857X driver, e.g.: USEMODULE="pcf8575 saul_gpio" make -C tests/drivers/saul BOARD=...
It is possible to use multiple devices and different variants of PCF857X I/O expanders at the same time. Either the board definition or the application must specify used PCF857X I/O expander variants by a list of used pseudomodules. For example, to use a PCF8574A and a PCF8575 I/O expander in one application, the make command would be:
USEMODULE="pcf8574a pcf8575" make -C tests/drivers/pcf857x BOARD=...
Furthermore, used devices have to be configured by defining the configuration parameter set pcf857x_params
of type pcf857x_params_t. The default configuration for one device is defined in drivers/pcf857x/pcf857x_params.h
. Either the board definition or the application can override it by placing a file pcf857x_params.h
in the board definition directory or the application directory $APPDIR
. For example, the definition of the configuration parameter array for the two devices above could be:
static const pcf857x_params_t pcf857x_params[] = { { .dev = I2C_DEV(0), .addr = 0, .exp = PCF857X_EXP_PCF8574A, .int_pin = GPIO_PIN(0, 1), }, { .dev = I2C_DEV(0), .addr = 0, .exp = PCF857X_EXP_PCF8575, .int_pin = GPIO_PIN(0, 2), }, };
Files | |
file | pcf857x.h |
file | pcf857x_params.h |
Default configuration for Texas Instruments PCF857X I2C I/O expanders. | |
Data Structures | |
struct | pcf857x_params_t |
PCF857X device initialization parameters. More... | |
struct | pcf857x_irq_event_t |
IRQ event type. More... | |
struct | pcf857x_t |
PCF857X device data structure type. More... | |
struct | pcf857x_saul_gpio_params_t |
PCF857X configuration structure for mapping expander pins to SAUL. More... | |
Macros | |
#define | PCF857X_GPIO_PIN(x, y) (y) |
conversion of (port x : pin y) to a pin number | |
Enumerations | |
enum | pcf857x_error_codes_t { PCF857X_OK = 0 , PCF857X_ERROR_I2C = ENXIO , PCF857X_ERROR_INV_EXP = ENOTSUP , PCF857X_ERROR_INV_MODE = EINVAL , PCF857X_ERROR_INV_FLANK = EINVAL , PCF857X_ERROR_INT_PIN = ENOSYS } |
Definition of PCF857X driver error codes. More... | |
enum | pcf857x_exp_t { PCF857X_EXP_PCF8574 , PCF857X_EXP_PCF8574A , PCF857X_EXP_PCF8575 , PCF857X_EXP_MAX } |
Definition of PCF857X expander variants. More... | |
Functions | |
int | pcf857x_init (pcf857x_t *dev, const pcf857x_params_t *params) |
Initialize the PCF857X I/O expander. | |
int | pcf857x_gpio_init (pcf857x_t *dev, uint8_t pin, gpio_mode_t mode) |
Initialize a PCF857X pin. | |
int | pcf857x_gpio_init_int (pcf857x_t *dev, uint8_t pin, gpio_mode_t mode, gpio_flank_t flank, gpio_cb_t isr, void *arg) |
Initialize a PCF857X pin for external interrupt usage. | |
int | pcf857x_gpio_read (pcf857x_t *dev, uint8_t pin) |
Get the value from PCF857X input pin. | |
void | pcf857x_gpio_write (pcf857x_t *dev, uint8_t pin, int value) |
Write the value to PCF857X input pin. | |
void | pcf857x_gpio_clear (pcf857x_t *dev, uint8_t pin) |
Clear the PCF857X output pin. | |
void | pcf857x_gpio_set (pcf857x_t *dev, uint8_t pin) |
Set the PCF857X output pin. | |
void | pcf857x_gpio_toggle (pcf857x_t *dev, uint8_t pin) |
Toggle the value of the PCF857X output pin. | |
void | pcf857x_gpio_irq_enable (pcf857x_t *dev, uint8_t pin) |
Enable pin interrupt. | |
void | pcf857x_gpio_irq_disable (pcf857x_t *dev, uint8_t pin) |
Disable pin interrupt. | |
Module dependent definitions and declarations | |
typedef uint16_t | pcf857x_data_t |
Data type that can mask all expander pins. | |
#define | PCF857X_GPIO_PIN_NUM (16) |
Maximum number of GPIO pins. | |
PCF857X I2C slave addresses | |
PCF857X I2C slave addresses are defined as an offset to a base address, which depends on the expander used. The address offset is in the range of 0 to 7. | |
#define | PCF8575_BASE_ADDR (0x20) |
PCF8575 I2C slave base address. | |
#define | PCF8574_BASE_ADDR (0x20) |
PCF8574 I2C slave base address. | |
#define | PCF8574A_BASE_ADDR (0x38) |
PCF8574A I2C slave base address. | |
PCF857X I/O expander pin number | |
#define | PCF8575_GPIO_PIN_NUM (16) |
PCF8575 has 16 I/O pins. | |
#define | PCF8574_GPIO_PIN_NUM (8) |
PCF8574 has 8 I/O pins. | |
#define | PCF8574A_GPIO_PIN_NUM (8) |
PCF8574A has 8 I/O pins. | |
#define PCF8574_BASE_ADDR (0x20) |
#define PCF8574A_BASE_ADDR (0x38) |
#define PCF8574A_GPIO_PIN_NUM (8) |
#define PCF8575_BASE_ADDR (0x20) |
#define PCF8575_GPIO_PIN_NUM (16) |
#define PCF857X_GPIO_PIN | ( | x, | |
y | |||
) | (y) |
#define PCF857X_GPIO_PIN_NUM (16) |
typedef uint16_t pcf857x_data_t |
Definition of PCF857X driver error codes.
enum pcf857x_exp_t |
Definition of PCF857X expander variants.
It is used in configuration parameters to specify the PCF857X expander used by device.
pcf8574
, pcf8574a
and pcf8575
. Enumerator | |
---|---|
PCF857X_EXP_PCF8574 | PCF8574 8 bit I/O expander used. |
PCF857X_EXP_PCF8574A | PCF8574A 8 bit I/O expander. |
PCF857X_EXP_PCF8575 | PCF8575 16 bit I/O expander. |
void pcf857x_gpio_clear | ( | pcf857x_t * | dev, |
uint8_t | pin | ||
) |
Clear the PCF857X output pin.
[in] | dev | descriptor of PCF857X I/O expander device |
[in] | pin | pin to clear, use PCF857X_GPIO_PIN(x,y) to specify |
int pcf857x_gpio_init | ( | pcf857x_t * | dev, |
uint8_t | pin, | ||
gpio_mode_t | mode | ||
) |
Initialize a PCF857X pin.
[in] | dev | descriptor of PCF857X I/O expander device |
[in] | pin | pin to initialize, use PCF857X_GPIO_PIN(x,y) to specify |
[in] | mode | mode of the pin, see gpio_t |
-EINVAL
.0 | on success |
<0 | a negative errno error code on error |
int pcf857x_gpio_init_int | ( | pcf857x_t * | dev, |
uint8_t | pin, | ||
gpio_mode_t | mode, | ||
gpio_flank_t | flank, | ||
gpio_cb_t | isr, | ||
void * | arg | ||
) |
Initialize a PCF857X 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.
pcf857x_irq*
-EINVAL
.[in] | dev | descriptor of PCF857X I/O expander device |
[in] | pin | pin to initialize, use PCF857X_GPIO_PIN(x,y) to specify |
[in] | mode | mode of the pin, see gpio_t |
[in] | flank | define the active flanks, see gpio_flank_t |
[in] | isr | ISR that is called back from interrupt context |
[in] | arg | optional argument passed to the callback |
0 | on success |
<0 | a negative errno error code on error |
void pcf857x_gpio_irq_disable | ( | pcf857x_t * | dev, |
uint8_t | pin | ||
) |
Disable pin interrupt.
pcf857x_irq*
[in] | dev | descriptor of PCF857X I/O expander device |
[in] | pin | pin to enable the interrupt for |
void pcf857x_gpio_irq_enable | ( | pcf857x_t * | dev, |
uint8_t | pin | ||
) |
Enable pin interrupt.
pcf857x_irq*
[in] | dev | descriptor of PCF857X I/O expander device |
[in] | pin | pin to enable the interrupt for |
int pcf857x_gpio_read | ( | pcf857x_t * | dev, |
uint8_t | pin | ||
) |
Get the value from PCF857X input pin.
[in] | dev | descriptor of PCF857X I/O expander device |
[in] | pin | pin to read, use PCF857X_GPIO_PIN(x,y) to specify |
void pcf857x_gpio_set | ( | pcf857x_t * | dev, |
uint8_t | pin | ||
) |
Set the PCF857X output pin.
[in] | dev | descriptor of PCF857X I/O expander device |
[in] | pin | pin to set, use PCF857X_GPIO_PIN(x,y) to specify |
void pcf857x_gpio_toggle | ( | pcf857x_t * | dev, |
uint8_t | pin | ||
) |
Toggle the value of the PCF857X output pin.
[in] | dev | descriptor of PCF857X I/O expander device |
[in] | pin | pin to toggle, use PCF857X_GPIO_PIN(x,y) to specify |
void pcf857x_gpio_write | ( | pcf857x_t * | dev, |
uint8_t | pin, | ||
int | value | ||
) |
Write the value to PCF857X input pin.
[in] | dev | descriptor of PCF857X I/O expander device |
[in] | pin | pin to write, use PCF857X_GPIO_PIN(x,y) to specify |
[in] | value | value to write |
int pcf857x_init | ( | pcf857x_t * | dev, |
const pcf857x_params_t * | params | ||
) |
Initialize the PCF857X I/O expander.
All expander pins are set to be input and are pulled up.
[in] | dev | descriptor of PCF857X I/O expander device |
[in] | params | configuration parameters, see pcf857x_params_t |
pcf857x_irq*
, the MCU GPIO pin for the interrupt signal has to be defined by the default configuration parameter PCF857X_PARAM_INT_PIN (pcf857x_params_t::int_pin).0 | on success |
<0 | a negative errno error code on error |