Include support for PCA9555 interrupt driven IO changes detection.

Currently using a signal, and a single notified task.
signal handling support moved to generic IO expander header (not pca specific)
This commit is contained in:
Sebastien Lorquet 2015-11-17 14:09:43 +01:00
parent 8242600e5e
commit 826aadbce8
4 changed files with 76 additions and 35 deletions

View File

@ -12,13 +12,6 @@ menuconfig IOEXPANDER
if IOEXPANDER
config IOEXPANDER_MULTIPIN
bool "Support multi-pin access routines"
default n
---help---
This settings enable the definition of routines for
optimized simultaneous access to multiple pins.
config IOEXPANDER_PCA9555
bool "PCA9555 I2C IO expander"
default n
@ -34,13 +27,28 @@ config PCA9555_MULTIPLE
---help---
Can be defined to support multiple PCA9555 devices on board.
config PCA9555_INT_DISABLE
bool "Disable PCA9555 Interrupt Support"
default y
config PCA9555_INT_ENABLE
bool "Enable PCA9555 Interrupt Support"
default n
select IOEXPANDER_INT_ENABLE
---help---
Disable driver interrupt functionality
Enable driver interrupt functionality
endif # IOEXPANDER_PCA9555
config IOEXPANDER_INT_ENABLE
bool
default y if PCA9555_INT_ENABLE
---help---
This is the global INT supported flag for io expanders
config IOEXPANDER_MULTIPIN
bool "Support multi-pin access routines"
default n
---help---
This settings enable the definition of routines for
optimized simultaneous access to multiple pins.
endif # IOEXPANDER
config USERLED

View File

@ -436,7 +436,7 @@ static int pca9555_multireadbuf(FAR struct ioexpander_dev_s *dev,
#endif
#ifndef CONFIG_PCA9555_INT_DISABLE
#ifdef CONFIG_PCA9555_INT_ENABLE
/****************************************************************************
* Name: pca9555_irqworker
@ -451,23 +451,54 @@ static void pca9555_irqworker(void *arg)
{
uint8_t addr = PCA9555_REG_INPUT;
uint8_t buf[2];
int ret;
FAR struct pca9555_dev_s *dev = (FAR struct pca9555_dev_s*)arg;
int ret, bits;
FAR struct pca9555_dev_s *pca = (FAR struct pca9555_dev_s*)arg;
/* read inputs */
ret = I2C_WRITEREAD(dev->i2c, &addr, 1, buf, 2);
dbg("> %02X %02X\n",buf[0],buf[1]);
ret = I2C_WRITEREAD(pca->i2c, &addr, 1, buf, 2);
if( ret != OK)
{
return;
}
bits = (buf[0]<<8) | buf[1];
/* if signal PID is registered, enqueue signal. */
if(pca->dev.sigpid)
{
#ifdef CONFIG_CAN_PASS_STRUCTS
union sigval value;
value.sival_int = bits;
ret = sigqueue(pca->dev.sigpid, pca->dev.sigval, value);
#else
ret = sigqueue(pca->dev.sigpid, pca->dev.sigval, (FAR void*)bits);
#endif
dbg("pca signal %04X (sig %d to pid %d)\n",bits, pca->dev.sigval, pca->dev.sigpid);
}
else
{
dbg("no handler registered\n");
}
/* re-enable */
dev->config->enable(dev->config, TRUE);
pca->config->enable(pca->config, TRUE);
}
/****************************************************************************
* Name: pca9555_interrupt
*
* Description:
* Handle GPIO interrupt events (this function executes in the
* context of the interrupt).
*
****************************************************************************/
static int pca9555_interrupt(int irq, FAR void *context)
{
/* To support multiple devices,
* retrieve the priv structure using the irq number */
register FAR struct pca9555_dev_s *dev = &g_pca9555;
register FAR struct pca9555_dev_s *pca = &g_pca9555;
/* In complex environments, we cannot do I2C transfers from the interrupt
* handler because semaphores are probably used to lock the I2C bus. In
@ -476,15 +507,15 @@ static int pca9555_interrupt(int irq, FAR void *context)
* a good thing to do in any event.
*/
DEBUGASSERT(work_available(&dev->work));
DEBUGASSERT(work_available(&pca->dev.work));
/* Notice that further GPIO interrupts are disabled until the work is
* actually performed. This is to prevent overrun of the worker thread.
* Interrupts are re-enabled in pca9555_irqworker() when the work is completed.
*/
dev->config->enable(dev->config, FALSE);
return work_queue(HPWORK, &dev->work, pca9555_irqworker, (FAR void *)dev, 0);
pca->config->enable(pca->config, FALSE);
return work_queue(HPWORK, &pca->dev.work, pca9555_irqworker, (FAR void *)pca, 0);
}
#endif
@ -546,7 +577,7 @@ FAR struct ioexpander_dev_s *pca9555_initialize(FAR struct i2c_dev_s *i2cdev,
I2C_SETADDRESS(i2cdev, config->address, 7);
I2C_SETFREQUENCY(i2cdev, config->frequency);
#ifndef CONFIG_PCA9555_INT_DISABLE
#ifdef CONFIG_PCA9555_INT_ENABLE
pcadev->config->attach(pcadev->config, pca9555_interrupt);
pcadev->config->enable(pcadev->config, TRUE);
#endif

View File

@ -48,7 +48,6 @@
#include <nuttx/wdog.h>
#include <nuttx/clock.h>
#include <nuttx/wqueue.h>
#include <nuttx/discrete/ioexpander.h>
#include <nuttx/discrete/pca9555.h>
@ -95,12 +94,6 @@
#error "CONFIG_I2C is required by PCA9555"
#endif
#ifndef CONFIG_PCA9555_INT_DISABLE
#ifndef CONFIG_SCHED_WORKQUEUE
#error "Work queue support required. CONFIG_SCHED_WORKQUEUE must be selected."
#endif
#endif
#define PCA9555_MAXDEVS 8
/* I2C frequency */
@ -123,18 +116,15 @@
struct pca9555_dev_s
{
struct ioexpander_dev_s dev; /* Nested structure to allow casting as public gpio expander. */
struct ioexpander_dev_s dev; /* Nested structure to allow casting as public gpio expander. */
#ifdef CONFIG_PCA9555_MULTIPLE
FAR struct pca9555_dev_s *flink; /* Supports a singly linked list of drivers */
FAR struct pca9555_dev_s * flink; /* Supports a singly linked list of drivers */
#endif
FAR struct pca9555_config_s *config; /* Board configuration data */
FAR struct i2c_dev_s *i2c; /* Saved I2C driver instance */
FAR struct i2c_dev_s * i2c; /* Saved I2C driver instance */
#ifndef CONFIG_PCA9555_INT_DISABLE
struct work_s work; /* Supports the interrupt handling "bottom half" */
#endif
};
#endif /* CONFIG_IOEXPANDER && CONFIG_IOEXPANDER_PCA9555 */

View File

@ -41,9 +41,16 @@
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/wqueue.h>
#if defined(CONFIG_IOEXPANDER)
#ifndef CONFIG_PCA9555_INT_DISABLE
#ifndef CONFIG_SCHED_WORKQUEUE
#error "Work queue support required. CONFIG_SCHED_WORKQUEUE must be selected."
#endif
#endif
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@ -249,6 +256,11 @@ struct ioexpander_ops_s
struct ioexpander_dev_s
{
FAR const struct ioexpander_ops_s *ops;
#ifdef CONFIG_IOEXPANDER_INT_ENABLE
struct work_s work; /* Supports the interrupt handling "bottom half" */
int sigpid; /* PID to be signaled in case of interrupt */
int sigval; /* signal to be sent in case of interrupt */
#endif
};
#endif //CONFIG_IOEXPANDER