From 3d5df2e5afc690d2a624cd304d62eef41c56bdbd Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 4 Aug 2016 16:19:52 -0600 Subject: [PATCH] Extend I/O Expander interrupt controls; Add test of level sensitve interrupt to Simulated I/O expander --- arch/sim/src/up_ioexpander.c | 39 +++++++++++++++++------ configs/sim/src/sim_ioexpander.c | 29 ++++++++++++++++- drivers/ioexpander/pcf8574.c | 3 ++ drivers/ioexpander/tca64xx.c | 3 ++ include/nuttx/ioexpander/ioexpander.h | 45 +++++++++++++++------------ 5 files changed, 89 insertions(+), 30 deletions(-) diff --git a/arch/sim/src/up_ioexpander.c b/arch/sim/src/up_ioexpander.c index 8eec0f9040..ca2a334910 100644 --- a/arch/sim/src/up_ioexpander.c +++ b/arch/sim/src/up_ioexpander.c @@ -59,6 +59,11 @@ #define SIM_POLLDELAY (CONFIG_SIM_INT_POLLDELAY / USEC_PER_TICK) +#define SIM_INT_ENABLED(d,p) \ + (((d)->intenab & ((ioe_pinset_t)1 << (p))) != 0) +#define SIM_INT_DISABLED(d,p) \ + (((d)->intenab & ((ioe_pinset_t)1 << (p))) == 0) + #define SIM_LEVEL_SENSITIVE(d,p) \ (((d)->trigger & ((ioe_pinset_t)1 << (p))) == 0) #define SIM_LEVEL_HIGH(d,p) \ @@ -99,6 +104,7 @@ struct sim_dev_s ioe_pinset_t invert; /* Pin value inversion */ ioe_pinset_t outval; /* Value of output pins */ ioe_pinset_t inval; /* Simulated input register */ + ioe_pinset_t intenab; /* Interrupt enable */ ioe_pinset_t last; /* Last pin inputs (for detection of changes) */ ioe_pinset_t trigger; /* Bit encoded: 0=level 1=edge */ ioe_pinset_t level[2]; /* Bit encoded: 01=high/rising, 10 low/falling, 11 both */ @@ -281,35 +287,44 @@ static int sim_option(FAR struct ioexpander_dev_s *dev, uint8_t pin, switch ((uintptr_t)value) { case IOEXPANDER_VAL_HIGH: /* Interrupt on high level */ + priv->intenab |= bit; priv->trigger &= ~bit; priv->level[0] |= bit; priv->level[1] &= ~bit; break; case IOEXPANDER_VAL_LOW: /* Interrupt on low level */ + priv->intenab |= bit; priv->trigger &= ~bit; priv->level[0] &= ~bit; priv->level[1] |= bit; break; case IOEXPANDER_VAL_RISING: /* Interrupt on rising edge */ + priv->intenab |= bit; priv->trigger |= bit; priv->level[0] |= bit; priv->level[1] &= ~bit; break; case IOEXPANDER_VAL_FALLING: /* Interrupt on falling edge */ + priv->intenab |= bit; priv->trigger |= bit; priv->level[0] &= ~bit; priv->level[1] |= bit; break; case IOEXPANDER_VAL_BOTH: /* Interrupt on both edges */ + priv->intenab |= bit; priv->trigger |= bit; priv->level[0] |= bit; priv->level[1] |= bit; break; + case IOEXPANDER_VAL_DISABLE: + priv->trigger &= ~bit; + break; + default: ret = -EINVAL; break; @@ -655,20 +670,26 @@ static ioe_pinset_t sim_int_update(FAR struct sim_dev_s *priv) for (pin = 0; pin < CONFIG_IOEXPANDER_NPINS; pin++) { - if (SIM_EDGE_SENSITIVE(priv, pin)) + /* Get the value of the pin (accounting for inversion) */ + + pinval = ((input & 1) != 0); + if ((priv->invert & (1 << pin)) != 0) + { + pinval = !pinval; + } + + if (SIM_INT_DISABLED(priv, pin)) + { + /* Interrupts disabled on this pin. Do nothing.. just skip to the + * next pin. + */ + } + else if (SIM_EDGE_SENSITIVE(priv, pin)) { /* Edge triggered. Was there a change in the level? */ if ((diff & 1) != 0) { - /* Get the value of the pin (accounting for inversion) */ - - pinval = ((input & 1) != 0); - if ((priv->invert & (1 << pin)) != 0) - { - pinval = !pinval; - } - /* Set interrupt as a function of edge type */ if ((!pinval && SIM_EDGE_FALLING(priv, pin)) || diff --git a/configs/sim/src/sim_ioexpander.c b/configs/sim/src/sim_ioexpander.c index 01cdb77ddf..c369c69af3 100644 --- a/configs/sim/src/sim_ioexpander.c +++ b/configs/sim/src/sim_ioexpander.c @@ -73,17 +73,44 @@ int sim_gpio_initialize(void) return -ENOMEM; } - /* Register three pin drivers */ + /* Register four pin drivers */ + + /* Pin 0: an non-inverted, input pin */ (void)IOEXP_SETDIRECTION(ioe, 0, IOEXPANDER_DIRECTION_IN); + (void)IOEXP_SETOPTION(ioe, 0, IOEXPANDER_OPTION_INVERT, + (FAR void *)IOEXPANDER_VAL_NORMAL); + (void)IOEXP_SETOPTION(ioe, 0, IOEXPANDER_OPTION_INTCFG, + (FAR void *)IOEXPANDER_VAL_DISABLE); (void)gpio_lower_half(ioe, 0, GPIO_INPUT_PIN, 0); + /* Pin 1: an non-inverted, output pin */ + (void)IOEXP_SETDIRECTION(ioe, 1, IOEXPANDER_DIRECTION_OUT); + (void)IOEXP_SETOPTION(ioe, 1, IOEXPANDER_OPTION_INVERT, + (FAR void *)IOEXPANDER_VAL_NORMAL); + (void)IOEXP_SETOPTION(ioe, 2, IOEXPANDER_OPTION_INTCFG, + (FAR void *)IOEXPANDER_VAL_DISABLE); (void)gpio_lower_half(ioe, 1, GPIO_OUTPUT_PIN, 1); + /* Pin 2: an non-inverted, edge interrupting pin */ + (void)IOEXP_SETDIRECTION(ioe, 2, IOEXPANDER_DIRECTION_IN); + (void)IOEXP_SETOPTION(ioe, 2, IOEXPANDER_OPTION_INVERT, + (FAR void *)IOEXPANDER_VAL_NORMAL); + (void)IOEXP_SETOPTION(ioe, 2, IOEXPANDER_OPTION_INTCFG, + (FAR void *)IOEXPANDER_VAL_BOTH); (void)gpio_lower_half(ioe, 2, GPIO_INTERRUPT_PIN, 2); + /* Pin 3: a non-inverted, level interrupting pin */ + + (void)IOEXP_SETDIRECTION(ioe, 3, IOEXPANDER_DIRECTION_IN); + (void)IOEXP_SETOPTION(ioe, 3, IOEXPANDER_OPTION_INVERT, + (FAR void *)IOEXPANDER_VAL_NORMAL); + (void)IOEXP_SETOPTION(ioe, 3, IOEXPANDER_OPTION_INTCFG, + (FAR void *)IOEXPANDER_VAL_HIGH); + (void)gpio_lower_half(ioe, 3, GPIO_INTERRUPT_PIN, 3); + return 0; } #endif /* CONFIG_EXAMPLES_GPIO && CONFIG_GPIO_LOWER_HALF */ diff --git a/drivers/ioexpander/pcf8574.c b/drivers/ioexpander/pcf8574.c index b8eee535b9..4751ae6991 100644 --- a/drivers/ioexpander/pcf8574.c +++ b/drivers/ioexpander/pcf8574.c @@ -366,6 +366,9 @@ static int pcf8574_option(FAR struct ioexpander_dev_s *dev, uint8_t pin, priv->level[1] |= bit; break; + case IOEXPANDER_VAL_DISABLE: + break; + default: ret = -EINVAL; } diff --git a/drivers/ioexpander/tca64xx.c b/drivers/ioexpander/tca64xx.c index 2b3b00cf05..b7eeb51119 100644 --- a/drivers/ioexpander/tca64xx.c +++ b/drivers/ioexpander/tca64xx.c @@ -612,6 +612,9 @@ static int tca64_option(FAR struct ioexpander_dev_s *dev, uint8_t pin, priv->level[1] |= bit; break; + case IOEXPANDER_VAL_DISABLE: + break; + default: ret = -EINVAL; } diff --git a/include/nuttx/ioexpander/ioexpander.h b/include/nuttx/ioexpander/ioexpander.h index 7bcdd45017..f149b7dfa7 100644 --- a/include/nuttx/ioexpander/ioexpander.h +++ b/include/nuttx/ioexpander/ioexpander.h @@ -61,25 +61,27 @@ /* Pin definitions **********************************************************/ -#define IOEXPANDER_DIRECTION_IN 0 -#define IOEXPANDER_DIRECTION_OUT 1 +#define IOEXPANDER_DIRECTION_IN 0 +#define IOEXPANDER_DIRECTION_OUT 1 -#define IOEXPANDER_PINMASK (((ioe_pinset_t)1 << CONFIG_IOEXPANDER_NPINS) - 1) -#define PINSET_ALL (~((ioe_pinset_t)0)) +#define IOEXPANDER_PINMASK (((ioe_pinset_t)1 << CONFIG_IOEXPANDER_NPINS) - 1) +#define PINSET_ALL (~((ioe_pinset_t)0)) /* Pin options */ -#define IOEXPANDER_OPTION_INVERT 1 /* Set the "active" level for a pin */ -# define IOEXPANDER_VAL_NORMAL 0 /* Normal, no inversion */ -# define IOEXPANDER_VAL_INVERT 1 /* Inverted */ +#define IOEXPANDER_OPTION_INVERT 1 /* Set the "active" level for a pin */ +# define IOEXPANDER_VAL_NORMAL 0 /* Normal, no inversion */ +# define IOEXPANDER_VAL_INVERT 1 /* Inverted */ -#define IOEXPANDER_OPTION_INTCFG 2 /* Configure interrupt for a pin */ -# define IOEXPANDER_VAL_LEVEL 1 /* xx1 Interrupt on level (vs. edge) */ -# define IOEXPANDER_VAL_HIGH 1 /* 001 Interrupt on high level */ -# define IOEXPANDER_VAL_LOW 3 /* 011 Interrupt on low level */ -# define IOEXPANDER_VAL_RISING 2 /* 010 Interrupt on rising edge */ -# define IOEXPANDER_VAL_FALLING 4 /* 100 Interrupt on falling edge */ -# define IOEXPANDER_VAL_BOTH 6 /* 110 Interrupt on both edges */ +#define IOEXPANDER_OPTION_INTCFG 2 /* Configure interrupt for a pin */ +# define IOEXPANDER_VAL_DISABLE 0 /* 0000 Disable pin interrupts */ +# define IOEXPANDER_VAL_LEVEL 1 /* xx01 Interrupt on level (vs. edge) */ +# define IOEXPANDER_VAL_HIGH 5 /* 0101 Interrupt on high level */ +# define IOEXPANDER_VAL_LOW 9 /* 1001 Interrupt on low level */ +# define IOEXPANDER_VAL_EDGE 2 /* xx10 Interrupt on edge (vs. level) */ +# define IOEXPANDER_VAL_RISING 6 /* 0110 Interrupt on rising edge */ +# define IOEXPANDER_VAL_FALLING 10 /* 1010 Interrupt on falling edge */ +# define IOEXPANDER_VAL_BOTH 14 /* 1110 Interrupt on both edges */ /* Access macros ************************************************************/ @@ -319,20 +321,23 @@ struct ioexpander_ops_s CODE int (*ioe_direction)(FAR struct ioexpander_dev_s *dev, uint8_t pin, int direction); CODE int (*ioe_option)(FAR struct ioexpander_dev_s *dev, uint8_t pin, - int opt, void *val); + int opt, FAR void *val); CODE int (*ioe_writepin)(FAR struct ioexpander_dev_s *dev, uint8_t pin, bool value); CODE int (*ioe_readpin)(FAR struct ioexpander_dev_s *dev, uint8_t pin, - bool *value); + FAR bool *value); CODE int (*ioe_readbuf)(FAR struct ioexpander_dev_s *dev, uint8_t pin, - bool *value); + FAR bool *value); #ifdef CONFIG_IOEXPANDER_MULTIPIN CODE int (*ioe_multiwritepin)(FAR struct ioexpander_dev_s *dev, - uint8_t *pins, bool *values, int count); + FAR uint8_t *pins, FAR bool *values, + int count); CODE int (*ioe_multireadpin)(FAR struct ioexpander_dev_s *dev, - uint8_t *pins, bool *values, int count); + FAR uint8_t *pins, FAR bool *values, + int count); CODE int (*ioe_multireadbuf)(FAR struct ioexpander_dev_s *dev, - uint8_t *pins, bool *values, int count); + FAR uint8_t *pins, FAR bool *values, + int count); #endif #ifdef CONFIG_IOEXPANDER_INT_ENABLE CODE FAR void *(*ioe_attach)(FAR struct ioexpander_dev_s *dev,