Уникальный device ID в микроконтроллерах STM32F0x1/STM32F0x2/STM32F0x8 (STM32F051R8T6).

В описании характеристик микроконтроллера STM32F051R8T6 обозначено, что он содержит 96-ти битный уникальный идентификатор. Данный ID бывает полезным, если устройству на основе микроконтроллера необходим уникальный номер. При наличии такой функции в аппаратных ресурсах микроконтроллера, отпадает необходимость самому производить прошивку идентификатора и следить за тем, чтобы каждый новый ID был уникальным. В случае семейства STM32F0x1/STM32F0x2/STM32F0x8 производитель гарантирует, что каждый микроконтроллер имеет свой уникальный номер.

Чтобы разобраться, где хранится 96-bit unique ID, нужно скачать с сайта производителя Reference Manual. В этом документе содержится подробное описание адресного пространства и описание регистров микроконтроллера.

На момент написания статьи данный документ назывался RM0091: STM32F0x1/STM32F0x2/STM32F0x8 advanced ARM®-based 32-bit MCUs В разделе 33.1 Unique device ID register (96 bits) описаны регистры, чтение из которых позволит получить уникальный номер микроконтроллера. Три 32-х битных регистра с базовым адресом 0x1FFF F7AC и смещением 0x00, 0x04, 0x08 хранят 96-bit unique. Из описания видно, что данные в этих регистрах представляет из себя не просто случайные данные, а техническую информацию, занесенную на фабрике на этапе производства кристаллов.

Для примера можно воспользоваться отладчиком IAR Embedded Workbench. После ввода микроконтроллера в режим отладки, следует открыть окно Viev -> Memory. В окно Go to: нужно ввести базовый адрес 0x1FFFF7AC и нажать энтер. Ниже на изображении выделен регион 0x1FFFF7AC - 0x1FFFF7B7. Первый регистр 0x1FFFF7AC - 0x1FFFF7AF содержит координаты кристалла на кремниевой пластине. Координата X по адресу 0x1FFFF7AC - 0x1FFFF7AD (на изображении 0x0053) и координата Y адрес 0x1FFFF7AE - 0x1FFFF7AF (на изображении 0x0044) Второй регистр 0x1FFFF7B0 - 0x1FFFF7B3 содержит номер пластины в партии и часть ASCII строки, которая кодирует партию пластин. Номер пластины находится по адресу 0x1FFFF7B0 (на изображении 0x0e) - целочисленное 8-ми битное значение. Следующий регион 0x1FFFF7B1 - 0x1FFFF7B3 совместно с третьим регистром 0x1FFFF7B4 - 0x1FFFF7B7 содержат ASCII символы. Значения 0x57, 0x36, 0x41, 0x36, 0x33, 0x32, 0x20 кодируют строку "W6A632 " - номер партии пластин (Lot number).

STM32F051R8T6_96_bit_unique_ID

Пример для чтения unique ID.

Чтобы прочитать структурированную информацию, можно объявить прототип структуры и обращаться к региону памяти через указатель этого прототипа.

#pragma pack(push,1)

typedef union {
struct
{
uint16_t x_coordinate;
uint16_t y_coordinate;
uint8_t waf_num;
uint8_t lot_num_ascii_string[7];
};
uint8_t RAW[12];
} uid_str_t;

#pragma pack(pop)

#pragma pack(push,1) - устанавливает выравнивание полей структуры равным одному байту, перед этим сохраняя текущие настройки выравнивания. В Cortex-M0/M3, как правило, поля структуры выровнены на границу машинного слова (4-ре байта). Такой подход позволяет получать поле за один цикл обращения к памяти. Тем не менее, контроллер памяти в ядрах Cortex-M0/M3 позволяет производить обращение к невыровненным данным, прозрачно для программиста разбивая запрос на две итерации.

typedef union { - объявляем объединение, состоящее из структуры и массива uint8_t RAW[12]. Объединение позволит читать как структурированные данные в виде полей, так и сырые данные.

struct - структура.

uint16_t x_coordinate; - координата X на пластине.

uint16_t y_coordinate; - координата Y на пластине.

uint8_t waf_num; - номер пластины.

uint8_t lot_num_ascii_string[7]; - массив ASCII-символов, закодированный номер лота.

uint8_t RAW[12]; - второе поле объединения это и есть 12 байт данных (96-bit uid)

} uid_str_t; - имя типа объединения.

#pragma pack(pop) возвращает настройки выравнивания по умолчанию.

После объявления указателя на структуру и присваивания ему базового адреса региона UID регистров появится возможность обращения к данным UID как к полям структуры через этот указатель.

// Объявление константы базового адреса UID региона.
#define UIDBASEADDRESS 0x1FFFF7AC
// Объявление указателя на объединение и присваивание
// ему базового адресе UID.
uid_str_t * uid_str_ptr = (void *)UIDBASEADDRESS;
// Пример чтения координаты X кристалла на пластине.
uint16_t x_coordinate = uid_str_ptr->x_coordinate;
// Чтение номера пластины на которой произведен кристалл.
uint8_t waf_num = uid_str_ptr->waf_num;
// Чтение первого символа из семи кодирующие партию пластин.
uint8_t char_string[7];
char_string[0] = uid_str_ptr->lot_num_ascii_string[0];

Отладчик позволяет выполнить функцию "Add to Watch" (вызывается правой кнопкой мыши на имени указателя во время отладки). В открытом окне появится указатель с возможностью подробного раскрытия всех полей с их описаниями типов и значениями. Конечно, отладчик покажет структуру в пошаговом режиме после присвоения базового адреса указателю. На изображении видно как в объединении поля RAW массива и структуры накладываются и интерпретируются в зависимости от типа.

STM32F051R8T6_96_bit_unique_ID

Если необходимо передать UID не по ссылке, а по значению. Можно создать пустой экземпляр структуры и скопировать в него данные при помощи memcpy.

uid_str_t uid_str;
memcpy((void *)&uid_str, (void *)UIDBASEADDRESS, sizeof(uid_str_t));

Объединение uid_str будет хранить в оперативной памяти скопированную информацию из регистров UID. Для работы memcpy следует включить string.h

Разделы Сайта