{"id":30457,"date":"2024-01-29T17:03:54","date_gmt":"2024-01-30T01:03:54","guid":{"rendered":"https:\/\/digilent.com\/blog\/?p=30457"},"modified":"2024-01-31T09:49:06","modified_gmt":"2024-01-31T17:49:06","slug":"the-hardware-engineers-guide-to-running-tests-in-linux-mode-on-adp3450","status":"publish","type":"post","link":"https:\/\/digilent.com\/blog\/the-hardware-engineers-guide-to-running-tests-in-linux-mode-on-adp3450\/","title":{"rendered":"The Hardware Engineer\u2019s Guide to Running Tests in Linux Mode on ADP3450"},"content":{"rendered":"<p>As a purely hardware engineer who primarily focuses on schematics, PCB layout, and the inevitable hardware test and debug, Python scripts and Linux scare the life out of me. At the same time, as I work primarily remotely and sometimes my hardware testing needs hours of idle tests before I can really do anything meaningful with them, I found myself searching for a solution to give me more freedom.<\/p>\n<p>Behold: The ADP3450\u2019s Linux Mode! Something which I initially was terrified of, but now cannot live without. Grabbing my laptop to go on site for a client commissioning while leaving my hardware tests running a long test script back in my home office? CHECK! \u2705<\/p>\n<p>I can\u2019t imagine life before having this option anymore. And I am SO excited to share with you how I learned this in the next section. I&#8217;ll break it down in a way that&#8217;s understandable for other hardware engineers and explain the bits I personally struggled with, which were often overlooked in other tutorials because they assumed a certain level of firmware experience.<\/p>\n<h2>Prerequisites<\/h2>\n<ul>\n<li>An <a href=\"https:\/\/digilent.com\/reference\/test-and-measurement\/analog-discovery-pro-3x50\/start\">ADP3450<\/a>! This isn\u2019t possible on other ADP models.<\/li>\n<li><a href=\"https:\/\/cloud.digilent.com\/login\">Waveforms<\/a> (you need to make a free account to download)<\/li>\n<li>A USB stick to transfer files to the ADP3450 (later we\u2019ll look at sending it over the network instead!)<\/li>\n<li><a href=\"https:\/\/code.visualstudio.com\/download\">VSCode<\/a> (or your favourite code editor)<\/li>\n<li><a href=\"https:\/\/www.python.org\/downloads\/\">Python<\/a> installed on your laptop for testing. Our ADP had Python 3.7.3 installed in its Linux Mode install.<\/li>\n<li>If you\u2019re on Windows:\n<ul>\n<li><a href=\"https:\/\/www.chiark.greenend.org.uk\/~sgtatham\/putty\/latest.html\">PuTTY<\/a> for connecting to the serial terminal on the ADP3450. You can get the latest MSI package. If you\u2019re in doubt which one you need, it\u2019s probably 64-bit x86!<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h2>Getting into Linux Mode<\/h2>\n<p>First things first, we\u2019ll need to boot our ADP3450 into Linux Mode so that we can perform our tests on it when we\u2019re away from our ADP3450!<\/p>\n<ul>\n<li>Connect your ADP3450 to your laptop via USB, connecting to the port labelled \u201cDevice\u201d.<\/li>\n<li>Open Waveforms<\/li>\n<li>In Settings &gt; Device Manager, select your connected ADP3450 and click Boot from the toolbar.<\/li>\n<\/ul>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/1-600x311.png\" alt=\"\" width=\"600\" height=\"311\" class=\"alignnone size-medium wp-image-30460\" srcset=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/1-600x311.png 600w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/1.png 960w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/2-600x505.png\" alt=\"\" width=\"600\" height=\"505\" class=\"alignnone size-medium wp-image-30461\" srcset=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/2-600x505.png 600w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/2-1024x862.png 1024w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/2-1536x1293.png 1536w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/2.png 2000w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<ul>\n<li>Select \u201cLinux\u201d and Apply &amp; Reboot.<\/li>\n<\/ul>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/3-600x543.png\" alt=\"\" width=\"600\" height=\"543\" class=\"alignnone size-medium wp-image-30462\" srcset=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/3-600x543.png 600w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/3-1024x927.png 1024w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/3.png 1150w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<ul>\n<li>If you\u2019re a Windows user:\n<ul>\n<li>Open \u201cDevice Manager\u201d (pro-tip: you can get to this quickly by right clicking the Start button!)<\/li>\n<li>Under the section \u201cPorts (COM &amp; LPT)\u201d, find your ADP3450. If you\u2019ve only got one device connected, you\u2019ll probably one see one item listed here! It should appear as \u201cUSB Serial Port (COM5)\u201d &#8211; Your number after COM may be different!<\/li>\n<li>Open PuTTY. It will open to the \u201cSession\u201d view in the sidebar.<\/li>\n<li>Under \u201cHost name (or IP address)\u201d, type the COM port we just found. We would type \u201cCOM5\u201d in our case!<\/li>\n<li>In the speed box, type 115200. This is the \u2018<a href=\"https:\/\/en.wikipedia.org\/wiki\/Baud\">baud rate<\/a>\u2019 of the ADP3450, the speed at which the device sends and receives messages over the serial port.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><!-- notionvc: 3c20823e-a927-4705-92a2-1ff67122b28c --><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/4-600x467.png\" alt=\"\" width=\"600\" height=\"467\" class=\"alignnone size-medium wp-image-30463\" srcset=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/4-600x467.png 600w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/4-1024x796.png 1024w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/4-1536x1194.png 1536w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/4.png 2000w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<ul>\n<li>If you\u2019re a macOS or Linux user:\n<ul>\n<li>Open a terminal<\/li>\n<li>Run <code>ls \/dev\/tty.*<\/code>, this will show you a list of connected device terminals. You should see something like <code>\/dev\/tty.usbserial-XXXXXXXX<\/code> show up in the output.<\/li>\n<li>Run <code>screen \/dev\/tty.usbserial-XXXXXXXX 115200<\/code>. This will connect you to the ADP serial terminal on the specified baud rate of 115200.<\/li>\n<\/ul>\n<\/li>\n<li>Once the device boots, you should see the prompt <code>ADPro login:<\/code>, if you don\u2019t hit enter a couple of times and it should show up.<\/li>\n<li>Login with the username <code>digilent<\/code> and the password <code>digilent<\/code> (your password won\u2019t be printed to the screen).<\/li>\n<\/ul>\n<h2>Writing our code to run on the ADP3450<\/h2>\n<h4>Importing our libraries<\/h4>\n<ul>\n<li>The first thing we need to do is set up our code with all the right imports and libraries so we can interact with the ADP3450. The dwf library (which stands for Digilent Waveforms) comes bundled with the WaveForms SDK, but is located in a slightly different place on disk depending on your operating system.<\/li>\n<li>This block of code figures out which operating system you\u2019re on and then loads the library into python from the right location.<\/li>\n<\/ul>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-python\" data-lang=\"Python\"><code># -----------------------\r\n# Import all of the required libraries\r\n\r\nimport ctypes                     # import the C compatible data types\r\nfrom sys import platform, path    # this is needed to check the OS type and get the PATH\r\nfrom time import sleep\r\nfrom datetime import datetime\r\n \r\n# load the dynamic library, get constants path (the path is OS specific)\r\nif platform.startswith(\"win\"):\r\n    # on Windows\r\n    dwf = ctypes.cdll.dwf\r\n    constants_path = \"C:\\Program Files (x86)\\Digilent\\WaveFormsSDK\\samples\\py\"\r\nelif platform.startswith(\"darwin\"):\r\n    # on macOS\r\n    lib_path = \"\/Library\/Frameworks\/dwf.framework\/dwf\"\r\n    dwf = ctypes.cdll.LoadLibrary(lib_path)\r\n    constants_path = \"\/Applications\/WaveForms.app\/Contents\/Resources\/SDK\/samples\/py\"\r\nelse:\r\n    # on Linux\r\n    dwf = ctypes.cdll.LoadLibrary(\"libdwf.so\")\r\n    constants_path = \"\/usr\/share\/digilent\/waveforms\/samples\/py\"\r\n\r\n# import constants\r\npath.append(constants_path)\r\nimport dwfconstants as constants<\/code><\/pre>\n<\/div>\n<h2>Connecting to the ADP with Python<\/h2>\n<ul>\n<li>Before we run the code, we need to close the Waveforms GUI app (the graphical app we just used to boot into Linux mode). This is because the ADP3450 can only be connected to from one place at a time and it is currently connected to from the GUI app. If we try to connect from our python script, we will likely get an error saying the device is busy and can\u2019t connect.<\/li>\n<li>We\u2019re now going to start using the Waveforms SDK. Digilent provides <a href=\"https:\/\/digilent.com\/reference\/software\/waveforms\/waveforms-sdk\/reference-manual\">documentation<\/a> for each function we\u2019ve used here, so you can Ctrl+F\/Cmd+F on their documentation page to search for the functions we\u2019re calling (like <code>FDwfDeviceConfigOpen<\/code>) to understand in more detail the arguments that we\u2019re passing to each function.<\/li>\n<li>First up, we need to connect to the device! As there\u2019s only one device plugged in, this should be the first available device we find!<\/li>\n<li>Once we\u2019re connected to the device, we will get a \u2018handle\u2019 returned to us that we need to use in our future blocks of code so we can correctly address the device we want to talk to! This is sort of like the ADP returning us a postal address so we know where to send our letters (or in our case, code instructions!) in future!<\/li>\n<\/ul>\n<p><!-- notionvc: f474b2cc-2382-469c-bef4-c9391142790e --><\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-python\" data-lang=\"Python\"><code># -------------------------\r\n# Connect to the device\r\n\r\ndef open_adp():\r\n    \"\"\"\r\n    Open the first available device\r\n    \"\"\"\r\n    # this is the device handle - it will be used by all functions to \"address\" the connected device. Here we're just making an empty C int that we can store our handle in when we get one!\r\n    hdwf = ctypes.c_int()\r\n    # connect to the first available device\r\n\t\t# We pass the empty c int as the last argument so the dwf library can fill it with the handle value once we're connected\r\n    print(\"Opening first device\")\r\n    dwf.FDwfDeviceConfigOpen(ctypes.c_int(-1), ctypes.c_int(0), ctypes.byref(hdwf))\r\n\r\n    if hdwf.value == 0:\r\n\t\t\t\t# If we don't get a value, something has gone wrong, so we will create a string buffer that we can store our error message in. That way we can print it out to the screen to understand better what has gone wrong!\r\n        print(\"failed to open device\")\r\n        szerr = ctypes.create_string_buffer(512)\r\n        dwf.FDwfGetLastErrorMsg(szerr)\r\n        print(str(szerr.value))\r\n        quit()\r\n\r\n    print(f\"Device ({hdwf.value}) successfully opened!\")\r\n\r\n    # Return the handle to be used in future function calls\r\n    return hdwf<\/code><\/pre>\n<\/div>\n<ul>\n<li>We also need to make a function to close the device, otherwise we might run into problems trying to reconnect to the device in future! It will probably throw us a \u201cDevice busy\u201d error if we don\u2019t close the device properly before trying to connect!<\/li>\n<\/ul>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-python\" data-lang=\"Python\"><code># -----------------\r\n# Close the device when we're done so it's available to other programs\/scripts\r\n\r\ndef close(hdwf):\r\n    print(\"Closing device\")\r\n    dwf.FDwfDeviceClose(hdwf)\r\n    return<\/code><\/pre>\n<\/div>\n<h2>Writing the tests you want<\/h2>\n<ul>\n<li>We are going to write functions so we can run the tests we want!<\/li>\n<li>Here\u2019s an example for measuring voltage. When we run this function in a bit, we\u2019ll call it using our device handle and the channel number that we want to record.<\/li>\n<\/ul>\n<p><!-- notionvc: a1adcde6-8f7a-4661-95e9-3a016613b675 --><\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-python\" data-lang=\"Python\"><code># -----------------\r\n# Measure a voltage\r\ndef measure_voltage(handle, channel):\r\n\"\"\"\r\nmeasure a voltage\r\nparameters: - device data\r\n- the selected oscilloscope channel (1-2, or 1-4)\r\n\r\nreturns: - the measured voltage in Volts\r\n\"\"\"\r\n# set up the instrument\r\ndwf.FDwfAnalogInConfigure(handle, ctypes.c_bool(False), ctypes.c_bool(False))\r\n\r\n# read data to an internal buffer\r\ndwf.FDwfAnalogInStatus(handle, ctypes.c_bool(False), ctypes.c_int(0))\r\n\r\n# Create an empty variable to store the measured voltage, like what we did with the handle earlier\r\nvoltage = ctypes.c_double()\r\n# extract data from that buffer and save it in the voltage variable.\r\n# The channels are 0 indexed in the library (0-1 or 0-3), but 1 indexed on the device itself (1-2 or 1-4), so we need to subtract 1 from the channel number we've provided to the function.\r\ndwf.FDwfAnalogInStatusSample(handle, ctypes.c_int(channel - 1), ctypes.byref(voltage))\r\n\r\n# store the result as float - a number with a decimal point!\r\nvoltage = voltage.value\r\nreturn voltage<\/code><\/pre>\n<\/div>\n<ul>\n<li>The dwf commands that end in <code>Configure<\/code> handle setting up the device for a specific action. With these arguments, we are setting up the device with the handle we\u2019ve given to our function at runtime, but we\u2019re not resetting the Auto trigger timeout or starting the capture just yet. This is what the two <code>False<\/code> arguments are doing!<\/li>\n<li>The <code>FDwfAnalogInStatus<\/code>command reads data from the device and stores it in a buffer.<\/li>\n<li>All of the other <code>FDwfAnalogInStatus*<\/code>commands (like the <code>FDwfAnalogInStatusSample<\/code> that we use in a second) don\u2019t communicate with the device and are instead used to handle and return the data from the previous <code>FDwfAnalogInStatus<\/code> <strong>call.<\/strong><\/li>\n<li>Speaking of which! <code>FDwfAnalogInStatusSample<\/code> gets us the last\u00a0ADC sample from the specified channel on the AnalogIn instrument.<\/li>\n<\/ul>\n<h2>Writing more tests<\/h2>\n<p>There are more examples of using the instruments over on <a href=\"https:\/\/digilent.com\/reference\/test-and-measurement\/guides\/waveforms-sdk-getting-started\">this page<\/a> in section 3, so you don\u2019t need to worry about writing all these test functions from scratch! You might have noticed the code in this guide looks slightly different though. Let\u2019s explain the differences so you use those examples without errors!<\/p>\n<ul>\n<li>In the Waveforms SDK documentation in Step 2, they describe a function called <code>open()<\/code>. We have renamed this <code>open_adp()<\/code>. The <code>open()<\/code> function is a built-in function in python used for opening files. Because we\u2019re opening files so we can write our experiment results to disk, we can\u2019t redefine this function like they have done in the Waveforms docs, otherwise every time we try to open a file, our program will try to open the ADP instead!<\/li>\n<li>The Waveforms docs <code>open()<\/code> function also returns a very slightly more complex object. I simplified this a bit so it only returns a handle, and not a name as well. All this means is that everywhere you see the examples pass in <code>data.handle<\/code>, we would just pass in <code>data<\/code> instead. I called my <code>data<\/code> variable <code>hdwf<\/code> instead so it was clearer that it was a handle to a digilent waveforms device!<\/li>\n<li>In short, if you\u2019ve copied all the code in this guide, where you see <code>data.handle<\/code>, change it for <code>hdwf<\/code> and where you see <code>open()<\/code> swap it for <code>open_adp()<\/code>!<\/li>\n<\/ul>\n<h2>Putting it all together!<\/h2>\n<p>Now that we\u2019ve got our imports sorted, got our functions for connecting to our device (and importantly, disconnecting as well!) as well as a nice voltage read function, we can now put this all together and call our functions to run our test!<\/p>\n<p><!-- notionvc: 7357ce0e-6229-474c-9a4e-7ca08b8db319 --><\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-python\" data-lang=\"Python\"><code># ------------\r\n# Put all of the pieces together ready to run in order!\r\ndef run():\r\n\t\t# First we open a handle to our ADP\r\n    hdwf = open_adp()\r\n\t\t# Get a timestamp so we can create a unique filename to store our results and not overwrite previous results files.\r\n    time_now = datetime.now().strftime(\"%Y-%m-%d_%H-%M-%S\")\r\n\t\t# Open a new output file\r\n    with open(f'.\/voltages.{time_now}.txt', 'w+') as outfile:\r\n        while True:\r\n\t\t\t\t\t\t# Record the voltage on channel 2 every second, printing it both to the screen and to the output file!\r\n            voltage_now = measure_voltage(hdwf, 2)\r\n            print(voltage_now)\r\n            outfile.write(f\"{voltage_now}\\n\")\r\n            sleep(1)\r\n\t\t# Once we're done, don't forget to close the device!\r\n    close(hdwf)\r\n\r\n\r\n# -------------------------\r\n# Run the program when it starts! This is a magic python function that runs our run function when the file is run.\r\nif __name__ == '__main__':\r\n    run()<\/code><\/pre>\n<\/div>\n<h2>The whole script in its entirety!<\/h2>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-python\" data-lang=\"Python\"><code># -----------------------\r\n# Import all of the required libraries\r\n\r\nimport ctypes  # import the C compatible data types\r\nfrom sys import platform, path  # this is needed to check the OS type and get the PATH\r\nfrom time import sleep\r\nfrom datetime import datetime\r\n\r\n# load the dynamic library, get constants path (the path is OS specific)\r\nif platform.startswith(\"win\"):\r\n    # on Windows\r\n    dwf = ctypes.cdll.dwf\r\n    constants_path = \"C:\\\\Program Files (x86)\\\\Digilent\\\\WaveFormsSDK\\\\samples\\\\py\"\r\nelif platform.startswith(\"darwin\"):\r\n    # on macOS\r\n    lib_path = \"\/Library\/Frameworks\/dwf.framework\/dwf\"\r\n    dwf = ctypes.cdll.LoadLibrary(lib_path)\r\n    constants_path = \"\/Applications\/WaveForms.app\/Contents\/Resources\/SDK\/samples\/py\"\r\nelse:\r\n    # on Linux\r\n    dwf = ctypes.cdll.LoadLibrary(\"libdwf.so\")\r\n    constants_path = \"\/usr\/share\/digilent\/waveforms\/samples\/py\"\r\n\r\n# import constants\r\npath.append(constants_path)\r\nimport dwfconstants as constants\r\n\r\n\r\n# -------------------------\r\n# Connect to the device\r\n\r\n\r\ndef open_adp():\r\n    \"\"\"\r\n    Open the first available device\r\n    \"\"\"\r\n    # this is the device handle - it will be used by all functions to \"address\" the connected device\r\n    hdwf = ctypes.c_int()\r\n    # connect to the first available device\r\n    print(\"Opening first device\")\r\n    dwf.FDwfDeviceConfigOpen(ctypes.c_int(-1), ctypes.c_int(0), ctypes.byref(hdwf))\r\n\r\n    if hdwf.value == 0:\r\n        print(\"failed to open device\")\r\n        szerr = ctypes.create_string_buffer(512)\r\n        dwf.FDwfGetLastErrorMsg(szerr)\r\n        print(str(szerr.value))\r\n        quit()\r\n\r\n    print(f\"Device ({hdwf.value}) successfully opened!\")\r\n\r\n    # Return the handle to be used in future function calls\r\n    return hdwf\r\n\r\n\r\n# -----------------\r\n# Close the device when we're done so it's available to other programs\/scripts\r\n\r\n\r\ndef close(hdwf):\r\n    print(\"Closing device\")\r\n    dwf.FDwfDeviceClose(hdwf)\r\n    return\r\n\r\n\r\n# -----------------\r\n# Measure a voltage\r\ndef measure_voltage(handle, channel):\r\n    \"\"\"\r\n    measure a voltage\r\n    parameters: - device data\r\n                - the selected oscilloscope channel (1-2, or 1-4)\r\n\r\n    returns:    - the measured voltage in Volts\r\n    \"\"\"\r\n    # set up the instrument\r\n    dwf.FDwfAnalogInConfigure(handle, ctypes.c_bool(False), ctypes.c_bool(False))\r\n\r\n    # read data to an internal buffer\r\n    dwf.FDwfAnalogInStatus(handle, ctypes.c_bool(False), ctypes.c_int(0))\r\n\r\n    # extract data from that buffer\r\n    voltage = ctypes.c_double()  # variable to store the measured voltage\r\n    dwf.FDwfAnalogInStatusSample(\r\n        handle, ctypes.c_int(channel - 1), ctypes.byref(voltage)\r\n    )\r\n\r\n    # store the result as float\r\n    voltage = voltage.value\r\n    return voltage\r\n\r\n\r\n# ------------\r\n# Put all of the pieces together ready to run in order!\r\ndef run():\r\n    hdwf = open_adp()\r\n    # More things in here to test!\r\n    time_now = datetime.now().strftime(\"%Y-%m-%d_%H-%M-%S\")\r\n    with open(f\".\/voltages.{time_now}.txt\", \"w+\") as outfile:\r\n        while True:\r\n            voltage_now = measure_voltage(hdwf, 2)\r\n            print(voltage_now)\r\n            outfile.write(f\"{voltage_now}\\n\")\r\n            sleep(1)\r\n    close(hdwf)\r\n\r\n\r\n# -------------------------\r\n# Run the program when it starts!\r\nif __name__ == \"__main__\":\r\n    run()<\/code><\/pre>\n<\/div>\n<h2>Testing your code<\/h2>\n<ul>\n<li>We can test this runs well by running it on our computer first before moving it to the ADP3450.<\/li>\n<li>This is as simple as running your python script. If you know what you\u2019re doing here and it runs fine, awesome! Let\u2019s move on to running it on the ADP3450!<\/li>\n<li>If you\u2019re a bit new to this, lets walk through getting set up to run your code in VSCode.<\/li>\n<\/ul>\n<h2>Getting set up to run code from VSCode!<\/h2>\n<ul>\n<li>First up, you\u2019ll need to make sure you\u2019re opening a folder in VSCode, not just the one python file. It\u2019s best if you create a separate folder for each project. If you haven\u2019t already, make a new folder and save your python script there.<\/li>\n<li>Open the whole folder in VSCode from File &gt; Open Folder\u2026<\/li>\n<li>By the way, my VSCode and terminal will probably look a little different in my screenshots to what you see because I\u2019ve got both my terminal and my VSCode editor set up with a few themes and tweaks that work for me, but all the instructions will work exactly the same for you on the default layouts!<\/li>\n<li>Let\u2019s set up a launch file that tells VSCode what to do when you run your code. Click on the \u201cRun and Debug\u201d tab in the left sidebar.<\/li>\n<\/ul>\n<p><!-- notionvc: c95cc773-e09f-4737-a355-4a64b9aa7dae --><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/5-600x348.png\" alt=\"\" width=\"600\" height=\"348\" class=\"alignnone size-medium wp-image-30468\" srcset=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/5-600x348.png 600w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/5-1024x595.png 1024w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/5-1536x892.png 1536w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/5.png 1860w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<ul>\n<li>Then click, \u201ccreate a launch.json file\u201d<\/li>\n<li>Select the first option that says \u201cPython File &#8211; Debug the currently active Python file\u201d<\/li>\n<\/ul>\n<p><!-- notionvc: 2defa32b-1332-4485-a182-f26468e636c6 --><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/6-600x211.png\" alt=\"\" width=\"600\" height=\"211\" class=\"alignnone size-medium wp-image-30469\" srcset=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/6-600x211.png 600w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/6-1024x359.png 1024w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/6-1536x539.png 1536w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/6.png 2000w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<ul>\n<li>This will create a new folder called .vscode with some default settings. We can leave these as they are and close the new launch.json file.<\/li>\n<li>Go back to your original python file and click the green play button in the Run and Debug sidebar!<\/li>\n<\/ul>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/7-600x465.png\" alt=\"\" width=\"600\" height=\"465\" class=\"alignnone size-medium wp-image-30470\" srcset=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/7-600x465.png 600w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/7-1024x793.png 1024w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/7-1536x1190.png 1536w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/7.png 2000w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<ul>\n<li>You should see your code run in the terminal! In my case, I get an error (but that\u2019s just because I haven\u2019t plugged in my ADP!). With your ADP plugged in, you should see it connect and start printing voltage readings to the screen. It will also write them to a new file in the same folder as your python script.<\/li>\n<\/ul>\n<h2>Running your code on the ADP3450<\/h2>\n<ul>\n<li>Pop your python script on a USB stick. Your USB stick must be FAT32 formatted.<\/li>\n<li>Plug your USB stick into your ADP! (In a future tutorial, we\u2019ll look at doing this without a USB stick with remote access)<\/li>\n<li>Go back to your terminal session running on your ADP (you were running this in PuTTY on Windows or in a terminal with the <code>screen<\/code> command on macOS\/Linux).<\/li>\n<li>On your ADP session, run <code>sudo fdisk -l<\/code> (that\u2019s lowercase l for list!)<\/li>\n<li>If you are asked for a sudo password, enter <code>digilent<\/code><\/li>\n<li>Find the device that looks like your USB stick, here it\u2019s our 30GB FAT32 device: <code>\/dev\/sda1<\/code><\/li>\n<\/ul>\n<p><!-- notionvc: 85309ad0-032a-48c0-9707-8a678b4466e1 --><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/8-600x382.png\" alt=\"\" width=\"600\" height=\"382\" class=\"alignnone size-medium wp-image-30471\" srcset=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/8-600x382.png 600w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/8-1024x652.png 1024w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/8-1536x978.png 1536w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/8.png 2000w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<ul>\n<li>Now we need to mount the USB to Linux on the ADP3450 so we can access the files on it.<\/li>\n<li><code>sudo mount \/dev\/sda1 \/mnt<\/code> makes the files available in the <code>\/mnt<\/code> directory.<\/li>\n<li><code>cd \/mnt<\/code> opens the USB stick.<\/li>\n<li>Run <code>ls<\/code> to see the files!<\/li>\n<li>Run <code>sudo python3 first_test.py<\/code> (replace first_test.py with the name of your python file!)<\/li>\n<li>You\u2019ll see it start to dump voltages to the screen!<\/li>\n<\/ul>\n<p><!-- notionvc: bf9f5172-7119-444c-8549-436c3356d925 --><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/9-600x399.png\" alt=\"\" width=\"600\" height=\"399\" class=\"alignnone size-medium wp-image-30472\" srcset=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/9-600x399.png 600w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/9-1024x681.png 1024w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/9-1536x1021.png 1536w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/9.png 2000w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<ul>\n<li>Now you can unplug your laptop and walk away, leaving the ADP3450 to run. It is writing the voltage results to a file on the USB stick. When you reconnect to the serial port later on, you\u2019ll start to see the voltages on the screen again and you can stop the test with \u201cCtrl+C\u201d.<\/li>\n<li>You\u2019re all done! Well done! Now go experiment with other instruments on the ADP3450! (of which there are many!)<\/li>\n<\/ul>\n<p><!-- notionvc: b1f8f248-1675-4934-9000-57e59e5cb962 --><\/p>\n<p>To follow along with Shrouk, check out the tutorial on our Youtube channel: <a href=\"https:\/\/youtu.be\/yCoqerUw7Vo\">https:\/\/youtu.be\/yCoqerUw7Vo<\/a><\/p>\n<p><!-- notionvc: e513acf2-66da-40ed-977b-97160e4340d2 --><\/p>\n<p><!-- notionvc: 239f3113-07a2-4a51-b75e-2215e779567e --><\/p>\n<p><!-- notionvc: ae1fa07b-83ea-4224-b29e-7efba688a773 --><\/p>\n<div class='watch-action'><div class='watch-position align-left'><div class='action-like'><a class='lbg-style6 like-30457 jlk' data-task='like' data-post_id='30457' data-nonce='8896bc70a6' rel='nofollow'><img src='https:\/\/digilent.com\/blog\/wp-content\/plugins\/wti-like-post-pro\/images\/pixel.gif' title='Like' \/><span class='lc-30457 lc'>+1<\/span><\/a><\/div><div class='action-unlike'><a class='unlbg-style6 unlike-30457 jlk' data-task='unlike' data-post_id='30457' data-nonce='8896bc70a6' rel='nofollow'><img src='https:\/\/digilent.com\/blog\/wp-content\/plugins\/wti-like-post-pro\/images\/pixel.gif' title='Unlike' \/><span class='unlc-30457 unlc'>0<\/span><\/a><\/div><\/div> <div class='status-30457 status align-left'><\/div><\/div><div class='wti-clear'><\/div>","protected":false},"excerpt":{"rendered":"<p>As a purely hardware engineer who primarily focuses on schematics, PCB layout, and the inevitable hardware test and debug, Python scripts and Linux scare the life out of me. At &hellip; <\/p>\n","protected":false},"author":66,"featured_media":30475,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[20,1563,1561],"tags":[4625,4372,4352,1452,4353,4616,4626,4627,144],"ppma_author":[4508],"class_list":["post-30457","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-products","category-guide","category-applications","tag-4625","tag-adp","tag-adp3450","tag-guide","tag-linux","tag-linux-mode","tag-python","tag-tests","tag-tutorial-2"],"jetpack_featured_media_url":"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2024\/01\/The-Hardware-Engineers-Guide-to-Running-Tests-in-Linux-Mode-on-ADP3450.png","jetpack_sharing_enabled":true,"authors":[{"term_id":4508,"user_id":66,"is_guest":0,"slug":"selattar","display_name":"Shrouk El-Attar","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/69127a2e3e75c6545785742713efb3d0104009fe78f7b68fc9c4149f77308483?s=96&d=mm&r=g","1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":"","9":"","10":""}],"post_mailing_queue_ids":[],"_links":{"self":[{"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/posts\/30457","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/users\/66"}],"replies":[{"embeddable":true,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/comments?post=30457"}],"version-history":[{"count":8,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/posts\/30457\/revisions"}],"predecessor-version":[{"id":30465,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/posts\/30457\/revisions\/30465"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/media\/30475"}],"wp:attachment":[{"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/media?parent=30457"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/categories?post=30457"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/tags?post=30457"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=30457"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}