ad9102 prestored saw done
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -44,6 +44,31 @@ def get_float(values, strId):
|
||||
window['-StartCycle-'].update(disabled = True)
|
||||
return value
|
||||
|
||||
def parse_optional_int(value):
|
||||
if value is None:
|
||||
return None
|
||||
s = str(value).strip()
|
||||
if s == "":
|
||||
return None
|
||||
try:
|
||||
return int(s, 0)
|
||||
except Exception:
|
||||
print(f"Invalid integer value: {s}")
|
||||
return None
|
||||
|
||||
def parse_optional_float(value):
|
||||
if value is None:
|
||||
return None
|
||||
s = str(value).strip()
|
||||
if s == "":
|
||||
return None
|
||||
s = s.replace(",", ".")
|
||||
try:
|
||||
return float(s)
|
||||
except Exception:
|
||||
print(f"Invalid float value: {s}")
|
||||
return None
|
||||
|
||||
def shorten(i):
|
||||
return "{:.2f}".format(round(i, 2))
|
||||
|
||||
@ -73,6 +98,13 @@ def set_initial_params():
|
||||
params['Delta_Current_2'] = 0.05
|
||||
params['Delta_Time'] = 50
|
||||
params['Tau'] = 10
|
||||
params['RampFreq'] = ''
|
||||
params['RampDuty'] = ''
|
||||
params['RampSawStep'] = ''
|
||||
params['RampPatPeriod'] = ''
|
||||
params['RampPatBase'] = 2
|
||||
params['RampDacClk'] = ''
|
||||
params['RampTriangle'] = True
|
||||
return params
|
||||
|
||||
def update_data_lists():
|
||||
@ -423,6 +455,23 @@ if __name__ == "__main__":
|
||||
params['Iset_2'] = float(values['-InputI2-'])
|
||||
dev.send_control_parameters(prt, params)
|
||||
#print(sending_param)
|
||||
elif event == '-StartRamp-':
|
||||
freq_hz = parse_optional_float(values.get('-RampFreq-'))
|
||||
duty = parse_optional_float(values.get('-RampDuty-'))
|
||||
if duty is not None:
|
||||
if duty > 1.0:
|
||||
duty = duty / 100.0
|
||||
if duty <= 0:
|
||||
duty = None
|
||||
saw_step = parse_optional_int(values.get('-RampSawStep-'))
|
||||
pat_period = parse_optional_int(values.get('-RampPatPeriod-'))
|
||||
pat_period_base = parse_optional_int(values.get('-RampPatBase-'))
|
||||
dac_clk_mhz = parse_optional_float(values.get('-RampDacClk-'))
|
||||
dac_clk_hz = dac_clk_mhz * 1e6 if dac_clk_mhz is not None else None
|
||||
triangle = values.get('-RampTriangle-', True)
|
||||
dev.start_ramp_max(prt, freq_hz=freq_hz, duty=duty, saw_step=saw_step,
|
||||
pat_period=pat_period, pat_period_base=pat_period_base,
|
||||
dac_clk_hz=dac_clk_hz, triangle=triangle)
|
||||
elif event == '-StopCycle-':
|
||||
window['-StopCycle-'].update(disabled = True)
|
||||
current_and_temperature_settings_available = True
|
||||
@ -466,4 +515,3 @@ if __name__ == "__main__":
|
||||
|
||||
dev.close_connection(prt)
|
||||
|
||||
|
||||
|
||||
@ -10,6 +10,13 @@ GET_DATA_TOTAL_LENGTH = 30 # Total number of bytes when getting DATA
|
||||
SEND_PARAMS_TOTAL_LENGTH = 30 # Total number of bytes when sending parameters
|
||||
TASK_ENABLE_COMMAND_LENGTH = 32 # Total number of bytes when sending TASK_ENABLE command
|
||||
|
||||
AD9833_CMD_TOTAL_LENGTH = 10 # Total bytes when sending AD9102 saw command
|
||||
AD9833_CMD_HEADER = "8888"
|
||||
AD9102_SAW_STEP_DEFAULT = 1
|
||||
AD9102_PAT_PERIOD_DEFAULT = 0xFFFF
|
||||
AD9102_PAT_PERIOD_BASE_DEFAULT = 0x02
|
||||
AD9102_DAC_CLK_HZ = None # set to actual DAC clock if you want freq->SAW_STEP conversion
|
||||
|
||||
class TaskType(IntEnum):
|
||||
Manual = 0x00
|
||||
ChangeCurrentLD1 = 0x01
|
||||
@ -148,6 +155,17 @@ def send_STATE(prt):
|
||||
pass
|
||||
|
||||
|
||||
def send_AD9833(prt, bytestring):
|
||||
''' Start/stop AD9833 output with triangle (ramp) mode (0x8888 + ...).
|
||||
Expected device answer: STATE.
|
||||
'''
|
||||
if len(bytestring) != AD9833_CMD_TOTAL_LENGTH:
|
||||
print("Error. Wrong parameter string for AD9833 command.")
|
||||
return None
|
||||
prt.write(bytestring)
|
||||
print("Sent: AD9833 ramp command.")
|
||||
|
||||
|
||||
# ---- Getting data
|
||||
|
||||
|
||||
@ -262,6 +280,76 @@ def create_TaskEnableCommand(sending_param):
|
||||
|
||||
return bytearray.fromhex(data)
|
||||
|
||||
|
||||
|
||||
def calc_saw_step_for_freq(freq_hz: float, dac_clk_hz: float, triangle: bool):
|
||||
if freq_hz <= 0 or dac_clk_hz is None or dac_clk_hz <= 0:
|
||||
return AD9102_SAW_STEP_DEFAULT
|
||||
n = 2 if triangle else 1
|
||||
step = int(round(dac_clk_hz / (freq_hz * n * 16384.0)))
|
||||
if step < 1:
|
||||
step = 1
|
||||
if step > 63:
|
||||
step = 63
|
||||
return step
|
||||
|
||||
|
||||
def calc_pat_period_for_duty(saw_step: int, duty: float, pat_period_base: int, triangle: bool):
|
||||
if duty is None or duty <= 0 or duty > 1.0:
|
||||
return AD9102_PAT_PERIOD_DEFAULT
|
||||
n = 2 if triangle else 1
|
||||
base_cycles = 16 if pat_period_base == 0 else pat_period_base
|
||||
ramp_cycles = n * 16384 * max(1, min(63, saw_step))
|
||||
pat_period = int(round(ramp_cycles / (duty * base_cycles)))
|
||||
if pat_period < 1:
|
||||
pat_period = 1
|
||||
if pat_period > 0xFFFF:
|
||||
pat_period = 0xFFFF
|
||||
return pat_period
|
||||
|
||||
|
||||
def create_AD9833_ramp_command(saw_step: int = None,
|
||||
pat_period: int = None,
|
||||
pat_period_base: int = None,
|
||||
enable: bool = True,
|
||||
triangle: bool = True):
|
||||
if saw_step is None:
|
||||
saw_step = AD9102_SAW_STEP_DEFAULT
|
||||
if pat_period is None:
|
||||
pat_period = AD9102_PAT_PERIOD_DEFAULT
|
||||
if pat_period_base is None:
|
||||
pat_period_base = AD9102_PAT_PERIOD_BASE_DEFAULT
|
||||
if saw_step < 1:
|
||||
saw_step = 1
|
||||
if saw_step > 63:
|
||||
saw_step = 63
|
||||
if pat_period < 0:
|
||||
pat_period = 0
|
||||
if pat_period > 0xFFFF:
|
||||
pat_period = 0xFFFF
|
||||
if pat_period_base < 0:
|
||||
pat_period_base = 0
|
||||
if pat_period_base > 0x0F:
|
||||
pat_period_base = 0x0F
|
||||
|
||||
flags = 0
|
||||
if enable:
|
||||
flags |= 0x0001
|
||||
if triangle:
|
||||
flags |= 0x0002
|
||||
|
||||
param0 = ((pat_period_base & 0x0F) << 8) | (saw_step & 0xFF)
|
||||
crc_word = flags ^ param0 ^ pat_period
|
||||
|
||||
data = flipfour(AD9833_CMD_HEADER) # Word 0 (header)
|
||||
data += flipfour(int_to_hex(flags))
|
||||
data += flipfour(int_to_hex(param0))
|
||||
data += flipfour(int_to_hex(pat_period))
|
||||
data += flipfour(int_to_hex(crc_word))
|
||||
|
||||
return bytearray.fromhex(data)
|
||||
|
||||
|
||||
def encode_Input(params):
|
||||
|
||||
if params is None:
|
||||
@ -295,24 +383,38 @@ def encode_Input(params):
|
||||
|
||||
def decode_STATE(state):
|
||||
st = flipfour(state)
|
||||
if st == '0000':
|
||||
if st is None or len(st) != 4:
|
||||
return "Error: invalid STATE length."
|
||||
|
||||
hi = int(st[0:2], 16)
|
||||
lo = int(st[2:4], 16)
|
||||
|
||||
errors = []
|
||||
if lo & 0x01:
|
||||
errors.append("SD Card reading/writing error (SD_ERR)")
|
||||
if lo & 0x02:
|
||||
errors.append("Command error (UART_ERR)")
|
||||
if lo & 0x04:
|
||||
errors.append("Wrong parameter value error (UART_DECODE_ERR)")
|
||||
if lo & 0x08:
|
||||
errors.append("Laser 1: TEC driver overheat (TEC1_ERR)")
|
||||
if lo & 0x10:
|
||||
errors.append("Laser 2: TEC driver overheat (TEC2_ERR)")
|
||||
if lo & 0x20:
|
||||
errors.append("Resetting system error (DEFAULT_ERR)")
|
||||
if lo & 0x40:
|
||||
errors.append("File deletion error (REMOVE_ERR)")
|
||||
if lo & 0x80:
|
||||
errors.append("AD9102 status check failed (AD9102_ERR)")
|
||||
|
||||
if not errors:
|
||||
status = "All ok."
|
||||
elif st == '0001':
|
||||
status = "SD Card reading/writing error (SD_ERR)."
|
||||
elif st == '0002':
|
||||
status = "Command error (UART_ERR)."
|
||||
elif st == '0004':
|
||||
status = "Wrong parameter value error (UART_DECODE_ERR)."
|
||||
elif st == '0008':
|
||||
status = "Laser 1: TEC driver overheat (TEC1_ERR)."
|
||||
elif st == '0010':
|
||||
status = "Laser 2: TEC driver overheat (TEC2_ERR)."
|
||||
elif st == '0020':
|
||||
status = "Resetting system error (DEFAULT_ERR)."
|
||||
elif st == '0040':
|
||||
status = "File deletion error (REMOVE_ERR)."
|
||||
else:
|
||||
status = "Unknown or reserved error."
|
||||
status = "; ".join(errors)
|
||||
|
||||
if hi != 0:
|
||||
status += f" | AD9102_PAT_STATUS=0x{hi:02X}"
|
||||
|
||||
return status
|
||||
|
||||
|
||||
@ -342,6 +444,3 @@ def decode_DATA(dh):
|
||||
|
||||
return data
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -110,6 +110,33 @@ def send_task_command(prt, sending_param):
|
||||
else:
|
||||
print("")
|
||||
|
||||
|
||||
|
||||
def start_ramp_max(prt, freq_hz=None, duty=None, saw_step=None, pat_period=None, pat_period_base=None, dac_clk_hz=None, triangle=True):
|
||||
# Start AD9102 sawtooth with configurable frequency/duty (via SAW_STEP and PAT_PERIOD)
|
||||
if pat_period_base is None:
|
||||
pat_period_base = cmd.AD9102_PAT_PERIOD_BASE_DEFAULT
|
||||
if saw_step is None and freq_hz is not None:
|
||||
if dac_clk_hz is None:
|
||||
dac_clk_hz = cmd.AD9102_DAC_CLK_HZ
|
||||
saw_step = cmd.calc_saw_step_for_freq(freq_hz, dac_clk_hz, triangle)
|
||||
if saw_step is None:
|
||||
saw_step = cmd.AD9102_SAW_STEP_DEFAULT
|
||||
if pat_period is None and duty is not None:
|
||||
pat_period = cmd.calc_pat_period_for_duty(saw_step, duty, pat_period_base, triangle)
|
||||
if pat_period is None:
|
||||
pat_period = cmd.AD9102_PAT_PERIOD_DEFAULT
|
||||
hexstring = cmd.create_AD9833_ramp_command(saw_step, pat_period, pat_period_base, enable=True, triangle=triangle)
|
||||
cmd.send_AD9833(prt, hexstring)
|
||||
time.sleep(WAIT_AFTER_SEND)
|
||||
status = cmd.get_STATE(prt).hex()
|
||||
if status is not None:
|
||||
print("Received: STATE. State status:", cmd.decode_STATE(status), "("+cmd.flipfour(status)+")")
|
||||
print("")
|
||||
else:
|
||||
print("")
|
||||
|
||||
|
||||
def request_data(prt):
|
||||
# Request data
|
||||
cmd.send_TRANS_ENABLE(prt)
|
||||
|
||||
35
gui.py
35
gui.py
@ -38,6 +38,16 @@ SET_TEXT_WIDTH_NEW = 40
|
||||
SET_START_BUTTON_TEXT = 'Пуск'
|
||||
SET_STOP_BUTTON_TEXT = 'Стоп'
|
||||
|
||||
SET_RAMP_BUTTON_TEXT = 'Пила'
|
||||
SET_RAMP_SECTION_TEXT = 'Настройка пилы (AD9102)'
|
||||
SET_RAMP_FREQ_TEXT = 'Частота (Гц):'
|
||||
SET_RAMP_DUTY_TEXT = 'Скважность (%):'
|
||||
SET_RAMP_SAWSTEP_TEXT = 'SAW_STEP (1-63):'
|
||||
SET_RAMP_PATPERIOD_TEXT = 'PAT_PERIOD (1-65535):'
|
||||
SET_RAMP_PATBASE_TEXT = 'PAT_PERIOD_BASE (0-15):'
|
||||
SET_RAMP_DACCLK_TEXT = 'DAC clk (МГц):'
|
||||
SET_RAMP_TRI_TEXT = 'Треугольник'
|
||||
|
||||
|
||||
GRAPH_POINTS_NUMBER = 100 # Number of most recent data points shown on charts
|
||||
GRAPH_CANVAS_SIZE = (0, 0)
|
||||
@ -195,9 +205,32 @@ def setup_gui(params):
|
||||
[sg.Text(SET_TAU_T_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
|
||||
sg.Input(params['Tau'], size=(SET_INPUT_WIDTH,1), key='-InputTau-', disabled=True, disabled_readonly_background_color="Gray")],
|
||||
|
||||
[sg.Text(SET_RAMP_SECTION_TEXT, size=(SET_TEXT_WIDTH_NEW,1))],
|
||||
|
||||
[sg.Text(SET_RAMP_FREQ_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
|
||||
sg.Input(params.get('RampFreq', ''), size=(SET_INPUT_WIDTH,1), key='-RampFreq-')],
|
||||
|
||||
[sg.Text(SET_RAMP_DUTY_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
|
||||
sg.Input(params.get('RampDuty', ''), size=(SET_INPUT_WIDTH,1), key='-RampDuty-')],
|
||||
|
||||
[sg.Text(SET_RAMP_SAWSTEP_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
|
||||
sg.Input(params.get('RampSawStep', ''), size=(SET_INPUT_WIDTH,1), key='-RampSawStep-')],
|
||||
|
||||
[sg.Text(SET_RAMP_PATPERIOD_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
|
||||
sg.Input(params.get('RampPatPeriod', ''), size=(SET_INPUT_WIDTH,1), key='-RampPatPeriod-')],
|
||||
|
||||
[sg.Text(SET_RAMP_PATBASE_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
|
||||
sg.Input(params.get('RampPatBase', ''), size=(SET_INPUT_WIDTH,1), key='-RampPatBase-')],
|
||||
|
||||
[sg.Text(SET_RAMP_DACCLK_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
|
||||
sg.Input(params.get('RampDacClk', ''), size=(SET_INPUT_WIDTH,1), key='-RampDacClk-')],
|
||||
|
||||
[sg.Text(SET_RAMP_TRI_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
|
||||
sg.Checkbox('', default=bool(params.get('RampTriangle', True)), key='-RampTriangle-')],
|
||||
|
||||
[sg.HSeparator(pad=H_SEPARATOR_PAD)],
|
||||
|
||||
[sg.Button(SET_START_BUTTON_TEXT, key='-StartCycle-', disabled_button_color=("Gray22", "Blue"), disabled=True), sg.Button(SET_STOP_BUTTON_TEXT, disabled_button_color=("Gray22", "Blue"), key='-StopCycle-', disabled=True)]]
|
||||
[sg.Button(SET_START_BUTTON_TEXT, key='-StartCycle-', disabled_button_color=("Gray22", "Blue"), disabled=True), sg.Button(SET_STOP_BUTTON_TEXT, disabled_button_color=("Gray22", "Blue"), key='-StopCycle-', disabled=True), sg.Button(SET_RAMP_BUTTON_TEXT, key='-StartRamp-', disabled_button_color=("Gray22", "Blue"))]]
|
||||
|
||||
|
||||
layout = [[sg.Column(layout_input_col1, pad=(0,0)), sg.VSeparator(pad=(4,0)), sg.Column(layout_input_col2, pad=(0,0)), sg.VSeparator(pad=(4,0)), sg.Column(layout_input_col3, pad=(0,0))],
|
||||
|
||||
4
run
4
run
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/bash
|
||||
#reset generator PCB
|
||||
pinctrl set 26 op dl # drive PCB NRST LOW -> reset stm32
|
||||
pinctrl set 26 op dh # turn stm32 back ON
|
||||
#pinctrl set 26 op dl # drive PCB NRST LOW -> reset stm32
|
||||
#pinctrl set 26 op dh # turn stm32 back ON
|
||||
|
||||
source .venv/bin/activate
|
||||
python3 _device_main.py
|
||||
|
||||
Reference in New Issue
Block a user