Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drivers/pca95xx: support for I2C GPIO expanders #9054

Closed
wants to merge 15 commits into from

Conversation

ZetaR60
Copy link
Contributor

@ZetaR60 ZetaR60 commented Apr 30, 2018

Contribution description

This adds support for a variety of I2C GPIO expanders.

Specific parts:

PCA9534, PCA9535, PCA9536, PCA9538, PCA9539, PCA9554, PCA9555, PCA9957, and variants such as PCA6408 and PCA6416, and TCA versions of these components. Probably some others that I didn't see on Digikey. Most of these are also available from multiple manufacturers. I am using the TCA9539.

Todo:

Full testing, fixes, and polish.

@ZetaR60
Copy link
Contributor Author

ZetaR60 commented May 1, 2018

Current progress:

@ZetaR60
Copy link
Contributor Author

ZetaR60 commented May 1, 2018

Reading and writing now works. Verified by multimeter.

@bergzand bergzand added Type: new feature The issue requests / The PR implemements a new feature for RIOT Area: drivers Area: Device drivers labels May 1, 2018
@bergzand bergzand requested a review from aabadie May 1, 2018 09:03
@ZetaR60
Copy link
Contributor Author

ZetaR60 commented May 2, 2018

Interrupts now work when #8951 is applied.

@ZetaR60
Copy link
Contributor Author

ZetaR60 commented May 6, 2018

Saul is now working. Everything now seems to be working properly.

BOARD = mega-xplained

Installed compiler toolchains 
-----------------------------
             native gcc: missing
      arm-none-eabi-gcc: missing
                avr-gcc: avr-gcc (Fedora 7.2.0-1.fc27) 7.2.0
       mips-mti-elf-gcc: missing
             msp430-gcc: missing
   riscv-none-embed-gcc: missing
                  clang: missing

Installed compiler libs
-----------------------
   arm-none-eabi-newlib: missing
    mips-mti-elf-newlib: missing
riscv-none-embed-newlib: missing
               avr-libc: "2.0.0" ("20150208")

Installed development tools
---------------------------
                  cmake: cmake version 3.11.0
               cppcheck: missing
                doxygen: missing
                 flake8: missing
                    git: git version 2.14.2
             coccinelle: missing

tests/driver_pca95xx

[liveuser@localhost-live driver_pca95xx]$ make BOARD=mega-xplained term
/home/liveuser/Desktop/RIOT_pca95xx/dist/tools/pyterm/pyterm -p "/dev/ttyUSB0" -b "9600"
No handlers could be found for logger "root"
2018-05-06 15:42:43,491 - INFO # Connect to serial port /dev/ttyUSB0
Welcome to pyterm!
Type '/exit' to exit.
2018-05-06 15:42:44,502 - INFO # 

2018-05-06 15:42:44,509 - INFO # main(): This is RIOT! (Version: 2018.04-devel-1008-g9b7df4-localhost-live-RIOT_pca95xx)
2018-05-06 15:42:44,511 - INFO # PCA95xx I2C GPIO expander driver test
2018-05-06 15:42:44,511 - INFO # 
> help
2018-05-06 15:42:46,259 - INFO #  help
2018-05-06 15:42:46,291 - INFO # Command              Description
2018-05-06 15:42:46,339 - INFO # ---------------------------------------
2018-05-06 15:42:46,388 - INFO # init_out             init as output (push-pull mode)
2018-05-06 15:42:46,420 - INFO # init_in              init as input
2018-05-06 15:42:46,483 - INFO # init_od              init as output (open-drain mode)
2018-05-06 15:42:46,515 - INFO # read                 read pin status
2018-05-06 15:42:46,563 - INFO # set                  set pin to HIGH
2018-05-06 15:42:46,595 - INFO # clear                set pin to LOW
2018-05-06 15:42:46,628 - INFO # toggle               toggle pin
2018-05-06 15:42:46,659 - INFO # write                write value to pin
> init_in 5
2018-05-06 15:42:49,795 - INFO #  init_in 5
> read 5
2018-05-06 15:42:51,459 - INFO #  read 5
2018-05-06 15:42:51,490 - INFO # PCA95xx pin 5 is HIGH
> init_out 5
2018-05-06 15:42:54,290 - INFO #  init_out 5
> clear 5
2018-05-06 15:42:57,569 - INFO #  clear 5
> read 5
2018-05-06 15:42:58,818 - INFO #  read 5
2018-05-06 15:42:58,849 - INFO # PCA95xx pin 5 is LOW
> set 5
2018-05-06 15:43:02,113 - INFO #  set 5
> read 5
2018-05-06 15:43:03,361 - INFO #  read 5
2018-05-06 15:43:03,392 - INFO # PCA95xx pin 5 is HIGH
> toggle 5
2018-05-06 15:43:10,383 - INFO #  toggle 5
> read 5
2018-05-06 15:43:11,600 - INFO #  read 5
2018-05-06 15:43:11,616 - INFO # PCA95xx pin 5 is LOW
> write 5 1
2018-05-06 15:43:17,518 - INFO #  write 5 1
> read 5
2018-05-06 15:43:18,975 - INFO #  read 5
2018-05-06 15:43:18,991 - INFO # PCA95xx pin 5 is HIGH
> write 5 0
2018-05-06 15:43:21,342 - INFO #  write 5 0
> read 5
2018-05-06 15:43:22,526 - INFO #  read 5
2018-05-06 15:43:22,542 - INFO # PCA95xx pin 5 is LOW
> init_od 5
2018-05-06 15:43:31,420 - INFO #  init_od 5
> read 5
2018-05-06 15:43:35,388 - INFO #  read 5
2018-05-06 15:43:35,404 - INFO # PCA95xx pin 5 is LOW
> toggle 5
2018-05-06 15:43:40,555 - INFO #  toggle 5
> read 5
2018-05-06 15:43:42,266 - INFO #  read 5
2018-05-06 15:43:42,298 - INFO # PCA95xx pin 5 is HIGH
> toggle 5
2018-05-06 15:43:46,314 - INFO #  toggle 5
> read 5
2018-05-06 15:43:47,578 - INFO #  read 5
2018-05-06 15:43:47,594 - INFO # PCA95xx pin 5 is LOW
> /exit
2018-05-06 15:45:22,694 - INFO # Exiting Pyterm

examples/default

With pin set to read (high-Z):

[liveuser@localhost-live default]$ make BOARD=mega-xplained term
/home/liveuser/Desktop/RIOT_pca95xx/dist/tools/pyterm/pyterm -p "/dev/ttyUSB0" -b "9600"
No handlers could be found for logger "root"
2018-05-06 15:59:04,624 - INFO # Connect to serial port /dev/ttyUSB0
Welcome to pyterm!
Type '/exit' to exit.
2018-05-06 15:59:05,635 - INFO # 

2018-05-06 15:59:05,642 - INFO # main(): This is RIOT! (Version: 2018.04-devel-1008-g9b7df4-localhost-live-RIOT_pca95xx)
2018-05-06 15:59:05,644 - INFO # Welcome to RIOT!
> help
2018-05-06 15:59:07,593 - INFO #  help
2018-05-06 15:59:07,625 - INFO # Command              Description
2018-05-06 15:59:07,657 - INFO # ---------------------------------------
2018-05-06 15:59:07,705 - INFO # reboot               Reboot the node
2018-05-06 15:59:07,769 - INFO # ps                   Prints information about running threads.
2018-05-06 15:59:07,833 - INFO # saul                 interact with sensors and actuators using SAUL
> saul
2018-05-06 15:59:09,464 - INFO #  saul
2018-05-06 15:59:09,480 - INFO # ID	Class		Name
2018-05-06 15:59:09,496 - INFO # #0	SENSE_BTN	Button 0
2018-05-06 15:59:09,513 - INFO # #1	SENSE_BTN	Button 1
2018-05-06 15:59:09,544 - INFO # #2	ACT_SWITCH	LED 1
2018-05-06 15:59:09,560 - INFO # #3	ACT_SWITCH	LED 3
2018-05-06 15:59:09,592 - INFO # #4	SENSE_ANALOG	NTC thermistor
2018-05-06 15:59:09,624 - INFO # #5	SENSE_ANALOG	Light sensor
2018-05-06 15:59:09,640 - INFO # #6	SENSE_ANALOG	RC filter
2018-05-06 15:59:09,672 - INFO # #7	ACT_SWITCH	pca95xx
> saul read 7
2018-05-06 15:59:12,040 - INFO #  saul read 7
2018-05-06 15:59:12,072 - INFO # Reading from #7 (pca95xx|ACT_SWITCH)
2018-05-06 15:59:12,088 - INFO # Data:	          1
> saul write 7 0
2018-05-06 15:59:16,408 - INFO #  saul write 7 0
2018-05-06 15:59:16,439 - INFO # Writing to device #7 - pca95xx
2018-05-06 15:59:16,456 - INFO # Data:	          0
2018-05-06 15:59:16,503 - INFO # data successfully written to device #7
> saul read 7
2018-05-06 15:59:18,935 - INFO #  saul read 7
2018-05-06 15:59:18,967 - INFO # Reading from #7 (pca95xx|ACT_SWITCH)
2018-05-06 15:59:18,983 - INFO # Data:	          1
> /exit
2018-05-06 15:59:30,554 - INFO # Exiting Pyterm

With pin set to output (push-pull):

[liveuser@localhost-live default]$ make BOARD=mega-xplained term
/home/liveuser/Desktop/RIOT_pca95xx/dist/tools/pyterm/pyterm -p "/dev/ttyUSB0" -b "9600"
No handlers could be found for logger "root"
2018-05-06 16:02:45,065 - INFO # Connect to serial port /dev/ttyUSB0
Welcome to pyterm!
Type '/exit' to exit.
2018-05-06 16:02:46,077 - INFO # 

2018-05-06 16:02:46,084 - INFO # main(): This is RIOT! (Version: 2018.04-devel-1008-g9b7df4-localhost-live-RIOT_pca95xx)
2018-05-06 16:02:46,085 - INFO # Welcome to RIOT!
> help
2018-05-06 16:02:48,587 - INFO #  help
2018-05-06 16:02:48,635 - INFO # Command              Description
2018-05-06 16:02:48,667 - INFO # ---------------------------------------
2018-05-06 16:02:48,715 - INFO # reboot               Reboot the node
2018-05-06 16:02:48,779 - INFO # ps                   Prints information about running threads.
2018-05-06 16:02:48,843 - INFO # saul                 interact with sensors and actuators using SAUL
> saul
2018-05-06 16:02:50,522 - INFO #  saul
2018-05-06 16:02:50,538 - INFO # ID	Class		Name
2018-05-06 16:02:50,554 - INFO # #0	SENSE_BTN	Button 0
2018-05-06 16:02:50,586 - INFO # #1	SENSE_BTN	Button 1
2018-05-06 16:02:50,602 - INFO # #2	ACT_SWITCH	LED 1
2018-05-06 16:02:50,618 - INFO # #3	ACT_SWITCH	LED 3
2018-05-06 16:02:50,650 - INFO # #4	SENSE_ANALOG	NTC thermistor
2018-05-06 16:02:50,682 - INFO # #5	SENSE_ANALOG	Light sensor
2018-05-06 16:02:50,714 - INFO # #6	SENSE_ANALOG	RC filter
2018-05-06 16:02:50,730 - INFO # #7	ACT_SWITCH	pca95xx
> saul read 7
2018-05-06 16:02:56,201 - INFO #  saul read 7
2018-05-06 16:02:56,249 - INFO # Reading from #7 (pca95xx|ACT_SWITCH)
2018-05-06 16:02:56,265 - INFO # Data:	          0
> saul write 7 1
2018-05-06 16:03:01,784 - INFO #  saul write 7 1
2018-05-06 16:03:01,816 - INFO # Writing to device #7 - pca95xx
2018-05-06 16:03:01,832 - INFO # Data:	          1
2018-05-06 16:03:01,864 - INFO # data successfully written to device #7
> saul read 7
2018-05-06 16:03:04,584 - INFO #  saul read 7
2018-05-06 16:03:04,616 - INFO # Reading from #7 (pca95xx|ACT_SWITCH)
2018-05-06 16:03:04,648 - INFO # Data:	          1
> saul write 7 0
2018-05-06 16:03:08,711 - INFO #  saul write 7 0
2018-05-06 16:03:08,743 - INFO # Writing to device #7 - pca95xx
2018-05-06 16:03:08,759 - INFO # Data:	          0
2018-05-06 16:03:08,791 - INFO # data successfully written to device #7
> saul read 7
2018-05-06 16:03:11,560 - INFO #  saul read 7
2018-05-06 16:03:11,607 - INFO # Reading from #7 (pca95xx|ACT_SWITCH)
2018-05-06 16:03:11,623 - INFO # Data:	          0
> /exit
2018-05-06 16:03:19,170 - INFO # Exiting Pyterm

With pin set to output (open-drain):

[liveuser@localhost-live default]$ make BOARD=mega-xplained term
/home/liveuser/Desktop/RIOT_pca95xx/dist/tools/pyterm/pyterm -p "/dev/ttyUSB0" -b "9600"
No handlers could be found for logger "root"
2018-05-06 16:05:29,572 - INFO # Connect to serial port /dev/ttyUSB0
Welcome to pyterm!
Type '/exit' to exit.
2018-05-06 16:05:30,584 - INFO # 

2018-05-06 16:05:30,591 - INFO # main(): This is RIOT! (Version: 2018.04-devel-1008-g9b7df4-localhost-live-RIOT_pca95xx)
2018-05-06 16:05:30,591 - INFO # Welcome to RIOT!
> help
2018-05-06 16:05:33,077 - INFO #  help
2018-05-06 16:05:33,125 - INFO # Command              Description
2018-05-06 16:05:33,157 - INFO # ---------------------------------------
2018-05-06 16:05:33,190 - INFO # reboot               Reboot the node
2018-05-06 16:05:33,269 - INFO # ps                   Prints information about running threads.
2018-05-06 16:05:33,333 - INFO # saul                 interact with sensors and actuators using SAUL
> saul
2018-05-06 16:05:34,037 - INFO #  saul
2018-05-06 16:05:34,053 - INFO # ID	Class		Name
2018-05-06 16:05:34,069 - INFO # #0	SENSE_BTN	Button 0
2018-05-06 16:05:34,086 - INFO # #1	SENSE_BTN	Button 1
2018-05-06 16:05:34,117 - INFO # #2	ACT_SWITCH	LED 1
2018-05-06 16:05:34,133 - INFO # #3	ACT_SWITCH	LED 3
2018-05-06 16:05:34,165 - INFO # #4	SENSE_ANALOG	NTC thermistor
2018-05-06 16:05:34,197 - INFO # #5	SENSE_ANALOG	Light sensor
2018-05-06 16:05:34,213 - INFO # #6	SENSE_ANALOG	RC filter
2018-05-06 16:05:34,245 - INFO # #7	ACT_SWITCH	pca95xx
> saul read 7
2018-05-06 16:05:36,885 - INFO #  saul read 7
2018-05-06 16:05:36,932 - INFO # Reading from #7 (pca95xx|ACT_SWITCH)
2018-05-06 16:05:36,948 - INFO # Data:	          0
> saul write 7 1
2018-05-06 16:05:40,933 - INFO #  saul write 7 1
2018-05-06 16:05:40,964 - INFO # Writing to device #7 - pca95xx
2018-05-06 16:05:40,980 - INFO # Data:	          1
2018-05-06 16:05:41,028 - INFO # data successfully written to device #7
> saul read 7
2018-05-06 16:05:43,955 - INFO #  saul read 7
2018-05-06 16:05:43,987 - INFO # Reading from #7 (pca95xx|ACT_SWITCH)
2018-05-06 16:05:44,004 - INFO # Data:	          1
> saul write 7 0
2018-05-06 16:05:52,899 - INFO #  saul write 7 0
2018-05-06 16:05:52,930 - INFO # Writing to device #7 - pca95xx
2018-05-06 16:05:52,947 - INFO # Data:	          0
2018-05-06 16:05:52,994 - INFO # data successfully written to device #7
> saul read 7
2018-05-06 16:05:55,458 - INFO #  saul read 7
2018-05-06 16:05:55,505 - INFO # Reading from #7 (pca95xx|ACT_SWITCH)
2018-05-06 16:05:55,521 - INFO # Data:	          0
> /exit
2018-05-06 16:06:14,726 - INFO # Exiting Pyterm

Copy link
Contributor

@aabadie aabadie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this one but I think the API should be slightly reworked.
The initialization of the I2C device could be factorized in a single function and GPIO manipulations (default init, init with int) could be handled in separate functions.
I also don't like split between regular GPIO parameters and interrupt pin parameters, only a single one should be used.
Also passing pin and flags in initialization parameters restricts the device use to a single pin, whereas it's able the control multiple ones from a single I2C bus.
What about having the device to manipulate a list of GPIO ?

#define PCA95XX_PARAM_PINS  { { .pin = 0, .flags = xx, .int_pin = GPIO_UNDEF},}

#define PCA95XX_PARAMS        { .i2c          = PCA95XX_PARAM_I2C,  \
                                .addr         = PCA95XX_PARAM_ADDR, \
                                .pins          = PCA95XX_PARAM_PINS, }

i2c_t i2c; /**< i2c device */
uint8_t addr; /**< i2c address */
gpio_t int_pin; /**< interrupt pin (GPIO_UNDEF if not connected) */
} pca95xx_int_params_t;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This parameter struct could be merged with pca95xx_params struct

*
* @return zero on successful initialization, non zero on error
*/
int pca95xx_int_init(pca95xx_int_t *dev, const pca95xx_int_params_t *params);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better to pass the callback and related arguments in the initialization function

return 1;
}

pca95xx_dev.params.pin = atoi(argv[1]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

normally, the params attribute correspond to initialization parameters and should not updated afterward. Would it make sense to introduce a new function in the API to initialize a specific pin instead of reinitializing the whole device?


static int init_out(int argc, char **argv)
{
pca95xx_dev.params.flags |= PCA95XX_HIGH_DRIVE | PCA95XX_LOW_DRIVE;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather introduce a set_flags function


return 0;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blank line could be removed

@ZetaR60
Copy link
Contributor Author

ZetaR60 commented May 7, 2018

@aabadie A number of the changes you request are things that I am dissatisfied with as well, but cause problems when trying to maintain SAUL compatibility. Combining the pin and interrupt parameters into one struct means that the interrupt parameters are replicated for every pin used by SAUL (up to 16, in this case). Also, placing the pin settings inside params maintains compatibility with SAUL param defines for reads/writes, but is a bit of a hack to modify it in other code. Manipulating multiple pins together would be reasonable on the backend, but would be very cumbersome to use on the CLI with SAUL. I don't quite know how to remove these hacks while maintaining reasonable and compatible behavior.

What SAUL really needs is a way of easily manipulating arrays of devices that have identical params except for an index value.

@aabadie
Copy link
Contributor

aabadie commented May 7, 2018

but cause problems when trying to maintain SAUL compatibility

Yeah, I forgot to put SAUL related things in my initial comment. The actual design in SAUL doesn't fit well with this kind of device I think. What is missing in SAUL is some kind of read/write function with a contextual parameter (could be the pin here).
The other question is: is SAUL compatibility mandatory now for this driver ?

@ZetaR60
Copy link
Contributor Author

ZetaR60 commented May 7, 2018

Perhaps I should do a partial rewrite under the following assumptions:

  • Similarity to gpio.h is maintained
  • There will be a follow-up PR at some point adding support for a contextual parameter to SAUL
  • SAUL support is not currently required, but forward compatibility with contextual parameter SAUL is

@ZetaR60
Copy link
Contributor Author

ZetaR60 commented May 17, 2018

Partial rewrite almost done. Reading and writing are working, but interrupts are not yet functional.

@ZetaR60
Copy link
Contributor Author

ZetaR60 commented May 17, 2018

@aabadie My partial rewrite is complete; everything is working; and it is ready for a re-review.

Test output (with debugging enabled):

[liveuser@localhost-live driver_pca95xx]$ make BOARD=mega-xplained term
/home/liveuser/Desktop/RIOT_pca95xx/dist/tools/pyterm/pyterm -p "/dev/ttyUSB0" -b "9600"
No handlers could be found for logger "root"
2018-05-17 16:37:54,365 - INFO # Connect to serial port /dev/ttyUSB0
Welcome to pyterm!
Type '/exit' to exit.
2018-05-17 16:37:55,376 - INFO # 

2018-05-17 16:37:55,383 - INFO # main(): This is RIOT! (Version: 2018.04-devel-1014-gc427a-localhost-live-RIOT_pca95xx)
2018-05-17 16:37:55,386 - INFO # PCA95xx I2C GPIO expander driver test
2018-05-17 16:37:55,387 - INFO # Initializing PCA95xx
2018-05-17 16:37:55,387 - INFO # [pca95xx] init - testing reg 4
> help
2018-05-17 16:37:56,738 - INFO #  help
2018-05-17 16:37:56,770 - INFO # Command              Description
2018-05-17 16:37:56,802 - INFO # ---------------------------------------
2018-05-17 16:37:56,866 - INFO # init_out             init as output (push-pull mode)
2018-05-17 16:37:56,898 - INFO # init_in              init as input
2018-05-17 16:37:56,946 - INFO # init_od              init as output (open-drain mode)
2018-05-17 16:37:56,994 - INFO # init_int             configure interrupt
2018-05-17 16:37:57,042 - INFO # irq_en               enable interrupt
2018-05-17 16:37:57,074 - INFO # irq_dis              disable interrupt
2018-05-17 16:37:57,106 - INFO # read                 read pin status
2018-05-17 16:37:57,154 - INFO # set                  set pin to HIGH
2018-05-17 16:37:57,186 - INFO # clear                set pin to LOW
2018-05-17 16:37:57,218 - INFO # toggle               toggle pin
2018-05-17 16:37:57,266 - INFO # write                write value to pin
> init_out 8
2018-05-17 16:38:02,402 - INFO #  init_out 8
2018-05-17 16:38:02,449 - INFO # [pca95xx] init_pin - enabled low drive on pin 8
2018-05-17 16:38:02,513 - INFO # [pca95xx] init_pin - enabled high drive on pin 8
2018-05-17 16:38:02,545 - INFO # [pca95xx] clear - driving pin 8 low
> read 8
2018-05-17 16:38:07,584 - INFO #  read 8
2018-05-17 16:38:07,616 - INFO # PCA95xx pin 8 is LOW
> set 8
2018-05-17 16:38:13,215 - INFO #  set 8
2018-05-17 16:38:13,247 - INFO # [pca95xx] set - driving pin 8 high
> read 8
2018-05-17 16:38:14,463 - INFO #  read 8
2018-05-17 16:38:14,495 - INFO # PCA95xx pin 8 is HIGH
> clear 8
2018-05-17 16:38:17,790 - INFO #  clear 8
2018-05-17 16:38:17,822 - INFO # [pca95xx] clear - driving pin 8 low
> read 8
2018-05-17 16:38:21,087 - INFO #  read 8
2018-05-17 16:38:21,103 - INFO # PCA95xx pin 8 is LOW
> toggle 8
2018-05-17 16:38:23,934 - INFO #  toggle 8
2018-05-17 16:38:23,965 - INFO # [pca95xx] set - driving pin 8 high
> read 8
2018-05-17 16:38:25,229 - INFO #  read 8
2018-05-17 16:38:25,245 - INFO # PCA95xx pin 8 is HIGH
> write 8 0
2018-05-17 16:38:32,925 - INFO #  write 8 0
2018-05-17 16:38:32,972 - INFO # [pca95xx] clear - driving pin 8 low
> read 8
2018-05-17 16:38:34,124 - INFO #  read 8
2018-05-17 16:38:34,141 - INFO # PCA95xx pin 8 is LOW
> write 8 1
2018-05-17 16:38:37,036 - INFO #  write 8 1
2018-05-17 16:38:37,067 - INFO # [pca95xx] set - driving pin 8 high
> read 8
2018-05-17 16:38:38,524 - INFO #  read 8
2018-05-17 16:38:38,555 - INFO # PCA95xx pin 8 is HIGH
> /exit
2018-05-17 16:38:52,764 - INFO # Exiting Pyterm
[liveuser@localhost-live driver_pca95xx]$
/home/liveuser/Desktop/RIOT_pca95xx/dist/tools/pyterm/pyterm -p "/dev/ttyUSB0" -b "9600"
No handlers could be found for logger "root"
2018-05-17 16:39:25,608 - INFO # Connect to serial port /dev/ttyUSB0
Welcome to pyterm!
Type '/exit' to exit.
2018-05-17 16:39:26,620 - INFO # 

2018-05-17 16:39:26,627 - INFO # main(): This is RIOT! (Version: 2018.04-devel-1014-gc427a-localhost-live-RIOT_pca95xx)
2018-05-17 16:39:26,629 - INFO # PCA95xx I2C GPIO expander driver test
2018-05-17 16:39:26,630 - INFO # Initializing PCA95xx
2018-05-17 16:39:26,632 - INFO # [pca95xx] init - testing reg 4
> help
2018-05-17 16:39:28,597 - INFO #  help
2018-05-17 16:39:28,629 - INFO # Command              Description
2018-05-17 16:39:28,661 - INFO # ---------------------------------------
2018-05-17 16:39:28,725 - INFO # init_out             init as output (push-pull mode)
2018-05-17 16:39:28,757 - INFO # init_in              init as input
2018-05-17 16:39:28,820 - INFO # init_od              init as output (open-drain mode)
2018-05-17 16:39:28,853 - INFO # init_int             configure interrupt
2018-05-17 16:39:28,901 - INFO # irq_en               enable interrupt
2018-05-17 16:39:28,933 - INFO # irq_dis              disable interrupt
2018-05-17 16:39:28,981 - INFO # read                 read pin status
2018-05-17 16:39:29,013 - INFO # set                  set pin to HIGH
2018-05-17 16:39:29,045 - INFO # clear                set pin to LOW
2018-05-17 16:39:29,078 - INFO # toggle               toggle pin
2018-05-17 16:39:29,125 - INFO # write                write value to pin
> init_in 8
2018-05-17 16:39:32,996 - INFO #  init_in 8
2018-05-17 16:39:33,044 - INFO # [pca95xx] init_pin - disabled low drive on pin 8
2018-05-17 16:39:33,108 - INFO # [pca95xx] init_pin - disabled high drive on pin 8
2018-05-17 16:39:33,140 - INFO # [pca95xx] clear - setting pin 8 to high-Z
> set 8
2018-05-17 16:39:37,987 - INFO #  set 8
2018-05-17 16:39:38,035 - INFO # [pca95xx] set - setting pin 8 to high-Z
> clear 8
2018-05-17 16:39:41,347 - INFO #  clear 8
2018-05-17 16:39:41,395 - INFO # [pca95xx] clear - setting pin 8 to high-Z
> init_od 8
2018-05-17 16:39:52,737 - INFO #  init_od 8
2018-05-17 16:39:52,801 - INFO # [pca95xx] init_pin - enabled low drive on pin 8
2018-05-17 16:39:52,849 - INFO # [pca95xx] init_pin - disabled high drive on pin 8
2018-05-17 16:39:52,881 - INFO # [pca95xx] clear - driving pin 8 low
> set 8
2018-05-17 16:39:57,328 - INFO #  set 8
2018-05-17 16:39:57,376 - INFO # [pca95xx] set - setting pin 8 to high-Z
> clear 8
2018-05-17 16:39:59,087 - INFO #  clear 8
2018-05-17 16:39:59,119 - INFO # [pca95xx] clear - driving pin 8 low
> /exit
2018-05-17 16:40:24,161 - INFO # Exiting Pyterm
[liveuser@localhost-live driver_pca95xx]$
[liveuser@localhost-live driver_pca95xx]$ make BOARD=mega-xplained term
/home/liveuser/Desktop/RIOT_pca95xx/dist/tools/pyterm/pyterm -p "/dev/ttyUSB0" -b "9600"
No handlers could be found for logger "root"
2018-05-17 16:56:18,197 - INFO # Connect to serial port /dev/ttyUSB0
Welcome to pyterm!
Type '/exit' to exit.
2018-05-17 16:56:19,208 - INFO # 

2018-05-17 16:56:19,215 - INFO # main(): This is RIOT! (Version: 2018.04-devel-1014-gc427a-localhost-live-RIOT_pca95xx)
2018-05-17 16:56:19,218 - INFO # PCA95xx I2C GPIO expander driver test
2018-05-17 16:56:19,219 - INFO # Initializing PCA95xx
2018-05-17 16:56:19,219 - INFO # [pca95xx] init - testing reg 4
2018-05-17 16:56:19,220 - INFO # [pca95xx] init - setting up int pin 18
> help
2018-05-17 16:56:20,972 - INFO #  help
2018-05-17 16:56:21,004 - INFO # Command              Description
2018-05-17 16:56:21,036 - INFO # ---------------------------------------
2018-05-17 16:56:21,100 - INFO # init_out             init as output (push-pull mode)
2018-05-17 16:56:21,132 - INFO # init_in              init as input
2018-05-17 16:56:21,196 - INFO # init_od              init as output (open-drain mode)
2018-05-17 16:56:21,228 - INFO # init_int             configure interrupt
2018-05-17 16:56:21,276 - INFO # irq_en               enable interrupt
2018-05-17 16:56:21,308 - INFO # irq_dis              disable interrupt
2018-05-17 16:56:21,356 - INFO # read                 read pin status
2018-05-17 16:56:21,388 - INFO # set                  set pin to HIGH
2018-05-17 16:56:21,420 - INFO # clear                set pin to LOW
2018-05-17 16:56:21,452 - INFO # toggle               toggle pin
2018-05-17 16:56:21,500 - INFO # write                write value to pin
> init_int 8
2018-05-17 16:56:25,179 - INFO #  init_int 8
2018-05-17 16:56:25,228 - INFO # [pca95xx] init_pin - disabled low drive on pin 8
2018-05-17 16:56:25,275 - INFO # [pca95xx] init_pin - disabled high drive on pin 8
2018-05-17 16:56:25,323 - INFO # [pca95xx] clear - setting pin 8 to high-Z
2018-05-17 16:56:25,387 - INFO # [pca95xx] init_int - interrupts initialized on pin 8
> irq_en 8
2018-05-17 16:56:28,554 - INFO #  irq_en 8
2018-05-17 16:56:28,603 - INFO # [pca95xx] irq_enable - enabling interrupts on pin 8
> read 8
2018-05-17 16:56:38,201 - INFO #  read 8
2018-05-17 16:56:38,233 - INFO # PCA95xx pin 8 is LOW
> 2018-05-17 16:56:47,175 - INFO #  PCA95xx PCINT on pin 8

2018-05-17 16:56:57,142 - INFO # read 8
2018-05-17 16:56:57,158 - INFO # PCA95xx pin 8 is HIGH
> irq_dis 8
2018-05-17 16:57:04,229 - INFO #  irq_dis 8
2018-05-17 16:57:04,277 - INFO # [pca95xx] irq_disable - disabling interrupts on pin 8
> /exit
2018-05-17 16:57:08,271 - INFO # Exiting Pyterm
[liveuser@localhost-live driver_pca95xx]$


/* Get input register */
reg_addr = _get_reg(0, DFLAGS, PCA95XX_INPUT_ADDR);
i2c_read_reg(I2C, ADDR, reg_addr, &reg[0]);
Copy link
Contributor

@gschorcht gschorcht Nov 26, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I already explained in PR #10430, this I2C read access might collide with an I2C write access to an output port in the case where ports of different expander devices at the same I2C bus are interconnected. This is at least the case for PCF857x I/O expanders. I don't know whether it is the same for PCA95xx expanders, but I would guess yes.

The reason is that an I2C write access to an output port of one device may cause an interrupt by an input port of another device before the I2C write access to the first device has been finished. The handling of the interrupt of the second device requires I2C read access. If the devices are connected to the same I2C bus, the current I2C write access to the first device avoids the required I2C read access from interrupt handler to the second device. The I2C read access fails and the interrupt is lost.

Because the interrupt handling occurs in the same thread context as the I2C write access which is interrupted, the mutex-based i2c_aquire does not help to prevent this conflict.
Even though mutex_lock sees a mutex that is locked it returns with continuation of the thread that has locked the mutex. Unfortunatly, this is the same thread that is in interrupt handling now 😟 That is, it starts to try the I2C read access even though the I2C bus is occupied.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting problem! Let's find a solution in #10430, so that we are not splitting the discussion. I will then apply a similar fix here.

@stale
Copy link

stale bot commented Aug 10, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you want me to ignore this issue, please mark it with the "State: don't stale" label. Thank you for your contributions.

@stale stale bot added the State: stale State: The issue / PR has no activity for >185 days label Aug 10, 2019
@stale stale bot closed this Sep 10, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: drivers Area: Device drivers State: stale State: The issue / PR has no activity for >185 days Type: new feature The issue requests / The PR implemements a new feature for RIOT
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants