Skip to content

Commit

Permalink
Expose the second I2C channel to make it easier to work with (#387)
Browse files Browse the repository at this point in the history
* Instantiate the external I2C interface to make programming with it easier, add europi_config parameters to set the necessary frequency & timeout of the external I2C channel. Add documentation to `interesting_things`.

* Add the timeout parameter to the mock I2C constructor for tests

* Fix up the I2C definition imports

* Add the new I2C settings to the configuration documentation
  • Loading branch information
chrisib authored Nov 11, 2024
1 parent 8006029 commit a8ed4ef
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 17 deletions.
19 changes: 19 additions & 0 deletions software/CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,47 @@ default configuration:
"DISPLAY_SDA": 0,
"DISPLAY_SCL": 1,
"DISPLAY_CHANNEL": 0,
"EXTERNAL_I2C_SDA": 2,
"EXTERNAL_I2C_SCL": 3,
"EXTERNAL_I2C_CHANNEL": 1,
"EXTERNAL_I2C_FREQUENCY": 100000,
"EXTERNAL_I2C_TIMEOUT": 50000,
"MAX_OUTPUT_VOLTAGE": 10,
"MAX_INPUT_VOLTAGE": 12,
"GATE_VOLTAGE": 5,
"MENU_AFTER_POWER_ON": false
}
```

CPU & Pico options:
- `EUROPI_MODEL` specifies the type of EuroPi module. Currently only `"europi"` is supported. Default: `"europi"`
- `PICO_MODEL` must be one of `"pico"` or `"pico w"`. Default: `"pico"`
- `CPU_FREQ` must be one of `250000000` or `125000000`. Default: `"250000000"`

Display options:
- `ROTATE_DISPLAY` must be one of `false` or `true`. Default: `false`
- `DISPLAY_WIDTH` is the width of the screen in pixels. The standard EuroPi screen is 128 pixels wide. Default: `128`
- `DISPLAY_HEIGHT` is the height of the screen in pixels. The standard EuroPi screen is 32 pixels tall. Default: `32`
- `DISPLAY_SDA` is the I²C SDA pin used for the display. Only SDA capable pins can be selected. Default: `0`
- `DISPLAY_SCL` is the I²C SCL pin used for the display. Only SCL capable pins can be selected. Default: `1`
- `DISPLAY_CHANNEL` is the I²C channel used for the display, either 0 or 1. Default: `0`

External I²C options:
- `EXTERNAL_I2C_SDA` is the I²C SDA pin used for the external I²C interface. Only SDA capable pis can be selected. Default: `2`
- `EXTERNAL_I2C_SCL` is the I²C SCL pin used for the external I²C interface. Only SCL capable pins can be selected. Default: `3`
- `EXTERNAL_I2C_CHANNEL` is the I²C channel used for the external I²C interface, either 0 or 1. Default: `1`
- `EXTERNAL_I2C_FREQUENCY` is the I²C frequency used for the external I²C interface. Default: `100000`
- `EXTERNAL_I2C_TIMEOUT` is the I²C timeout in microseconds for the external I²C interface. Default: `50000`

I/O voltage options:
- `MAX_OUTPUT_VOLTAGE` is an integer in the range `[0, 10]` indicating the maximum voltage CV output can generate. Default: `10`
The hardware is capable of 10V maximum
- `MAX_INPUT_VOLTAGE` is an integer in the range `[0, 12]` indicating the maximum allowed voltage into the `ain` jack.
The hardware is capable of 12V maximum. Default: `12`
- `GATE_VOLTAGE` is an integer in the range `[0, 10]` indicating the voltage that an output will produce when `cvx.on()`
is called. This value must not be higher than `MAX_OUTPUT_VOLTAGE`. Default: `5`

Power options:
- `MENU_AFTER_POWER_ON` is a boolean indicating whether or not the module should always return to the main menu when
it powers on. By default the EuroPi will re-launch the last-used program instead of returning to the main menu. Default: `false`

Expand Down
25 changes: 17 additions & 8 deletions software/firmware/europi.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@
# OLED component display dimensions.
OLED_WIDTH = europi_config.DISPLAY_WIDTH
OLED_HEIGHT = europi_config.DISPLAY_HEIGHT
I2C_SDA = europi_config.DISPLAY_SDA
I2C_SCL = europi_config.DISPLAY_SCL
I2C_CHANNEL = europi_config.DISPLAY_CHANNEL
I2C_FREQUENCY = 400000
OLED_I2C_SDA = europi_config.DISPLAY_SDA
OLED_I2C_SCL = europi_config.DISPLAY_SCL
OLED_I2C_CHANNEL = europi_config.DISPLAY_CHANNEL
OLED_I2C_FREQUENCY = europi_config.DISPLAY_FREQUENCY

# Standard max int consts.
MAX_UINT16 = 65535
Expand Down Expand Up @@ -502,12 +502,12 @@ class Display(SSD1306_I2C):

def __init__(
self,
sda=I2C_SDA,
scl=I2C_SCL,
sda=OLED_I2C_SDA,
scl=OLED_I2C_SCL,
width=OLED_WIDTH,
height=OLED_HEIGHT,
channel=I2C_CHANNEL,
freq=I2C_FREQUENCY,
channel=OLED_I2C_CHANNEL,
freq=OLED_I2C_FREQUENCY,
):
i2c = I2C(channel, sda=Pin(sda), scl=Pin(scl), freq=freq)
self.width = width
Expand Down Expand Up @@ -639,6 +639,15 @@ def value(self, value):
cv6 = Output(PIN_CV6)
cvs = [cv1, cv2, cv3, cv4, cv5, cv6]

# External I2C
external_i2c = I2C(
europi_config.EXTERNAL_I2C_CHANNEL,
sda=Pin(europi_config.EXTERNAL_I2C_SDA),
scl=Pin(europi_config.EXTERNAL_I2C_SCL),
freq=europi_config.EXTERNAL_I2C_FREQUENCY,
timeout=europi_config.EXTERNAL_I2C_TIMEOUT,
)

usb_connected = DigitalReader(PIN_USB_CONNECTED, 0)

# Overclock the Pico for improved performance.
Expand Down
40 changes: 37 additions & 3 deletions software/firmware/europi_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,46 @@ def config_points(cls):
choices=[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 27],
default=1,
),
configuration.integer(
configuration.choice(
name="DISPLAY_CHANNEL",
minimum=0,
maximum=1,
choices=[0, 1],
default=0
),
configuration.integer(
name="DISPLAY_FREQUENCY",
minimum=0,
maximum=1000000,
default=400000
),

# External I2C connection (header between Pico & power connector)
configuration.choice(
name="EXTERNAL_I2C_SDA",
choices=[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 26],
default=2,
),
configuration.choice(
name="EXTERNAL_I2C_SCL",
choices=[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 27],
default=3,
),
configuration.choice(
name="EXTERNAL_I2C_CHANNEL",
choices=[0, 1],
default=1
),
configuration.integer(
name="EXTERNAL_I2C_FREQUENCY",
minimum=0,
maximum=1000000, # 1M max
default=100000 # 100k default
),
configuration.integer(
name="EXTERNAL_I2C_TIMEOUT",
minimum=0,
maximum=100000,
default=50000
),

# I/O voltage settings
configuration.floatingPoint(
Expand Down
10 changes: 5 additions & 5 deletions software/firmware/experimental/custom_font.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@

from europi import (
OLED_WIDTH,
I2C_FREQUENCY,
OLED_I2C_FREQUENCY,
OLED_HEIGHT,
I2C_SDA,
I2C_SCL,
I2C_CHANNEL,
OLED_I2C_SDA,
OLED_I2C_SCL,
OLED_I2C_CHANNEL,
TEST_ENV,
CHAR_HEIGHT,
)
Expand Down Expand Up @@ -79,7 +79,7 @@ class CustomFontDisplay(BasicDisplay):
def __init__(self, default_font=None): # by default will use the monospaced 8x8 font
self.writers = {} # re-usable large font writer instances
self.default_font = default_font
super().__init__(I2C_SDA, I2C_SCL, channel=I2C_CHANNEL)
super().__init__(OLED_I2C_SDA, OLED_I2C_SCL, channel=OLED_I2C_CHANNEL)

def _writer(self, font):
"""Returns the large font writer for the specified font."""
Expand Down
38 changes: 38 additions & 0 deletions software/interesting_things.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,41 @@ while True:
```

This code proves the speed of the Pico to the extent that if you send audio to the analogue input, you can hear a very bitcrushed but recognisable version of it at CV output 1.


## Connecting I2C devices
EuroPi has 1 I2C channel available for connecting external devices. The header pins for this connection are located
between the Pico and the module's power connector.

To use an external I2C device, you will need to connect it to the ground, 3.3V supply, SDA, and SCL pins of the I2C
header. You must also specify the frequency of the I2C channel by creating or modifying `config/EuroPiConfig.json`
on the module:
```json
{
"EXTERNAL_I2C_FREQUENCY": 400000
}
```
Specify the desired frequency with the `EXTERNAL_I2C_FREQUENCY` key in the JSON object. The default frequency is
`100000` (100k). Rates of up to 1M can be specified, but nothing faster than 400k has been officially tested.
(The OLED display connected to the other I2C channel uses a frequency of 400k).

By default the I2C channel uses a timeout of 50000 microseconds. To change this, set the `EXTERNAL_I2C_TIMEOUT`
parameter in `config/EuroPiConfig.json`:
```json
{
"EXTERNAL_I2C_TIMEOUT": 100000
}
```
The timeout value specificed is in microseconds.

To use the external I2C connection in your programs, use
```python
from europi import external_i2c

external_i2c.writeto(...)
external_i2c.readfrom(...)
# etc...
```

The `external_i2c` object is an instance of `machine.I2C`, so refer to [the official documentation](https://docs.micropython.org/en/latest/library/machine.I2C.html)
for more information on using I2C.
2 changes: 1 addition & 1 deletion software/tests/mocks/machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def read_u16(self, *args):


class I2C:
def __init__(self, channel, sda, scl, freq, *args):
def __init__(self, channel, sda, scl, freq=400000, timeout=50000, *args):
pass

def scan(self):
Expand Down

0 comments on commit a8ed4ef

Please sign in to comment.