Specific Process Knowledge/Etch/DRIE-Pegasus/Notation: Difference between revisions

From LabAdviser
Jmli (talk | contribs)
No edit summary
Jmli (talk | contribs)
No edit summary
Line 67: Line 67:
| colspan="4" | Temperature 20 degs, HBC 10 torr
| colspan="4" | Temperature 20 degs, HBC 10 torr
|}
|}
<syntaxhighlight lang="python" line>
import SEM_API_fix as SEM_API
import matplotlib.pyplot as plt
import numpy as np
import time
import math
from contextlib import contextmanager
import tkinter as tk
from tkinter import StringVar
class Col_WD:
    def __init__(self, inputImages, inputOverlaps):
        self.var_WD0_str = StringVar()
        self.var_WD_0 = 1
        self.var_WDext_str = StringVar()
        self.var_WD_ext = 1
        self.var_WDwob_str = StringVar()
        self.var_Unshake_str = StringVar()
        self.var_inputImages = inputImages 
        self.var_inputOverlaps = inputOverlaps 
    def button_WD0set(self):
        with SEM_API.SEM_API("local") as sem:
            self.var_WD_0 = sem.GetValue("AP_WD")
            self.var_WD0_str.set("WD_0="+ str(round(self.var_WD_0*1000,3))+"mm")
   
    def button_WDextSet(self):
        with SEM_API.SEM_API("local") as sem:
            WDget = sem.GetValue("AP_WD")
            self.var_WD_ext = abs(round((WDget-self.var_WD_0)/self.var_WD_0*100,3))
            self.var_WDext_str.set("WD_range="+ str(self.var_WD_ext)+"%")
   
    def button_WDwob(self):
        # Set the initial conditions
        set_conditions()
        # Calculate the total number of images and the working distance factor
        total_images = int(round(self.var_inputImages))
        wd_factor = self.var_WD_ext / 100
        overlap_difference = self.var_inputImages - self.var_inputOverlaps
        # Use context manager to handle SEM_API connection once
        with SEM_API.SEM_API("local") as sem:
            for i in range(total_images):
                # Calculate the working distance once per iteration
                wd = self.var_WD_0 * (1 + wd_factor * math.sin(2 * math.pi * i / overlap_difference))
                sem.SetValue("AP_WD", wd)
                # Call the function to acquire the image
                acquire_image()
                # Update the progress
                print(f"# {i + 1} of {total_images} done")
        # Update the GUI
        self.var_WDwob_str.set("Shake completed")
   
    def button_Unshake(self):
        self.var_Unshake_str.set("Unshaking no working")
class Col_AP:
    def __init__(self, inputImages, inputOverlaps):
        self.var_AP0_str = StringVar()
        self.var_AP_0 = 1
        self.var_APext_str = StringVar()
        self.var_APext = 1
        self.var_APwobX_str = StringVar()
        self.var_APwobY_str = StringVar()
        self.var_inputImages = inputImages 
        self.var_inputOverlaps = inputOverlaps
       
    def button_AP0(self):
        with SEM_API.SEM_API("local") as sem:
            self.var_AP_0 = sem.GetValue("AP_APERTURE_ALIGN_X")
            self.var_WD0_str.set("WD_0="+ str(round(self.var_WD_0*1000,3))+"mm")
        self.var_AP0_str.set("Button 5 Pressed")
   
    def button_APext(self):
        self.var_APext_str.set("Button 6 Pressed")
   
    def button_APwobX(self):
        self.var_APwobX_str.set("Button 7 Pressed")
   
    def button_APwobY(self):
       
        self.var_APwobY_str.set("Button 8 Pressed")
class Col_Stig:
    def __init__(self, inputImages, inputOverlaps):
        self.var1 = StringVar()
        self.var2 = StringVar()
        self.var3 = StringVar()
        self.var4 = StringVar()
        self.inputImages = inputImages 
        self.inputOverlaps = inputOverlaps
    def button_Stig0(self):
        #sem.GetValue("AP_STIG_X")
        self.var1.set("Button 9 Pressed")
   
    def button_Stigext(self):
        self.var2.set("Button 10 Pressed")
   
    def button_StigwobX(self):
        self.var3.set("Button 11 Pressed")
   
    def button_StigwobY(self):
        self.var4.set("Button 12 Pressed")
def set_conditions():
    with SEM_API.SEM_API("local") as sem:
        sem.SetValue("DP_IMAGE_STORE",1)
        sem.Execute("CMD_MODE_NORMAL")
        sem.Execute("CMD_SCANRATE8")       
        sem.Execute("CMD_UNFREEZE_ALL")
def acquire_image():
    # Call to the SEM API has been done prior to this function
    with SEM_API.SEM_API("local") as sem:
        sem.Execute("CMD_UNFREEZE_ALL")
        time.sleep(0.1)  # wait briefly before freezing
        sem.Execute("CMD_FREEZE_ALL")
   
        # Check for the beam to be unblanked, avoiding excessive waiting
        while sem.GetState("DP_BEAM_BLANKED") == "No":
            time.sleep(1)  # reduced wait time in the loop for efficiency
   
        # Execute the photo-taking command
        sem.Execute("CMD_TAKE_PHOTO")
def create_gui():
    root = tk.Tk()
    root.title("SEM Shaker 2")
    # Input fields with labels
    tk.Label(root, text="# images:").grid(row=0, column=0)
    inputImages_entry = tk.Entry(root)
    inputImages_entry.grid(row=0, column=1)
    tk.Label(root, text="# overlaps:").grid(row=1, column=0)
    inputOverlaps_entry = tk.Entry(root)
    inputOverlaps_entry.grid(row=1, column=1)
    # Function to update input values
    def update_inputs():
        try:
            inputImages = float(inputImages_entry.get())
            inputOverlaps = float(inputOverlaps_entry.get())
        except ValueError:
            return
    # Create instances of each column class
        column1 = Col_WD(inputImages, inputOverlaps)
        column2 = Col_AP(inputImages, inputOverlaps)
        column3 = Col_Stig(inputImages, inputOverlaps)
    # Buttons and corresponding labels
        #buttons = [
        #    [(column1.button_WD0set, column1.var_WD0_str), (column2.button_AP0, column2.var_AP0_str), (column3.button_Stig0, column3.var1)],
        #    [(column1.button_WDextSet, column1.var_WDext_str), (column2.button_APext, column2.var_APext_str), (column3.button_Stigext, column3.var2)],
        #    [(column1.button_WDwob, column1.var_WDwob_str), (column2.button_APwobX, column2.var_APwobX_str), (column3.button_StigwobX, column3.var3)],
        #    [(column1.button_Unshake, column1.var_Unshake_str), (column2.button_APwobY, column2.var_APwobY_str), (column3.button_StigwobY, column3.var4)]
        #]
        button = tk.Button(root, text=f"WD_0", command=column1.button_WD0set)
        button.grid(row=3, column=1)
        label = tk.Label(root, textvariable=column1.var_WD0_str)
        label.grid(row=7, column=1)
        button = tk.Button(root, text=f"AP_0", command=column2.button_AP0)
        button.grid(row=3, column=2)
        label = tk.Label(root, textvariable=column2.var_AP0_str)
        label.grid(row=7, column=2)
        button = tk.Button(root, text=f"Stig_0", command=column3.button_Stig0)
        button.grid(row=3, column=3)
        label = tk.Label(root, textvariable=column3.var1)
        label.grid(row=7, column=3)
        button = tk.Button(root, text=f"WD_rng", command=column1.button_WDextSet)
        button.grid(row=4, column=1)
        label = tk.Label(root, textvariable=column1.var_WDext_str)
        label.grid(row=8, column=1)
        button = tk.Button(root, text=f"AP_rng", command=column2.button_APext)
        button.grid(row=4, column=2)
        label = tk.Label(root, textvariable=column2.var_APext_str)
        label.grid(row=8, column=2)
        button = tk.Button(root, text=f"Stig_rng", command=column3.button_Stigext)
        button.grid(row=4, column=3)
        label = tk.Label(root, textvariable=column3.var2)
        label.grid(row=8, column=3)
        button = tk.Button(root, text=f"Shake WD", command=column1.button_WDwob)
        button.grid(row=5, column=1)
        label = tk.Label(root, textvariable=column1.var_WDwob_str)
        label.grid(row=9, column=1)
        button = tk.Button(root, text=f"Shake AP X", command=column2.button_APwobX)
        button.grid(row=5, column=2)
        label = tk.Label(root, textvariable=column2.var_APwobX_str)
        label.grid(row=9, column=2)
        button = tk.Button(root, text=f"Shake Stig X", command=column3.button_StigwobX)
        button.grid(row=5, column=3)
        label = tk.Label(root, textvariable=column3.var3)
        label.grid(row=9, column=3)
        button = tk.Button(root, text=f"Unshake", command=column1.button_Unshake)
        button.grid(row=6, column=1)
        label = tk.Label(root, textvariable=column1.var_Unshake_str)
        label.grid(row=10, column=1)
        button = tk.Button(root, text=f"Shake AP Y", command=column2.button_APwobY)
        button.grid(row=6, column=2)
        label = tk.Label(root, textvariable=column2.var_APwobY_str)
        label.grid(row=10, column=2)
        button = tk.Button(root, text=f"Shake Stig Y", command=column3.button_StigwobY)
        button.grid(row=6, column=3)
        label = tk.Label(root, textvariable=column3.var4)
        label.grid(row=10, column=3)
    # Button to update inputs and create button actions
    update_button = tk.Button(root, text="Update Inputs", command=update_inputs)
    update_button.grid(row=2, column=1)
    root.mainloop()
#if __name__ == "__main__":
create_gui()
</syntaxhighlight>

Revision as of 12:23, 22 September 2024


Unless otherwise stated, the content of this page was created by the dry etch group at DTU Nanolab

How to read the notation on process recipes

Look at two examples from the etch cycle of Step1 of the Process A shown in bold below:

  1. The Platen power has the setting 120 >> 140 (1.5s) 45 - it is to be interpreted as:
    1. In the first 1.5 seconds of the every cycle the platen power has a value that is ramped (indicated by >>) from 120 W initially to 150 W in the end
    2. During the remainder of the cycle the platen power is kept constant at 45 W.
  2. The Pressure has the setting 25 (1.5 s) 90 >> 150 - it is to be interpreted as:
    1. In the first 1.5 seconds the pressure is constant at 25 mtorr.
    2. During the remainder of the cycle the pressure has i higher value that is ramped from 90 initially to 150 mtorr in the last etch cycle.


Process A recipe
Step 1 Step 2
Parameter Etch Dep Etch Dep
Gas flow (sccm) SF6 350 (1.5 s) 550 C4F8 200 SF6 350 (1.5 s) 550 C4F8 200
Cycle time (secs) 7.0 4.0 7.0 4.0
Pressure (mtorr) 25 (1.5 s) 90 >> 150 25 25 (1.5 s) 150 25
Coil power (W) 2800 2000 2800 2000
Platen power (W) 120 >> 140 (1.5) 45 0 140 (1.5) 45 0
Cycles 11 (keep fixed) 44 (vary this)
Common Temperature 20 degs, HBC 10 torr



import SEM_API_fix as SEM_API
import matplotlib.pyplot as plt
import numpy as np
import time 
import math
from contextlib import contextmanager

import tkinter as tk
from tkinter import StringVar

class Col_WD:
    def __init__(self, inputImages, inputOverlaps):
        self.var_WD0_str = StringVar()
        self.var_WD_0 = 1
        self.var_WDext_str = StringVar()
        self.var_WD_ext = 1
        self.var_WDwob_str = StringVar()
        self.var_Unshake_str = StringVar()
        self.var_inputImages = inputImages  
        self.var_inputOverlaps = inputOverlaps  

    def button_WD0set(self):
        with SEM_API.SEM_API("local") as sem:
            self.var_WD_0 = sem.GetValue("AP_WD")
            self.var_WD0_str.set("WD_0="+ str(round(self.var_WD_0*1000,3))+"mm")
    
    def button_WDextSet(self):
        with SEM_API.SEM_API("local") as sem:
            WDget = sem.GetValue("AP_WD")
            self.var_WD_ext = abs(round((WDget-self.var_WD_0)/self.var_WD_0*100,3))
            self.var_WDext_str.set("WD_range="+ str(self.var_WD_ext)+"%")
    
    def button_WDwob(self):
        # Set the initial conditions
        set_conditions()
        # Calculate the total number of images and the working distance factor
        total_images = int(round(self.var_inputImages))
        wd_factor = self.var_WD_ext / 100
        overlap_difference = self.var_inputImages - self.var_inputOverlaps

        # Use context manager to handle SEM_API connection once
        with SEM_API.SEM_API("local") as sem:
            for i in range(total_images):
                # Calculate the working distance once per iteration
                wd = self.var_WD_0 * (1 + wd_factor * math.sin(2 * math.pi * i / overlap_difference))
                sem.SetValue("AP_WD", wd)
                # Call the function to acquire the image
                acquire_image() 
                # Update the progress
                print(f"# {i + 1} of {total_images} done")
        # Update the GUI
        self.var_WDwob_str.set("Shake completed")
    
    def button_Unshake(self):
        self.var_Unshake_str.set("Unshaking no working")

class Col_AP:
    def __init__(self, inputImages, inputOverlaps):
        self.var_AP0_str = StringVar()
        self.var_AP_0 = 1
        self.var_APext_str = StringVar()
        self.var_APext = 1
        self.var_APwobX_str = StringVar()
        self.var_APwobY_str = StringVar()
        self.var_inputImages = inputImages  
        self.var_inputOverlaps = inputOverlaps 
        
    def button_AP0(self):
        with SEM_API.SEM_API("local") as sem:
            self.var_AP_0 = sem.GetValue("AP_APERTURE_ALIGN_X")
            self.var_WD0_str.set("WD_0="+ str(round(self.var_WD_0*1000,3))+"mm")

        self.var_AP0_str.set("Button 5 Pressed")
    
    def button_APext(self):
        self.var_APext_str.set("Button 6 Pressed")
    
    def button_APwobX(self):
        self.var_APwobX_str.set("Button 7 Pressed")
    
    def button_APwobY(self):
        
        self.var_APwobY_str.set("Button 8 Pressed")

class Col_Stig:
    def __init__(self, inputImages, inputOverlaps):
        self.var1 = StringVar()
        self.var2 = StringVar()
        self.var3 = StringVar()
        self.var4 = StringVar()
        self.inputImages = inputImages  
        self.inputOverlaps = inputOverlaps

    def button_Stig0(self):
        #sem.GetValue("AP_STIG_X")
        self.var1.set("Button 9 Pressed")
    
    def button_Stigext(self):
        self.var2.set("Button 10 Pressed")
    
    def button_StigwobX(self):
        self.var3.set("Button 11 Pressed")
    
    def button_StigwobY(self):
        self.var4.set("Button 12 Pressed")

def set_conditions():
    with SEM_API.SEM_API("local") as sem:
        sem.SetValue("DP_IMAGE_STORE",1)
        sem.Execute("CMD_MODE_NORMAL")
        sem.Execute("CMD_SCANRATE8")        
        sem.Execute("CMD_UNFREEZE_ALL")

def acquire_image():
    # Call to the SEM API has been done prior to this function
    with SEM_API.SEM_API("local") as sem:
        sem.Execute("CMD_UNFREEZE_ALL")
        time.sleep(0.1)  # wait briefly before freezing
        sem.Execute("CMD_FREEZE_ALL")
    
        # Check for the beam to be unblanked, avoiding excessive waiting
        while sem.GetState("DP_BEAM_BLANKED") == "No":
            time.sleep(1)  # reduced wait time in the loop for efficiency
    
        # Execute the photo-taking command
        sem.Execute("CMD_TAKE_PHOTO") 

def create_gui():
    root = tk.Tk()
    root.title("SEM Shaker 2")

    # Input fields with labels
    tk.Label(root, text="# images:").grid(row=0, column=0)
    inputImages_entry = tk.Entry(root)
    inputImages_entry.grid(row=0, column=1)

    tk.Label(root, text="# overlaps:").grid(row=1, column=0)
    inputOverlaps_entry = tk.Entry(root)
    inputOverlaps_entry.grid(row=1, column=1)

    # Function to update input values
    def update_inputs():
        try:
            inputImages = float(inputImages_entry.get())
            inputOverlaps = float(inputOverlaps_entry.get())
        except ValueError:
            return

    # Create instances of each column class
        column1 = Col_WD(inputImages, inputOverlaps)
        column2 = Col_AP(inputImages, inputOverlaps)
        column3 = Col_Stig(inputImages, inputOverlaps)

    # Buttons and corresponding labels
        #buttons = [
        #    [(column1.button_WD0set, column1.var_WD0_str), (column2.button_AP0, column2.var_AP0_str), (column3.button_Stig0, column3.var1)],
        #    [(column1.button_WDextSet, column1.var_WDext_str), (column2.button_APext, column2.var_APext_str), (column3.button_Stigext, column3.var2)],
        #    [(column1.button_WDwob, column1.var_WDwob_str), (column2.button_APwobX, column2.var_APwobX_str), (column3.button_StigwobX, column3.var3)],
        #    [(column1.button_Unshake, column1.var_Unshake_str), (column2.button_APwobY, column2.var_APwobY_str), (column3.button_StigwobY, column3.var4)]
        #]

        button = tk.Button(root, text=f"WD_0", command=column1.button_WD0set)
        button.grid(row=3, column=1)
        label = tk.Label(root, textvariable=column1.var_WD0_str)
        label.grid(row=7, column=1)

        button = tk.Button(root, text=f"AP_0", command=column2.button_AP0)
        button.grid(row=3, column=2)
        label = tk.Label(root, textvariable=column2.var_AP0_str)
        label.grid(row=7, column=2)

        button = tk.Button(root, text=f"Stig_0", command=column3.button_Stig0)
        button.grid(row=3, column=3)
        label = tk.Label(root, textvariable=column3.var1)
        label.grid(row=7, column=3)

        button = tk.Button(root, text=f"WD_rng", command=column1.button_WDextSet)
        button.grid(row=4, column=1)
        label = tk.Label(root, textvariable=column1.var_WDext_str)
        label.grid(row=8, column=1)

        button = tk.Button(root, text=f"AP_rng", command=column2.button_APext)
        button.grid(row=4, column=2)
        label = tk.Label(root, textvariable=column2.var_APext_str)
        label.grid(row=8, column=2)

        button = tk.Button(root, text=f"Stig_rng", command=column3.button_Stigext)
        button.grid(row=4, column=3)
        label = tk.Label(root, textvariable=column3.var2)
        label.grid(row=8, column=3)

        button = tk.Button(root, text=f"Shake WD", command=column1.button_WDwob)
        button.grid(row=5, column=1)
        label = tk.Label(root, textvariable=column1.var_WDwob_str)
        label.grid(row=9, column=1)

        button = tk.Button(root, text=f"Shake AP X", command=column2.button_APwobX)
        button.grid(row=5, column=2)
        label = tk.Label(root, textvariable=column2.var_APwobX_str)
        label.grid(row=9, column=2)

        button = tk.Button(root, text=f"Shake Stig X", command=column3.button_StigwobX)
        button.grid(row=5, column=3)
        label = tk.Label(root, textvariable=column3.var3)
        label.grid(row=9, column=3)

        button = tk.Button(root, text=f"Unshake", command=column1.button_Unshake)
        button.grid(row=6, column=1)
        label = tk.Label(root, textvariable=column1.var_Unshake_str)
        label.grid(row=10, column=1)

        button = tk.Button(root, text=f"Shake AP Y", command=column2.button_APwobY)
        button.grid(row=6, column=2)
        label = tk.Label(root, textvariable=column2.var_APwobY_str)
        label.grid(row=10, column=2)

        button = tk.Button(root, text=f"Shake Stig Y", command=column3.button_StigwobY)
        button.grid(row=6, column=3)
        label = tk.Label(root, textvariable=column3.var4)
        label.grid(row=10, column=3)

    # Button to update inputs and create button actions
    update_button = tk.Button(root, text="Update Inputs", command=update_inputs)
    update_button.grid(row=2, column=1)

    root.mainloop()

#if __name__ == "__main__":
create_gui()