[经验分享] 【GD32F350学习小记】唯一ID获取以及Printf函数重映射

justd0   2018-9-20 00:08 楼主
论坛活动报名获得的开发板Colibri-F350RX,腾开手头的任务探索下这款搭载M4核的国产MCU。开发板上已经设计好了烧写、调试模块,资料在https://www.eeworld.com.cn/huodong/Gigadevice_GD32F350Contest_201808/的资料下载专栏里,下载后安装驱动和IDE库依赖,直接插上usb就可以愉快的玩耍了。

上电靓照一张

1.jpg

小试牛刀

资料中有提供的350demo测试程序,官方库函数已经封装好了,而且备注简介明了,对于之前有接触过MCU编程的应该阅读无压力。

打开工程后,可以看到demo程序里提供了LED、KEY和UART的测试程序,通过对exmaple.h头文件中的EVB_EXAMPLE宏定义调整来选择不同的测试程序。为了测试UART,我将其选择为:

#include "colibri_bsp.h"

#define CH13_BOARD_UART_EXAMPLE    (132)
#define CH13_BOARD_LED_EXAMPLE     (133)
#define CH13_BOARD_KEY_EXAMPLE     (134)

#define EVB_EXAMPLE  CH13_BOARD_UART_EXAMPLE

可以看到board_uart_example.c文件中程序如下:

#include "example.h"

#if (EVB_EXAMPLE == CH13_BOARD_UART_EXAMPLE)

int main(void)
{
    EvbUart1Config();
    while(1)
    {
        for (int i =0;  i<0xfffff; i++);   
                EvbUart1WriteStr("HelloWorldn");

    }
        return 0;
}

直接通过编译,下载到开发板上,就能通过串口调试助手收到发来的数据啦~

2.png

虽然demo程序中有EvbUart1WriteStr(const char* str)void EvbUart1Printf(char* fmt, ...)但是第一个函数只能发送字符串类型数据,而第二个函数虽有和Printf函数相同的功能,但是他需要自己定义一个buffer空间并且实现函数效率并不高的样子,主要是printf()简洁熟悉啊。

Printf函数重映射

使用过MCU的朋友们肯定用过Printf函数,在GD32F350上开启这个函数并不复杂~

  1. 在工程中引用标准输入输出库#include "stdio.h"

  2. 在你工程里任意位置重映射下fputc函数

    int fputc(int ch, FILE *f)
    {
           usart_data_transmit(USART1, ch);
           while (RESET == usart_flag_get(USART1,USART_FLAG_TC));
           return ch;
    }

就可以使用熟悉而简单的printf函数了~

全球唯一ID

设备的电子签名中包含的存储容量信息和96位的唯一设备ID。它被存储在片上闪存的信息模块中。 96位唯一设备ID对于每颗芯片而言都是唯一的,所以它可以用作序列号,或安全密钥的一部分, 等等。

GD32F3X0芯片存储容量信息基地址:0x1FFFF7E0,设备唯一ID基地址:0x1FFFF7AC(31:0位)、0x1FFFF7B0 (63:32位)和0x1FFFF7B4(95:64位)三个地址下,地址由厂家设定,用户不能自行更改,而且寄存器只能按照字(32位)访问。

#include "example.h"

#if (EVB_EXAMPLE == CH13_BOARD_UART_EXAMPLE)

int main(void)
{

    uint32_t Flash_Size = *(uint32_t *)(0x1FFFF7E0);
    //获取MCU唯一ID
        uint32_t Unique_ID1 = *(uint32_t *)(0x1FFFF7AC);        //UNIQUE_ID[31: 0]
        uint32_t Unique_ID2 = *(uint32_t *)(0x1FFFF7B0);        //UNIQUE_ID[63:32]
        uint32_t Unique_ID3 = *(uint32_t *)(0x1FFFF7B4);        //UNIQUE_ID[95:63]
    EvbUart1Config();
    while(1)
    {
        for (int i =0;  i<0xfffff; i++);   
                printf("This is Colibri-F350RB ID:%x %x %x (hex)                         Flash_Size:%dn",Unique_ID3,Unique_ID2,Unique_ID1,Flash_Size);        
    }
        return 0;
}

通过对寄存器指针进行访问,获得MCU唯一ID,可以用于软件加密、序列号等等方面。

本帖最后由 justd0 于 2018-9-20 00:08 编辑

回复评论 (4)

不错,谢谢分享,楼主继续加油,期待你的大作
专注智能产品的研究与开发,专注于电子电路的生产与制造……QQ:2912615383,电子爱好者群: void
点赞  2018-9-20 07:15
//========================================================== //读stm32的id void READ_Unique_ID(volatile u32 *p) {         volatile u32 Addr;         Addr=0x20000006;    //让逆向的人误以为是ram变量   Addr-=0x800;    Addr-=0x1e;         //addr等于id的基地址0x1ffff7e8         p[0] = *(vu32*)(Addr);         p[1] = *(vu32*)(Addr+4);         p[2] = *(vu32*)(Addr+8);         } //============================================================
点赞  2022-8-3 14:49

三、利用id做软件加密



1,如果板子上有外部存储器,可以先编写一个程序,利用算法把id计算得到一些值存入外部存储器,然后再烧写真正的程序,真正的程序去校验外部存储器的数据是否合法即可



 



2,利用板子上按键组合,或是上电按住某些键,程序在这个时候利用算法把id计算得到一些值存入程序区(stm8为EE区),程序运行时去验证程序区数据是否正确



 



3,轩微编程器有软件加密的功能,编程器会读芯片id,根据算法直接改写缓冲区,达到软件加密的作用



 



4,读出的id通过一定算法,例如异或加上一个数,得到的数据存入flash(只运行一次,运行后标志位也存入flash),下次读到这个标志位,就不运行这个程序。//Q9272078



 



四、做软件加密时注意



1,不要在程序中直接出现id地址,例如STM32:1FFFF7E8 1FFFF7EC 1FFFF7F0   STM8: 0x4865~0x4870



2, 利用校验和或是crc对程序区进行校验,防止改程序


点赞  2022-8-3 14:49

谢谢,楼主,如果想重映射两个串口,这个fputc函数怎么支持对两个串口重映射

点赞  2022-12-3 11:54
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复