【正点原子FPGA连载】第十三章QSPI Flash读写测试实验 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南
1)实验平台:正点原子MPSoC开发板
2)平台购买地址:https://detail.tmall.com/item.htm?id=692450874670
3)全套实验源码+手册+视频下载地址: http://www.openedv.com/thread-340252-1-1.html
第十三章QSPI Flash读写测试实验
PS的输入/输出外设(IOP)有两个具有不同功能特性和IO接口性能的QSPI控制器。它们共享相同的APB从接口和MIO引脚。一次只能使用控制器中的一个。QSPI控制器可以访问多比特位宽的Flash设备,以实现较少的引脚数达到高吞吐量的应用。
本章我们将通过QSPI Flash控制器,来完成对QSPI Flash的读写操作。本章包括以下几个部分:
1313.1简介
13.2实验任务
13.3硬件设计
13.4软件设计
13.5下载验证
13.1简介
MPSOC中的QSPI Flash控制器分为传统QSPI控制器(LQSPI)和通用QSPI控制器(GQSPI)两个。传统QSPI控制器通过AXI从接口提供了线性可寻址的内存空间。支持引导配置(BOOT)和应用软件配置的就地执行(execute-in-place)。通用QSPI控制器提供I/O,DMA和SPI三种接口模式,不支持引导(BOOT)和就地执行(execute-in-place)。I/O接口配置如下图所示:

图13.1.1 QSPI I/O接口配置
传统QSPI控制器(LQSPI)只在线性寻址模式下工作。在这种模式下,可以连接一个或两个Flash器件,为了最小化引脚数量,两块Flash可以通过8bit并行模式或者4bit堆叠排列模式连接到传统QSPI控制器。线性地址模式下,控制器通过使用部分器件操作来消除读Flash时的软件开销。QSPI控制器给Flash发送命令,控制Flash总线到AXI接口的数据流。控制器响应AXI接口上的Flash存储器请求,把Flash存储器当作ROM存储器。
通用QSPI控制器(GQSPI)满足软件对通用低级访问的要求。由于QSPI控制器的通用性,软件可以在任何模式下生成任何命令序列。同时,QSPI控制器支持SPI、Dual SPI和Quad SPI模式下的功能。QSPI控制器运行在I/O、DMA和SPI三种模式下。通用QSPI控制器也支持连接一块或两块Flash设备,为了最小化引脚数量,两块Flash可以通过8bit并行模式或者4bit堆叠排列模式连接到通用QSPI控制器。
在通用I/O模式下,软件和存储设备密切交互。软件将Flash命令写到通用FIFO中,并将数据写到TXFIFO。软件读取RXD寄存器,获取从Flash设备接收到的数据。在I/O模式下,通用QSPI控制器消除了写TXFIFO时产生的软件开销。
在通用DMA模式下,内部DMA模块将Flash设备中的数据传输到系统内存中。这种模式避免了用处理器从Flash中读数据,并且消除了TXFIFO中写满来自Flash数据时产生的软件开销。
在SPI模式下,通用QSPI控制器可以作为标准SPI控制器使用。
双QSPI结构框图如下图所示,控制器由一个传统线性QSPI控制器和一个通用QSPI控制器组成。当控制寄存器设置为1时,选择通用QSPI控制器。传统QSPI控制器和通用QSPI控制器共享带延迟线的接收捕获逻辑。

图13.1.2 双QSPI控制器
13.2实验任务
本章的实验任务是使用QSPI Flash控制器,先后对开发板上的QSPI Flash进行写、读操作。通过对比读出的数据是否等于写入的数据,从而验证读写操作是否正确。
13.3硬件设计
根据实验任务我们可以画出本次实验的系统框图,如下图所示:

图 13.3.1 系统框图
从图 13.3.1中可以看出,本次实验是在“Hello Wold”实验的基础上增加了一个QSPI Flash控制器。我们将通过该控制器对QSPI Flash进行读写操作,并通过串口打印读写数据对比之后的结果。
首先创建Vivado工程,工程名为“qspi_flash_test”,然后创建Block Design设计(system.bd)并添加Zynq Ultrascale+ MPSOC模块。接下来按照《“Hello World”实验》中的步骤对Zynq Ultrascale+ MPSOC模块进行配置,配置完成后我们要添加本次实验所使用的QSPI Flash控制器模块。如下图所示:

图 13.3.2 QSPI配置界面
如图 13.3.2所示,在左侧导航栏中选择“I/O Configuraton”,然后在右侧勾选“QSPI”,并选择“Single”模式,QSPI Data Mode选择“x4”,QSPI使用默认的“MIO0…5”。“Single”指的是单个Flash器件。看以看出,该模式下控制器使用了MIO0至MIO5共6个引脚。
最后点击右下角的“OK”,本次实验Zynq Ultrascale+ MPSOC处理系统就配置完成了。配置完成后的模块如下图所示:

图 13.3.3 Zynq Ultrascale+ MPSOC模块
到这里我们的Block Design就设计完成了,在Diagram窗口空白处右击,然后选择“Validate Design”验证设计。验证完成后弹出对话框提示“Validation Successful”表明设计无误,点击“OK”确认。最后按快捷键“Ctrl + S”保存设计。
接下来在Source窗口中右键点击Block Design设计文件“system.bd”,然后依次执行“Generate Output Products”和“Create HDL Wrapper”。
然后在菜单栏中选择 File > Export > Export hardware,将硬件文件导出到新建的vitis文件夹下,最后在菜单栏选择Tools > Launch Vitis,将路径设置到本工程的vitis文件夹下,启动Vitis软件。
13.4软件设计
在Vitis软件中新建名为“qspi_flash_test”的应用工程。然后为应用工程新建一个源文件“main.c”,我们在新建的main.c文件中输入本次实验的代码。代码的主体部分如下所示:
1 #include "xparameters.h" /* Vitis generated parameters */
2 #include "xqspipsu.h" /* QSPIPSU device driver */
3 #include "xil_printf.h"
4 #include "xil_cache.h"
5
6 //定义flash读写命令
7 #define WRITE_STATUS_CMD 0x01
8 #define WRITE_CMD 0x02
9 #define READ_CMD 0x03
10 #define WRITE_DISABLE_CMD 0x04
11 #define READ_STATUS_CMD 0x05
12 #define WRITE_ENABLE_CMD 0x06
13 #define VOLATILE_WRITE_ENABLE_CMD 0x50
14 #define QUAD_MODE_ENABLE_BIT 0x06
15 #define FAST_READ_CMD 0x0B
16 #define DUAL_READ_CMD 0x3B
17 #define QUAD_READ_CMD 0x6B
18 #define BULK_ERASE_CMD 0xC7
19 #define SEC_ERASE_CMD 0xD8
20 #define READ_ID 0x9F
21 #define READ_CONFIG_CMD 0x35
22 #define WRITE_CONFIG_CMD 0x01
23
24 #define READ_CMD_4B 0x13
25 #define FAST_READ_CMD_4B 0x0C
26 #define DUAL_READ_CMD_4B 0x3C
27 #define QUAD_READ_CMD_4B 0x6C
28
29 #define READ_FLAG_STATUS_CMD 0x70
30
31 #define COMMAND_OFFSET 0 //Flash instruction
32 #define ADDRESS_1_OFFSET 1 //数据偏移地址的最高位
33 #define ADDRESS_2_OFFSET 2 //数据偏移地址的中间位
34 #define ADDRESS_3_OFFSET 3 //数据偏移地址的最低位
35 #define ADDRESS_4_OFFSET 4 //数据偏移地址为四字节时 最低位
36
37 #define DATA_OFFSET 5 //Start of Data for Read/Write
38 #define DUMMY_OFFSET 4 //Dummy byte offset for fast, dual and quad reads
39
40 #define DUMMY_SIZE 1 //Number of dummy bytes for fast, dual and quad reads
41
42 #define DUMMY_CLOCKS 8 //Number of dummy bytes for fast, dual and quad reads
43
44 #define RD_ID_SIZE 4 //Read ID command + 3 bytes ID response
45 #define BULK_ERASE_SIZE 1 //Bulk Erase command size
46 #define SEC_ERASE_SIZE 4 //Sector Erase command + Sector address
47 #define BANK_SEL_SIZE 2 //BRWR or EARWR command + 1 byte bank value
48
49 #define RD_CFG_SIZE 2 //1 byte Configuration register + RD CFG command
50
51 #define WR_CFG_SIZE 3 //WRR command + 1 byte each Status and Config Reg
52
53 #define DIE_ERASE_SIZE 4 //Die Erase command + Die address
54
55 #define OVERHEAD_SIZE 4
56
57 //flash基地址
58 #define FLASH1BASE 0x0000000
59
60 //16MB
61 #define SIXTEENMB 0x1000000
62
63 //quad enable mask bit
64 #define FLASH_QUAD_EN_MASK 0x02
65
66 #define FLASH_SRWD_MASK 0x80
67
68 // Bank mask
69 #define BANKMASK 0xF000000
70
71
72 // Identification of Flash
73 // Micron:
74 // Byte 0 is Manufacturer ID;
75 // Byte 1 is first byte of Device ID - 0xBB or 0xBA
76 // Byte 2 is second byte of Device ID describes flash size:
77 // 128Mbit : 0x18; 256Mbit : 0x19; 512Mbit : 0x20
78 #define MICRON_ID_BYTE0 0x20
79 #define MICRON_ID_BYTE2_128 0x18
80 #define MICRON_ID_BYTE2_256 0x19
81 #define MICRON_ID_BYTE2_512 0x20
82 #define MICRON_ID_BYTE2_1G 0x21
83 #define MICRON_ID_BYTE2_2G 0x22
84
85 // Spansion:
86 // Byte 0 is Manufacturer ID;
87 // Byte 1 is Device ID - Memory Interface type - 0x20 or 0x02
88 // Byte 2 is second byte of Device ID describes flash size:
89 // 128Mbit : 0x18; 256Mbit : 0x19; 512Mbit : 0x20
90 #define SPANSION_ID_BYTE0 0x01
91 #define SPANSION_ID_BYTE2_64 0x17
92 #define SPANSION_ID_BYTE2_128 0x18
93 #define SPANSION_ID_BYTE2_256 0x19
94 #define SPANSION_ID_BYTE2_512 0x20
95
96 #define WINBOND_ID_BYTE0 0xEF
97 #define WINBOND_ID_BYTE2_128 0x18
98
99 #define ISSI_ID_BYTE0 0x9D
100 #define ISSI_ID_BYTE2_08 0x14
101 #define ISSI_ID_BYTE2_16 0x15
102 #define ISSI_ID_BYTE2_32 0x16
103 #define ISSI_ID_BYTE2_64 0x17
104 #define ISSI_ID_BYTE2_128 0x18
105 #define ISSI_ID_BYTE2_256 0x19
106 #define ISSI_ID_BYTE2_512 0x1a
107
108 #define QSPIPSU_DEVICE_ID XPAR_XQSPIPSU_0_DEVICE_ID
109
110 //flash页的数量
111 #define PAGE_COUNT 32
112
113 //页大小的最大值
114 #define MAX_PAGE_SIZE 1024
115
116 #define TEST_ADDRESS 0x000000
117
118 #define UNIQUE_VALUE 0x06
119
120 /**************************** Type Definitions *******************************/
121 typedef struct{
122 u32 SectSize; //扇区大小
123 u32 NumSect; //扇区总个数
124 u32 PageSize; //页大小
125 u32 NumPage; //总页数
126 u32 FlashDeviceSize; //一个存储器件的大小
127 u8 ManufacturerID; //制造商ID
128 u8 DeviceIDMemSize; //指出存储容量的器件ID
129 u32 SectMask; //扇区开始地址掩码
130 u8 NumDie; // No. of die forming a single flash
131 } FlashInfo;
132
133 u8 ReadCmd;
134 u8 WriteCmd;
135 u8 StatusCmd;
136 u8 SectorEraseCmd;
137 u8 FSRFlag;
138
139 /************************** Function Prototypes ******************************/
140
141 int QspiPsuPolledFlashExample(XQspiPsu *QspiPsuInstancePtr, u16 QspiPsuDeviceId);
142 int FlashReadID(XQspiPsu *QspiPsuPtr);
143 int FlashErase(XQspiPsu *QspiPsuPtr, u32 Address, u32 ByteCount, u8 *WriteBfrPtr);
144 int FlashWrite(XQspiPsu *QspiPsuPtr, u32 Address, u32 ByteCount, u8 Command,
145 u8 *WriteBfrPtr);
146 int FlashRead(XQspiPsu *QspiPsuPtr, u32 Address, u32 ByteCount, u8 Command,
147 u8 *WriteBfrPtr, u8 *ReadBfrPtr);
148 u32 GetRealAddr(XQspiPsu *QspiPsuPtr, u32 Address);
149 int BulkErase(XQspiPsu *QspiPsuPtr, u8 *WriteBfrPtr);
150 int FlashEnableQuadMode(XQspiPsu *QspiPsuPtr);
151 /************************** Variable Definitions *****************************/
152 u8 TxBfrPtr;
153 u8 ReadBfrPtr[3];
154 FlashInfo Flash_Config_Table[] = {
155 {SECTOR_SIZE_64K, NUM_OF_SECTORS128, BYTES256_PER_PAGE,
156 0x8000, 0x800000, SPANSION_ID_BYTE0,
157 SPANSION_ID_BYTE2_64, 0xFFFF0000, 1}
158 };
159
160 u32 FlashMake;
161 u32 FCTIndex; //闪存配置表的索引
162
163 //QSPI实例
164 static XQspiPsu QspiPsuInstance;
165
166 static XQspiPsu_Msg FlashMsg[5];
167
168 //测试变量 用于产生发送数据
169 int Test = 1;
170
171 //用于存储读写数据的变量
172 u8 ReadBuffer[(PAGE_COUNT * MAX_PAGE_SIZE) + (DATA_OFFSET + DUMMY_SIZE)*8] __attribute__ ((aligned(64)));
173 u8 WriteBuffer[(PAGE_COUNT * MAX_PAGE_SIZE) + DATA_OFFSET];
174 u8 CmdBfr[8];
175
176 u32 MaxData = PAGE_COUNT*256;
177
178 //主函数
179 int main(void)
180 {
181 int Status;
182
183 xil_printf("QSPIPSU Generic Flash Polled Example Test \r\n");
184
185 //调用QspiPsu Polled example
186 Status = QspiPsuPolledFlashExample(&QspiPsuInstance, QSPIPSU_DEVICE_ID);
187 if (Status != XST_SUCCESS) {
188 xil_printf("QSPIPSU Generic Flash Polled Example Failed\r\n");
189 return XST_FAILURE;
190 }
191
192 xil_printf("Successfully ran QSPIPSU Generic Flash Polled Example\r\n");
193 return XST_SUCCESS;
194 }
首先,本次实验的C程序是在官方提供的示例程序“xqspipsu_generic_flash_polled_example.c”的基础上修改得到的,该示例程序演示了如何使用轮询模式对QSPI Flash进行读写操作。
在程序的开头,我们定义了一系列的参数,包括Flash器件的指令、Flash BUFFER中各数据段的偏移量、Flash器件PAGE、SECTOR的数目和大小等信息。这些信息针对不同型号的Flash器件有所不同,需要通过查看器件的数据手册得到。
接下来在程序第141至150行声明了八个函数,这些函数是前面我们提到的示例程序中所提供的。我们对其中的函数QspiPsuPolledFlashExample(XQspiPsu *QspiPsuInstancePtr, u16 QspiPsuDeviceId)、FlashReadID(XQspiPsu *QspiPsuPtr)进行修改,从而简化读写测试过程。而其他的函数如擦除FlashErase( )、写操作FlashWrite( )、读操作FlashRead( )等,改动不大。
程序的主函数特别简单,就是通过调用修改之后的示例函数QspiPsuPolledFlashExample ( )来对Flash进行读写测试,并打印最终的测试结果。下面是该示例函数的代码:
198 int QspiPsuPolledFlashExample(XQspiPsu *QspiPsuInstancePtr, u16 QspiPsuDeviceId)
199 {
200 u8 UniqueValue;
201 int Count;
202 int Page;
203 XQspiPsu_Config *QspiPsuConfig;
204 int ReadBfrSize;
205
206 ReadBfrSize = (PAGE_COUNT * MAX_PAGE_SIZE) +
207 (DATA_OFFSET + DUMMY_SIZE)*8;
208
209 //根据ID查找Qspi配置信息
210 QspiPsuConfig = XQspiPsu_LookupConfig(QspiPsuDeviceId);
211 if (QspiPsuConfig == NULL) {
212 return XST_FAILURE;
213 }
214
215 //初始化Qspi
216 XQspiPsu_CfgInitialize(QspiPsuInstancePtr, QspiPsuConfig,
217 QspiPsuConfig->BaseAddress);
218
219 //设置Options
220 XQspiPsu_SetOptions(QspiPsuInstancePtr, XQSPIPSU_MANUAL_START_OPTION);
221
222 //为qspi时钟设置分频系数
223 XQspiPsu_SetClkPrescaler(QspiPsuInstancePtr, XQSPIPSU_CLK_PRESCALE_8);
224
225 XQspiPsu_SelectFlash(QspiPsuInstancePtr,
226 XQSPIPSU_SELECT_FLASH_CS_LOWER,
227 XQSPIPSU_SELECT_FLASH_BUS_LOWER);
228
229 //读Flash ID
230 FlashReadID(QspiPsuInstancePtr);
231
232
233 //Initialize MaxData according to page size.
234
235 MaxData = PAGE_COUNT * (Flash_Config_Table[FCTIndex].PageSize);
236
237 //使能flash quad模式
238 FlashEnableQuadMode(QspiPsuInstancePtr);
239
242 //Address size and read command selection
243 ReadCmd = QUAD_READ_CMD;
244 WriteCmd = WRITE_CMD;
245 SectorEraseCmd = SEC_ERASE_CMD;
246
247 /* Status cmd - SR or FSR selection */
248 if ((Flash_Config_Table[FCTIndex].NumDie > 1) &&
249 (FlashMake == MICRON_ID_BYTE0)) {
250 StatusCmd = READ_FLAG_STATUS_CMD;
251 FSRFlag = 1;
252 } else {
253 StatusCmd = READ_STATUS_CMD;
254 FSRFlag = 0;
255 }
256
257 for (UniqueValue = UNIQUE_VALUE, Count = 0;
258 Count < Flash_Config_Table[FCTIndex].PageSize;
259 Count++, UniqueValue++) {
260 WriteBuffer[Count] = (u8)(UniqueValue + Test);
261 }
262
263 for (Count = 0; Count < ReadBfrSize; Count++) {
264 ReadBuffer[Count] = 0;
265 }
266
267 //擦除flash
268 FlashErase(QspiPsuInstancePtr, TEST_ADDRESS, MaxData, CmdBfr);
269
270 for (Page = 0; Page < PAGE_COUNT; Page++) {
271 FlashWrite(QspiPsuInstancePtr,
272 (Page * Flash_Config_Table[FCTIndex].PageSize) + TEST_ADDRESS,
273 Flash_Config_Table[FCTIndex].PageSize,
274 WriteCmd, WriteBuffer);
275 }
276
277 //从flash中读出数据
278 FlashRead(QspiPsuInstancePtr, TEST_ADDRESS, MaxData, ReadCmd,
279 CmdBfr, ReadBuffer);
280
281 //读出的数据和写入的数据对比
282 for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MaxData;
283 Count++, UniqueValue++) {
284 if (ReadBuffer[Count] != (u8)(UniqueValue + Test)) {
285 return XST_FAILURE;
286 }
287 }
288
289 return XST_SUCCESS;
290 }
在示例函数中,首先查找QSPI Flash控制器配置信息,接着对控制器驱动进行初始化,如代码的第210行至217行所示。向WriteBuffer中写入数据,然后将WriteBuffer中的数据写到Flash中,如代码第270行至第275行所示。注意在写Flash之前,调用FlashErase( )函数对Flash进行擦除,这是因为Flash写操作只能将1写成0,不能将0写成1,而擦除操作才能将0写成1。
最后,在程序的第282至287行,通过对比写入BUFFER的数据与读BUFFER中的数据是否一致,从而判断Flash读写测试实验是否成功。
程序的剩余部分是前面所声明的一系列操作Flash的函数的实现,因为我们将其当作库函数直接调用,因此代码就不再贴出来了。大家有兴趣的话也可以研究一下,这些函数是如何将读写指令和数据转换成QSPI Flash所要求的命令格式的。实际上,这些函数的功能也都是通过调用xqspipsu.h头文件中的库函数XQspiPsu_PolledTransfer( )来实现的。
13.5下载验证
首先我们将下载器与开发板上的JTAG接口连接,下载器另外一端与电脑连接。然后使用USB连接线将开发板的USB_UART接口(PS PORT)与电脑连接,用于串口通信。最后连接开发板的电源,给开发板供电。
打开Vitis Terminal终端,设置并连接串口。然后下载本次实验的程序,下载完成后,在下方的Terminal中可以看到应用程序打印的信息“Successfully ran QSPIPSU Generic Flash Polled Test”,如下图所示:

图 13.5.1 串口打印结果
从图 13.5.1中可以看出,本次实验所实现的QSPI Flash读写测试功能,在MPSOC开发板上面下载验证成功。
相关文章:
【正点原子FPGA连载】第十三章QSPI Flash读写测试实验 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南
1)实验平台:正点原子MPSoC开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id692450874670 3)全套实验源码手册视频下载地址: http://www.openedv.com/thread-340252-1-1.html 第十三章QSPI Fl…...
深入理解mysql的内核查询成本计算
MySql系列整体栏目 内容链接地址【一】深入理解mysql索引本质https://blog.csdn.net/zhenghuishengq/article/details/121027025【二】深入理解mysql索引优化以及explain关键字https://blog.csdn.net/zhenghuishengq/article/details/124552080【三】深入理解mysql的索引分类&a…...
LeetCode 141. 环形链表
原题链接 难度:easy\color{Green}{easy}easy 题目描述 给你一个链表的头节点 headheadhead ,判断链表中是否有环。 如果链表中有某个节点,可以通过连续跟踪 nextnextnext 指针再次到达,则链表中存在环。 为了表示给定链表中的…...
git提交
文章目录关于数据库:桌面/vue-admin/vue_shop_api 的 git 输入 打开 phpStudy ->mySQL管理器 导入文件同时输入密码,和文件名 node app.js 错误区: $ git branch // git branch 查看分支 只有一个main分支不见master解决: gi…...
Java中常见的编码集问题
收录于热门专栏Java基础教程系列(进阶篇) 一、遇到一个问题 1、读取CSV文件 package com.guor.demo.charset;import java.io.BufferedReader; import java.io.FileReader; import java.util.ArrayList; import java.util.HashMap; import java.util.L…...
数据结构与算法(Java版) | 就让我们来看看几个实际编程中遇到的问题吧!
上一讲,我给大家简单介绍了一下数据结构,以及数据结构与算法之间的关系,照理来说,接下来我就应该要给大家详细介绍线性结构和非线性结构了,但是在此之前,我决定还是先带着大家看几个实际编程中遇到的问题&a…...
【C++算法】dfs深度优先搜索(上) ——【全面深度剖析+经典例题展示】
💃🏼 本人简介:男 👶🏼 年龄:18 📕 ps:七八天没更新了欸,这几天刚搞完元宇宙,上午一直练🚗,下午背四级单词和刷题来着,还在忙一些学弟…...
总结高频率Vue面试题
目录 什么是三次握手? 什么是四次挥手?(close触发) 什么是VUEX? 什么是同源----跨域? 什么是Promise? 什么是fexl布局? 数据类型 什么是深浅拷贝? 什么是懒加载&…...
IP协议详解
目录 前言: IP协议 提出问题 解决方案 地址管理 子网掩码 路由选择 小结: 前言: IP协议作为网络层知名协议。当数据经过传输层使用TCP或者UDP对数据进行封装,然后当数据到达网络层,基于TCP或UDP数据包继续进行…...
webpack5 基础配置
在开发中,我们会使用 vue、react、less、scss等语法进行开发项目,但是浏览器只能识别 js、css,或者说在js中使用了es6中的import 导入 这时候也需要打包工具去转换成浏览器可以识别的语句。 一、使用webpack 1.初始化package.json npm i…...
IDEA入门安装使用教程
一、背景 作为一个Java开发者,有非常多编辑工具供我们选择,比如Eclipse、IntelliJ IDEA、NetBeans、Visual Studio Code、Sublime Text等等,这些有免费也有收费的,但是就目前市场占比来说普遍使用Eclipse和IntelliJ IDEA这两款主…...
Lambda表达式使用及详解
一 Lambda表达式的简介 Lambda表达式(闭包):java8的新特性,lambda运行将函数作为一个方法的参数,也就是函数作为参数传递到方法中。使用lambda表达式可以让代码更加简洁。 Lambda表达式的使用场景:用以简…...
JAVA练习52-打家劫舍
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一、题目-打家劫舍 1.题目描述 2.思路与代码 2.1 思路 2.2 代码 总结 前言 提示:这里可以添加本文要记录的大概内容: 2月16日练习内容 提…...
简单谈一谈幂等测试
1、什么是幂等测试 幂等是一个抽象的概念,在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同,即多次调用方法或者接口不会改变业务状态,可以保证重复调用的结果和单次调用的结果一致。幂等测试,则主…...
typescript复习笔记
数组类型-限定每一项的类型 //写法一 const arrNumber: number[] [1, 2, 3] const arrString: string[] [a, b, c] //写法二 const arrNumber2: Array<number> [1, 2, 3] const arrString2: Array<string> [a, b, c]联合类型 符号是 | //数组可以存放字符串或…...
webstorm开发electron,调试主进程方案
官网教程地址:https://www.electronjs.org/zh/docs/latest/tutorial/debugging-main-process 我只能说官网太看得起人了,整这么简易的教程…… 命令行开关 第一步还是要按要求在我们的package.json里加上端口监听:–inspect5858 我的命令…...
2W字正则表达式基础知识总结,这一篇就够了!!(含前端常用案例,建议收藏)
正则表达式 (Regular Expression,简称 RE 或 regexp ) 是一种文本模式,包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为"元字符")正则表达式使用单个字符串来描述、匹配一系列匹…...
自学web前端觉得好难,可能你遇到了这些困境
好多人跟我说上学的时候也学过前端,毕业了想从事web前端开发的工作,但自学起来好难,快要放弃了,所以我总结了一些大家遇到的困境,希望对你会有所帮助。 目录 1. 意志是否坚定 2. 没有找到合适自己的老师 3. 为了找…...
ASEMI中低压MOS管18N20参数,18N20封装,18N20尺寸
编辑-Z ASEMI中低压MOS管18N20参数: 型号:18N20 漏极-源极电压(VDS):200V 栅源电压(VGS):30V 漏极电流(ID):18A 功耗(PD&#x…...
[NetBackup]客户端安装后server无法连通client
client name处填写客户端主机名,server to use for backups and restores处填写server端名字,与hosts文件内保持一致;source client for restores处填写client主机名,与server端hosts文件中保持一致,与主机实际名称保持…...
【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...
微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
通过MicroSip配置自己的freeswitch服务器进行调试记录
之前用docker安装的freeswitch的,启动是正常的, 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...
SpringAI实战:ChatModel智能对话全解
一、引言:Spring AI 与 Chat Model 的核心价值 🚀 在 Java 生态中集成大模型能力,Spring AI 提供了高效的解决方案 🤖。其中 Chat Model 作为核心交互组件,通过标准化接口简化了与大语言模型(LLM࿰…...
