diff --git a/__pycache__/device_commands.cpython-312.pyc b/__pycache__/device_commands.cpython-312.pyc index 11be430..05daede 100644 Binary files a/__pycache__/device_commands.cpython-312.pyc and b/__pycache__/device_commands.cpython-312.pyc differ diff --git a/__pycache__/device_interaction.cpython-312.pyc b/__pycache__/device_interaction.cpython-312.pyc index 1abc2f4..f457764 100644 Binary files a/__pycache__/device_interaction.cpython-312.pyc and b/__pycache__/device_interaction.cpython-312.pyc differ diff --git a/__pycache__/gui.cpython-312.pyc b/__pycache__/gui.cpython-312.pyc index a11ad81..2f446a1 100644 Binary files a/__pycache__/gui.cpython-312.pyc and b/__pycache__/gui.cpython-312.pyc differ diff --git a/_device_main.py b/_device_main.py index e269164..eebeb26 100644 --- a/_device_main.py +++ b/_device_main.py @@ -27,10 +27,13 @@ INITIAL_CURRENT_2 = 35 # 64.0879 max # Set initial current for Laser 2, in mA AD9833_FREQ_DEFAULT_KHZ = 125.0 AD9833_MCLK_DEFAULT_MHZ = 20.0 DS1809_MAX_STEP = 63 -DS1809_DEFAULT_STEP = 0 +DS1809_DEFAULT_STEP = 3 DS1809_INIT_HOME_PULSES = 64 DS1809_INIT_PULSE_MS = 2 DS1809_INIT_STARTUP_DELAY_S = 0.35 +STM32_DAC_VREF = 2.5 +STM32_DAC_MAX_CODE = 4095 +PA4_DAC_DEFAULT_VOLT = 0.0 #### ---- Functions @@ -94,6 +97,16 @@ def format_ds1809_status(step): return f"{step}/{DS1809_MAX_STEP} шагов" +def voltage_to_dac_code(voltage_v): + if voltage_v is None: + return 0 + if voltage_v < 0.0: + voltage_v = 0.0 + if voltage_v > STM32_DAC_VREF: + voltage_v = STM32_DAC_VREF + return int(round((voltage_v / STM32_DAC_VREF) * STM32_DAC_MAX_CODE)) + + def initialize_ds1809_position(prt, default_step): default_step = clamp_int(int(default_step), 0, DS1809_MAX_STEP) @@ -154,6 +167,8 @@ def set_initial_params(): params['Ad9833Triangle'] = True params['DS1809Step'] = DS1809_DEFAULT_STEP params['DS1809Status'] = format_ds1809_status(DS1809_DEFAULT_STEP) + params['PA4DacVolt'] = str(PA4_DAC_DEFAULT_VOLT) + params['PA4DacStatus'] = f"0 / {STM32_DAC_MAX_CODE}" return params def update_data_lists(): @@ -570,6 +585,21 @@ if __name__ == "__main__": params['DS1809Step'] = ds1809_step params['DS1809Status'] = format_ds1809_status(ds1809_step) window['-DS1809Status-'].update(params['DS1809Status']) + elif event == '-SetPA4Dac-': + voltage_v = parse_optional_float(values.get('-PA4DacVolt-')) + if voltage_v is None: + print('Invalid PA4 DAC voltage value.') + else: + if voltage_v < 0.0: + voltage_v = 0.0 + if voltage_v > STM32_DAC_VREF: + voltage_v = STM32_DAC_VREF + dac_code = voltage_to_dac_code(voltage_v) + dev.set_stm32_dac(prt, dac_code=dac_code, enable=True) + params['PA4DacVolt'] = f"{voltage_v:.3f}" + params['PA4DacStatus'] = f"{dac_code} / {STM32_DAC_MAX_CODE}" + window['-PA4DacVolt-'].update(params['PA4DacVolt']) + window['-PA4DacStatus-'].update(params['PA4DacStatus']) elif event == '-StopCycle-': window['-StopCycle-'].update(disabled = True) current_and_temperature_settings_available = True diff --git a/device_commands.py b/device_commands.py index 14a0ffa..db9a6d3 100644 --- a/device_commands.py +++ b/device_commands.py @@ -16,6 +16,8 @@ AD9833_CMD_TOTAL_LENGTH = 10 # Total bytes when sending AD9833 command AD9833_CMD_HEADER = "9999" DS1809_CMD_TOTAL_LENGTH = 10 # Total bytes when sending DS1809 UC/DC pulse command DS1809_CMD_HEADER = "AAAA" +STM32_DAC_CMD_TOTAL_LENGTH = 10 # Total bytes when sending STM32 DAC command +STM32_DAC_CMD_HEADER = "BBBB" AD9102_SAW_STEP_DEFAULT = 1 AD9102_PAT_PERIOD_DEFAULT = 0xFFFF AD9102_PAT_PERIOD_BASE_DEFAULT = 0x02 @@ -31,6 +33,9 @@ AD9833_MCLK_HZ_DEFAULT = 20_000_000 DS1809_FLAG_UC = 0x0001 DS1809_FLAG_DC = 0x0002 DS1809_PULSE_MS_DEFAULT = 2 +STM32_DAC_FLAG_ENABLE = 0x0001 +STM32_DAC_CODE_MAX = 4095 +STM32_DAC_VREF_DEFAULT = 3.3 class TaskType(IntEnum): Manual = 0x00 @@ -203,6 +208,17 @@ def send_DS1809(prt, bytestring): print("Sent: DS1809 pulse command.") +def send_STM32_DAC(prt, bytestring): + ''' Set STM32 internal DAC output on PA4 (0xBBBB + ...). + Expected device answer: STATE. + ''' + if len(bytestring) != STM32_DAC_CMD_TOTAL_LENGTH: + print("Error. Wrong parameter string for STM32 DAC command.") + return None + prt.write(bytestring) + print("Sent: STM32 DAC command.") + + # ---- Getting data @@ -496,6 +512,28 @@ def create_DS1809_pulse_command(uc: bool = False, return bytearray.fromhex(data) +def create_STM32_DAC_command(dac_code: int, enable: bool = True): + if dac_code is None: + dac_code = 0 + if dac_code < 0: + dac_code = 0 + if dac_code > STM32_DAC_CODE_MAX: + dac_code = STM32_DAC_CODE_MAX + + flags = STM32_DAC_FLAG_ENABLE if enable else 0 + param0 = int(dac_code) & 0x0FFF + param1 = 0 + crc_word = flags ^ param0 ^ param1 + + data = flipfour(STM32_DAC_CMD_HEADER) # Word 0 (header) + data += flipfour(int_to_hex(flags)) + data += flipfour(int_to_hex(param0)) + data += flipfour(int_to_hex(param1)) + data += flipfour(int_to_hex(crc_word)) + + return bytearray.fromhex(data) + + def encode_Input(params): if params is None: diff --git a/device_interaction.py b/device_interaction.py index ceb721e..fb570b0 100644 --- a/device_interaction.py +++ b/device_interaction.py @@ -147,6 +147,13 @@ def start_ad9833_ramp(prt, freq_hz=None, mclk_hz=None, triangle=True, enable=Tru return _print_state_reply(cmd.get_STATE(prt)) +def set_stm32_dac(prt, dac_code, enable=True): + hexstring = cmd.create_STM32_DAC_command(dac_code=dac_code, enable=enable) + cmd.send_STM32_DAC(prt, hexstring) + time.sleep(WAIT_AFTER_SEND) + return _print_state_reply(cmd.get_STATE(prt)) + + def _wait_for_min_bytes(prt, expected_len, timeout_s, poll_s=0.01): deadline = time.time() + timeout_s while time.time() < deadline: diff --git a/gui.py b/gui.py index 6bdeddf..05484b5 100644 --- a/gui.py +++ b/gui.py @@ -59,6 +59,10 @@ SET_DS1809_SECTION_TEXT = 'DS1809 (UC/DC)' SET_DS1809_UC_BUTTON_TEXT = 'UC импульс' SET_DS1809_DC_BUTTON_TEXT = 'DC импульс' SET_DS1809_STATUS_TEXT = 'Позиция DS1809:' +SET_STM32_DAC_SECTION_TEXT = 'STM32 DAC (PA4)' +SET_STM32_DAC_VOLT_TEXT = 'Напряжение DAC PA4 (В, 0..2.5):' +SET_STM32_DAC_BUTTON_TEXT = 'Установить DAC' +SET_STM32_DAC_STATUS_TEXT = 'Код DAC PA4:' GRAPH_POINTS_NUMBER = 100 # Number of most recent data points shown on charts @@ -295,6 +299,18 @@ def setup_gui(params): sg.Text(params.get('DS1809Status', '--'), key='-DS1809Status-', size=(20,1))], [sg.HSeparator(pad=H_SEPARATOR_PAD)], + + [sg.Text(SET_STM32_DAC_SECTION_TEXT, size=(SET_TEXT_WIDTH_NEW,1))], + + [sg.Text(SET_STM32_DAC_VOLT_TEXT, size=(SET_TEXT_WIDTH_NEW,1)), + sg.Input(params.get('PA4DacVolt', '0.0'), size=(SET_INPUT_WIDTH,1), key='-PA4DacVolt-')], + + [sg.Button(SET_STM32_DAC_BUTTON_TEXT, key='-SetPA4Dac-', disabled_button_color=("Gray22", "Blue"))], + + [sg.Text(SET_STM32_DAC_STATUS_TEXT, size=(SET_TEXT_WIDTH_NEW,1)), + sg.Text(params.get('PA4DacStatus', '0 / 4095'), key='-PA4DacStatus-', size=(20,1))], + + [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_RAMP_BUTTON_TEXT, key='-StartRamp-', disabled_button_color=("Gray22", "Blue")), sg.Button(SET_AD9833_BUTTON_TEXT, key='-StartRamp9833-', disabled_button_color=("Gray22", "Blue"))]]