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

Calibration update #379

Open
wants to merge 30 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
d034cf2
Add missing temperature pin
chrisib Jan 10, 2025
80882c9
Rewrite the calibration program to support 5V low-accuracy calibratio…
chrisib Sep 11, 2024
8df3da5
Implement a new Thermometer class to wrap the temperature sensor. Add…
chrisib Sep 11, 2024
7b8e97b
Linting
chrisib Sep 11, 2024
81fb866
Linting
chrisib Sep 11, 2024
ebfc0be
get_temperature -> read_temperature()
chrisib Sep 12, 2024
21f5cb6
Implement a new class for checking the USB connection; Pin 24 doesn't…
chrisib Sep 12, 2024
c44ecb6
Fix typos
chrisib Sep 12, 2024
69a7889
Add `class mem` and `mem32` to mocks/machine
chrisib Sep 12, 2024
a4f1ade
Typo in docstring
chrisib Sep 12, 2024
6d01735
Add per-output calibration instead of just CV1
chrisib Sep 15, 2024
d94c2eb
Indentation cleanup
chrisib Sep 15, 2024
133a2b0
Trailing comma
chrisib Sep 15, 2024
139643a
Rename Output.calibration_values -> Output._calibration_values
chrisib Sep 15, 2024
e38bc60
Add new tools directory to the UF2 builder script
chrisib Oct 9, 2024
4ba118d
Add tools.about for easily checking the version, CPU clocking, & conf…
chrisib Nov 11, 2024
9f7ce74
Linting
chrisib Nov 11, 2024
a4d3ed5
Linting
chrisib Nov 11, 2024
5ade4db
Split the output calibration into two stages for improved accuracy
chrisib Nov 20, 2024
8066662
Record twice as many samples, but discard the highest and lowest 1/4 …
chrisib Nov 20, 2024
1336de5
Linting
chrisib Nov 20, 2024
585a93a
Increase the sleep during the fine-calibration step, sleep before rea…
chrisib Nov 20, 2024
47f08fb
Increase samples in diagnostic, refactor the calibration to target th…
chrisib Nov 20, 2024
904a845
Reduce the samples back to 512, refactor the coarse/fine calibration …
chrisib Nov 21, 2024
e9ed480
Linting
chrisib Nov 21, 2024
efaa964
Increment the counter, fix the elif condition in the fine calibration
chrisib Nov 21, 2024
6ad4996
Put the system tools in alphabetical order
chrisib Jan 9, 2025
23017aa
Revert a change in a comment
chrisib Jan 10, 2025
dac7f31
Add a hardware mods file to keep track of unofficial changes to the h…
chrisib Jan 10, 2025
fadccbc
1uF -> 1nF, simplify image URLs
chrisib Jan 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions hardware/EuroPi/hardware_mods.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Hardware Mods

This file documents some common hardware modifications to EuroPi. These modifications are wholly
at your own risk; if performed wrong they could cause damage to your module!

## Alternative to OLED jumper wires

Instead of [soldering jumper wires](/hardware/EuroPi/build_guide.md#oled-configuration) to configure
the OLED, you can instead install a 2x4 bank of headers and use 4 jumpers. This makes it easy to
reconfigure the OLED connection, which may be useful if you ever need to replace the display.

<img src="https://github.com/user-attachments/assets/a308995c-de30-41ae-a7e0-2f714e3f8513" width="420">

_Header pins and jumpers used in the CPC orientation_

## Reducing analogue input noise

The original analogue input stage, as designed by Émilie Gillet (of Mutable Instruments fame) includes
a 1nF capacitor located in parallel with the final resistor:

<img src="https://github.com/user-attachments/assets/02dbf7f8-5e39-422a-82a9-104fbe0589e7" width="600">

_The input stage of Mutable Instruments Braids. Note the `1n` capacitor in the upper-right._

If you find your EuroPi's V/Oct outputs are incorrect, or are seeing an undesirable amount of jitter on
`AIN`, you can add a 1nF capacitor in parallel with `R23`. The easiest way to do this is to _carefully_
solder the 1nF capacitor directly to the back-side of `R23`, as shown below:

<img src="https://github.com/user-attachments/assets/2d7d6dcc-7dc1-433d-98c0-6ff8be978cc7" width="360">

_A 1nF capacitor soldered to the back-side of the EuroPi PCB, in parallel with `R23`_

After soldering the 1nF capactor in place, you should [recalibrate EuroPi](/software/firmware/tools/calibrate.md).
9 changes: 0 additions & 9 deletions software/contrib/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -279,15 +279,6 @@ Using the threshold knob and analogue input, users can determine whether a 1 or
<i>Author: [awonak](https://github.com/awonak)</i>
<br><i>Labels: Clock, Random, CV Generation</i>

### Diagnostic \[ [documentation](/software/contrib/diagnostic.md) | [script](/software/contrib/diagnostic.py) \]
Test the hardware of the module

The values of all inputs are shown on the display, and the outputs are set to fixed voltages.
Users can rotate the outputs to ensure they each output the same voltage when sent the same instruction from the script

<i>Author: [mjaskula](https://github.com/mjaskula)</i>
<br><i>Labels: utility</i>

### Hello World \[ [script](/software/contrib/hello_world.py) \]
An example script for the menu system

Expand Down
9 changes: 6 additions & 3 deletions software/contrib/menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
["Conway", "contrib.conway.Conway"],
["CVecorder", "contrib.cvecorder.CVecorder"],
["DCSN-2", "contrib.dscn2.Dcsn2"],
["Diagnostic", "contrib.diagnostic.Diagnostic"],
["EgressusMelodiam", "contrib.egressus_melodiam.EgressusMelodiam"],
["EnvelopeGen", "contrib.envelope_generator.EnvelopeGenerator"],
["Euclid", "contrib.euclid.EuclideanRhythms"],
Expand Down Expand Up @@ -64,8 +63,12 @@
["Turing Machine", "contrib.turing_machine.EuroPiTuringMachine"],
["Volts", "contrib.volts.OffsetVoltages"],

["_Calibrate", "calibrate.Calibrate"], # this one should always be second to last!
["_BootloaderMode", "bootloader_mode.BootloaderMode"] # this one should always be last!
# System tools, in alphabetical order with a _ prefix

["_About", "tools.about.About"],
["_BootloaderMode", "bootloader_mode.BootloaderMode"],
["_Calibrate", "tools.calibrate.Calibrate"],
["_Diagnostic", "tools.diagnostic.Diagnostic"],
])
# fmt: on

Expand Down
114 changes: 0 additions & 114 deletions software/firmware/calibrate.py

This file was deleted.

55 changes: 42 additions & 13 deletions software/firmware/europi.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,23 @@

from experimental.experimental_config import load_experimental_config


if sys.implementation.name == "micropython":
TEST_ENV = False # We're in micropython, so we can assume access to real hardware
else:
TEST_ENV = True # This var is set when we don't have any real hardware, for example in a test or doc generation setting

# How many CV outputs are there?
# On EuroPi this 6, but future versions (e.g. EuroPi X may have more)
NUM_CVS = 6

# Import the calibration values
# These are generated by tools/calibrate.py, but do not exist by default
try:
from calibration_values import INPUT_CALIBRATION_VALUES, OUTPUT_CALIBRATION_VALUES
except ImportError:
# Note: run calibrate.py to get a more precise calibration.
# Default calibration values are close-enough to reasonable performance, but aren't great
INPUT_CALIBRATION_VALUES = [384, 44634]
OUTPUT_CALIBRATION_VALUES = [
0,
Expand All @@ -58,6 +67,12 @@
56950,
63475,
]
# Legacy calibration using only CV1; apply the same calibration values to each output
if type(OUTPUT_CALIBRATION_VALUES[0]) is int:
cv1_values = OUTPUT_CALIBRATION_VALUES
OUTPUT_CALIBRATION_VALUES = []
for i in range(NUM_CVS):
OUTPUT_CALIBRATION_VALUES.append(cv1_values)


# Initialize EuroPi global singleton instance variables
Expand Down Expand Up @@ -104,7 +119,9 @@
PIN_CV4 = 17
PIN_CV5 = 18
PIN_CV6 = 19
PIN_USB_CONNECTED = 24 # Does not work on Pico 2
PIN_USB_CONNECTED = 24
PIN_TEMPERATURE = 4


# Helper functions.

Expand Down Expand Up @@ -493,17 +510,24 @@ class Output:
calibration is important if you want to be able to output precise voltages.
"""

def __init__(self, pin, min_voltage=MIN_OUTPUT_VOLTAGE, max_voltage=MAX_OUTPUT_VOLTAGE):
def __init__(
self,
pin,
min_voltage=MIN_OUTPUT_VOLTAGE,
max_voltage=MAX_OUTPUT_VOLTAGE,
calibration_values=OUTPUT_CALIBRATION_VALUES[0],
):
self.pin = PWM(Pin(pin))
self.pin.freq(PWM_FREQ)
self._duty = 0
self.MIN_VOLTAGE = min_voltage
self.MAX_VOLTAGE = max_voltage
self.gate_voltage = clamp(europi_config.GATE_VOLTAGE, self.MIN_VOLTAGE, self.MAX_VOLTAGE)

self._calibration_values = calibration_values
self._duty = 0
self._gradients = []
for index, value in enumerate(OUTPUT_CALIBRATION_VALUES[:-1]):
self._gradients.append(OUTPUT_CALIBRATION_VALUES[index + 1] - value)
for index, value in enumerate(self._calibration_values[:-1]):
self._gradients.append(self._calibration_values[index + 1] - value)
self._gradients.append(self._gradients[-1])

def _set_duty(self, cycle):
Expand All @@ -517,7 +541,7 @@ def voltage(self, voltage=None):
return self._duty / MAX_UINT16
voltage = clamp(voltage, self.MIN_VOLTAGE, self.MAX_VOLTAGE)
index = int(voltage // 1)
self._set_duty(OUTPUT_CALIBRATION_VALUES[index] + (self._gradients[index] * (voltage % 1)))
self._set_duty(self._calibration_values[index] + (self._gradients[index] * (voltage % 1)))

def on(self):
"""Set the voltage HIGH at 5 volts."""
Expand Down Expand Up @@ -545,7 +569,9 @@ def value(self, value):
class Thermometer:
"""
Wrapper for the temperature sensor connected to Pin 4

Reports the module's current temperature in Celsius.

If the module's temperature sensor is not working correctly, the temperature will always be reported as None
"""

Expand All @@ -564,6 +590,7 @@ def __init__(self):
def read_temperature(self):
"""
Read the ADC and return the current temperature

@return The current temperature in Celsius, or None if the hardware did not initialze properly
"""
if self.pin:
Expand All @@ -576,6 +603,7 @@ def read_temperature(self):
class UsbConnection:
"""
Checks the USB terminal is connected or not

On the original Pico we can check Pin 24, but on the Pico 2 this does not work. In that case
check the SIE_STATUS register and check bit 16
"""
Expand All @@ -594,6 +622,7 @@ def value(self):
# see https://forum.micropython.org/viewtopic.php?t=10814#p59545
SIE_STATUS = 0x50110000 + 0x50
BIT_CONNECTED = 1 << 16

if mem32[SIE_STATUS] & BIT_CONNECTED:
return 1
else:
Expand Down Expand Up @@ -633,13 +662,13 @@ def value(self):
height=europi_config.DISPLAY_HEIGHT,
)


cv1 = Output(PIN_CV1)
cv2 = Output(PIN_CV2)
cv3 = Output(PIN_CV3)
cv4 = Output(PIN_CV4)
cv5 = Output(PIN_CV5)
cv6 = Output(PIN_CV6)
# Output CVs
cv1 = Output(PIN_CV1, calibration_values=OUTPUT_CALIBRATION_VALUES[0])
cv2 = Output(PIN_CV2, calibration_values=OUTPUT_CALIBRATION_VALUES[1])
cv3 = Output(PIN_CV3, calibration_values=OUTPUT_CALIBRATION_VALUES[2])
cv4 = Output(PIN_CV4, calibration_values=OUTPUT_CALIBRATION_VALUES[3])
cv5 = Output(PIN_CV5, calibration_values=OUTPUT_CALIBRATION_VALUES[4])
cv6 = Output(PIN_CV6, calibration_values=OUTPUT_CALIBRATION_VALUES[5])
cvs = [cv1, cv2, cv3, cv4, cv5, cv6]

# Helper object to detect if the USB cable is connected or not
Expand Down
3 changes: 3 additions & 0 deletions software/firmware/tools/about.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# About

Displays version & other information about the software
25 changes: 25 additions & 0 deletions software/firmware/tools/about.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from europi import *
from europi_script import EuroPiScript
from time import sleep
from version import __version__


class About(EuroPiScript):
def __init__(self):
super().__init__()

def main(self):
turn_off_all_cvs()

oled.centre_text(
f"""EuroPi v{__version__}
{europi_config.EUROPI_MODEL}/{europi_config.PICO_MODEL}
{europi_config.CPU_FREQ}"""
)

while True:
sleep(1)


if __name__ == "__main__":
About().main()
35 changes: 35 additions & 0 deletions software/firmware/tools/calibrate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Calibration

Input & output calibration too for EuroPi.

## Required Equipment

Calibration requires the following physical setup:
1. EuroPi _must_ be connected to rack power
2. For low-accuracy calibration you need either another EuroRack module or an external voltage source capable of
generating precise voltages of either 5V or 10V
3. For high-accuracy calibration you need another EuroRack module or adjustable external voltage source capable of
generating precise voltages of 1.0, 2.0, 3.0, ..., 9.0, 10.0V.

## Usage

Calibration is interactive with instructions displayed on-screen. These instructions are summarized below:
1. Make sure the module is powered from your Eurorack power supply.
2. Select input calibration mode by turning `K2`. Press `B2` when ready
a. low-accuracy with 10V input
b. low-accuracy with 5V input
c. high-accuracy with variable 0-10V input
3. Disconnect all patch cables from the module. Press `B1`
4. Connect your voltage source to `AIN`. Press `B1` when instructed.
a. low-accuracy with 10V input: connect 10V to `AIN`
b. low-accuracy with 5V input: connect 5V to `AIN`
c. high-accuracy: read the on-screen instructions and connect the specified voltages when required.
5. Connect `CV1` directly to `AIN`. Press `B1`. Wait for the module to perform the output calibration.
6. Repeat step 5 for `CV2`, `CV3`, etc... until all CV outputs are calibrated
7. Reboot the module when prompted. The new calibration will be applied automatically.

Calibration data is saved to `/lib/calibration_values.py`. DO NOT delete this file; if you delete it you will have to
complete the calibration again.

After calibrating and rebooting the module it is recommended to run the `Diagnostic` program to verify that the
inputs and outputs have been properly calibrated.
Loading
Loading