more class definitions

This commit is contained in:
Mikayla Dobson
2023-04-15 11:35:41 -05:00
parent 338b0756c8
commit 5b9629a2ca
3 changed files with 252 additions and 108 deletions

View File

@@ -1,22 +1,105 @@
"""
MicroPython Library for MCP3008 8-channel ADC with SPI
Datasheet for the MCP3008: https://www.microchip.com/datasheet/MCP3008
This code makes much use of Adafruit's CircuitPython code at
https://github.com/adafruit/Adafruit_CircuitPython_MCP3xxx
adapted for MicroPython.
Tested on the Raspberry Pi Pico.
Thanks, @Raspberry_Pi and @Adafruit, for all you've given us!
"""
import machine import machine
# adapted from MCCP3008 class by @romilly, which was adapted from Adafruit CircuitPython driver
# source: https://github.com/romilly/pico-code/blob/master/src/pico_code/pico/mcp3008/mcp3008.py
class MCP3008:
def __init__(self, spi: machine.SPI, chip_select: machine.Pin, ref_voltage=3.3):
self.chip_select = chip_select
self.chip_select.value(1)
class MCP3008:
def __init__(self, spi, cs, ref_voltage=3.3):
"""
Create MCP3008 instance
Args:
spi: configured SPI bus
cs: pin to use for chip select
ref_voltage: r
"""
self.cs = cs
self.cs.value(1) # ncs on
self._spi = spi self._spi = spi
self._out_buffer = bytearray(3) self._out_buf = bytearray(3)
self._out_buffer[0] = 0x01 self._out_buf[0] = 0x01
self._in_buffer = bytearray(3) self._in_buf = bytearray(3)
self._ref_voltage = ref_voltage self._ref_voltage = ref_voltage
def get_voltage(self): def reference_voltage(self) -> float:
"""Returns the MCP3xxx's reference voltage as a float."""
return self._ref_voltage return self._ref_voltage
def read(self, pin): def read(self, pin, is_differential=False):
self.chip_select.value(0) """
self._out_buffer[1] = pin << 4 read a voltage or voltage difference using the MCP3008.
self._spi
Args:
pin: the pin to use
is_differential: if true, return the potential difference between two pins,
Returns:
voltage in range [0, 1023] where 1023 = VREF (3V3)
"""
self.cs.value(0) # select
self._out_buf[1] = ((not is_differential) << 7) | (pin << 4)
self._spi.write_readinto(self._out_buf, self._in_buf)
self.cs.value(1) # turn off
return ((self._in_buf[1] & 0x03) << 8) | self._in_buf[2]
# And here's the code for the loop-back test.
from machine import Pin, SPI
from time import sleep
spi = SPI(0, sck=Pin(2),mosi=Pin(3),miso=Pin(4), baudrate=100000)
cs = Pin(22, Pin.OUT)
cs.value(1) # disable chip at start
chip = MCP3008(spi, cs)
def loop():
cv_one = chip.read(0)
cv_two = chip.read(1)
cv_three = chip.read(2)
print(f"input one: {cv_one}, input two: {cv_two}, input three: {cv_three}")
sleep(0.01)
cv_one = chip.read(0)
cv_two = chip.read(1)
cv_three = chip.read(2)
print(f"input one: {cv_one}, input two: {cv_two}, input three: {cv_three}")
sleep(0.01)
class Module(MCP3008):
def __init__(self, module_function, spi, cs, ref_voltage=3.3):
super().__init__(spi, cs, ref_voltage)
self.module_function = module_function
def read_all(self):
return {
'pot_one': self.read(0),
'pot_two': self.read(1),
'pot_three': self.read(2),
'pot_four': self.read(3),
'cv_in_one': self.read(4),
'cv_in_two': self.read(5),
'cv_in_three': self.read(6),
'cv_in_four': self.read(7)
}

229
main.py
View File

@@ -1,7 +1,7 @@
from machine import Pin, ADC, PWM, SPI from machine import Pin, ADC, PWM, SPI
from utime import sleep
from random import randint from random import randint
from math import floor, ceil from math import floor, ceil
from time import sleep
__SYSTEM_PWM_FREQUENCY__ = 1000 __SYSTEM_PWM_FREQUENCY__ = 1000
@@ -118,6 +118,25 @@ class Hertz:
self.tick_freq = self.ONE_HERTZ * hz self.tick_freq = self.ONE_HERTZ * hz
pass pass
class Oscillator:
def __init__(self, waveform = 'sine', downsampling: int = 0, current_tick: int = 0) -> None:
self.waveform = waveform if waveform in WAVEFORMS else None
self.downsampling = downsampling
self.current_tick = current_tick
self.value = 0
def out(self):
if (self.waveform is 'square'):
self.value = not self.value
else:
current_step = SINE_WAVE[floor(self.current_tick)]
interval = self.downsampling if self.downsampling > 0 else 1
self.current_tick = self.current_tick + interval if self.current_tick + interval < len(SINE_WAVE) else 0
return current_step
def out_u16(self):
return polar_to_u16(self.out())
# basic set of analog input behaviors # basic set of analog input behaviors
class AnalogInput: class AnalogInput:
def __init__(self, ADC_PIN): def __init__(self, ADC_PIN):
@@ -168,121 +187,145 @@ class DigitalOut:
DEFINITIONS FOR HARDWARE PERIPHERALS DEFINITIONS FOR HARDWARE PERIPHERALS
""" """
# adapted from MCCP3008 class by @romilly, which was adapted from Adafruit CircuitPython driver # from MCCP3008 class by @romilly, which was adapted from Adafruit CircuitPython driver
# source: https://github.com/romilly/pico-code/blob/master/src/pico_code/pico/mcp3008/mcp3008.py # source: https://github.com/romilly/pico-code/blob/master/src/pico_code/pico/mcp3008/mcp3008.py
class MCP3008: class MCP3008:
def __init__(self, spi: SPI, chip_select: Pin, ref_voltage=3.3): def __init__(self, spi, cs, ref_voltage=3.3):
self.chip_select = chip_select """
self.chip_select.value(1) Create MCP3008 instance
Args:
spi: configured SPI bus
cs: pin to use for chip select
ref_voltage: r
"""
self.cs = cs
self.cs.value(1) # ncs on
self._spi = spi self._spi = spi
self._out_buffer = bytearray(3) self._out_buf = bytearray(3)
self._out_buffer[0] = 0x01 self._out_buf[0] = 0x01
self._in_buffer = bytearray(3) self._in_buf = bytearray(3)
self._ref_voltage = ref_voltage self._ref_voltage = ref_voltage
def get_voltage(self): def reference_voltage(self) -> float:
"""Returns the MCP3xxx's reference voltage as a float."""
return self._ref_voltage return self._ref_voltage
def read(self, pin): def read(self, pin, is_differential=False):
self.chip_select.value(0) """
self._out_buffer[1] = pin << 4 read a voltage or voltage difference using the MCP3008.
self._spi.write_readinto(self._out_buffer, self._in_buffer)
self.chip_select.value(1) # turn off
return ((self._in_buffer[1] & 0x03) << 8) | self._in_buffer[2]
class Oscillator: Args:
def __init__(self, waveform = 'sine', downsampling: int = 0, current_tick: int = 0) -> None: pin: the pin to use
self.waveform = waveform if waveform in WAVEFORMS else None is_differential: if true, return the potential difference between two pins,
self.downsampling = downsampling
self.current_tick = current_tick
self.value = 0
def out(self):
if (self.waveform is 'square'): Returns:
self.value = not self.value voltage in range [0, 1023] where 1023 = VREF (3V3)
"""
self.cs.value(0) # select
self._out_buf[1] = ((not is_differential) << 7) | (pin << 4)
self._spi.write_readinto(self._out_buf, self._in_buf)
self.cs.value(1) # turn off
return ((self._in_buf[1] & 0x03) << 8) | self._in_buf[2]
class Module:
def __init__(self, mcp3008: MCP3008, out_one: int, out_two: int):
self.chip = mcp3008
self.cv_out_one = PWMOutput(out_one)
self.cv_out_two = PWMOutput(out_two)
def cleanup(self):
self.cv_out_one.set_duty(0)
self.cv_out_two.set_duty(0)
def read_one(self, pin: int):
return self.chip.read(pin)
def read_all(self):
return {
'pot_one': chip.read(0),
'pot_two': chip.read(1),
'pot_three': chip.read(2),
'pot_four': chip.read(3),
'cv_in_one': chip.read(4),
'cv_in_two': chip.read(5),
'cv_in_three': chip.read(6),
'cv_in_four': chip.read(7)
}
def loop(self, sleep_interval=0.01, function=None):
if function:
function()
else: else:
current_step = SINE_WAVE[floor(self.current_tick)] print()
interval = self.downsampling if self.downsampling > 0 else 1 # convert to u16
self.current_tick = self.current_tick + interval if self.current_tick + interval < len(SINE_WAVE) else 0 # cv_in_value = self.chip.read(4) * 64
return current_step # print(cv_in_value)
# self.cv_out_one.set_duty(cv_in_value)
class Synthesizer:
# PIN CONFIGURATION
p1 = None # GP0 sleep(sleep_interval)
p2 = None # GP1
# p3 = GND
p4 = None # GP2
p5 = None # GP3
p6 = None # GP4
p7 = None # GP5
# p8 = GND
p9 = None # GP6
p10 = None
p11 = None
p12 = None
# p13 = GND
p14 = None # GP10
p15 = None
p16 = None
p17 = None
# p18 = GND
p19 = None # GP14
p20 = None
p21 = None
p22 = None
# p23 = GND
p24 = None # GP18
p25 = None
p26 = None
p27 = None
# p28 = GND
p29 = None # GP22
# p30 = RUN
p31 = None # GP26, ADC0
p32 = None # GP27, ADC1
# p33 = GND, AGND
p34 = None # GP28, ADC2
p35 = None # ADC_VREF
# p36 = 3v3(out)
# p37 = 3V3_EN
# p38 = GND
# p39 = VSYS
# p40 = VBUS
def __init__(self, config):
self.config = config
gate_out = PWMOutput(15, 0) class ADSR(Module):
voct_out = PWMOutput(16, 0) def __init__(self, mcp3008: MCP3008, out_one: int, out_two: int):
super().__init__(mcp3008, out_one, out_two)
# spi = SPI(0, sck=Pin(2), mosi=Pin(3), miso=Pin(4), baudrate=100_000) def loop(self, time_interval=0.01):
# chip_select = Pin(22, Pin.OUT) if time_interval < 0:
# chip_select.value(1) raise Exception("Time interval may not be less than 0")
elif time_interval > 1:
raise Exception("Time interval may not be greater than 1")
# square = Pin(21, Pin.OUT) # only move on to envelope generation when a gate is detected
# mcp = MCP3008(spi, chip_select) if self.chip.read(4) is not 0:
# get data and convert to polar
attack = (self.chip.read(0) / 1024)
decay = (self.chip.read(1) / 1024)
sustain = self.chip.read(2) / 1024
release = (self.chip.read(3) / 1024)
cv_one = PWMOutput(16) counter = 0
led_one = PWMOutput(17) value = 0
pot = Potentiometer(0) print(self.chip.read(4))
osc = Oscillator('sine', 32) attack_steps = floor(attack / time_interval)
while counter < attack_steps:
value = value + time_interval
counter = counter + 1
print(value)
self.cv_out_one.set_duty(floor(value))
timer = 1 decay_steps = floor(decay / time_interval)
sleep_interval = 0.01 while counter < attack_steps + decay_steps:
value = value - time_interval
counter = counter + 1
print(value)
self.cv_out_one.set_duty(floor(value))
sleep(time_interval)
"""
variable initialization and prep for loop
"""
spi = SPI(0, sck=Pin(2),mosi=Pin(3),miso=Pin(4), baudrate=100000)
cs = Pin(22, Pin.OUT)
cs.value(1) # disable chip at start
chip = MCP3008(spi, cs)
module = Module(chip, out_one=14, out_two=15)
adsr = ADSR(chip, out_one=14, out_two=15)
try: try:
while True: while True:
current_step = polar_to_u16(osc.out()) adsr.loop()
led_one.set_duty(current_step)
cv_one.set_duty(current_step)
sleep(0.001 + (pot.read_polar() / 32))
except KeyboardInterrupt: except KeyboardInterrupt:
module.cleanup()
print("Exiting program...") print("Exiting program...")
led_one.set_duty(0)
cv_one.set_duty(0)

18
sandbox.py Normal file
View File

@@ -0,0 +1,18 @@
def envelope_generator(start=1, target=10, slew_rate=512):
"""
Creates a generator function returning the absolute value differece between
the start and target voltages over the given duration in ms.
"""
cv_diff = abs(target - start)
cur = min(start, target)
_target = max(start, target)
slew_rate = max(slew_rate, 1) # avoid div by zero
env_progress = 1
while cur < _target:
cur = env_progress * cv_diff
yield cur
result = envelope_generator()
print(result)