Generating Serial Numbers in XJEase

XJRunner can generate / read and log unique board identifiers during testing, such as serial numbers and MAC addresses. This application note describes how these should be handled by the XJEase code.

Serial numbers (or other unique board identifiers) are passed between the XJEase code and XJRunner using the built-in global string variable SERIAL_NUMBER. There are two aspects of handling serial numbers:

Generating Serial Numbers

In XJRunner, the Serial Number tab of the Project Manager provides three ways of generating serial numbers.

XJRunner generates serial numbers

XJRunner can generate simple incrementing serial numbers with a prefix and/or suffix, such as the range SN0001B – SN9999B. If more complex board identifiers are needed, such as MAC addresses, there are two other options:

User inputs serial numbers

For example, the boards may have a barcode with their serial number. Using a barcode reader, the tester can input these into XJRunner.

Take serial numbers from the test system

Just as XJRunner can generate serial numbers and pass them to XJEase for programming into the board, XJEase can generate serial numbers and pass them back to XJRunner for logging. We will now look at this option in more detail.

Generating serial numbers in XJEase

If XJEase will be generating the serial numbers, it must do so in a function with the name NEW_SERIAL_NUMBER. Using this name lets XJRunner know when a new serial number has been generated, so that it can log the value of the variable SERIAL_NUMBER.

The function NEW_SERIAL_NUMBER is just an XJEase test function from the XJEase project file – it must also be listed in the TEST LIST section of the project preamble.

It is generally a good idea to put serial number functions at the end of your TEST LIST, so that you can be sure the board has passed the tests before assigning it a serial number.

Example code:

[Circuit Preamble]
TEST LIST
...
"Program Serial Number"
NEW_SERIAL_NUMBER; // Set up the global variable SERIAL_NUMBER.
IC3.ProgSerNo; // Program the new serial number into EEPROM.
// See below for more details.
END;
...
END

...

[after preamble]
// An example of how to increment a serial number held in a file.
NEW_SERIAL_NUMBER()(INT Failed)
INT serial WIDTH 32;
FILE file;
INT result;

Failed := FALSE;

// Open the file.
FOPEN("CurrentSerialNumber.txt", "r+")(file);
IF FERROR() THEN
PRINT("Error opening CurrentSerialNumber.txt\n");
Failed := TRUE;
RETURN;
END;

// Wait for the file lock to become available.
DO
FLOCK(file, 1)(result);
WHILE result != 0
END;

// Read the previous serial number from the file.
// N.B. Serial numbers are 32 bits.
FGETI(file, 32)(serial);

// Increment the serial number.
serial := serial + 1;
SERIAL_NUMBER := FORMAT(serial, "%i");

// Return to the beginning of the file.
FSEEK(file, 0, 0);
// Save the new serial number.
FWRITE(file, serial);
IF FERROR() THEN
PRINT("Error writing to CurrentSerialNumber.txt\n");
Failed := TRUE;
RETURN;
END;

// Unlock the file and close it.
FUNLOCK(file);
FCLOSE(file);
END;

Programming Serial Numbers

Once the variable SERIAL_NUMBER has been set up (either by XJRunner or by a NEW_SERIAL_NUMBER function), the serial number will then typically be programmed into the board.

Example code:

[Circuit Preamble]
TEST LIST
...
"Program Serial Number"
NEW_SERIAL_NUMBER; // Set the global variable SERIAL_NUMBER.
IC3.ProgSerNo; // Program the new serial number into EEPROM.
END;
...
END

[Test Code for IC3 (EEPROM) in device file]
ProgSerNo()(INT Failed)
INT serNo1, serNo2, serNo3, serNo4;
INT serial WIDTH 32;

// Convert serial number string to an integer.
serial := STRTOINT(SERIAL_NUMBER);

// Write four data bytes to the EEPROM.
I2C_Write(0x0, I2C_ADDRESS, serial[7..0]);
I2C_Write(0x1, I2C_ADDRESS, serial[15..8]);
I2C_Write(0x2, I2C_ADDRESS, serial[23..16]);
I2C_Write(0x3, I2C_ADDRESS, serial[31..24]);

// Read the bytes back.
I2C_Read(0, I2C_ADDRESS)(serNo1);
I2C_Read(1, I2C_ADDRESS)(serNo2);
I2C_Read(2, I2C_ADDRESS)(serNo3);
I2C_Read(3, I2C_ADDRESS)(serNo4);

// Check the read-back data.
IF( (serNo1 != serial[7..0]) ||
(serNo2 != serial[15..8]) ||
(serNo3 != serial[23..16]) ||
(serNo4 != serial[31..24]) ) THEN
Failed := 1; // Fail
ELSE
Failed := 0; // Pass
END;
END;

Want to be the first to know of new eBooks and JTAG Resources?

Find out how XJTAG can help you test your PCB faster
From Prototype To Manufacture