当前位置:首页 > > ZYNQ


QSPI是Quad SPI的简写,表示4线spi,是Motorola公司推出的SPI接口的扩展,比SPI应用更加广泛,本文主要演示zynq 7000下对QSPI 的读写操作,以及读取8字节唯一ID, 可以用于简单加密。

本文分为5部分:

  • 硬件设计

  • 软件设计

  • 测试验证

  • 总结

  • 扩展

本文的前提条件是读者会helloworld 实验,也就是会zynq 7000的SDK开发过程,如果不会,那先去看我的zynq 7000下的helloworld 实验,或者开发板提供的helloworld 实验教程。

我实验平台是黑金的核心板AC7010, 其板上的QSPI芯片是W25Q256FV

1  硬件设计

硬件设计基本和helloworld 一样,不同的是要选择QSPI, 否则怎么做实验呢。还有工程名字取为qspi。

在zynq配置的peripheral I/O Pins里选择Quad SPI Flash, 如图:

在zynq配置的MIO configuration里选择Quad SPI Flash的每个脚为 fast, 如图:

除此以外,都和hello world 实验的硬件设计一样。

2:软件设计

在SDK里 新建工程,取名为qspi_t , 在Next 里可以选择hello world 或者empty project。

下载我提供的xqspips_flash_polled_example.c 文件, 放入.src ,就是hellowrld.c 的地方,删除helloworld.c 。

为什么取这样一个名字呢?

这是Xilinx提供的样例程序,你可以在你的xilinx 目录下搜索到这个文件。我提供的程序是在其上修改得到的。

FlashWrite,FlashRead,FlashErase,FlashReadID都是样例程序里包含的。

我做的工作只是修改了main函数,还有仿照FlashReadID, 编写了一个FlashReadUID函数。

FlashWrite, 写Flash, 其参数是QSPI驱动指针, FLash写的起始地址, 写入字节数, 写命令:

 1void FlashWrite(XQspiPs *QspiPtr, u32 Address, u32 ByteCount, u8 Command)  2{  3 u8 WriteEnableCmd = { WRITE_ENABLE_CMD };  4 u8 ReadStatusCmd[] = { READ_STATUS_CMD, 0 }; /* must send 2 bytes */  5 u8 FlashStatus[2];  6  7 /*  8 * Send the write enable command to the FLASH so that it can be  9 * written to, this needs to be sent as a seperate transfer before 10 * the write 11 */ 12 XQspiPs_PolledTransfer(QspiPtr, &WriteEnableCmd, NULL, 13 sizeof(WriteEnableCmd)); 14 15 16 /* 17 * Setup the write command with the specified address and data for the 18 * FLASH 19 */ 20 WriteBuffer[COMMAND_OFFSET]   = Command; 21 WriteBuffer[ADDRESS_1_OFFSET] = (u8)((Address & 0xFF0000) >> 16); 22 WriteBuffer[ADDRESS_2_OFFSET] = (u8)((Address & 0xFF00) >> 8); 23 WriteBuffer[ADDRESS_3_OFFSET] = (u8)(Address & 0xFF); 24 25 /* 26 * Send the write command, address, and data to the FLASH to be 27 * written, no receive buffer is specified since there is nothing to 28 * receive 29 */ 30 XQspiPs_PolledTransfer(QspiPtr, WriteBuffer, NULL, 31 ByteCount + OVERHEAD_SIZE); 32 33 /* 34 * Wait for the write command to the FLASH to be completed, it takes 35 * some time for the data to be written 36 */ 37 while (1) { 38 /* 39 * Poll the status register of the FLASH to determine when it 40 * completes, by sending a read status command and receiving the 41 * status byte 42 */ 43 XQspiPs_PolledTransfer(QspiPtr, ReadStatusCmd, FlashStatus, 44 sizeof(ReadStatusCmd)); 45 46 /* 47 * If the status indicates the write is done, then stop waiting, 48 * if a value of 0xFF in the status byte is read from the 49 * device and this loop never exits, the device slave select is 50 * possibly incorrect such that the device status is not being 51 * read 52 */ 53 if ((FlashStatus[1] & 0x01) == 0) { 54 break; 55 } 56 } 57}

FlashRead, 读Flash, 其参数是QSPI驱动指针, FLash读的起始地址, 读取字节数, 读命令

 1void FlashRead(XQspiPs *QspiPtr, u32 Address, u32 ByteCount, u8 Command)  2{  3 /*  4 * Setup the write command with the specified address and data for the  5 * FLASH  6 */  7 WriteBuffer[COMMAND_OFFSET]   = Command;  8 WriteBuffer[ADDRESS_1_OFFSET] = (u8)((Address & 0xFF0000) >> 16);  9 WriteBuffer[ADDRESS_2_OFFSET] = (u8)((Address & 0xFF00) >> 8); 10 WriteBuffer[ADDRESS_3_OFFSET] = (u8)(Address & 0xFF); 11 12 if ((Command == FAST_READ_CMD) || (Command == DUAL_READ_CMD) || 13 (Command == QUAD_READ_CMD)) { 14 ByteCount += DUMMY_SIZE; 15 } 16 /* 17 * Send the read command to the FLASH to read the specified number 18 * of bytes from the FLASH, send the read command and address and 19 * receive the specified number of bytes of data in the data buffer 20 */ 21 XQspiPs_PolledTransfer(QspiPtr, WriteBuffer, ReadBuffer, 22 ByteCount + OVERHEAD_SIZE); 23}

FlashErase, 擦出Flash, 其参数是QSPI驱动指针, FLash擦除起始地址, 擦除字节数。

 1void FlashErase(XQspiPs *QspiPtr, u32 Address, u32 ByteCount)  2{  3 u8 WriteEnableCmd = { WRITE_ENABLE_CMD };  4 u8 ReadStatusCmd[] = { READ_STATUS_CMD, 0 }; /* must send 2 bytes */  5 u8 FlashStatus[2];  6 int Sector;  7  8 /*  9 * If erase size is same as the total size of the flash, use bulk erase  10 * command  11 */  12 if (ByteCount == (NUM_SECTORS * SECTOR_SIZE)) {  13 /*  14 * Send the write enable command to the FLASH so that it can be  15 * written to, this needs to be sent as a seperate transfer  16 * before the erase  17 */  18 XQspiPs_PolledTransfer(QspiPtr, &WriteEnableCmd, NULL,  19 sizeof(WriteEnableCmd));  20  21 /*  22 * Setup the bulk erase command  23 */  24 WriteBuffer[COMMAND_OFFSET]   = BULK_ERASE_CMD;  25  26 /*  27 * Send the bulk erase command; no receive buffer is specified  28 * since there is nothing to receive  29 */  30 XQspiPs_PolledTransfer(QspiPtr, WriteBuffer, NULL,  31 BULK_ERASE_SIZE);  32  33 /*  34 * Wait for the erase command to the FLASH to be completed  35 */  36 while (1) {  37 /*  38 * Poll the status register of the device to determine  39 * when it completes, by sending a read status command  40 * and receiving the status byte  41 */  42 XQspiPs_PolledTransfer(QspiPtr, ReadStatusCmd,  43 FlashStatus,  44 sizeof(ReadStatusCmd));  45  46 /*  47 * If the status indicates the write is done, then stop  48 * waiting; if a value of 0xFF in the status byte is  49 * read from the device and this loop never exits, the  50 * device slave select is possibly incorrect such that  51 * the device status is not being read  52 */  53 if ((FlashStatus[1] & 0x01) == 0) {  54 break;  55 }  56 }  57  58 return;  59 }  60  61 /*  62 * If the erase size is less than the total size of the flash, use  63 * sector erase command  64 */  65 for (Sector = 0; Sector < ((ByteCount / SECTOR_SIZE) + 1); Sector++) {  66 /*  67 * Send the write enable command to the SEEPOM so that it can be  68 * written to, this needs to be sent as a seperate transfer  69 * before the write  70 */  71 XQspiPs_PolledTransfer(QspiPtr, &WriteEnableCmd, NULL,  72 sizeof(WriteEnableCmd));  73  74 /*  75 * Setup the write command with the specified address and data  76 * for the FLASH  77 */  78 WriteBuffer[COMMAND_OFFSET]   = SEC_ERASE_CMD;  79 WriteBuffer[ADDRESS_1_OFFSET] = (u8)(Address >> 16);  80 WriteBuffer[ADDRESS_2_OFFSET] = (u8)(Address >> 8);  81 WriteBuffer[ADDRESS_3_OFFSET] = (u8)(Address & 0xFF);  82  83 /*  84 * Send the sector erase command and address; no receive buffer  85 * is specified since there is nothing to receive  86 */  87 XQspiPs_PolledTransfer(QspiPtr, WriteBuffer, NULL,  88 SEC_ERASE_SIZE);  89  90 /*  91 * Wait for the sector erse command to the FLASH to be completed  92 */  93 while (1) {  94 /*  95 * Poll the status register of the device to determine  96 * when it completes, by sending a read status command  97 * and receiving the status byte  98 */  99 XQspiPs_PolledTransfer(QspiPtr, ReadStatusCmd, 100 FlashStatus, 101 sizeof(ReadStatusCmd)); 102 103 /* 104 * If the status indicates the write is done, then stop 105 * waiting, if a value of 0xFF in the status byte is 106 * read from the device and this loop never exits, the 107 * device slave select is possibly incorrect such that 108 * the device status is not being read 109 */ 110 if ((FlashStatus[1] & 0x01) == 0) { 111 break; 112 } 113 } 114 115 Address += SECTOR_SIZE; 116 } 117}

写命令其实只有一个WRITE_CMD, 但读命令有4个选择:

  • READ_CMD

  • FAST_READ_CMD

  • DUAL_READ_CMD

  • QUAD_READ_CMD

FlashReadID就是读取JEDEC ID

 1int FlashReadID(void)  2{  3 int Status;  4  5 /*  6 * Read ID in Auto mode.  7 */  8 WriteBuffer[COMMAND_OFFSET]   = READ_ID;  9 WriteBuffer[ADDRESS_1_OFFSET] = 0x23; /* 3 dummy bytes */ 10 WriteBuffer[ADDRESS_2_OFFSET] = 0x08; 11 WriteBuffer[ADDRESS_3_OFFSET] = 0x09; 12 13 Status = XQspiPs_PolledTransfer(&QspiInstance, WriteBuffer, ReadBuffer, 14 RD_ID_SIZE); 15 if (Status != XST_SUCCESS) { 16 return XST_FAILURE; 17 } 18 19 xil_printf("Flash  JEDEC ID=0x%x 0x%x 0x%x\n\r", ReadBuffer[1], ReadBuffer[2], 20 ReadBuffer[3]); 21 22 return XST_SUCCESS; 23}

FlashReadUID是我仿照上面函数写的, 我查看了W25Q256FV的手册,读取唯一ID的cmd 是0x4B, 我不确定其他芯片是否一样,你需要自己查看。

 1int FlashReadUID(void)  2{  3 int Status;  4  5 /*  6 * Read ID in Auto mode.  7 */  8 WriteBuffer[COMMAND_OFFSET]   = 0x4B;  9 WriteBuffer[ADDRESS_1_OFFSET] = 0x23; /* 3 dummy bytes */ 10 WriteBuffer[ADDRESS_2_OFFSET] = 0x08; 11 WriteBuffer[ADDRESS_3_OFFSET] = 0x09; 12 13 Status = XQspiPs_PolledTransfer(&QspiInstance, WriteBuffer, ReadBuffer, 14 16); 15 if (Status != XST_SUCCESS) { 16 return XST_FAILURE; 17 } 18 19 xil_printf("Flash Unique ID=0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n\r",ReadBuffer[5], ReadBuffer[6], ReadBuffer[7], ReadBuffer[8], ReadBuffer[9], ReadBuffer[10], ReadBuffer[11], ReadBuffer[12]); 20 21 return XST_SUCCESS; 22}

主程序的流程是:

基本初始化,获取Flash 的驱动指针,给WriteBuffer数组赋值,就是打算 写什么东西进去,调用2个id 读取, 擦除,读取,显示内容,写入, 读取,显示内容,调用2个id 读取并显示。

3:程序运行

以下是程序运行在串口监视终端上的显示内容:


4:总结

按资料介绍,唯一id 每个芯片都是不一样的,可不可以把你 的id 告诉我,看看是不是都不一样。

如果这样的话,我们就可以用这个id 加密,就是用一个算法,比如des,des3,得到一个结果,而这个结果只有知道算法的人才知道。

把这个结果填入一个地方,那就是程序员认可了。这样如果简单复制程序,那就不行的,防止盗版。

5 : 扩展

其实xilinx 也有一套加密的算法,xilinx 的加密方法相关文档是:

https://www.xilinx.com/support/documentation/user_guides/ug1025-zynq-secure-boot-gsg.pdf

xapp1175_zynq_secure_boot.pdf

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
关闭