cancel
Showing results for 
Search instead for 
Did you mean: 

How to obtain and use the STM32 96-bit UID

MCU Support TD
ST Employee

Introduction

Some STM32 MCUs embed two unique identifiers: a unique 96-bit unique identifier and device ID. This article shows how to both obtain these values in your code, and describe some possible use cases for them.

1. 96-bit unique ID

This 96-bit UID is unique for every STM32 ever made. These 96-bit unique IDs are created as a combination of unique fabrication parameters:

  • UID[31:0]: X and Y coordinates on the wafer expressed in BCD format
  • UID[63:40]: LOT_NUM[23:0] Lot number (ASCII encoded)
  • UID[39:32]: WAF_NUM[7:0] Wafer number (8-bit unsigned number)
  • UID[95:64]: LOT_NUM[55:24] Lot number (ASCII encoded)

It is common to use this UID as a serial number or as a key for secure applications. 

2. Obtaining the UID

The HAL libraries provide a way to read the three words of the 96-bit UID.

uint32_t uid[3];

uid[0] = HAL_GetUIDw0();
uid[1] = HAL_GetUIDw1();
uid[2] = HAL_GetUIDw2();

If you are not using HAL, then the CMSIS device header provides a definition for the address of the UID. Even without HAL, you have a uniform way to obtain the UID.

uint32_t uid[3];

uid[0] = *(uint32_t *)UID_BASE;
uid[1] = *(uint32_t *)(UID_BASE + 4);
uid[2] = *(uint32_t *)(UID_BASE + 8);

As a validation, you can check the 2nd and 3rd bytes of the UID, which are mostly ascii encoded. Reading these values as bytes, you should be able to see the ascii encoding of the lot numbers:

uint8_t lot1[4];
uint8_t lot2[4];
uint8_t *ptr;

ptr = (uint8_t *)&uid[1];
for (uint8_t i = 0; i < 4; i++) {
  lot1[i] = ptr[i];
}

ptr = (uint8_t *)&uid[2];
for (uint8_t i = 0; i < 4; i++) {
  lot2[i] = ptr[i];
}

 

MCUSupportTD_0-1703015576603.png

2.1 STM32H5 specific issue

When trying to read the UID for the H5, you will run into a hard fault if you have ICACHE enabled. Furthermore, if you have not set up an MPU region for the address of the UID. Unlike other STM32, the UID address is located in the range of the USER flash.

#define UID_BASE                (0x08FFF800UL) /*!< Unique device ID register base address */

According to the reference manuals RM0492 and RM0481 section 7.3.2: "By default, all the AHB memory range is cacheable. For regions where caching is not practical (OTP, RO, data area), MPU must be used to disable local cacheability." Since the above address is in the AHB memory range, it is necessary to create an MPU region to remove the cacheability of this region. The screenshot below is a CubeMX configuration of the MPU:

MCUSupportTD_1-1703018522618.png
MPU_Region_InitTypeDef MPU_InitStruct = {0};
MPU_Attributes_InitTypeDef MPU_AttributesInit = {0};

/* Disables the MPU */
HAL_MPU_Disable();

/** Initializes and configures the Region and the memory to be protected
*/
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.BaseAddress = 0x08FFF800;
MPU_InitStruct.LimitAddress = 0x08FFFFFF;
MPU_InitStruct.AttributesIndex = MPU_ATTRIBUTES_NUMBER0;
MPU_InitStruct.AccessPermission = MPU_REGION_ALL_RO;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;

HAL_MPU_ConfigRegion(&MPU_InitStruct);
MPU_AttributesInit.Number = MPU_REGION_NUMBER0;
MPU_AttributesInit.Attributes = MPU_DEVICE_nGnRnE | MPU_NOT_CACHEABLE
                            | MPU_TRANSIENT | MPU_NO_ALLOCATE;

HAL_MPU_ConfigMemoryAttributes(&MPU_AttributesInit);
/* Enables the MPU */
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

Conclusion 

Using either the HAL libraries or standard CMSIS definitions, in most cases it is simple to obtain the STM32's 96-bit unique identifier. The ID is guaranteed to be unique for all STM32, so it is useful for applications that need a serial number for a product, or need a key that can be used for security applications. If you run into a hard fault while trying to obtain the UID on devices with ICACHE, be sure to check the reference manual for your particular STM32 to see if you need to configure the MPU to disable cacheability for the memory address containing the UID.

Related links

Reference manual RM0492: STM32H503 line Arm®-based 32-bit MCUs

Reference manual RM0481: STM32H563/H573 and STM32H562 Arm®-based 32-bit MCUs

Comments
Kraal
Senior III

Great news !

Because last time I asked why the STM32G070 did NOT have the UID specified in its datasheet and / or related manual, I got told that UID is not a feature available to ALL STM32 and since STM32G070 is part of value-line products, it should not have it.

Which does not make sense to me because:

  • We have several G070 with UID that matches the description above and are different to each other
  • Since it is "burned" during the wafer process it has no additional cost (please correct me if I'm wrong on this point).

I should add that stm32g070xx.h does list the UID base address.

Edit: I don't mean to sound harsh, I just want an official statement from ST regarding the UID for ALL STM32 MCUs, or only some of them.

MCU Support TD
ST Employee

@Kraal ,

I have done testing myself and also confirmed that the G0x0 family does have a UID in the address you would expect it to be. At first I also though this was a mistake in the documentation, but it is not. 

 

The UID does physically exist on the G0x0 series, but since it is not listed in the reference manual, this means it was not tested during factory production. This means that although the UID is in the silicon, we do not absolutely guarantee it's functionality, since it hasn't been tested in the factory. I will edit the article to make this fact more clear. On an MCU such as the G0x0, you may find that you never have a problem using the UIDs within, but if you ever do have a problem with it (not encoded properly, or not unique), essentially you are on your own to deal with it since ST did not guarantee the functionality.

 

Although I agree that there is not much extra cost incurred from emplacing the ID itself (in fact, it may cost more not to do it, since putting it there is likely baked into the fab process), but oftentimes the cost of a piece of silicon can have just as much to do with verification process as it does with the fabrication. For example, the higher temperature variants of our MCUs cost more not because of major differences in fabrication, but rather because every function within it must be tested and verified to work at those higher temperatures. It is possible to run a lower temperature variant part in a higher temperature range and still have it work, but since the part was not tested and verified in that range, if it does fail ST would not have any liability. In a safety critical application with high temperature, the extra cost is worth the peace of mind knowing it has been tested. The time and equipment involved in the verification process adds cost. In order to reduce costs, the UID functionality on the G0x0 family has not been tested and verified.

 

Apologies for the confusion and thanks for bringing this to my attention. I will update the article accordingly.

 

 

 

Is it etched on the wafer, or just written to OTP cells when the wafer is probed/pretested?

Kraal
Senior III

@MCU Support TD,

Thank you for the detailed answer. I understand that ST does not want to support something not tested, as well as I understand that the UID for the G070 can disappear in the next years after process optimization.

Like @Tesla DeLorean I am curious about the exact way of how the UID is put in the chips.

 

Best regards,

Kraal

MCU Support TD
ST Employee

@Kraal @Tesla DeLorean 

The memory address for the UID is part of the system memory, it uses the same ROM that the system memory bootloader does. I am unsure the underlying architecture, I would need to ask a designer. I am assuming it is OTP "fuses" rather than charge traps that are baked in at manufacturing chemically, since the latter would make it more difficult for versioning and provisioning of the system memory bootloader.

miladmohtashamirad
Associate III

Hi. 
I'm trying to set the same configs for MPU on STM32H573IIK3Q in UI, and It keeps setting the base address back to 0x0. However, If I modify the generated code and set the base address to 0x08FFF800 it works without any issue. 
Is there anything else in the UI that I need to set before I setup the MPU regions?
Kind Regards.

miladmohtashamirad_0-1728865961234.png

 

 

Version history
Last update:
‎2024-06-18 12:52 AM
Updated by: