你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32F103单片机读取芯片自身ID

[复制链接]
STMCU小助手 发布时间:2022-3-19 20:31
  每一个STM32单片机出厂的时候都有全球唯一的ID,当在数据安全性比较高的地方,需要对每一个接入系统的芯片进行身份验证,那么这个芯片自身的ID号就可以作为它的身份信息。

产品唯一的身份标识非常适合:

用来作为序列号(例如USB字符序列号或者其他的终端应用)
用来作为密码,在编写闪存时,将此唯一标识与软件加解密算法结合使用,提高代码在闪存存储器内的安全性。
用来激活带安全机制的自举过程
  96位的产品唯一身份标识所提供的参考号码对任意一个STM32微控制器,在任何情况下都是唯一的。用户在何种情况下,都不能修改这个身份标识。


这个96位的产品唯一身份标识,按照用户不同的用法,可以以字节(8位)为单位读取,也可以以
半字(16位)或者全字(32位)读取。

TCCR6_EQ2Q]W`LGB0[YY`BD.png

T(FCKE]YS9SGM5$OE4Z6W`I.png


  不仅可以读取到芯片的ID,还能读出芯片的存储器容量。

{1KDBWLIE@9}VB(6VA`5V}K.png

  芯片型号也同样可以读出来。

GSG3KSD[V%D@[BC)7YM3@QL.png

02$EDL`NO9{{`SAFBLT{4.png

下面就通过代码来读取这几个数据。

  1. //读取芯片ID
  2. void GetChipID ( void )
  3. {
  4.     u32 CpuID[3];                                                        //小端模式
  5.     CpuID[0] = * ( vu32 * ) ( 0x1ffff7e8 ); //高32位地址
  6.     CpuID[1] = * ( vu32 * ) ( 0x1ffff7ec ); //中32位地址
  7.     CpuID[2] = * ( vu32 * ) ( 0x1ffff7f0 ); //低32位地址
  8.     printf ( "此芯片唯一ID为:0x%x-%x-%x \r\n", CpuID[0], CpuID[1], CpuID[2] );
  9. }
  10. //获取芯片Flash大小
  11. void GetFlashSize ( void )
  12. {
  13.     u16 stm32_Flash_Size;
  14.     stm32_Flash_Size = * ( u16 * ) ( 0x1FFFF7E0 ); //闪存容量寄存器
  15.     printf ( "芯片闪存容量大小为:%x \r\n", stm32_Flash_Size );
  16. }

  17. //读取芯片型号
  18. void Main_Chip_Type(void)
  19. {
  20.         u32 type;
  21.         type = *( unsigned  int * )( 0xE0042000 );        //MCU ID
  22.         printf ( "芯片型号为:0x%x \r\n", type );
  23. }

  24. int main ( void )
  25. {
  26.     NVIC_PriorityGroupConfig ( NVIC_PriorityGroup_2 );
  27.     uart_init ( 115200 );
  28.     delay_init();       //延时函数初始化
  29.     LED_Init();         //初始化与LED连接的硬件接口

  30.     GetChipID();
  31.     GetFlashSize();
  32.     Main_Chip_Type();

  33.     while(1);
  34. }
复制代码

通过串口打印出芯片的ID

此芯片唯一ID为: 0x66eff51-51578248-87074312
芯片闪存容量大小为:   40
芯片型号为:  0x20036410

C6O6@4XG{N8D_{@9PS9((`I.png

然后通过单步调试,直接观察内存中的数据。

]TQO}J}_SX`SSE@{T`~OVBQ.png

然后观察内存中地址0x1FFFF7E0开始的数据

4)MQ[NI@B[Q1K5IFT{K17~D.png

可以看出0x1FFFF7E0开始的16位数据为0x0040换算为10进制数据就是64,说明当前用的芯片的容量是64K。接下来从0x1ffff7e8地址开始的12个字节,也就是96位存储的就是芯片的ID。内存中ID号存储为低位在前高位在后,而打印出来的数据是高位在前,低位在后。打印的前32位是 06 6e ff 51对应在内存中的存储顺序51应该是第一位,06是最后一位。

最后在0xE0042000地址查看单片机的型号。

92W40PWD8{H98F`UP(TAI@2.png

低12位数据是 0x410,也就是设备编码为0x410,通过对比文档可以看出这个是中容量产品。高16位是0x2003,对比文档可以看出,这个是中容量产品,版本号为Y。

由于这些ID号都存储在指定的内存地址中,而系统没有提供专用的读取这些ID号的函数,所以读取数据的时候,只能通过指针的方式去读取,首先将数据加一级指针转换为地址,然后加二级指针,表示读取当前地址中存储的内容。这种操作方法在库函数的头文件中使用的比较多。比如在stm32f10x.h中就可以看到对GPIOA的定义。

  1. #define PERIPH_BASE           ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region */

  2. #define APB2PERIPH_BASE       (PERIPH_BASE + 0x10000)

  3. #define GPIOA_BASE            (APB2PERIPH_BASE + 0x0800)

  4. #define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)

  5. typedef struct
  6. {
  7.   __IO uint32_t CRL;
  8.   __IO uint32_t CRH;
  9.   __IO uint32_t IDR;
  10.   __IO uint32_t ODR;
  11.   __IO uint32_t BSRR;
  12.   __IO uint32_t BRR;
  13.   __IO uint32_t LCKR;
  14. } GPIO_TypeDef;
复制代码

将地址值逐个替换后为 #define GPIOA ((GPIO_TypeDef *) 0x4001 0800),相当于在 0x4001 0800 地址处定义了GPIOA的结构体。查阅芯片资料可知,GPIOA的起始地址就是0x4001 0800。

WBSDS9BWYF(G[EBRZG}46.png

这样操作GPIOA的的时候就和上面读取ID的方法是一样的,相当于直接读写对应地址中的值。



收藏 评论0 发布时间:2022-3-19 20:31

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版