parent
92d3724dcd
commit
d8cf016f87
@ -0,0 +1,228 @@ |
|||||||
|
import gex |
||||||
|
|
||||||
|
CMD_WAVE_DC = 0 |
||||||
|
CMD_WAVE_SINE = 1 |
||||||
|
CMD_WAVE_TRIANGLE = 2 |
||||||
|
CMD_WAVE_SAWTOOTH_UP = 3 |
||||||
|
CMD_WAVE_SAWTOOTH_DOWN = 4 |
||||||
|
CMD_WAVE_RECTANGLE = 5 |
||||||
|
|
||||||
|
CMD_SYNC = 10 |
||||||
|
|
||||||
|
CMD_SET_FREQUENCY = 20 |
||||||
|
CMD_SET_PHASE = 21 |
||||||
|
CMD_SET_DITHER = 22 |
||||||
|
|
||||||
|
LUT_LEN = 8192 |
||||||
|
|
||||||
|
class DAC(gex.Unit): |
||||||
|
""" |
||||||
|
Analog output (2 channels) |
||||||
|
""" |
||||||
|
|
||||||
|
def _type(self): |
||||||
|
return 'DAC' |
||||||
|
|
||||||
|
|
||||||
|
def dc(self, channel, level, confirm=True): |
||||||
|
""" |
||||||
|
Set DC levels, 0-4095. None to leave the level unchanged |
||||||
|
|
||||||
|
channel: 1,2 (3 = both) |
||||||
|
level: 0-4095 |
||||||
|
""" |
||||||
|
if channel != 1 and channel != 2 and channel != 3: |
||||||
|
raise Exception("Bad channel arg: %s" % channel) |
||||||
|
|
||||||
|
pb = gex.PayloadBuilder() |
||||||
|
pb.u8(channel) |
||||||
|
pb.u16(level) |
||||||
|
|
||||||
|
if channel==3: |
||||||
|
pb.u16(level) |
||||||
|
|
||||||
|
self._send(CMD_WAVE_DC, pld=pb.close(), confirm=confirm) |
||||||
|
|
||||||
|
|
||||||
|
def dc_dual(self, ch1, ch2, confirm=True): |
||||||
|
""" |
||||||
|
Set DC levels, 0-4095 |
||||||
|
""" |
||||||
|
|
||||||
|
pb = gex.PayloadBuilder() |
||||||
|
pb.u8(0b11) |
||||||
|
pb.u16(ch1) |
||||||
|
pb.u16(ch2) |
||||||
|
self._send(CMD_WAVE_DC, pld=pb.close(), confirm=confirm) |
||||||
|
|
||||||
|
|
||||||
|
def rectangle(self, channel, duty=None, high=None, low=None, confirm=True): |
||||||
|
""" Enter rectangle gen mode (duty 0..1000) """ |
||||||
|
|
||||||
|
if channel != 1 and channel != 2 and channel != 3: |
||||||
|
raise Exception("Bad channel arg: %s" % channel) |
||||||
|
|
||||||
|
pb = gex.PayloadBuilder() |
||||||
|
pb.u8(channel) # 0b01 or 0b10 |
||||||
|
|
||||||
|
for i in range(0,1 if channel != 3 else 2): # repeat if dual |
||||||
|
pb.u16(round(duty * LUT_LEN) if duty is not None # todo ?? |
||||||
|
else 0xFFFF) |
||||||
|
|
||||||
|
pb.u16(high if high is not None else 0xFFFF) |
||||||
|
pb.u16(low if low is not None else 0xFFFF) |
||||||
|
|
||||||
|
self._send(CMD_WAVE_RECTANGLE, pld=pb.close(), confirm=confirm) |
||||||
|
|
||||||
|
|
||||||
|
def rectangle_dual(self, |
||||||
|
duty1=None, duty2=None, |
||||||
|
high1=None, high2=None, |
||||||
|
low1=None, low2=None, |
||||||
|
confirm=True): |
||||||
|
""" Set rectangle dual (both at once in sync) """ |
||||||
|
|
||||||
|
pb = gex.PayloadBuilder() |
||||||
|
pb.u8(0b11) # 0b01 or 0b10 |
||||||
|
|
||||||
|
pb.u16(round(duty1*LUT_LEN)) |
||||||
|
pb.u16(high1 if high1 is not None else 0xFFFF) |
||||||
|
pb.u16(low1 if low1 is not None else 0xFFFF) |
||||||
|
|
||||||
|
pb.u16(round(duty2*LUT_LEN)) |
||||||
|
pb.u16(high2 if high2 is not None else 0xFFFF) |
||||||
|
pb.u16(low2 if low2 is not None else 0xFFFF) |
||||||
|
|
||||||
|
self._send(CMD_WAVE_RECTANGLE, pld=pb.close(), confirm=confirm) |
||||||
|
|
||||||
|
|
||||||
|
def sync(self, confirm=True): |
||||||
|
self._send(CMD_SYNC, confirm=confirm) |
||||||
|
|
||||||
|
|
||||||
|
def waveform(self, channel, waveform, confirm=True): |
||||||
|
""" |
||||||
|
Set a waveform. For DC or rectangle, |
||||||
|
use the dedicated functions with extra parameters |
||||||
|
|
||||||
|
channel: 1,2 (3 = both) |
||||||
|
waveform: |
||||||
|
- None - leave unchanged |
||||||
|
- SINE |
||||||
|
- TRIANGLE |
||||||
|
- SAW_UP |
||||||
|
- SAW_DOWN |
||||||
|
""" |
||||||
|
|
||||||
|
lookup = {'SINE': CMD_WAVE_SINE, |
||||||
|
'SIN': CMD_WAVE_SINE, |
||||||
|
|
||||||
|
'TRI': CMD_WAVE_TRIANGLE, |
||||||
|
'TRIANGLE': CMD_WAVE_TRIANGLE, |
||||||
|
|
||||||
|
'SAW': CMD_WAVE_SAWTOOTH_UP, |
||||||
|
'RAMP': CMD_WAVE_SAWTOOTH_UP, |
||||||
|
'RAMP_UP': CMD_WAVE_SAWTOOTH_UP, |
||||||
|
'SAW_UP': CMD_WAVE_SAWTOOTH_UP, |
||||||
|
|
||||||
|
'SAW_DOWN': CMD_WAVE_SAWTOOTH_DOWN, |
||||||
|
'RAMP_DOWN': CMD_WAVE_SAWTOOTH_DOWN, |
||||||
|
} |
||||||
|
|
||||||
|
if channel != 1 and channel != 2 and channel != 3: |
||||||
|
raise Exception("Bad channel arg: %s" % channel) |
||||||
|
|
||||||
|
pb = gex.PayloadBuilder() |
||||||
|
pb.u8(channel) # 0b01 or 0b10 |
||||||
|
self._send(lookup[waveform], pld=pb.close(), confirm=confirm) |
||||||
|
|
||||||
|
|
||||||
|
def set_frequency(self, channel, freq, confirm=True): |
||||||
|
""" |
||||||
|
Set frequency using float in Hz |
||||||
|
""" |
||||||
|
|
||||||
|
if channel != 1 and channel != 2 and channel != 3: |
||||||
|
raise Exception("Bad channel arg: %s" % channel) |
||||||
|
|
||||||
|
pb = gex.PayloadBuilder() |
||||||
|
pb.u8(channel) |
||||||
|
pb.float(freq) |
||||||
|
|
||||||
|
if channel == 3: |
||||||
|
pb.float(freq) |
||||||
|
|
||||||
|
self._send(CMD_SET_FREQUENCY, pld=pb.close(), confirm=confirm) |
||||||
|
|
||||||
|
|
||||||
|
def set_frequency_dual(self, freq1, freq2, confirm=True): |
||||||
|
""" |
||||||
|
Set frequency of both channels using float in Hz |
||||||
|
""" |
||||||
|
|
||||||
|
pb = gex.PayloadBuilder() |
||||||
|
pb.u8(0b11) |
||||||
|
pb.float(freq1) |
||||||
|
pb.float(freq2) |
||||||
|
|
||||||
|
self._send(CMD_SET_FREQUENCY, pld=pb.close(), confirm=confirm) |
||||||
|
|
||||||
|
|
||||||
|
def set_phase(self, channel, phase360, confirm=True): |
||||||
|
""" |
||||||
|
Set channel phase relative to it's "base phase". |
||||||
|
If both channels use the same frequency, this could be used for drawing XY figures. |
||||||
|
""" |
||||||
|
|
||||||
|
if channel != 1 and channel != 2 and channel != 3: |
||||||
|
raise Exception("Bad channel arg: %s" % channel) |
||||||
|
|
||||||
|
pb = gex.PayloadBuilder() |
||||||
|
pb.u8(channel) |
||||||
|
pb.u16(round((phase360/360) * LUT_LEN)) |
||||||
|
|
||||||
|
if channel == 3: |
||||||
|
pb.u16(round((phase360/360) * LUT_LEN)) |
||||||
|
|
||||||
|
self._send(CMD_SET_PHASE, pld=pb.close(), confirm=confirm) |
||||||
|
|
||||||
|
|
||||||
|
def set_phase_dual(self, phase1, phase2, confirm=True): |
||||||
|
""" |
||||||
|
Set phase for both channels at once |
||||||
|
""" |
||||||
|
|
||||||
|
pb = gex.PayloadBuilder() |
||||||
|
pb.u8(0b11) |
||||||
|
pb.u16((phase1/360) * LUT_LEN) |
||||||
|
pb.u16((phase2/360) * LUT_LEN) |
||||||
|
|
||||||
|
self._send(CMD_SET_PHASE, pld=pb.close(), confirm=confirm) |
||||||
|
|
||||||
|
|
||||||
|
def set_dither(self, channel, type=None, bits=None, confirm=True): |
||||||
|
""" |
||||||
|
Set dithering (superimposed noise waveform) |
||||||
|
type: NONE, TRIANGLE, WHITE |
||||||
|
bits: 1-12 |
||||||
|
""" |
||||||
|
|
||||||
|
if channel != 1 and channel != 2 and channel != 3: |
||||||
|
raise Exception("Bad channel arg: %s" % channel) |
||||||
|
|
||||||
|
lookup = {'NONE': 0, |
||||||
|
|
||||||
|
'WHITE': 1, |
||||||
|
'NOISE': 1, |
||||||
|
|
||||||
|
'TRIANGLE': 2, |
||||||
|
'TRI': 2} |
||||||
|
|
||||||
|
pb = gex.PayloadBuilder() |
||||||
|
pb.u8(channel) |
||||||
|
|
||||||
|
for i in range(0,1 if channel != 3 else 2): # repeat if dual |
||||||
|
pb.u8(lookup[type] if type is not None else 0xFF) |
||||||
|
pb.u8(bits if bits is not None else 0xFF) |
||||||
|
|
||||||
|
self._send(CMD_SET_DITHER, pld=pb.close(), confirm=confirm) |
@ -0,0 +1,46 @@ |
|||||||
|
#!/bin/env python3 |
||||||
|
import time |
||||||
|
import math |
||||||
|
|
||||||
|
import gex |
||||||
|
|
||||||
|
from scipy.io import wavfile |
||||||
|
|
||||||
|
with gex.Client(gex.TrxRawUSB()) as client: |
||||||
|
dac = gex.DAC(client, 'dac') |
||||||
|
|
||||||
|
# dac.set_dither(1, 'TRI', 8) |
||||||
|
# # dac.set_dither(3, 'NONE', 8) |
||||||
|
# # # |
||||||
|
# # # dac.set_frequency(2, 1) |
||||||
|
# # # dac.set_frequency(1, 10.01) |
||||||
|
# dac.set_waveform(1, 'SIN') |
||||||
|
# # dac.set_waveform(2, 'RAMP') |
||||||
|
# |
||||||
|
# dac.rectangle(2, 0.5, 4095, 0) |
||||||
|
# |
||||||
|
# dac.set_frequency(1, 100) |
||||||
|
# dac.set_frequency(2, 50) |
||||||
|
# # |
||||||
|
# dac.sync() |
||||||
|
|
||||||
|
for i in range(0, 1000): |
||||||
|
dac.set_frequency(1, i) |
||||||
|
time.sleep(0.001) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# dac.waveform(1, 'SIN') |
||||||
|
# # dac.set_frequency(1, 1000) |
||||||
|
# # dac.dc(1,1000) |
||||||
|
# dac.dc(2,1000) |
||||||
|
|
||||||
|
# |
||||||
|
# for i in range(0,360*5, 3): |
||||||
|
# dac.dc_dual(round(2047+math.cos(((i*3.01)/180)*math.pi)*1900), |
||||||
|
# round(2047+math.sin(((i*2.01)/180)*math.pi)*1900), |
||||||
|
# confirm=False) |
||||||
|
# time.sleep(0.01) |
||||||
|
# |
||||||
|
# dac.dc_dual(2047,2047) |
||||||
|
|
Loading…
Reference in new issue