Name | pimoroni-ioexpander JSON |
Version |
1.0.1
JSON |
| download |
home_page | None |
Summary | Python library for the Pimoroni IO Expander |
upload_time | 2024-06-06 13:16:34 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.7 |
license | MIT License Copyright (c) 2018 Pimoroni Ltd. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
keywords |
pi
raspberry
|
VCS |
|
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# IO Expander
[![Build Status](https://img.shields.io/github/actions/workflow/status/pimoroni/ioe-python/test.yml?branch=main)](https://github.com/pimoroni/ioe-python/actions/workflows/test.yml)
[![Coverage Status](https://coveralls.io/repos/github/pimoroni/ioe-python/badge.svg?branch=master)](https://coveralls.io/github/pimoroni/ioe-python?branch=master)
[![PyPi Package](https://img.shields.io/pypi/v/pimoroni-ioexpander.svg)](https://pypi.python.org/pypi/pimoroni-ioexpander)
[![Python Versions](https://img.shields.io/pypi/pyversions/pimoroni-ioexpander.svg)](https://pypi.python.org/pypi/pimoroni-ioexpander)
IO Expander Breakout uses a Nuvoton MS51 microcontroller and I2C to give you 14 additional input/output pins to connect things up to. Eight of the pins are hooked up to an Analog to Digital Converter and six of the pins can be used as (up to 16-bit) PWM outputs.
This library is also used to power our other Nuvoton-based boards and breakouts!
## Where to buy
### HATs
* Weather HAT: https://shop.pimoroni.com/products/weather-hat-only
* Inventor HAT Mini: https://shop.pimoroni.com/products/inventor-hat-mini
### Breakouts
* IO Expander Breakout: https://shop.pimoroni.com/products/io-expander
* RGB Potentiometer Breakout: https://shop.pimoroni.com/products/rgb-potentiometer-breakout
* RGB Encoder Breakout: https://shop.pimoroni.com/products/rgb-encoder-breakout
* MICS6814 3-in-1 Gas Sensor Breakout: https://shop.pimoroni.com/products/mics6814-gas-sensor-breakout
# Getting the Library
**Stable library only (no examples) from PyPi:**
* Just run `python3 -m pip install pimoroni-ioexpander`
In some cases you may need to install pip with: `sudo apt install python3-pip`
**Stable library, with latest examples from GitHub:**
* `git clone https://github.com/pimoroni/ioe-python`
* `cd ioe-python`
* `./install.sh`
**Latest/development library and examples from GitHub:**
* `git clone https://github.com/pimoroni/ioe-python`
* `cd ioe-python`
* `./install.sh --unstable`
# Configuring your Raspberry Pi
## Enable I2C
In order to use the IO Expander, you need to enable the I2C interface of your Raspberry Pi. This can be done in the terminal by running:
* `sudo raspi-config nonint do_i2c 0`
Alternatively, you can enable the I2C interface by:
* running `sudo raspi-config` and enabling the option under **Interfacing Options**.
* opening the graphical **Raspberry Pi Configuration** application from the **Preferences** menu.
You may need to reboot after enabling I2C for the change to take effect.
## Note for Raspberry Pi 1
The first version of the Raspberry Pi uses SMBus 0 instead of 1. The ioe-python library uses SMBus 1 by default.
You can change the SMBus that is used by adding `smbus_id=0` to your calls to `io.IOE(...)`. If you want your code to run on multiple revisions of the Pi without having to change your code depending on the Raspberry Pi revision, you can make your code check the `Revision` part of `/proc/cpuinfo` and set the SMBus accordingly. Revisions `0002` and `0003` use SMBus 0. All others use SMBus 1.
# Examples and Usage
There are various examples to get you started with your IO Expander. With the library installed on your Raspberry Pi, these can be found in the `~/Pimoroni/pimoroni-ioexpander/examples` directory.
To take IO Expander further, the full API is described in the [library reference](/REFERENCE.md), with additional feature specific information found in the [docs folder](/docs).
# Removing the Library
To uninstall the library only (keeping all examples):
* Just run `python3 -m pip uninstall pimoroni-ioexpander`
Or if you have grabbed the library from Github:
* `cd ioe-python`
* `./uninstall.sh`
# Reference
## Pins
### IO Expander
All pins are capable as functioning as general purpose inputs and outputs, and reading rotary encoders, but may additionally function as a PWM output and/or ADC input.
| # | Port | ADC | PWM | Encoder |
|----|------|--------|--------|---------|
| 1 | P1.5 | | [Ch 5] | Ch 1 |
| 2 | P1.0 | | [Ch 2] | Ch 2 |
| 3 | P1.2 | | [Ch 0] | Ch 3 |
| 4 | P1.4 | | [Ch 1] | Ch 4 |
| 5 | P0.0 | | [Ch 3] | Ch 5 |
| 6 | P0.1 | | [Ch 4] | Ch 6 |
| 7 | P1.1 | [Ch 7] | Ch 1 | Ch 7 |
| 8 | P0.3 | [Ch 6] | Ch 5 | Ch 8 |
| 9 | P0.4 | [Ch 5] | Ch 3 | Ch 9 |
| 10 | P3.0 | [Ch 1] | | Ch 10 |
| 11 | P0.6 | [Ch 3] | | Ch 11 |
| 12 | P0.5 | [Ch 4] | Ch 2 | Ch 12 |
| 13 | P0.7 | [Ch 2] | | Ch 13 |
| 14 | P1.7 | [Ch 0] | | Ch 14 |
[ ] = labelled pin functions
### Super IO Expander
| # | Port | ADC | PWM | Alt PWM | Encoder |
|-----|------|---------|--------------|--------------|-----------|
| [1] | P3.5 | | | | Ch 14 |
| [2] | P3.6 | | | | Ch 15 |
| 3 | P0.6 | [Ch 3] | | | Ch 11 |
| 4 | P0.7 | [Ch 2] | | | Ch 13 |
| 5 | P1.7 | [Ch 0] | Mod 3 Ch 0 | | |
| 6 | P3.0 | [Ch 1] | Mod 2 Ch 1 | | Ch 10 |
| 7 | P0.4 | [Ch 5] | Mod 0 Ch 3 | Mod 2 Ch 1 | Ch 9 |
| 8 | P0.5 | [Ch 4] | Mod 0 Ch 2 | Mod 2 Ch 0 | |
| 9 | P1.3 | [Ch 13] | | | Ch 0 |
| 10 | P2.5 | [Ch 15] | | | |
| 11 | P1.1 | [Ch 7] | Mod 0 Ch 1 | Mod 1 Ch 1 | |
| 12 | P0.3 | [Ch 6] | Mod 0 Ch 5 | Mod 3 Ch 1 | Ch 8 |
| 13 | P2.4 | [Ch 12] | | | Ch 7 |
| 14 | P2.3 | [Ch 11] | Mod 1 Ch 0 | | Ch 6 |
| 15 | P3.3 | | [Mod 0 Ch 0] | | |
| 16 | P0.1 | | [Mod 0 Ch 4] | Mod 3 Ch 0 | |
| 17 | P1.5 | | [Mod 0 Ch 5] | Mod 3 Ch 1 | Ch 1 |
| 18 | P1.4 | Ch 14 | [Mod 0 Ch 1] | Mod 1 Ch 1 | Ch 4 |
| 19 | P0.0 | | [Mod 0 Ch 3] | Mod 2 Ch 1 | Ch 5 |
| 20 | P1.0 | | [Mod 0 Ch 2] | Mod 2 Ch 0 | Ch 2 |
| 21 | P2.1 | Ch 9 | [Mod 2 Ch 0] | | |
| 22 | P2.2 | Ch 10 | [Mod 1 Ch 1] | | |
| 23 | P1.2 | | Mod 0 Ch 0 | [Mod 1 Ch 0] | Ch 3 |
| 24 | P3.2 | | [Mod 3 Ch 0] | | |
| 25 | P3.4 | | [Mod 3 Ch 1] | | |
| 26 | P3.1 | | [Mod 2 Ch 1] | | Ch 12 |
[ ] = labelled pin functions
## Functions
In all cases you will need to create an instance of the `IOE` class to manage your IO expander (or the `SuperIOE` if using a Super IO Expander board):
```python
import ioexpander
# For IO Expander boards
ioe = ioexpander.IOE()
# For Super IO Expander boards
ioe = ioexpander.SuperIOE()
```
### General-purpose IO
All pins support general-purpose IO and can be configured either as a high-impedance input, quasi-bidirectional input with pull-up, open-drain output or push-pull output. These modes are applicable to different use-cases and we mention some basic examples below.
#### High-impedance input
For input pins you will usually use `ioexpander.IN` which sets pins to input-only, high-impedance mode. This mode does not support pull-ups on the pins, and is useful for reading logic levels which are asserted to a high/low value.
To set a pin as a high-impedance input:
```python
ioe.set_mode(1, ioexpander.IN)
```
And read its value:
```python
value = ioe.input(1)
```
#### Input with pull-up
For reading buttons, or other inputs which sink the connected pin to ground (open drain IO pins for example) you should use the `ioexpander.IN_PU` mode.
In this mode the pin is set to a quasi-bidirectional input, and a pull-up resistor is asserted pulling the logic level weakly HIGH.
```python
ioe.set_mode(1, ioexpander.IN_PU)
```
Wire a button between ground, and the IO pin and read its value:
```python
value = ioe.input(1)
```
A value of 0 (`LOW`) corresponds to a pushed button.
#### Output
For output pins you may choose one of the following output modes:
* `ioexpander.PIN_MODE_PP` - Output, Push-Pull mode. Drives a pin either HIGH or LOW.
* `ioexpander.PIN_MODE_OD` - Output, Open-Drain mode. Drives low, or leaves the pin floating
Push-pull mode is non-inverting, and useful for controlling a connected device (such as a shift register or motor driver), or switching an NPN transistor.
Open-drain mode effectively inverts the signal, since outputting a HIGH will connect the pin to Ground. Open-drain outputs are used in multi-drop protocols like i2c, but can also be used for devices or digital logic that requires an active low input.
To set a pin as a push-pull output:
```python
ioe.set_mode(1, ioexpander.PIN_MODE_PP)
```
And set its value:
```python
ioe.output(1, 0) # Low (Floating in OD)
ioe.output(1, 1) # High (Low in OD)
```
Or an open-drain output:
```python
ioe.set_mode(1, ioexpander.PIN_MODE_OD)
```
And set its value:
```python
ioe.output(1, 0) # High (High-impedance floating)
ioe.output(1, 1) # Low (Pulls to ground)
```
Note: when using open-drain mode (`PIN_MODE_OD`), writing a `1` will pull the pin low and writing a `0` will leave the pin floating.
### Analog Inputs (ADC)
Pins 7, 8, 9 10, 11, 12, 13, and 14 support analog input.
IO Expander's `input` method will automatically give you a voltage for pins configured in ADC mode:
```python
ioe.set_mode(7, ioexpander.ADC)
voltage = ioe.input(7)
```
This is scaled against the ADC vref value, which can be read/set with:
```python
ioe.set_adc_vref(5)
vref = ioe.get_adc_vref()
```
For accurate analog readings, the vref value (which defaults to 3.3) should match the voltage at which the breakout is being powered. In most cases this will be either 3.3v or 5v.
### Pulse Width Modulation Outputs (PWM)
Pins 1, 2, 4, 5, and 6 support PWM output as marked. Additionally pins 7, 8, 9 and 12 (marked as ADC on the IO expander) can be configured as PWM outputs.
```python
ioe.set_mode(1, ioexpander.PWM)
```
PWM outputs can optionally be inverted which us useful where you might be driving inverting buffers or common-cathode LEDs:
```python
ioe.set_mode(1, ioexpander.PWM, invert=True)
```
PWM, by default, uses the 24MHz FSYS clock and has 16bit period and duty-cycle registers.
There are 8 dividers available to slow the clock input into the PWM generator:
* 1/1
* 1/2
* 1/4
* 1/8
* 1/16
* 1/32
* 1/64
* 1/128
These can be set with `set_pwm_control`:
```python
ioe.set_pwm_control(divider=8)
```
In order to dial in the frequency you need, you must consider the 24MHz clock, the available divider options and the maximum value of the period register.
For example, for a 50Hz servo frequency you would use a 1/8 divider, and a period of 60,000:
```
24,000,000 / 8 / 60,000 = 50
````
```python
ioe.set_pwm_control(divider=8)
ioe.set_pwm_period(60000)
```
Then you can use duty-cycle values from 3000 to 6000 (1ms to 2ms) to create a servo control pulse.
### Rotary Encoder Decoding
The IO Expander supports decoding the waveform from up to four rotary encoders. The A and B pins must be specified and are configured as schmitt trigger inputs with a pull-up, if the C pin is specified then it's set to open-drain and driven low. For example:
```python
ENC_CHANNEL = 1
POT_ENC_A = 12
POT_ENC_B = 3
POT_ENC_C = 11
ioe.setup_rotary_encoder(ENC_CHANNEL, POT_ENC_A, POT_ENC_B, pin_c=POT_ENC_C)
```
Each encoder channel has its own signed, 8bit count register which stores the continuous count of pulses as the encoder is rotated. This register is not reset between reads, and will overflow from 127 to -128 in one direction, and from -128 to 127 in the other.
In order to maintain a count across reads, this overflow event should be used to increment/decrement an offset which is then added to the register value. This is all done inside the IO Expander library, so you can simply read a continuous value using:
```python
count = ioe.read_rotary_encoder(1)
```
This value will correspond to the number of rotations of your rotary encoder dial, multiplied by the resolution of the encoder.
The rotary encoder channels will assert an interrupt when a value is changed, in your program main loop you should check for this interrupt, read the encoder value and clear the interrupt flag:
```
while True:
if ioe.get_interrupt():
count = ioe.read_rotary_encoder(1)
ioe.clear_interrupt()
```
Note: in order to track overflows you will need to ensure this interrupt code can run fast enough to catch them. In most cases - ie: a person turning a dial with a 24 step resolution - even 1-second intervals are fine, but for decoding a motor you will want to sample much faster. For example a motor running at 20k RPM with a 12 step resolution would need to be sampled around 31 times a second or approximately every 30ms.
#### Super IO Changes
On the Super IO Expander, encoder counting has been increased to 16 bit to remove the note above of requiring that motor encoders be read every 30ms to avoid an overflow. An overflow will still occur but now from 32767 to -32768 in one direction, and from -32768 to 32767 in the other.
### Configuring Interrupts
IO Expander has an interrupt register to indicate a variety of state changes. On its own this interrupt register isn't much more useful than polling, but IO Expander can also generate an interrupt on its INT pin - connected to BCM 4 via Breakout Garden HAT - which you can then monitor with your GPIO library of choice.
By default the interrupt output pin is not used, but you can enable it on setup like so:
```python
import ioexpander
ioe = ioexpander.IOE(interrupt_pin=4)
```
In this instance `4` corresponds to `BCM4` on the Raspberry Pi. Specifying an interrupt pin will enable interrupt output on the IO Expander and set up `RPi.GPIO`.
Alternatively you can handle the interrupt how you see fit by initialising the library and enabling the interrupt output manually:
```python
import ioexpander
ioe = ioexpander.IOE()
ioe.enable_interrupt_out()
```
In either case the current state of the interrupt register (and pin) can be read by running:
```python
ioe.get_interrupt()
```
And cleared with:
```python
ioe.clear_interrupt()
```
If you're using the IO Expander library to handle interrupts then you can bind a handler to the interrupt event:
```python
import ioexpander
ioe = ioexpander.IOE(interrupt_pin=4)
def callback(channel):
# Handle interrupt here
ioe.clear_interrupt()
ioe.on_interrupt(callback)
```
## Function Reference
Here is the complete list of functions common to both the `IOE` and `SuperIOE` classes:
```python
i2c_read8(reg)
i2c_read12(reg_l, reg_h)
i2c_read16(reg_l, reg_h)
i2c_write8(reg, value)
i2c_write16(reg_l, reg_h, value)
get_pin(pin)
setup_switch_counter(pin, mode=IN_PU)
read_switch_counter(pin)
clear_switch_counter(pin)
setup_rotary_encoder(channel, pin_a, pin_b, pin_c=None, count_microsteps=False)
read_rotary_encoder(channel)
clear_rotary_encoder(channel)
set_bits(reg, bits)
set_bit(reg, bit)
clr_bits(reg, bits)
clr_bit(reg, bit)
get_bit(reg, bit)
change_bit(reg, bit, state)
enable_interrupt_out(pin_swap=False)
disable_interrupt_out()
get_interrupt()
clear_interrupt()
set_pin_interrupt(pin, enabled)
on_interrupt(callback)
set_i2c_addr(i2c_addr)
set_adc_vref(vref)
get_adc_vref()
enable_adc()
disable_adc()
get_chip_id()
get_version()
reset()
get_pwm_module(pin)
pwm_load(pwm_module=0, wait_for_load=True)
pwm_loading(pwm_module=0)
pwm_clear(pwm_module=0, wait_for_clear=True)
pwm_clearing(pwm_module=0)
set_pwm_control(divider, pwm_module=0)
set_pwm_period(value, pwm_module=0, load=True, wait_for_load=True)
set_pwm_frequency(frequency, pwm_module=0, load=True, wait_for_load=True)
get_mode(pin)
set_mode(pin, mode, schmitt_trigger=False, invert=False)
input(pin, adc_timeout=1)
output(pin, value, load=True, wait_for_load=True)
get_pwm_regs(pin)
get_alt_pwm_regs(pin)
get_pin_regs(pin)
switch_pwm_to_alt(pin)
```
Here is the initialiser for the `IOE` class:
```python
IOE(i2c_addr=None, interrupt_timeout=1.0, interrupt_pin=None, interrupt_pull_up=False, gpio=None, smbus_id=1, skip_chip_id_check=False, perform_reset=False)
```
Here is the initialise and additional functions for the `SuperIOE` class:
```python
SuperIOE(i2c_addr=None, interrupt_timeout=1.0, interrupt_pin=None, interrupt_pull_up=False, gpio=None, smbus_id=1, skip_chip_id_check=False, perform_reset=False, is_super_io=True)
activate_watchdog()
deactivate_Watchdog()
is_watchdog_active()
reset_watchdog_counter()
watchdog_timeout_occurred()
clear_watchdog_timeout()
set_watchdog_control(divider)
i2c_multi_read(reg_base, count)
read_rotary_encoders(start_channel, end_channel)
```
## Constants Reference
Here is the list of constants on the `pimoroni-ioexpander` module:
### Pin Mode Constants
* `IN` = `PIN_MODE_IN`
* `IN_PULL_UP` = `PIN_MODE_PU`
* `IN_PU` = `PIN_MODE_PU`
* `OUT` = `PIN_MODE_PP`
* `PWM` = `PIN_MODE_PWM`
* `ADC` = `PIN_MODE_ADC`
### State Constants
* `HIGH` = `1`
* `LOW` = `0`
### PWM Constants
* `CLOCK_FREQ` = `24000000`
* `MAX_PERIOD` = `(1 << 16) - 1`
* `MAX_DIVIDER` = `(1 << 7)`
# Changelog
1.0.1
-----
* Fix bug in SuperIOE constructor (add i2c bus number)
1.0.0
-----
* Add dependency on smbus2
* Add support for alternate i2c bus number
* Port to hatch/pyproject.toml
0.0.5
-----
* Improved readme and documentation
* Linting fixes
0.0.4
-----
* Add support for bigger nuvoton chip
* Add wrappers for controlling motors, servos, and encoders
0.0.3
-----
* Add support for 7-bit switch/pulse counters
0.0.2
-----
* Call read/write in a single i2c_rdwr to maintain thread safety
0.0.1
-----
* Initial Release
Raw data
{
"_id": null,
"home_page": null,
"name": "pimoroni-ioexpander",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": "Philip Howard <phil@pimoroni.com>, Christopher Parrott <chris@pimoroni.com>",
"keywords": "Pi, Raspberry",
"author": null,
"author_email": "Philip Howard <phil@pimoroni.com>",
"download_url": "https://files.pythonhosted.org/packages/f2/3f/244b478bb01358f801cf75fad3a788a6242c9b0839f936b9d047ad290567/pimoroni_ioexpander-1.0.1.tar.gz",
"platform": null,
"description": "# IO Expander\n\n[![Build Status](https://img.shields.io/github/actions/workflow/status/pimoroni/ioe-python/test.yml?branch=main)](https://github.com/pimoroni/ioe-python/actions/workflows/test.yml)\n[![Coverage Status](https://coveralls.io/repos/github/pimoroni/ioe-python/badge.svg?branch=master)](https://coveralls.io/github/pimoroni/ioe-python?branch=master)\n[![PyPi Package](https://img.shields.io/pypi/v/pimoroni-ioexpander.svg)](https://pypi.python.org/pypi/pimoroni-ioexpander)\n[![Python Versions](https://img.shields.io/pypi/pyversions/pimoroni-ioexpander.svg)](https://pypi.python.org/pypi/pimoroni-ioexpander)\n\nIO Expander Breakout uses a Nuvoton MS51 microcontroller and I2C to give you 14 additional input/output pins to connect things up to. Eight of the pins are hooked up to an Analog to Digital Converter and six of the pins can be used as (up to 16-bit) PWM outputs.\n\nThis library is also used to power our other Nuvoton-based boards and breakouts!\n\n## Where to buy\n\n### HATs\n\n* Weather HAT: https://shop.pimoroni.com/products/weather-hat-only\n* Inventor HAT Mini: https://shop.pimoroni.com/products/inventor-hat-mini\n\n\n### Breakouts\n\n* IO Expander Breakout: https://shop.pimoroni.com/products/io-expander\n* RGB Potentiometer Breakout: https://shop.pimoroni.com/products/rgb-potentiometer-breakout\n* RGB Encoder Breakout: https://shop.pimoroni.com/products/rgb-encoder-breakout\n* MICS6814 3-in-1 Gas Sensor Breakout: https://shop.pimoroni.com/products/mics6814-gas-sensor-breakout\n\n\n# Getting the Library\n\n**Stable library only (no examples) from PyPi:**\n\n* Just run `python3 -m pip install pimoroni-ioexpander`\n\nIn some cases you may need to install pip with: `sudo apt install python3-pip`\n\n**Stable library, with latest examples from GitHub:**\n\n* `git clone https://github.com/pimoroni/ioe-python`\n* `cd ioe-python`\n* `./install.sh`\n\n**Latest/development library and examples from GitHub:**\n\n* `git clone https://github.com/pimoroni/ioe-python`\n* `cd ioe-python`\n* `./install.sh --unstable`\n\n\n# Configuring your Raspberry Pi\n\n## Enable I2C\n\nIn order to use the IO Expander, you need to enable the I2C interface of your Raspberry Pi. This can be done in the terminal by running:\n\n* `sudo raspi-config nonint do_i2c 0`\n\nAlternatively, you can enable the I2C interface by:\n* running `sudo raspi-config` and enabling the option under **Interfacing Options**.\n* opening the graphical **Raspberry Pi Configuration** application from the **Preferences** menu.\n\nYou may need to reboot after enabling I2C for the change to take effect.\n\n## Note for Raspberry Pi 1\n\nThe first version of the Raspberry Pi uses SMBus 0 instead of 1. The ioe-python library uses SMBus 1 by default.\nYou can change the SMBus that is used by adding `smbus_id=0` to your calls to `io.IOE(...)`. If you want your code to run on multiple revisions of the Pi without having to change your code depending on the Raspberry Pi revision, you can make your code check the `Revision` part of `/proc/cpuinfo` and set the SMBus accordingly. Revisions `0002` and `0003` use SMBus 0. All others use SMBus 1.\n\n# Examples and Usage\n\nThere are various examples to get you started with your IO Expander. With the library installed on your Raspberry Pi, these can be found in the `~/Pimoroni/pimoroni-ioexpander/examples` directory.\n\nTo take IO Expander further, the full API is described in the [library reference](/REFERENCE.md), with additional feature specific information found in the [docs folder](/docs).\n\n\n# Removing the Library\n\nTo uninstall the library only (keeping all examples):\n\n* Just run `python3 -m pip uninstall pimoroni-ioexpander`\n\nOr if you have grabbed the library from Github:\n\n* `cd ioe-python`\n* `./uninstall.sh`\n\n# Reference\n\n## Pins\n\n### IO Expander\n\nAll pins are capable as functioning as general purpose inputs and outputs, and reading rotary encoders, but may additionally function as a PWM output and/or ADC input.\n\n| # | Port | ADC | PWM | Encoder |\n|----|------|--------|--------|---------|\n| 1 | P1.5 | | [Ch 5] | Ch 1 |\n| 2 | P1.0 | | [Ch 2] | Ch 2 |\n| 3 | P1.2 | | [Ch 0] | Ch 3 |\n| 4 | P1.4 | | [Ch 1] | Ch 4 |\n| 5 | P0.0 | | [Ch 3] | Ch 5 |\n| 6 | P0.1 | | [Ch 4] | Ch 6 |\n| 7 | P1.1 | [Ch 7] | Ch 1 | Ch 7 |\n| 8 | P0.3 | [Ch 6] | Ch 5 | Ch 8 |\n| 9 | P0.4 | [Ch 5] | Ch 3 | Ch 9 |\n| 10 | P3.0 | [Ch 1] | | Ch 10 |\n| 11 | P0.6 | [Ch 3] | | Ch 11 |\n| 12 | P0.5 | [Ch 4] | Ch 2 | Ch 12 |\n| 13 | P0.7 | [Ch 2] | | Ch 13 |\n| 14 | P1.7 | [Ch 0] | | Ch 14 |\n\n[ ] = labelled pin functions\n\n\n### Super IO Expander\n\n| # | Port | ADC | PWM | Alt PWM | Encoder |\n|-----|------|---------|--------------|--------------|-----------|\n| [1] | P3.5 | | | | Ch 14 |\n| [2] | P3.6 | | | | Ch 15 |\n| 3 | P0.6 | [Ch 3] | | | Ch 11 |\n| 4 | P0.7 | [Ch 2] | | | Ch 13 |\n| 5 | P1.7 | [Ch 0] | Mod 3 Ch 0 | | |\n| 6 | P3.0 | [Ch 1] | Mod 2 Ch 1 | | Ch 10 |\n| 7 | P0.4 | [Ch 5] | Mod 0 Ch 3 | Mod 2 Ch 1 | Ch 9 |\n| 8 | P0.5 | [Ch 4] | Mod 0 Ch 2 | Mod 2 Ch 0 | |\n| 9 | P1.3 | [Ch 13] | | | Ch 0 |\n| 10 | P2.5 | [Ch 15] | | | |\n| 11 | P1.1 | [Ch 7] | Mod 0 Ch 1 | Mod 1 Ch 1 | |\n| 12 | P0.3 | [Ch 6] | Mod 0 Ch 5 | Mod 3 Ch 1 | Ch 8 |\n| 13 | P2.4 | [Ch 12] | | | Ch 7 |\n| 14 | P2.3 | [Ch 11] | Mod 1 Ch 0 | | Ch 6 |\n| 15 | P3.3 | | [Mod 0 Ch 0] | | |\n| 16 | P0.1 | | [Mod 0 Ch 4] | Mod 3 Ch 0 | |\n| 17 | P1.5 | | [Mod 0 Ch 5] | Mod 3 Ch 1 | Ch 1 |\n| 18 | P1.4 | Ch 14 | [Mod 0 Ch 1] | Mod 1 Ch 1 | Ch 4 |\n| 19 | P0.0 | | [Mod 0 Ch 3] | Mod 2 Ch 1 | Ch 5 |\n| 20 | P1.0 | | [Mod 0 Ch 2] | Mod 2 Ch 0 | Ch 2 |\n| 21 | P2.1 | Ch 9 | [Mod 2 Ch 0] | | |\n| 22 | P2.2 | Ch 10 | [Mod 1 Ch 1] | | |\n| 23 | P1.2 | | Mod 0 Ch 0 | [Mod 1 Ch 0] | Ch 3 |\n| 24 | P3.2 | | [Mod 3 Ch 0] | | |\n| 25 | P3.4 | | [Mod 3 Ch 1] | | |\n| 26 | P3.1 | | [Mod 2 Ch 1] | | Ch 12 |\n\n[ ] = labelled pin functions\n\n## Functions\n\nIn all cases you will need to create an instance of the `IOE` class to manage your IO expander (or the `SuperIOE` if using a Super IO Expander board):\n\n```python\nimport ioexpander\n\n# For IO Expander boards\nioe = ioexpander.IOE()\n\n# For Super IO Expander boards\nioe = ioexpander.SuperIOE()\n```\n\n### General-purpose IO\n\nAll pins support general-purpose IO and can be configured either as a high-impedance input, quasi-bidirectional input with pull-up, open-drain output or push-pull output. These modes are applicable to different use-cases and we mention some basic examples below.\n\n#### High-impedance input\n\nFor input pins you will usually use `ioexpander.IN` which sets pins to input-only, high-impedance mode. This mode does not support pull-ups on the pins, and is useful for reading logic levels which are asserted to a high/low value.\n\nTo set a pin as a high-impedance input:\n\n```python\nioe.set_mode(1, ioexpander.IN)\n```\n\nAnd read its value:\n\n```python\nvalue = ioe.input(1)\n```\n\n#### Input with pull-up\n\nFor reading buttons, or other inputs which sink the connected pin to ground (open drain IO pins for example) you should use the `ioexpander.IN_PU` mode.\n\nIn this mode the pin is set to a quasi-bidirectional input, and a pull-up resistor is asserted pulling the logic level weakly HIGH.\n\n```python\nioe.set_mode(1, ioexpander.IN_PU)\n```\n\nWire a button between ground, and the IO pin and read its value:\n\n```python\nvalue = ioe.input(1)\n```\n\nA value of 0 (`LOW`) corresponds to a pushed button.\n\n#### Output\n\nFor output pins you may choose one of the following output modes:\n\n* `ioexpander.PIN_MODE_PP` - Output, Push-Pull mode. Drives a pin either HIGH or LOW.\n* `ioexpander.PIN_MODE_OD` - Output, Open-Drain mode. Drives low, or leaves the pin floating\n\nPush-pull mode is non-inverting, and useful for controlling a connected device (such as a shift register or motor driver), or switching an NPN transistor.\n\nOpen-drain mode effectively inverts the signal, since outputting a HIGH will connect the pin to Ground. Open-drain outputs are used in multi-drop protocols like i2c, but can also be used for devices or digital logic that requires an active low input.\n\nTo set a pin as a push-pull output:\n\n```python\nioe.set_mode(1, ioexpander.PIN_MODE_PP)\n```\n\nAnd set its value:\n\n```python\nioe.output(1, 0) # Low (Floating in OD)\nioe.output(1, 1) # High (Low in OD)\n```\n\nOr an open-drain output:\n\n```python\nioe.set_mode(1, ioexpander.PIN_MODE_OD)\n```\n\nAnd set its value:\n\n```python\nioe.output(1, 0) # High (High-impedance floating)\nioe.output(1, 1) # Low (Pulls to ground)\n```\n\nNote: when using open-drain mode (`PIN_MODE_OD`), writing a `1` will pull the pin low and writing a `0` will leave the pin floating.\n\n### Analog Inputs (ADC)\n\nPins 7, 8, 9 10, 11, 12, 13, and 14 support analog input.\n\nIO Expander's `input` method will automatically give you a voltage for pins configured in ADC mode:\n\n```python\nioe.set_mode(7, ioexpander.ADC)\nvoltage = ioe.input(7)\n```\n\nThis is scaled against the ADC vref value, which can be read/set with:\n\n```python\nioe.set_adc_vref(5)\nvref = ioe.get_adc_vref()\n```\n\nFor accurate analog readings, the vref value (which defaults to 3.3) should match the voltage at which the breakout is being powered. In most cases this will be either 3.3v or 5v.\n\n### Pulse Width Modulation Outputs (PWM)\n\nPins 1, 2, 4, 5, and 6 support PWM output as marked. Additionally pins 7, 8, 9 and 12 (marked as ADC on the IO expander) can be configured as PWM outputs.\n\n```python\nioe.set_mode(1, ioexpander.PWM)\n```\n\nPWM outputs can optionally be inverted which us useful where you might be driving inverting buffers or common-cathode LEDs:\n\n```python\nioe.set_mode(1, ioexpander.PWM, invert=True)\n```\n\nPWM, by default, uses the 24MHz FSYS clock and has 16bit period and duty-cycle registers.\n\nThere are 8 dividers available to slow the clock input into the PWM generator:\n\n* 1/1\n* 1/2\n* 1/4\n* 1/8\n* 1/16\n* 1/32\n* 1/64\n* 1/128\n\nThese can be set with `set_pwm_control`:\n\n```python\nioe.set_pwm_control(divider=8)\n```\n\nIn order to dial in the frequency you need, you must consider the 24MHz clock, the available divider options and the maximum value of the period register.\n\nFor example, for a 50Hz servo frequency you would use a 1/8 divider, and a period of 60,000:\n\n```\n24,000,000 / 8 / 60,000 = 50\n````\n\n```python\nioe.set_pwm_control(divider=8)\nioe.set_pwm_period(60000)\n```\n\nThen you can use duty-cycle values from 3000 to 6000 (1ms to 2ms) to create a servo control pulse.\n\n### Rotary Encoder Decoding\n\nThe IO Expander supports decoding the waveform from up to four rotary encoders. The A and B pins must be specified and are configured as schmitt trigger inputs with a pull-up, if the C pin is specified then it's set to open-drain and driven low. For example:\n\n```python\nENC_CHANNEL = 1\nPOT_ENC_A = 12\nPOT_ENC_B = 3\nPOT_ENC_C = 11\nioe.setup_rotary_encoder(ENC_CHANNEL, POT_ENC_A, POT_ENC_B, pin_c=POT_ENC_C)\n```\n\nEach encoder channel has its own signed, 8bit count register which stores the continuous count of pulses as the encoder is rotated. This register is not reset between reads, and will overflow from 127 to -128 in one direction, and from -128 to 127 in the other.\n\nIn order to maintain a count across reads, this overflow event should be used to increment/decrement an offset which is then added to the register value. This is all done inside the IO Expander library, so you can simply read a continuous value using:\n\n```python\ncount = ioe.read_rotary_encoder(1)\n```\n\nThis value will correspond to the number of rotations of your rotary encoder dial, multiplied by the resolution of the encoder.\n\nThe rotary encoder channels will assert an interrupt when a value is changed, in your program main loop you should check for this interrupt, read the encoder value and clear the interrupt flag:\n\n```\nwhile True:\n if ioe.get_interrupt():\n count = ioe.read_rotary_encoder(1)\n ioe.clear_interrupt()\n```\n\nNote: in order to track overflows you will need to ensure this interrupt code can run fast enough to catch them. In most cases - ie: a person turning a dial with a 24 step resolution - even 1-second intervals are fine, but for decoding a motor you will want to sample much faster. For example a motor running at 20k RPM with a 12 step resolution would need to be sampled around 31 times a second or approximately every 30ms.\n\n#### Super IO Changes\n\nOn the Super IO Expander, encoder counting has been increased to 16 bit to remove the note above of requiring that motor encoders be read every 30ms to avoid an overflow. An overflow will still occur but now from 32767 to -32768 in one direction, and from -32768 to 32767 in the other.\n\n### Configuring Interrupts\n\nIO Expander has an interrupt register to indicate a variety of state changes. On its own this interrupt register isn't much more useful than polling, but IO Expander can also generate an interrupt on its INT pin - connected to BCM 4 via Breakout Garden HAT - which you can then monitor with your GPIO library of choice.\n\nBy default the interrupt output pin is not used, but you can enable it on setup like so:\n\n```python\nimport ioexpander\n\nioe = ioexpander.IOE(interrupt_pin=4)\n```\n\nIn this instance `4` corresponds to `BCM4` on the Raspberry Pi. Specifying an interrupt pin will enable interrupt output on the IO Expander and set up `RPi.GPIO`.\n\nAlternatively you can handle the interrupt how you see fit by initialising the library and enabling the interrupt output manually:\n\n```python\nimport ioexpander\n\nioe = ioexpander.IOE()\nioe.enable_interrupt_out()\n```\n\nIn either case the current state of the interrupt register (and pin) can be read by running:\n\n```python\nioe.get_interrupt()\n```\n\nAnd cleared with:\n\n```python\nioe.clear_interrupt()\n```\n\nIf you're using the IO Expander library to handle interrupts then you can bind a handler to the interrupt event:\n\n```python\nimport ioexpander\n\nioe = ioexpander.IOE(interrupt_pin=4)\n\ndef callback(channel):\n # Handle interrupt here\n ioe.clear_interrupt()\n\nioe.on_interrupt(callback)\n```\n\n\n## Function Reference\n\nHere is the complete list of functions common to both the `IOE` and `SuperIOE` classes:\n\n```python\ni2c_read8(reg)\ni2c_read12(reg_l, reg_h)\ni2c_read16(reg_l, reg_h)\ni2c_write8(reg, value)\ni2c_write16(reg_l, reg_h, value)\nget_pin(pin)\nsetup_switch_counter(pin, mode=IN_PU)\nread_switch_counter(pin)\nclear_switch_counter(pin)\nsetup_rotary_encoder(channel, pin_a, pin_b, pin_c=None, count_microsteps=False)\nread_rotary_encoder(channel)\nclear_rotary_encoder(channel)\nset_bits(reg, bits)\nset_bit(reg, bit)\nclr_bits(reg, bits)\nclr_bit(reg, bit)\nget_bit(reg, bit)\nchange_bit(reg, bit, state)\nenable_interrupt_out(pin_swap=False)\ndisable_interrupt_out()\nget_interrupt()\nclear_interrupt()\nset_pin_interrupt(pin, enabled)\non_interrupt(callback)\nset_i2c_addr(i2c_addr)\nset_adc_vref(vref)\nget_adc_vref()\nenable_adc()\ndisable_adc()\nget_chip_id()\nget_version()\nreset()\nget_pwm_module(pin)\npwm_load(pwm_module=0, wait_for_load=True)\npwm_loading(pwm_module=0)\npwm_clear(pwm_module=0, wait_for_clear=True)\npwm_clearing(pwm_module=0)\nset_pwm_control(divider, pwm_module=0)\nset_pwm_period(value, pwm_module=0, load=True, wait_for_load=True)\nset_pwm_frequency(frequency, pwm_module=0, load=True, wait_for_load=True)\nget_mode(pin)\nset_mode(pin, mode, schmitt_trigger=False, invert=False)\ninput(pin, adc_timeout=1)\noutput(pin, value, load=True, wait_for_load=True)\nget_pwm_regs(pin)\nget_alt_pwm_regs(pin)\nget_pin_regs(pin)\nswitch_pwm_to_alt(pin)\n```\n\nHere is the initialiser for the `IOE` class:\n\n```python\nIOE(i2c_addr=None, interrupt_timeout=1.0, interrupt_pin=None, interrupt_pull_up=False, gpio=None, smbus_id=1, skip_chip_id_check=False, perform_reset=False)\n```\n\nHere is the initialise and additional functions for the `SuperIOE` class:\n\n```python\nSuperIOE(i2c_addr=None, interrupt_timeout=1.0, interrupt_pin=None, interrupt_pull_up=False, gpio=None, smbus_id=1, skip_chip_id_check=False, perform_reset=False, is_super_io=True)\nactivate_watchdog()\ndeactivate_Watchdog()\nis_watchdog_active()\nreset_watchdog_counter()\nwatchdog_timeout_occurred()\nclear_watchdog_timeout()\nset_watchdog_control(divider)\ni2c_multi_read(reg_base, count)\nread_rotary_encoders(start_channel, end_channel)\n```\n\n## Constants Reference\n\nHere is the list of constants on the `pimoroni-ioexpander` module:\n\n### Pin Mode Constants\n\n* `IN` = `PIN_MODE_IN`\n* `IN_PULL_UP` = `PIN_MODE_PU`\n* `IN_PU` = `PIN_MODE_PU`\n* `OUT` = `PIN_MODE_PP`\n* `PWM` = `PIN_MODE_PWM`\n* `ADC` = `PIN_MODE_ADC`\n\n\n### State Constants\n\n* `HIGH` = `1`\n* `LOW` = `0`\n\n\n### PWM Constants\n\n* `CLOCK_FREQ` = `24000000`\n* `MAX_PERIOD` = `(1 << 16) - 1`\n* `MAX_DIVIDER` = `(1 << 7)`\n\n# Changelog\n\n1.0.1\n-----\n\n* Fix bug in SuperIOE constructor (add i2c bus number)\n\n1.0.0\n-----\n\n* Add dependency on smbus2\n* Add support for alternate i2c bus number\n* Port to hatch/pyproject.toml\n\n0.0.5\n-----\n\n* Improved readme and documentation\n* Linting fixes\n\n0.0.4\n-----\n\n* Add support for bigger nuvoton chip\n* Add wrappers for controlling motors, servos, and encoders\n\n0.0.3\n-----\n\n* Add support for 7-bit switch/pulse counters\n\n0.0.2\n-----\n\n* Call read/write in a single i2c_rdwr to maintain thread safety\n\n0.0.1\n-----\n\n* Initial Release\n",
"bugtrack_url": null,
"license": "MIT License Copyright (c) 2018 Pimoroni Ltd. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.",
"summary": "Python library for the Pimoroni IO Expander",
"version": "1.0.1",
"project_urls": {
"GitHub": "https://www.github.com/pimoroni/ioe-python",
"Homepage": "https://www.pimoroni.com"
},
"split_keywords": [
"pi",
" raspberry"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "031462132e6fd108395278a50f4ffcccaa19c91c803f49880524d8f8da8d27a4",
"md5": "7932a5e9020c21913a2b16dead332e9a",
"sha256": "11495fe509c40cbcc60e2ff6077e58416d896493fe746a7ac58878170f899180"
},
"downloads": -1,
"filename": "pimoroni_ioexpander-1.0.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "7932a5e9020c21913a2b16dead332e9a",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7",
"size": 52160,
"upload_time": "2024-06-06T13:16:32",
"upload_time_iso_8601": "2024-06-06T13:16:32.757350Z",
"url": "https://files.pythonhosted.org/packages/03/14/62132e6fd108395278a50f4ffcccaa19c91c803f49880524d8f8da8d27a4/pimoroni_ioexpander-1.0.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "f23f244b478bb01358f801cf75fad3a788a6242c9b0839f936b9d047ad290567",
"md5": "1d37d031967be411274250c638bad91c",
"sha256": "7a647b4e3032c06c381857ca254780c269f0c94df0fbd604dcaa561e1df6f387"
},
"downloads": -1,
"filename": "pimoroni_ioexpander-1.0.1.tar.gz",
"has_sig": false,
"md5_digest": "1d37d031967be411274250c638bad91c",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 54188,
"upload_time": "2024-06-06T13:16:34",
"upload_time_iso_8601": "2024-06-06T13:16:34.985610Z",
"url": "https://files.pythonhosted.org/packages/f2/3f/244b478bb01358f801cf75fad3a788a6242c9b0839f936b9d047ad290567/pimoroni_ioexpander-1.0.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-06-06 13:16:34",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "pimoroni",
"github_project": "ioe-python",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"tox": true,
"lcname": "pimoroni-ioexpander"
}