Уникальный идентификатор (Unique ID) — уникальный номер устройства, позволяющий отличать его от других устройств.
Примеры:
Токен, где в качестве имени или номера используется уникальный идентификатор. Идентификаторы активно используются практически во всех информационных системах.
Уникальный признак субъекта или объекта доступа.
Хорошим примером будет создание глобальной базы устройств, для обновления и контроля версий прошивок.
1-ое устройство STM32VL-Discovery
Основной документ: “RM0041: STM32F100xx advanced ARM-based 32-bit MCUs”
Регистр “уникальный идентификатор устройства” (96 бит)
Уникальный идентификатор устройства идеально подходит для:
для использования в качестве серийных номеров
для использования в качестве ключей безопасности в целях повышения безопасности кода во флэш-памяти во время
работы и комбинируя этот уникальный идентификатор с криптографических примитивами программного обеспечения и
протоколами для программирования внутренней флэш-памяти
активировать безопасные процессы загрузки и т.д.
96-битный уникальный идентификатор устройства обеспечивает ссылочный номер, который является уникальным для любого
устройства и в любом контексте. Эти биты не могут быть изменены пользователем.
Базовый адрес: 0x1FFFF7E8
Для использования Unique ID, необходимо в программу добавить следующий код:
volatile uint32_t *UniqueID = (uint32_t *)0x1FFFF7E8; volatile uint32_t __UniqueID[3]; __UniqueID[0] = UniqueID[0]; __UniqueID[1] = UniqueID[1]; __UniqueID[2] = UniqueID[2];

2-ое устройство STM32F429I-Discovery
Основной документ RM0090 Reference manual STM32F405/415, STM32F407/417, STM32F427/437 and STM32F429/439 advanced ARM®-based 32-bit MCUs
Базовый адрес: 0x1FFF7A10
volatile uint32_t *UniqueID = (uint32_t *)0x1FFF7A10; volatile uint32_t __UniqueID[3]; __UniqueID[0] = UniqueID[0]; __UniqueID[1] = UniqueID[1]; __UniqueID[2] = UniqueID[2];

3-ое устройство sam3u4c (128-bit)
Среда для программирования: Atmel Studio 6.2
Основной документ: SAM3U Series Complete Atmel | SMART ARM-based Flash MCU
DATASHEET
Базовый адрес: 0x400E0740

Принципы работы тот же самый, единственное отличие, доступ к ключу не такой простой, как у ST.
uint32_t chipid_read(Chipid *p_chipid, chipid_data_t *p_chipid_data)
{
if (NULL == p_chipid_data) {
return 0xFFFFFFFF;
}
p_chipid_data->ul_version =
(p_chipid->CHIPID_CIDR & CHIPID_CIDR_VERSION_Msk) >>
CHIPID_CIDR_VERSION_Pos;
p_chipid_data->ul_eproc =
(p_chipid->CHIPID_CIDR & CHIPID_CIDR_EPROC_Msk) >>
CHIPID_CIDR_EPROC_Pos;
p_chipid_data->ul_nvpsiz =
(p_chipid->CHIPID_CIDR & CHIPID_CIDR_NVPSIZ_Msk) >>
CHIPID_CIDR_NVPSIZ_Pos;
p_chipid_data->ul_nvpsiz2 =
(p_chipid->CHIPID_CIDR & CHIPID_CIDR_NVPSIZ2_Pos) >>
CHIPID_CIDR_NVPSIZ2_Pos;
p_chipid_data->ul_sramsiz =
(p_chipid->CHIPID_CIDR & CHIPID_CIDR_SRAMSIZ_Msk) >>
CHIPID_CIDR_SRAMSIZ_Pos;
p_chipid_data->ul_arch =
(p_chipid->CHIPID_CIDR & CHIPID_CIDR_ARCH_Msk) >>
CHIPID_CIDR_ARCH_Pos;
p_chipid_data->ul_nvptyp =
(p_chipid->CHIPID_CIDR & CHIPID_CIDR_NVPTYP_Msk) >>
CHIPID_CIDR_NVPTYP_Pos;
p_chipid_data->ul_extflag =
(p_chipid->CHIPID_CIDR & CHIPID_CIDR_EXT) >> 31;
if (p_chipid_data->ul_extflag) {
p_chipid_data->ul_extid =
p_chipid->CHIPID_EXID & CHIPID_EXID_EXID_Msk;
}
return 0;
}
Основная часть программы:
#include <string.h>
#include "asf.h"
#include "stdio_serial.h"
#include "conf_board.h"
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
extern "C" {
#endif
/**INDENT-ON**/
/// @endcond
#define STRING_EOL "\r"
#define STRING_HEADER "-- CHIPID Example --\r\n" \
"-- "BOARD_NAME" --\r\n" \
"-- Compiled: "__DATE__" "__TIME__" --"STRING_EOL
//! Chip ID catalog information: Type ID and its description stream
typedef struct chipidtype {
/// Identifier
uint32_t num;
/// Type
uint8_t p_str[80];
} chipidtype_t;
//! Number of Embedded Processors Supported
#define CHIPID_EPROC_SIZE 7
//! Embedded Processors support list
const chipidtype_t chipid_eproc[CHIPID_EPROC_SIZE] = {
// identifier description
{0x1, "ARM946ES"},
{0x2, "ARM7TDMI"},
{0x3, "Cortex-M3"},
{0x4, "ARM920T"},
{0x5, "ARM926EJS"},
{0x6, "Cortex-A5"},
{0x7, "Cortex-M4"}
};
//! Number of 1st Non-Volatile Program Memories Supported
#define CHIPID_NVPSIZE_SIZE 16
//! 1st Non-Volatile Program Memories support list
const chipidtype_t chipid_nvpsize[CHIPID_NVPSIZE_SIZE] = {
// identifier description
{0x0, "None"},
{0x1, "8K bytes"},
{0x2, "16K bytes"},
{0x3, "32K bytes"},
{0x4, "Reserved"},
{0x5, "64K bytes"},
{0x6, "Reserved"},
{0x7, "128K bytes"},
{0x8, "Reserved"},
{0x9, "256K bytes"},
{0xA, "512K bytes"},
{0xB, "Reserved"},
{0xC, "1024K bytes"},
{0xD, "Reserved"},
{0xE, "2048K bytes"},
{0xF, "Reserved"}
};
//! Number of 2nd Non-Volatile Program Memories Supported
#define CHIPID_NVPSIZE2_SIZE 16
//! 2nd Non-Volatile Program Memories support list
const chipidtype_t chipid_nvpsize2[CHIPID_NVPSIZE2_SIZE] = {
// identifier description
{0x0, "None"},
{0x1, "8K bytes"},
{0x2, "16K bytes"},
{0x3, "32K bytes"},
{0x4, "Reserved"},
{0x5, "64K bytes"},
{0x6, "Reserved"},
{0x7, "128K bytes"},
{0x8, "Reserved"},
{0x9, "256K bytes"},
{0xA, "512K bytes"},
{0xB, "Reserved"},
{0xC, "1024K bytes"},
{0xD, "Reserved"},
{0xE, "2048K bytes"},
{0xF, "Reserved"}
};
//! Number of SRAMs Supported
#define CHIPID_SRAMSIZE_SIZE 16
//! SRAMs support list
const chipidtype_t chipid_sramsize[CHIPID_SRAMSIZE_SIZE] = {
// identifier description
{0x0, "48K bytes"},
{0x1, "1K bytes"},
{0x2, "2K bytes"},
{0x3, "6K bytes"},
{0x4, "112K bytes"},
{0x5, "4K bytes"},
{0x6, "80K bytes"},
{0x7, "160K bytes"},
{0x8, "8K bytes"},
{0x9, "16K bytes"},
{0xA, "32K bytes"},
{0xB, "64K bytes"},
{0xC, "128K bytes"},
{0xD, "256K bytes"},
{0xE, "96K bytes"},
{0xF, "512K bytes"}
};
//! Number of architectures Supported
#define CHIPID_ARCH_SIZE 43
//! Architectures support list
const chipidtype_t chipid_archsize[CHIPID_ARCH_SIZE] = {
// identifier description
{0x19, "AT91SAM9xx Series"},
{0x29, "AT91SAM9XExx Series"},
{0x34, "AT91x34 series"},
{0x37, "CAP7 Series"},
{0x39, "CAP9 Series"},
{0x3B, "CAP11 Series"},
{0x3C, "SAM4E Series"},
{0x40, "AT91x40 Series"},
{0x42, "AT91x42 Series"},
{0x43, "AT91SAMG51 Series"},
{0x44, "AT91SAMG55 Series(49-lead version)"},
{0x45, "AT91SAMG55 Series(64-lead version)"},
{0x46, "AT91SAMG55 Series(100-lead version)"},
{0x47, "AT91SAMG53/SAMG54 Series"},
{0x55, "AT91x55 Series"},
{0x60, "AT91SAM7Axx Series"},
{0x61, "AT91SAM7AQxx Series"},
{0x63, "AT91x63 Series"},
{0x64, "SAM4CxC Series"},
{0x70, "AT91SAM7Sxx Series"},
{0x71, "AT91SAM7XCxx Series"},
{0x72, "AT91SAM7SExx Series"},
{0x73, "AT91SAM7Lxx Series"},
{0x75, "AT91SAM7Xxx Series"},
{0x76, "AT91SAM7SLxx Series"},
{0x80, "ATSAM3UxC Series"},
{0x81, "ATSAM3UxE Series"},
{0x83, "ATSAM3A/SAM4A xC Series"},
{0x84, "ATSAM3X/SAM4X xC Series"},
{0x85, "ATSAM3X/SAM4X xE Series"},
{0x86, "ATSAM3X/SAM4X xG Series"},
{0x88, "ATSAM3S/SAM4S xA Series"},
{0x89, "ATSAM3S/SAM4S xB Series"},
{0x8A, "ATSAM3S/SAM4S xC Series"},
{0x92, "AT91x92 Series"},
{0x93, "ATSAM3NxA/SAM4NxA Series"},
{0x94, "ATSAM3NxB/SAM4NxB Series"},
{0x95, "ATSAM3NxC/SAM4NxC Series"},
{0x98, "ATSAM3SDxA Series"},
{0x99, "ATSAM3SDxB Series"},
{0x9A, "ATSAM3SDxC Series"},
{0xA5, "ATSAM5A Series"},
{0xF0, "AT75Cxx Series"}
};
//! Number of ROMs Supported
#define CHIPID_NVPTYPE_SIZE 5
//! ROMs support list
const chipidtype_t chipid_nvptype[CHIPID_NVPTYPE_SIZE] = {
/* identifier description */
{0x0, "ROM"},
{0x1, "ROMless or on-chip Flash"},
{0x4, "SRAM emulating ROM"},
{0x2, "Embedded Flash Memory"},
{0x3, "ROM and Embedded Flash Memory, NVPSIZ is ROM size, NVPSIZ2 is Flash size"}
};
//! ChipID data read
chipid_data_t g_chipid_data;
/**
* \brief The function finds chipid from specific list according to ul_id
*
* \param p_cid_types Pointer to the chipid list.
* \param ul_size chipid list size
* \param ul_id chipid number
* \param p_cid_type pointer to chipid type
* \return true if ID is found in list
*/
static bool chipid_find(const chipidtype_t *p_cid_types,
uint32_t ul_size, uint32_t ul_id, chipidtype_t *p_cid_type)
{
uint32_t ul_counter;
for (ul_counter = 0; ul_counter < ul_size; ul_counter++) {
if (p_cid_types[ul_counter].num == ul_id) {
memcpy(p_cid_type, &p_cid_types[ul_counter], sizeof(chipidtype_t));
return true;
}
}
return false;
}
/**
* \brief The function prints specific chipid data structure.
*
* \param p_chipid_data Pointer to the chipid data.
*/
static void chipid_print(chipid_data_t *p_chipid_data)
{
bool b_found;
chipidtype_t cid_type;
/* Version */
printf("Version\t0x%lx.\r\n", (unsigned long)p_chipid_data->ul_version);
/* Find Embedded Processor */
b_found = chipid_find(chipid_eproc, CHIPID_EPROC_SIZE,
p_chipid_data->ul_eproc, &cid_type);
if (b_found) {
printf("Embedded Processor\t%s.\r\n", cid_type.p_str);
}
/* Find non-volatile program memory size */
b_found = chipid_find(chipid_nvpsize, CHIPID_NVPSIZE_SIZE,
p_chipid_data->ul_nvpsiz, &cid_type);
if (b_found) {
printf("Nonvolatile program memory size\t%s.\r\n", cid_type.p_str);
}
/* Find the second non-volatile program memory size */
b_found = chipid_find(chipid_nvpsize2, CHIPID_NVPSIZE2_SIZE,
p_chipid_data->ul_nvpsiz2, &cid_type);
if (b_found) {
printf("Second nonvolatile program memory size\t%s.\r\n",
cid_type.p_str);
}
/* Find internal SRAM size */
b_found = chipid_find(chipid_sramsize, CHIPID_SRAMSIZE_SIZE,
p_chipid_data->ul_sramsiz, &cid_type);
if (b_found) {
printf("Internal SRAM size\t%s.\r\n", cid_type.p_str);
}
/* Find architecture identifier */
b_found = chipid_find(chipid_archsize, CHIPID_ARCH_SIZE,
p_chipid_data->ul_arch, &cid_type);
if (b_found) {
printf("Architecture identifier\t%s.\r\n", cid_type.p_str);
}
/* Find non-volatile program memory type */
b_found = chipid_find(chipid_nvptype, CHIPID_NVPTYPE_SIZE,
p_chipid_data->ul_nvptyp, &cid_type);
if (b_found) {
printf("Nonvolatile program memory type\t%s.\r\n", cid_type.p_str);
}
/* Find extension flag */
if (p_chipid_data->ul_extflag) {
printf("Extended chip ID is\t0x%lx. \r\n",
(unsigned long)p_chipid_data->ul_extid);
} else {
puts("Extended chip ID does not exist. \r");
}
}
/**
* \brief Configure UART console.
*/
static void configure_console(void)
{
const usart_serial_options_t uart_serial_options = {
.baudrate = CONF_UART_BAUDRATE,
#ifdef CONF_UART_CHAR_LENGTH
.charlength = CONF_UART_CHAR_LENGTH,
#endif
.paritytype = CONF_UART_PARITY,
#ifdef CONF_UART_STOP_BITS
.stopbits = CONF_UART_STOP_BITS,
#endif
};
/* Configure console UART. */
sysclk_enable_peripheral_clock(CONSOLE_UART_ID);
stdio_serial_init(CONF_UART, &uart_serial_options);
}
/**
* \brief Application entry point.
*
* \return Unused (ANSI-C compatibility).
*/
int main(void)
{
/* Initialize the system */
sysclk_init();
board_init();
/* Initialize the console uart */
configure_console();
puts(STRING_HEADER);
/* Read CHIPID */
chipid_read(CHIPID, &g_chipid_data);
/* Dump CHIPID information */
chipid_print(&g_chipid_data);
while (1) {
}
}
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
}
#endif
/**INDENT-ON**/
/// @endcond
