Updated Metrology_Services to support importing Tencor data into CLEAN_INSP records associated with WM_OUT lots.

This commit is contained in:
Infineon\StieberD
2025-11-11 16:32:44 -07:00
parent 169fabdac6
commit 77d2f5f6ab
2 changed files with 240 additions and 196 deletions

View File

@ -2089,18 +2089,19 @@ end service
Service ImportTencorData(RunData)
ErrorMessage = ''
Machine = 'Tencor'
Timestamp = RunData<9>
HazeAvg = RunData<10>
RDSKeyID = RunData<28>
LegacyLotId = RunData<28>
ScanRecipe = RunData<30>
SoDAvg = RunData<39>
SoDMax = RunData<40>
SoDMin = RunData<41>
ScanTool = RunData<43>
Swap '%' with ' ' in ScanTool
LegacyLotId@ = RDSKeyID
LegacyLotId@ = LegacyLotId
Convert @Lower_Case to @Upper_Case in ScanTool
Swap ' AM' with 'AM' in Timestamp
@ -2112,7 +2113,7 @@ Service ImportTencorData(RunData)
SODVals = ''
SortVals = ''
SODStartTime = Time()
SODWaferArray = QA_Services('GetSODPerWafer', RDSKeyID, ScanRecipe, Timestamp)
SODWaferArray = QA_Services('GetSODPerWafer', LegacyLotId, ScanRecipe, Timestamp)
SODStopTime = Time()
TimeTaken = SODStopTime - SODStartTime
LogData = ''
@ -2121,20 +2122,61 @@ Service ImportTencorData(RunData)
LogData<3> = LegacyLotId@
LogData<4> = 'Time taken to import SOD data: ':TimeTaken:' seconds.'
Logging_Services('AppendLog', objSODPerfLog, LogData, @RM, @FM)
If SODWaferArray NE '' then
WaferNos = SODWaferArray<1>
SODVals = SODWaferArray<2>
SortVals = SODWaferArray<3>
For each WaferNo in WaferNos using @VM
If WaferNo NE '' then QA_Services('PostWaferImageRequest', RDSKeyID, WaferNo, ScanRecipe)
If WaferNo NE '' then QA_Services('PostWaferImageRequest', LegacyLotId, WaferNo, ScanRecipe)
Next Wafer
end
LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', RDSKeyID, 'RDS')
Swap '.' with '*' in LegacyLotId ; // Swap . with * used on labels
Swap 'O' with '' in LegacyLotId ; // Remove 'O' prefix used on labels for WM_OUT lots
Begin Case
Case RowExists('RDS', LegacyLotId)
LegacyLotType = 'RDS'
ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', LegacyLotId)
If Error_Services('NoError') then
CIKeyStages = ReactRunRec<REACT_RUN_CI_STAGE$>
CIKeyIDs = ReactRunRec<REACT_RUN_CI_NO$>
PSN = Xlate('RDS', LegacyLotId, 'PROD_SPEC_ID', 'X')
If PSN EQ '' then
ErrorMessage = 'Error in ':Service:' service. Null PSN returned from RDS ':LegacyLotId
Metrology_Services('LogResults', LegacyLotId, Machine, 'UID001', Service : ' : Error reading PSN from RDS.')
end
end else
ErrorMessage = Error_Services('GetMessage')
Metrology_Services('LogResults', LegacyLotId, Machine, 'UID001', Service : ' : ' : ErrorMessage)
end
Case RowExists('WM_OUT', LegacyLotId)
LegacyLotType = 'WM_OUT'
CIKeyStages = ''
CIKeyIDs = Xlate('WM_OUT', LegacyLotId, 'EPO_CI_NO', 'X')
If CIKeyIDs NE '' then CIKeyStages = Xlate('CLEAN_INSP', CIKeyIDs, CLEAN_INSP_STAGE$, 'X')
PSN = Xlate('WM_OUT', LegacyLotId, 'PS_NO', 'X')
If PSN EQ '' then
ErrorMessage = 'Error in ':Service:' service. Null PSN returned from WM_OUT ':LegacyLotId
Metrology_Services('LogResults', LegacyLotId, Machine, 'UID001', Service : ' : Error reading PSN from WM_OUT.')
end
Case Otherwise$
LegacyLotType = ''
ErrorMessage = 'Error in ':Service:' services. Legacy lot id not found in RDS or WM_OUT tables.'
End Case
LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', LegacyLotId, LegacyLotType)
If LotId NE '' then
If DCount(LotId, @VM) EQ 1 then
// Import into new metrology data structures
MetTestId = Met_Test_Services('CreateMetTest', LotId, RDSKeyID, '', ScanRecipe)
MetTestId = Met_Test_Services('CreateMetTest', LotId, LegacyLotId, '', ScanRecipe)
If Error_Services('NoError') then
Met_Test_Services('SetPropsAndLimits', MetTestId)
If Error_Services('HasError') then
@ -2187,17 +2229,12 @@ Service ImportTencorData(RunData)
end
end else
Swap @VM with ',' in LotId
ErrorMsg = 'Error in ':Service:' service. Number of lot ids returned does not equal 1. Lot ids: ':LotId
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : ErrorMsg)
MetTestErrorMessage = 'Error in ':Service:' service. Number of lot ids returned does not equal 1. Lot ids: ':LotId
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : MetTestErrorMessage)
end
end
If RowExists('RDS', RDSKeyID) then
// Try to read the CleanInsp datarow. Use this to identify the RDSKeyID.
ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSKeyID)
If Error_Services('NoError') then
// Get the PSN to determine if this recipe is part of the LWI stage or the POST stage.
PSN = Xlate('RDS', RDSKeyID, 'PROD_SPEC_ID', 'X')
If (ErrorMessage EQ '') then
PRSStageKeys = Xlate('PROD_SPEC', PSN, 'PRS_STAGE_KEY', 'X')
StageFound = False$
Stage = ''
@ -2208,8 +2245,6 @@ Service ImportTencorData(RunData)
Stage = Field(PRSStageKey, '*', 2, 1)
end
Next PRSStageKey
CIKeyStages = ReactRunRec<REACT_RUN_CI_STAGE$>
CIKeyIDs = ReactRunRec<REACT_RUN_CI_NO$>
Locate Stage in CIKeyStages using @VM setting vPos then
// Stage is prescribed or user created the record from the UI.
CIKeyID = CIKeyIDs<0, vPos>
@ -2255,14 +2290,14 @@ Service ImportTencorData(RunData)
Database_Services('WriteDataRow', 'CLEAN_INSP', CIKeyID, CleanInspRec, True$, False$, True$)
end else
ErrorMessage = 'Tencor recipe ' : ScanRecipe : ' not found in SurfScan recipe list.'
Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : ErrorMessage)
Metrology_Services('LogResults', LegacyLotId, Machine, 'UID001', Service : ' : ' : ErrorMessage)
// Set recipe mismatch flag for MFS purposes
CleanInspRec<CLEAN_INSP_SCAN_RECIPE_MISMATCH$> = ScanRecipe
Database_Services('WriteDataRow', 'CLEAN_INSP', CIKeyID, CleanInspRec, True$, False$, True$)
end
end else
ErrorMessage = 'Scan Recipe is missing.'
Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : ErrorMessage)
Metrology_Services('LogResults', LegacyLotId, Machine, 'UID001', Service : ' : ' : ErrorMessage)
end
Database_Services('ReleaseKeyIDLock', 'CLEAN_INSP', CIKeyID)
end else
@ -2270,54 +2305,61 @@ Service ImportTencorData(RunData)
// metrology file is not deleted so that the service can try to import it
// again once the lock is released.
ErrorMessage = 'Error in service ':Service:'. Failed to lock CLEAN_INSP record: ':CIKeyID:'.'
Metrology_Services('LogResults', RDSKeyID, Machine, 'UID002', Service : ' : ' : ErrorMessage)
Metrology_Services('LogResults', LegacyLotId, Machine, 'UID002', Service : ' : ' : ErrorMessage)
end
end else
ErrorMessage = 'CI Key ID is missing.'
Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : ErrorMessage)
Metrology_Services('LogResults', LegacyLotId, Machine, 'UID001', Service : ' : ' : ErrorMessage)
end
end else
// Added 8/13/2020 JRO
// We can enter in some conditional logic here for Production UAT
// If statement to gate from production below
// Ad-hoc POST stage SURFSCAN logic
PostStartTime = Time()
if Indexc(ScanRecipe, 'POST', 1) then
// Locate 'POST' in ScanRecipe Using "" setting pPos then
ReactRunRec = Xlate('REACT_RUN',RDSKeyID, '', 'X')
WONo = ReactRunRec<REACT_RUN_WO_NO$>;//WONo
WOStep = ReactRunRec<REACT_RUN_WO_STEP$>;//WOStep
CassNo = ReactRunRec<REACT_RUN_CASS_NO$>;//CassNo
Stage = 'POST';//Stages
PSNo = XLATE('RDS',RDSKeyID,RDS_PROD_SPEC_ID$,'X');//PSNo
DefectSpec = Xlate('PRS_STAGE', PSNo : '*LWI', PRS_STAGE_SURF_DEFECTS$, 'X');//Since there is no set spec for a non-existent stage we need to take one from the unloading step.
HazeSpec = Xlate('PRS_STAGE', PSNo : '*LWI', PRS_STAGE_SURF_HAZE$, 'X');//Since there is no set spec for a non-existent stage we need to take one from the unloading step.
if IndexC(ScanRecipe, 'POST', 1) then
Begin Case
Case LegacyLotType EQ 'RDS'
ReactRunRec = Xlate('REACT_RUN', LegacyLotId, '', 'X')
WONo = ReactRunRec<REACT_RUN_WO_NO$>
WOStep = ReactRunRec<REACT_RUN_WO_STEP$>
CassNo = ReactRunRec<REACT_RUN_CASS_NO$>
Case LegacyLotType EQ 'WM_OUT'
WONo = Field(LegacyLotId, '*', 1, 1)
WOStep = Field(LegacyLotId, '*', 2, 1)
CassNo = Field(LegacyLotId, '*', 3, 1)
Case Otherwise$
ErrorMessage = 'Error in ':Service:' services. Invalid LegacyLotType.'
End Case
Stage = 'POST'
DefectSpec = Xlate('PRS_STAGE', PSN : '*LWI', PRS_STAGE_SURF_DEFECTS$, 'X');//Since there is no set spec for a non-existent stage we need to take one from the unloading step.
HazeSpec = Xlate('PRS_STAGE', PSN : '*LWI', PRS_STAGE_SURF_HAZE$, 'X');//Since there is no set spec for a non-existent stage we need to take one from the unloading step.
// Check if CI was created already(usually during cleans) JRO-9-28
CIStages = ReactRunRec<REACT_RUN_CI_STAGE$>
Locate 'POST' in CIStages using @VM setting sPos then
Locate 'POST' in CIKeyStages using @VM setting sPos then
// Existing POST CI record found, fetch it.
CINo = ReactRunRec<REACT_RUN_CI_NO$,sPos>
CINo = CIKeyIDs<0, sPos>
CleanInspRec = Xlate('CLEAN_INSP', CINo,'','X')
IF CleanInspRec<CLEAN_INSP_SCAN_SOD_PER_WAFER$> NE '' THEN
// Append a value mark to the end of the field so that we can add another set of data
CleanInspRec<CLEAN_INSP_SCAN_SOD_PER_WAFER$> = CleanInspRec<CLEAN_INSP_SCAN_SOD_PER_WAFER$> : @VM
END
exists = True$
Exists = True$
end else
// No Exisiting POST CI record found, Create new CI record
exists = False$
Exists = False$
oCIParms = ''
oCIParms = WONo:@RM
oCIParms := WOStep:@RM
oCIParms := CassNo:@RM
oCIParms := Stage:@RM
oCIParms := RDSKeyID:@RM
oCIParms := PSNo:@RM
If LegacyLotType EQ 'RDS' then oCIParms := LegacyLotId:@RM
oCIParms := PSN:@RM
CleanInspRec = ''
CleanInspRec<CLEAN_INSP_WO_NO$> = WONo
CleanInspRec<CLEAN_INSP_WO_STEP$> = WOStep
CleanInspRec<CLEAN_INSP_CASS_NO$> = CassNo
CleanInspRec<CLEAN_INSP_STAGE$> = Stage
CleanInspRec<CLEAN_INSP_RDS_NO$> = RDSKeyID
If LegacyLotType EQ 'RDS' then CleanInspRec<CLEAN_INSP_RDS_NO$> = LegacyLotId
end
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_RECIPE$, -1, 0, ScanRecipe)
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_TOOL$, -1, 0, ScanTool)
@ -2343,13 +2385,28 @@ Service ImportTencorData(RunData)
end
Next Wafer
end
If exists EQ False$ then
oCIParms := CleanInspRec
oCIParms := CleanInspRec ;
CINo = obj_Clean_Insp('Create',oCIParms)
If Error_Services('NoError') then
Begin Case
Case LegacyLotType EQ 'RDS'
ReactRunRec = INSERT(ReactRunRec,REACT_RUN_CI_NO$,-1,0,CINo)
ReactRunRec = INSERT(ReactRunRec,REACT_RUN_CI_STAGE$,-1,0,Stage)
obj_Tables('WriteRec','REACT_RUN':@RM:RDSKeyID:@RM:@RM:ReactRunRec)
obj_Tables('WriteRec','REACT_RUN':@RM:LegacyLotId:@RM:@RM:ReactRunRec)
Case LegacyLotType EQ 'WM_OUT'
WOMatRec = Database_Services('ReadDataRow', 'WO_MAT', WONo:'*':CassNo)
If Error_Services('NoError') then
WOMatRec = Insert(WOMatRec, WO_MAT_EPO_CI_NO$, -1, 0, CINo)
Database_Services('WriteDataRow', 'WO_MAT', WONo:'*':CassNo, WOMatRec, True$, False$, False$)
end
Case Otherwise$
ErrorMessage = 'Error in ':Service:' services. Invalid LegacyLotType.'
End Case
If ErrorMessage EQ '' then
obj_Tables('WriteRec','CLEAN_INSP':@RM:CINo:@RM:@RM:CleanInspRec)
PostStopTime = Time()
TimeTaken = PostStopTime - PostStartTime
@ -2359,6 +2416,8 @@ Service ImportTencorData(RunData)
LogData<3> = LegacyLotId@
LogData<4> = 'Time taken to import POST data: ':TimeTaken:' seconds.'
Logging_Services('AppendLog', objPOSTPerfLog, LogData, @RM, @FM)
end
end else
// Record error. Ensure metrology run data file is not deleted by including UID002 in the
// error message that is placed onto error stack in Error_Services.
@ -2374,8 +2433,8 @@ Service ImportTencorData(RunData)
If QualScan EQ False$ then
Recipients = XLATE('NOTIFICATION','TENCOR_NOTIFICATIONS',NOTIFICATION_USER_ID$,'X')
SentFrom = 'OI Admin'
Subject = 'Tencor SurfScan Import Failure for RDS ':RDSKeyID:'.'
Message = 'Scanned recipe ':ScanRecipe:' not found in PSN ':PSN:' for RDS ':RDSKeyID:'.'
Subject = 'Tencor SurfScan Import Failure for ':LegacyLotType:' ':LegacyLotId:'.'
Message = 'Scanned recipe ':ScanRecipe:' not found in PSN ':PSN:' for ':LegacyLotType:' ':LegacyLotId:'.'
AttachWindow = ''
AttachKey = ''
SendToGroup = ''
@ -2384,14 +2443,8 @@ Service ImportTencorData(RunData)
end
end
end
end else
ErrorMessage = Error_Services('GetMessage')
Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : ErrorMessage)
end
end else
ErrorMessage = 'Invalid RDS Key ID.'
Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : ErrorMessage)
end
If ErrorMessage NE '' then Error_Services('Add', ErrorMessage)
end service
@ -3680,3 +3733,4 @@ LoadRunDataToDatabase:
return

View File

@ -1012,7 +1012,7 @@ Service GetSODPerWafer(RDSKey, TencorRecipe, ScanDTM)
If RDSKey NE '' and TencorRecipe NE '' then
If Num(ScanDTM) then ScanDTM = OConv(ScanDTM, 'DT/^S')
Query = "DECLARE @RDS varchar(10) "
Query = "DECLARE @RDS varchar(255) "
Query := "DECLARE @RECIPE varchar(30) "
Query := "DECLARE @INSERT_DT datetime "
Query := "SET @RDS = '":RDSKey:"' "
@ -1199,7 +1199,7 @@ Service ProcessWaferImageRequests()
PSN = Xlate('RDS', RDSNo, 'PROD_SPEC_ID', 'X')
// Format Wafer Number for SQL Query
WaferNo = Fmt(TrimF(WaferNo), 'R(0)#2')
Query = "DECLARE @RDS varchar(10) " |
Query = "DECLARE @RDS varchar(255) " |
: "DECLARE @RECIPE varchar(30) " |
: "DECLARE @WFRID varchar(10) " |
: "SET @RDS = '":RDSNo:"' " |
@ -3833,13 +3833,3 @@ ClearCursors:
return