Device driver for Texas Instruments PCF857X I2C I/O expanders. More...

Detailed Description

Device driver for Texas Instruments PCF857X I2C I/O expanders.

driver for Texas Instruments PCF857X I2C I/O expanders

Overview

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/driver_pcf857x BOARD=...

At least one PCF857X I2C I/O expander variant has to be specified. The driver module pcf857x is then enabled implicitly.

Note
While PCF8575 is working in I2C fast mode with up to 400 kHz clock frequency, PCF8574 and PCF8574A are only specified for I2C normal mode with up to 100 kHz clock frequency. However, they seem also to work at 400 kHz clock frequency.

The driver interface is kept as compatible as possible with the peripheral GPIO interface. The only differences are that

Defined pseudomodules

The 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


Note
At least one of the modules pcf8574, pcf8574a and pcf8575 has to be used.

Expander GPIOs

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:

Note
Since the expander I/O pins are quasi-bidirectional without direction control, the only actively driven level is the output LOW. Therefore the driver physically supports only the modes GPIO_IN_PU and GPIO_OD_PU. The other logically identical modes GPIO_IN, GPIO_OUT and GPIO_OD are emulated. Please keep this in mind when connecting these pins to other open-drain output pins that do not generate active signals. The GPIO_IN_PD mode is not supported.

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

Interrupts

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/driver_pcf857x BOARD=...


Note
If an output of the expander is connected to an input of the same expander, there is no interrupt triggered by the input when the output changes. Therefore, a write operation to an output with pcf857x_gpio_write, pcf857x_gpio_clear, pcf857x_gpio_set or pcf857x_gpio_toggle leads to an additional read-after-write operation, if interrupts are used.

The use of interrupts therefore increases the read performance considerably, since I2C read operations are required only when the inputs change. But the write performance is reduced to the half.

The Interrupt Context Problem

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.

SAUL Capabilities

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.

Note
Module 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/saul BOARD=...

Using Multiple Devices

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/driver_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),
     },
 };
Author
Gunar Schorcht gunar.nosp@m.@sch.nosp@m.orcht.nosp@m..net

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)   ((gpio_t)((x << 3) | y))
 conversion of (port x : pin y) to a pin number
 

Enumerations

enum  pcf857x_error_codes_t {
  PCF857X_OK , PCF857X_ERROR_I2C , PCF857X_ERROR_INV_EXP , PCF857X_ERROR_INV_MODE ,
  PCF857X_ERROR_INV_FLANK , PCF857X_ERROR_INT_PIN
}
 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. More...
 
int pcf857x_gpio_init (pcf857x_t *dev, gpio_t pin, gpio_mode_t mode)
 Initialize a PCF857X pin. More...
 
int pcf857x_gpio_init_int (pcf857x_t *dev, gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, gpio_cb_t isr, void *arg)
 Initialize a PCF857X pin for external interrupt usage. More...
 
int pcf857x_gpio_read (pcf857x_t *dev, gpio_t pin)
 Get the value from PCF857X input pin. More...
 
void pcf857x_gpio_write (pcf857x_t *dev, gpio_t pin, int value)
 Write the value to PCF857X input pin. More...
 
void pcf857x_gpio_clear (pcf857x_t *dev, gpio_t pin)
 Clear the PCF857X output pin. More...
 
void pcf857x_gpio_set (pcf857x_t *dev, gpio_t pin)
 Set the PCF857X output pin. More...
 
void pcf857x_gpio_toggle (pcf857x_t *dev, gpio_t pin)
 Toggle the value of the PCF857X output pin. More...
 
void pcf857x_gpio_irq_enable (pcf857x_t *dev, gpio_t pin)
 Enable pin interrupt. More...
 
void pcf857x_gpio_irq_disable (pcf857x_t *dev, gpio_t pin)
 Disable pin interrupt. More...
 

Module dependent definitions and declarations

typedef uint16_t pcf857x_data_t
 Data type that can mask all expander pins. More...
 
#define PCF857X_GPIO_PIN_NUM   (16)
 Maximum number of GPIO pins. More...
 

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. More...
 
#define PCF8574_BASE_ADDR   (0x20)
 PCF8574 I2C slave base address. More...
 
#define PCF8574A_BASE_ADDR   (0x38)
 PCF8574A I2C slave base address. More...
 

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.
 

Macro Definition Documentation

◆ PCF8574_BASE_ADDR

#define PCF8574_BASE_ADDR   (0x20)

PCF8574 I2C slave base address.

Addresses are then in range from 0x20 to 0x27

Definition at line 280 of file pcf857x.h.

◆ PCF8574A_BASE_ADDR

#define PCF8574A_BASE_ADDR   (0x38)

PCF8574A I2C slave base address.

Addresses are then in range from 0x38 to 0x3f

Definition at line 283 of file pcf857x.h.

◆ PCF8575_BASE_ADDR

#define PCF8575_BASE_ADDR   (0x20)

PCF8575 I2C slave base address.

Addresses are then in range from 0x20 to 0x27

Definition at line 277 of file pcf857x.h.

◆ PCF857X_GPIO_PIN_NUM

#define PCF857X_GPIO_PIN_NUM   (16)

Maximum number of GPIO pins.

Defines the maximum number of GPIO pins of all PCF857X I/O expanders used. If a PCF8575 is used, the maximum number is 16 I/O pins.

Definition at line 310 of file pcf857x.h.

Typedef Documentation

◆ pcf857x_data_t

typedef uint16_t pcf857x_data_t

Data type that can mask all expander pins.

If a PCF8575 is used, the 16 I/O pins have to be masked.

Definition at line 317 of file pcf857x.h.

Enumeration Type Documentation

◆ pcf857x_error_codes_t

Definition of PCF857X driver error codes.

Enumerator
PCF857X_OK 

success

PCF857X_ERROR_I2C 

I2C communication error.

PCF857X_ERROR_INV_EXP 

invalid expander variant

PCF857X_ERROR_INV_MODE 

invalid pin mode

PCF857X_ERROR_INV_FLANK 

invalid interrupt flank

PCF857X_ERROR_INT_PIN 

interrupt pin initialization failed

Definition at line 328 of file pcf857x.h.

◆ pcf857x_exp_t

Definition of PCF857X expander variants.

It is used in configuration parameters to specify the PCF857X expander used by device.

Note
Expander variants known by the driver depend on enabled pseudomodules 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.

Definition at line 346 of file pcf857x.h.

Function Documentation

◆ pcf857x_gpio_clear()

void pcf857x_gpio_clear ( pcf857x_t dev,
gpio_t  pin 
)

Clear the PCF857X output pin.

Parameters
[in]devdescriptor of PCF857X I/O expander device
[in]pinpin to clear, use PCF857X_GPIO_PIN(x,y) to specify

◆ pcf857x_gpio_init()

int pcf857x_gpio_init ( pcf857x_t dev,
gpio_t  pin,
gpio_mode_t  mode 
)

Initialize a PCF857X pin.

Parameters
[in]devdescriptor of PCF857X I/O expander device
[in]pinpin to initialize, use PCF857X_GPIO_PIN(x,y) to specify
[in]modemode of the pin, see gpio_t
Note
  • Since the expander I/O pins are quasi-bidirectional without direction control, the only actively driven level is the output LOW. Therefore the driver physically supports only the modes GPIO_IN_PU and GPIO_OD_PU. The other logically identical modes GPIO_IN, GPIO_OUT and GPIO_OD are emulated. For the GPIO_IN_PU mode the function returns with PCF857X_ERROR_INV_MODE.
  • After initialization in GPIO_OUT mode the pin is actively driven LOW, after initialization in all other modes the pin is pulled-up to HIGH.
Return values
PCF857X_OKon success
PCF857X_ERROR_*a negative error code on error, see pcf857x_error_codes_t

◆ pcf857x_gpio_init_int()

int pcf857x_gpio_init_int ( pcf857x_t dev,
gpio_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.

Precondition
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).
Note
  • This function is only available if interrupt handling is enabled by one of the modules pcf857x_irq*
  • Since the expander I/O pins are quasi-bidirectional without direction control, the only actively driven level is the output LOW. Therefore the driver physically supports only the modes GPIO_IN_PU and GPIO_OD_PU. The other logically identical modes GPIO_IN, GPIO_OUT and GPIO_OD are emulated. For the GPIO_IN_PU mode the function returns with PCF857X_ERROR_INV_MODE.
  • After initialization in GPIO_OUT mode the pin is actively driven LOW, after initialization in all other modes the pin is pulled-up to HIGH.
Parameters
[in]devdescriptor of PCF857X I/O expander device
[in]pinpin to initialize, use PCF857X_GPIO_PIN(x,y) to specify
[in]modemode of the pin, see gpio_t
[in]flankdefine the active flanks, see gpio_flank_t
[in]isrISR that is called back from interrupt context
[in]argoptional argument passed to the callback
Return values
PCF857X_OKon success
PCF857X_ERROR_*a negative error code on error, see pcf857x_error_codes_t

◆ pcf857x_gpio_irq_disable()

void pcf857x_gpio_irq_disable ( pcf857x_t dev,
gpio_t  pin 
)

Disable pin interrupt.

Note
This function is only available if interrupt handling is enabled by one of the modules pcf857x_irq*
Parameters
[in]devdescriptor of PCF857X I/O expander device
[in]pinpin to enable the interrupt for

◆ pcf857x_gpio_irq_enable()

void pcf857x_gpio_irq_enable ( pcf857x_t dev,
gpio_t  pin 
)

Enable pin interrupt.

Note
This function is only available if interrupt handling is enabled by one of the modules pcf857x_irq*
Parameters
[in]devdescriptor of PCF857X I/O expander device
[in]pinpin to enable the interrupt for

◆ pcf857x_gpio_read()

int pcf857x_gpio_read ( pcf857x_t dev,
gpio_t  pin 
)

Get the value from PCF857X input pin.

Note
If the PCF857X interrupt is used, the read operation does not perform an I2C read operation since the last input pin value is already read.
Parameters
[in]devdescriptor of PCF857X I/O expander device
[in]pinpin to read, use PCF857X_GPIO_PIN(x,y) to specify

◆ pcf857x_gpio_set()

void pcf857x_gpio_set ( pcf857x_t dev,
gpio_t  pin 
)

Set the PCF857X output pin.

Parameters
[in]devdescriptor of PCF857X I/O expander device
[in]pinpin to set, use PCF857X_GPIO_PIN(x,y) to specify

◆ pcf857x_gpio_toggle()

void pcf857x_gpio_toggle ( pcf857x_t dev,
gpio_t  pin 
)

Toggle the value of the PCF857X output pin.

Parameters
[in]devdescriptor of PCF857X I/O expander device
[in]pinpin to toggle, use PCF857X_GPIO_PIN(x,y) to specify

◆ pcf857x_gpio_write()

void pcf857x_gpio_write ( pcf857x_t dev,
gpio_t  pin,
int  value 
)

Write the value to PCF857X input pin.

Parameters
[in]devdescriptor of PCF857X I/O expander device
[in]pinpin to write, use PCF857X_GPIO_PIN(x,y) to specify
[in]valuevalue to write

◆ pcf857x_init()

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.

Parameters
[in]devdescriptor of PCF857X I/O expander device
[in]paramsconfiguration parameters, see pcf857x_params_t
Precondition
If the interrupt handling is enabled by one of the modules 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).
Return values
PCF857X_OKon success
PCF857X_ERROR_*a negative error code on error, see pcf857x_error_codes_t