Cannot use audio board after 1.8 update #70
-
Hello everyone, After updating to the 1.8 version, there seems to be some conflict in our setup between the rotary encoder on behavior port 1 and the audio board on behavior port 4. The state coded yellow on the state plots has audio output concurrent to the speed recording. Audio is not working. I'd be grateful if someone could point out a possible oversight that could be causing this after the update. |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments 8 replies
-
Hi, After the upgrade, it is a good idea to reupload the framework to the pyboard as well as retransfer the hardware definition if you are using one. This is especially relevant if you are upgrading from a pyControl version previous to 1.7. Do you recall what version of pyControl you were previously using? If the framework and hardware definition reuploading does not fix things, can we further isolate the problem? Can you confirm that the audio board alone is working by running a simplified task? Try running the following task or something similar to confirm the audio is working. from pyControl.utility import *
from devices import *
blue_LED = Digital_output('B4')
states = ['LED_on', 'LED_off']
events = []
initial_state = 'LED_off'
speaker = Audio_board(board.port_4) # Instantiate audio board.
def LED_on(event):
if event == 'entry':
timed_goto_state('LED_off', 0.5 * second)
blue_LED.on()
speaker.sine(5000) # Play a 5KHz sine wave.
elif event == 'exit':
blue_LED.off()
speaker.off()
def LED_off(event):
if event == 'entry':
timed_goto_state('LED_on', 0.5 * second)
def run_end(): # Turn off hardware at end of run.
blue_LED.off()
speaker.off() |
Beta Was this translation helpful? Give feedback.
-
Hi, Are you using the standard six port breakout board ( best, Thomas |
Beta Was this translation helpful? Give feedback.
-
Well spotted @alustig3, it is the change to using hardware timer 2 in the import pyb
import math
from . import hardware as hw
_sine_len = 100 # Number of points in sine wave.
_sine_buf = bytearray([128+int(127*math.sin(2*math.pi*i/_sine_len)) for i in range(_sine_len)])
_sqr_buf = bytearray([255,0])
_click_buf = bytearray([255,0,255,255,0,0]+4*[255]+4*[0]+8*[255]+8*[0]
+16*[255]+16*[0]+32*[255]+32*[0]+[128])
_off_buf = bytearray([128])
# Audio output ----------------------------------------------------------------
class Audio_output(hw.IO_object):
def __init__(self, channel=1):
assert channel in [1,2], '! Channel number invalid, must be 1 or 2.'
self._DAC = pyb.DAC(channel)
self._timer = pyb.Timer(hw.available_timers.pop())
self._func = None # Function currently being used for sweeped sound (sine, square or noise)
self._freq = 0
self._freq_ind = 0
self.off()
hw.assign_ID(self)
# User functions
def off(self):
self._DAC.write_timed(_off_buf, pyb.Timer(3, freq=10000), mode=pyb.DAC.NORMAL)
self._timer.deinit()
self._playing = False
def sine(self, freq): # Play a sine wave tone at the specified frequency.
self._DAC.write_timed(_sine_buf, pyb.Timer(3, freq=freq*_sine_len), mode=pyb.DAC.CIRCULAR)
def square(self, freq): # Play a square wave tone at the specified frequency.
self._DAC.write_timed(_sqr_buf, pyb.Timer(3, freq=freq*2), mode=pyb.DAC.CIRCULAR)
def noise(self, freq=10000): # Play white noise with specified maximum frequency.
self._DAC.noise(freq*2)
def click(self, timer=None): # Play a single click.
self._DAC.write_timed(_click_buf, pyb.Timer(3, freq=40000), mode=pyb.DAC.NORMAL)
def clicks(self, rate): # Play clicks at specified rate.
self._timer.init(freq=rate)
self._timer.callback(self.click)
def pulsed_sine(self, freq, pulse_rate): # Play a sine wave pulsed at the specified rate.
self._pulsed_sound(freq, pulse_rate, self.sine)
def pulsed_square(self, freq, pulse_rate): # Play a square wave pulsed at the specified rate.
self._pulsed_sound(freq, pulse_rate, self.square)
def pulsed_noise(self, freq, pulse_rate):
self._pulsed_sound(freq, pulse_rate, self.noise)
def stepped_sine(self, start_freq, end_freq, n_steps, step_rate):
self._sound_step(start_freq, end_freq, n_steps, step_rate, self.sine)
def stepped_square(self, start_freq, end_freq, n_steps, step_rate):
self._sound_step(start_freq, end_freq, n_steps, step_rate, self.square)
# Support functions
def _pulsed_sound(self, freq, pulse_rate, func):
self._freq = freq
self._func = func
self._timer.init(freq=2*pulse_rate)
self._timer.callback(self._toggle_sound)
def _toggle_sound(self, timer):
if self._playing:
self._DAC.write(127)
self._playing = False
else:
self._func(self._freq)
self._playing = True
def _sound_step(self, start_freq, end_freq, n_steps, step_rate, func):
freq_ratio = (end_freq/start_freq)**(1./(n_steps-1))
self._freq = [int(start_freq * (freq_ratio**i)) for i in range(n_steps)]
self._freq_ind = 0
self._func = func
self._timer.init(freq=step_rate)
self._timer.callback(self._step_sound)
def _step_sound(self, timer): # Timer callback to increment frequency during sweeped sounds.
self._func(self._freq[self._freq_ind])
self._freq_ind = (self._freq_ind+1) % len(self._freq) |
Beta Was this translation helpful? Give feedback.
-
Ah, looking at the docs for the micropython DAC here it seems that not all timers can be used for triggering the DAC.write_timed (used for audio output) and Timer 3 which I specified in the previous code does not work. The version of import pyb
import math
from . import hardware as hw
_sine_len = 100 # Number of points in sine wave.
_sine_buf = bytearray([128+int(127*math.sin(2*math.pi*i/_sine_len)) for i in range(_sine_len)])
_sqr_buf = bytearray([255,0])
_click_buf = bytearray([255,0,255,255,0,0]+4*[255]+4*[0]+8*[255]+8*[0]
+16*[255]+16*[0]+32*[255]+32*[0]+[128])
_off_buf = bytearray([128])
# Audio output ----------------------------------------------------------------
class Audio_output(hw.IO_object):
def __init__(self, channel=1):
assert channel in [1,2], '! Channel number invalid, must be 1 or 2.'
self._DAC = pyb.DAC(channel)
self._timer = pyb.Timer(hw.available_timers.pop())
self._func = None # Function currently being used for sweeped sound (sine, square or noise)
self._freq = 0
self._freq_ind = 0
self.off()
hw.assign_ID(self)
# User functions
def off(self):
self._DAC.write_timed(_off_buf, pyb.Timer(4, freq=10000), mode=pyb.DAC.NORMAL)
self._timer.deinit()
self._playing = False
def sine(self, freq): # Play a sine wave tone at the specified frequency.
self._DAC.write_timed(_sine_buf, pyb.Timer(4, freq=freq*_sine_len), mode=pyb.DAC.CIRCULAR)
def square(self, freq): # Play a square wave tone at the specified frequency.
self._DAC.write_timed(_sqr_buf, pyb.Timer(4, freq=freq*2), mode=pyb.DAC.CIRCULAR)
def noise(self, freq=10000): # Play white noise with specified maximum frequency.
self._DAC.noise(freq*2)
def click(self, timer=None): # Play a single click.
self._DAC.write_timed(_click_buf, pyb.Timer(4, freq=40000), mode=pyb.DAC.NORMAL)
def clicks(self, rate): # Play clicks at specified rate.
self._timer.init(freq=rate)
self._timer.callback(self.click)
def pulsed_sine(self, freq, pulse_rate): # Play a sine wave pulsed at the specified rate.
self._pulsed_sound(freq, pulse_rate, self.sine)
def pulsed_square(self, freq, pulse_rate): # Play a square wave pulsed at the specified rate.
self._pulsed_sound(freq, pulse_rate, self.square)
def pulsed_noise(self, freq, pulse_rate):
self._pulsed_sound(freq, pulse_rate, self.noise)
def stepped_sine(self, start_freq, end_freq, n_steps, step_rate):
self._sound_step(start_freq, end_freq, n_steps, step_rate, self.sine)
def stepped_square(self, start_freq, end_freq, n_steps, step_rate):
self._sound_step(start_freq, end_freq, n_steps, step_rate, self.square)
# Support functions
def _pulsed_sound(self, freq, pulse_rate, func):
self._freq = freq
self._func = func
self._timer.init(freq=2*pulse_rate)
self._timer.callback(self._toggle_sound)
def _toggle_sound(self, timer):
if self._playing:
self._DAC.write(127)
self._playing = False
else:
self._func(self._freq)
self._playing = True
def _sound_step(self, start_freq, end_freq, n_steps, step_rate, func):
freq_ratio = (end_freq/start_freq)**(1./(n_steps-1))
self._freq = [int(start_freq * (freq_ratio**i)) for i in range(n_steps)]
self._freq_ind = 0
self._func = func
self._timer.init(freq=step_rate)
self._timer.callback(self._step_sound)
def _step_sound(self, timer): # Timer callback to increment frequency during sweeped sounds.
self._func(self._freq[self._freq_ind])
self._freq_ind = (self._freq_ind+1) % len(self._freq) |
Beta Was this translation helpful? Give feedback.
-
Great, I've done a new release, v1.8.1 in which the bug is fixed. |
Beta Was this translation helpful? Give feedback.
Great, I've done a new release, v1.8.1 in which the bug is fixed.