Уникальный 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).
Пример для чтения unique ID.
Чтобы прочитать структурированную информацию, можно объявить прототип структуры и обращаться к региону памяти через указатель этого прототипа.
#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 как к полям структуры через этот указатель.
Отладчик позволяет выполнить функцию "Add to Watch" (вызывается правой кнопкой мыши на имени указателя во время отладки). В открытом окне появится указатель с возможностью подробного раскрытия всех полей с их описаниями типов и значениями. Конечно, отладчик покажет структуру в пошаговом режиме после присвоения базового адреса указателю. На изображении видно как в объединении поля RAW массива и структуры накладываются и интерпретируются в зависимости от типа.
Если необходимо передать UID не по ссылке, а по значению. Можно создать пустой экземпляр структуры и скопировать в него данные при помощи memcpy.
Объединение uid_str будет хранить в оперативной памяти скопированную информацию из регистров UID. Для работы memcpy следует включить string.h