# Copyright 2024 Allen Synthesis
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from europi_script import EuroPiScript
from software.firmware.europi import (
from europi import MAX_INPUT_VOLTAGE, OLED_HEIGHT, OLED_WIDTH, ain, b1, b2, cv1, cv2, cv4, din, k1, k2, oled
Y_TRUE = int(OLED_HEIGHT / 3 * 2)
Y_FALSE = int(OLED_HEIGHT / 3)
D_WAVE_HEIGHT = Y_TRUE - Y_FALSE + 1
RIGHT_EDGE = OLED_WIDTH - 1
Y_PIXELS = OLED_HEIGHT - 1
class Scope(EuroPiScript):
Can we make a functional oscilloscope on the EuroPi? Kinda! This script displays the inputs received on both the analog
and digital inputs. Both waves can be toggled, and when no waves are displayed we switch to a text output, which also
includes the knob values. The knobs each control an aspect of the x and y resolution respectively, allowing you to coax
a little more detail out of the display.
Note that the digital wave is displayed at a fixed y position that is not related to the value of the analog wave.
- negative voltages are clipped to 0
- screen height is only 32 pixels, so limited resolution
- we can only refresh the screen so fast
- analog pass through will be 'digitized'
knob1 - samples per screen refresh. This effectively lets you 'zoom in' on the x-axis. Start at the lowest setting, 1 sample.
knob2 - y voltage scale (only affects analog wave). This effectively lets you 'zoom in' on the low voltages. Start at
the highest setting, 10v.
button1 - toggle digital wave display
button2 - toggle analog wave display
out1 - digital in pass through
out2 - analog in pass through
out4 - inverted digital pass through
def __init__(self) -> None:
self.enabled = [True, True] # digital, analog
self.enabled[index] = not self.enabled[index]
return k1.read_position(MAX_RATE) + 1
def read_max_disp_voltage():
return k2.read_position(math.ceil(MAX_INPUT_VOLTAGE)) + 1
def calc_y_pos(max_disp_voltage, a_voltage):
return Y_PIXELS - int(a_voltage / max_disp_voltage * Y_PIXELS)
b1.handler(self.toggle(0))
b2.handler(self.toggle(1))
rate = self.read_sample_rate()
max_disp_voltage = self.read_max_disp_voltage()
oled.vline(RIGHT_EDGE, 0, OLED_HEIGHT, 0)
if self.enabled[0]: # digital wave
y_pos = Y_TRUE if d_value else Y_FALSE
oled.pixel(RIGHT_EDGE, OLED_HEIGHT - y_pos, 1)
oled.vline(RIGHT_EDGE, Y_FALSE + 1, D_WAVE_HEIGHT, 1)
a_voltage = ain.read_voltage(1)
if self.enabled[1]: # analog wave
y_pos = self.calc_y_pos(max_disp_voltage, a_voltage)
oled.pixel(RIGHT_EDGE, y_pos, 1)
if not self.enabled[0] and not self.enabled[1]: # details output
rate = self.read_sample_rate()
max_disp_voltage = self.read_max_disp_voltage()
oled.text(f"a: {a_voltage:4.1f}v d:{d_value}", 2, 3, 1)
oled.text(f"samples: {rate:3}", 2, 13, 1)
oled.text(f"y scale: {max_disp_voltage:4.1f}v", 2, 23, 1)
if __name__ == "__main__":