-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathchuck_poi_stepping.py
128 lines (104 loc) · 4.95 KB
/
chuck_poi_stepping.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
from sentio_prober_control.Sentio.ProberSentio import SentioProber
from sentio_prober_control.Sentio.Enumerations import ChuckSite, Stage, PoiReferenceXy, Module, TestSelection, RoutingStartPoint, RoutingPriority
#
# This example will demonstrate how to navigate the chuck with a point of interest list (POI)
#
# This script will set up a list with POI spread across the die. It will then use the chuck to step
# over all POI in the list for all active dies
#
# Required Preconditions to run this script
# - You need a system with a motorized chuck
# - a chuck home position must be set
#
def check_preconditions(prober : SentioProber) -> None:
# 1.) Check whether the machine has a motorized chuck.
if not prober.has_chuck_xyz():
raise Exception("This script requires a motorized chuck in order to run!")
# 2.) Check whether the home position of the chuck wafer site is set
hasHome, hasContact, overtravelActive, vacuumOn = prober.get_chuck_site_status(ChuckSite.Wafer)
if not hasHome:
raise Exception("Home position must be set to execute this script!")
# 3.) Check whether the die reference position is set.
# This script requires a valid die reference position. The die reference position is the distance from the corner
# of the die to the pad. Only when it is set can SENTIO know where the pad is located inside the die.
if not prober.map.die_reference_is_set():
raise Exception("The die reference position is not trained! Therefore SENTIO does know where the home position is located inside the die!")
#
# Distribute 9 POI across the die. The POI layout will look like shown here:
#
# 1-------------2-------------3
# | |
# | |
# | |
# | |
# | |
# 4 5 6
# | |
# | |
# | |
# | |
# | |
# 7-------------8-------------9
#
# - Numbers indicate the POI index and their position.
# - POI number 5 is at the center of the die
def set_poi(prober : SentioProber) -> None:
# 1.) get the die Size
sx, sy = prober.map.get_index_size()
print(f"Die size is {sx}, {sy} µm")
# IMPORTANT:
# The POI MUST be inside of the Die! If you set up POI at the edge of the wafer you may experience undefined
# behavior!
# - If you place a poi on a die edge it cannot be assigned to a specific die because its
# position is ambiguous.
# - The chuck can be positioned with +/- 1..2 microns accuracy. This area should be avoided when setting poi!
# - Sentio is using the chuck position to determine the current die. If the chuck is closer than 1 µm to a die edge
# SENTIO may incorrectly determine that it is in the neighboring die due to limited chuck accuracy!
# - In this example I avoid the trouble by assuming the die is slightly smaller than it really is.
edge_margin = 4
sx -= edge_margin # 2 µm on the sides of the die are the poi "no go" zone
sy -= edge_margin # 2 µm on the sides of the die are the poi "no go" zone
die_center_x = sx / 2
die_center_y = sy / 2
# Create this many rows and columns of POI.
ncols = 3
nrows = 3
dx = sx / (ncols-1)
dy = sy / (nrows-1)
print(f"Creating {ncols * nrows} points of interest:")
# Set up a poi map for the chuck which i using the die center as a reference position
prober.map.poi.reset(Stage.Chuck, PoiReferenceXy.DieCenter)
ct = 0
for r in range(-nrows//2, nrows//2):
for c in range(-ncols//2, ncols//2):
ct = ct + 1
poi_x = die_center_x + c * dx
poi_y = die_center_y + r * dy
print(f"Poi {ct} at {poi_x}, {poi_y} µm")
prober.map.poi.add(poi_x, poi_y, f"poi_{ct}")
def main() -> None:
prober = SentioProber.create_prober("tcpip", "127.0.0.1:35555")
check_preconditions(prober)
set_poi(prober)
prober.select_module(Module.Wafermap)
# Stepping loop:
# - Step over all active dies. For each die step over all poi
# - for this example we will NOT go into contact!
prober.map.path.select_dies(TestSelection.All)
prober.map.path.set_routing(RoutingStartPoint.UpperRight, RoutingPriority.ColBiDir)
num_poi = prober.map.poi.get_num()
prober.map.step_first_die()
while True:
# Variant 1: Step over all POI (comment Variant 2 to us this)
selected_poi : range | list[str] = range(0, num_poi)
# Variant 2: Step over a selection of POI
selected_poi = [ 'poi_1', 'poi_5', 'poi_9']
# Do the poi stepping
for i in selected_poi:
prober.map.poi.step(i)
# Step to the next die
prober.map.step_next_die()
if prober.map.end_of_route():
break
if __name__ == "__main__":
main()