写在前面:
本文章旨在总结备份、方便以后查询,由于是个人总结,如有不对,欢迎指正;另外,内容大部分来自网络、书籍、和各类手册,如若侵权请告知,马上删帖致歉。
在 STM32的全系列 MCU中均有一个 96位的唯一设备标识符。在 ST的相关资料中,对其功能的描述有 3各方面:
96 位的唯一设备标识符提供了一个对于任何设备和任何上下文都唯一的参考号码。用户永远不能改变这些位。
96 位的唯一设备标识符也可以以单字节/半字/字等不同方式读取,然后使用自定义算法连接起来。
对于不同型号的 STM32芯片来讲,其唯一设备 ID 寄存器(96 位)的地址是不一样的:
例如,STM32F4系列的:
当我们在应用中时,只需要用下面的程序读取出来就好了:
typedef struct
{
uint32_t id[3];
} ChipID;
typedef enum {
STM32F0 = 0x1FFFF7AC,
STM32F1 = 0x1FFFF7E8,
STM32F2 = 0x1FFF7A10,
STM32F3 = 0x1FFFF7AC,
STM32F4 = 0x1FFF7A10,
STM32F7 = 0x1FF0F420,
STM32L0 = 0x1FF80050,
STM32L1 = 0x1FF80050,
STM32L4 = 0x1FFF7590,
STM32H7 = 0x1FF0F420,
}MCUTypedef;
ChipID Get_ChipID(MCUTypedef MCU)
{
ChipID chipid = {
0};
chipid.id[0] = *(__I uint32_t *)(MCU + 0x00);
chipid.id[1] = *(__I uint32_t *)(MCU + 0x04);
chipid.id[2] = *(__I uint32_t *)(MCU + 0x08);
// DEBUG_PRINTF("ID Code:0x%08X\r\n", chipid.id[0]);
// DEBUG_PRINTF("ID Code:0x%08X\r\n", chipid.id[1]);
// DEBUG_PRINTF("ID Code:0x%08X\r\n", chipid.id[2]);
return chipid;
}
至于后期怎么利用这个 ID,采取怎样的办法加密就看个人了。
在上图中可以看到,还有一个特殊地址,那就是容量地址。
同样的,对于不同型号的 STM32芯片,其地址也是不一样的,这个可以看上面的图。
当我们用 ST-LINK Utility读取 STM32F1系列的容量信息时,得到下图:
地址中框选的 “0080” 表示的是十六进制,它的数据存储位数是 16位数据,所以我们用 16bit来显示,接着我们看下它的寄存器描述:
可以看到,地址所对应的容量对的上芯片的实际容量,而且也跟右上角的 “Flash Size” 给出的 128KBytes对的上。
用 ST-LINK Utility读取芯片信息时,可以看到下图的显示信息:
那么,第二跟第三的这俩个 ID是在哪里读取出来的呢?
这就是要讲的器件 ID号了,注意这个 ID跟上面第一大点所阐述的唯一 ID号不同,上面所说的唯一 ID相当于一个物理介质,是固定不变全球唯一的、伴随它终身的一个烙印;而现在这个器件 ID是可以相同的,属于那种种族标识符。
它存在于 DBGMCU_IDCODE寄存器中,对于不同的 STM32型号,其描述都不一样,例如:
在这里,可以看到,即使是同系列的 STM32F4,也会再细分不同的器件 ID。
如此一来,到了这里应该就知道上述的:第二个 Device ID是属于 DBGMCU_IDCODE寄存器里的 DEV_ID[11:0]这个集合里面的;第三个 Revision ID是属于 DBGMCU_IDCODE寄存器里的 REV_ID[15:0]这个集合里面的。
而至于 Revision ID,在对应的勘察手册上,有对该类不同版本的芯片描述:
扯了这么多,其实想说的是,利用第二、三大点,可以有效的识别 STM32的芯片是不是假芯或者是否以小(容量)充大(容量)的;翻新的谁也救不了,毕竟能用主义。
好家伙,官板还有这般操作?莫非这就是究极版