嵌入式开发八:STM32启动过程分析

      本次给大家分析 STM32F4 的启动过程,这里的启动过程是指从 STM32 芯片上电复位执行的第一条指令开始,到执行用户编写的 main 函数这之间的过程。我们编写程序,基本都是用 C 语言编写,并且以 main 函数作为程序的入口。但是事实上,main 函数并非最先执行的,在此之前需要做一些准备工作,准备工作通过启动文件的程序来完成。理解 STM32 启动过程,对今后的学习和分析 STM32 程序有很大的帮助。本文主要是了解启动文件的作用。

目录

一、内存管理

1.0 内存管理的概念       

1.1  stmf407内存大小和分布

1.2  Flash和RAM介绍

1.2.1 FLASH是什么?

1.2.2 RAM是什么?

1.3  STM32的内存管理

1.3.1 STM32存储器架构

1.3.2 STM32的存储器映射分析

1.3.3 STM32内存分析

1.3.4 单片机和 x86CPU运行程序的不同 

二、STM32启动分析

2.1 启动模式

2.2 启动文件分析

2.2.0 什么是启动文件

2.2.1 启动文件中的一些指令

​2.2.2 启动文件代码讲解

2.3map文件分析


一、内存管理

1.0 内存管理的概念       

1、内存管理

        是指软件运行时对计算机内存资源的分配和使用的技术。主要的目的是如何高效,快速的分配,并且在适当的时候释放和回收内存资源内存管理的实现方法有很多种,他们其实最终都是要实现 2 个函数:malloc 和 free;malloc 函数用于内存申请,free 函数用于内存释放。

2、进程内存分区:
       不管什么样的操作系统、什么样的计算机架构,进程使用的内存都可以按照功能大致分成以下4个部分。

(1)代码区:这个区域存储着被装入执行的二进制机器代码,处理器会到这个区域取指令并执行。
(2)数据区:用于存储全局变量等。
(3)堆区:进程可以在堆区动态地请求一定大小的内存,并在用完之后归还给堆区。动态分配内存和回收内存是堆区的特点。
(4)栈区:用于动态地存储函数之间的调用关系,以保证被调用函数在返回时恢复到主调函数中继续执行。

 3、进程执行过程

       在Windows平台下,高级语言写出的程序经过编译链接,最终会变成所谓的PE文件。当PE文件被装载运行后,就成了所谓的进程。

  1. PE文件代码段中包含的二进制的机器代码会被装入内存的代码区(.text)
  2. 处理器将到内存的代码区一条一条地取出指令和操作数,并送入算术逻辑单元进行运算;
  3. 如果代码中请求开辟动态内存,则会在内存的堆区分配一块大小合适的区域返回给代码区的代码使用;
  4. 当函数调用发生时,函数的调用关系等信息会动态地保存在内存的栈区,以供处理器在执行完被调用函数的代码时,返回被调函数。

1.1  stmf407内存大小和分布

1.2  Flash和RAM介绍

     使用一个STM32芯片,对于内存而言有两个直观的指标就是 RAM 大小,FLASH大小,那么着两个大小意味着什么?怎么去理解这两个内存,那就得从什么是Flash,什么是RAM说起。先来看一张图:

1.2.1 FLASH是什么?

       通过上图我们可以知道,FLASH属于 非易失性存储器:扩展一点说,FLASH又称为闪存,不仅具备电子可擦除可编程(EEPROM)的性能,不会因为断电丢失数据同时可以快速读取数据,U盘和MP3里用的就是这种存储器。在以前的嵌入式芯片中,存储设备一直使用ROM(EPROM),随着技术的进步,现在嵌入式中基本都是FLASH,用作存储Bootloader以及操作系统或者程序代码或者直接当硬盘使用(U盘)。然后 Flash 主要有两种NOR Flash和NADN Flash。

       NOR Flash的读取和我们常见的SDRAM的读取是一样,用户可以直接运行装载在NOR FLASH里面的代码,这样可以减少SRAM的容量从而节约了成本。

         NAND Flash没有采取内存的随机读取技术,它的读取是以一次读取一块的形式来进行的,通常是一次读取512个字节,采用这种技术的Flash比较廉价。用户不能直接运行NAND Flash上的代码,因此好多使用NAND Flash的开发板除了使用NAND Flah以外,还作上了一块小的NOR Flash来运行启动代码。

       STM32单片机内部的FLASH为 NOR FLASH,有1M大小。 Flash 相对容量大,掉电数据不丢失,主要用来存储代码,以及一些掉电不丢失的用户数据。

1.2.2 RAM是什么?

         RAM 属于易失性存储器:RAM随机存储器(Random Access Memory)表示既可以从中读取数据,也可以写入数据。当机器电源关闭时,存于其中的数据就会丢失。比如电脑的内存条

       RAM有两大类,一种称为静态RAM(Static RAM/SRAM),SRAM速度非常快,是目前读写最快的存储设备了,但是它也非常昂贵,所以只在要求很苛刻的地方使用,譬如CPU的一级缓冲,二级缓冲。另一种称为动态RAM(Dynamic RAM/DRAM),DRAM保留数据的时间很短,速度也比SRAM慢,不过它还是比任何的ROM都要快,但从价格上来说DRAM相比SRAM要便宜很多,计算机内存就是DRAM的。

        为什么需要RAM,因为相对FlASH而言,RAM的速度快很多,所有数据在FLASH里面读取太慢了,为了加快速度,就把一些需要和CPU交换的数据读到RAM里来执行(注意这里不是全部数据,只是一部分需要的数据,这个在后面介绍STM32的内存管理中会提到)。STM32单片机内部的 RAM 为 SRAM。 RAM相对容量小,速度快,掉电数据丢失,其作用是用来存取各种动态的输入输出数据、中间计算结果以及与外部存储器交换的数据和暂存数据

在单片机中,RAM主要是做运行时数据存储器,FLASH主要是程序存储器,EEPROM主要是用以在程序运行保存一些需要掉电不丢失的数据。

1.3  STM32的内存管理

       我们知道,STM32大都属于Cortex-M系列的处理器,可以对32的存储器进行寻址,因此存储器的寻址空间能够达到4G,这就意味着指令和数据共用相同的地址空间,也就是将程序存储器(FLASH)、数据存储器(SRAM)、寄存器和输入输出端口被组织在同一个4GB的线性地址空间内。数据字节以小端格式存放在存储器中。一个字里的最低地址字节被认为是该字的最低有效字节,而最高地址字节是最高有效字节。

1.3.1 STM32存储器架构

     4G的地址空间就是地址编码的范围。

      所谓编码就是对每一个程序存储器、数据存储器、寄存器和输入输出端口(一个字节)分配一个唯一的地址号码,这个过程又叫做“编址”或者“地址映射”。这个过程就好像在日常生活中我们给每家每户分配一个地址门牌号。与编码相对应的是“寻址”过程——分配一个地址号码给一个存储单元的目的是为了便于找到它,完成数据的读写,这就是“寻址”,因此地址空间有时候又被称作“寻址空间”。

有了4G的可寻址空间,我们就可通过寻址来操作相应的地址对象。这就需要将程序存储器、数据存储器、寄存器和输入输出端口进行统一编号,也就是存储器映射。存储器映射是指把芯片中或芯片外的FLASH,RAM,外设,BOOTBLOCK等进行统一编址。即用地址来表示对象。这个地址绝大多数是由厂家规定好的,用户只能用而不能改。用户只能在挂外部RAM或FLASH的情况下可进行自定义。

1.3.2 STM32的存储器映射分析

       ST将所有的存储器及外设资源都映射在一个4GB的地址空间上(8个块),每个块512MB,从而可以通过访问对应的地址,访问具体的外设。其映射关系如图所示:

STM32 的内存管理就是对 0X0800 0000 开始的 Flash 部分 和 0x2000 0000 开始的 SRAM 部分使用管理。

STM32的SRAM

          不同类型的STM32单片机的SRAM大小是不一样的,但起始地址都是0x2000 0000,终止地址都是0x2000 0000+其固定的容量大小。SRAM的理解比较简单,其作用是用来存取各种动态的输入输出数据、中间计算结果以及与外部存储器交换的数据和暂存数据。设备断电后,SRAM中存储的数据就会丢失。

STM32的Flash

      STM32的Flash,严格说,应该是Flash模块。该Flash模块包括:Flash主存储区(Main memory)、Flash信息区(Informationblock),以及Flash存储接口寄存器区(Flash memory interface)。

主存储器,该部分用来存放代码和数据常数(如加const类型的数据)。对于大容量产品,其被划分为256页,每页2K,小容量和中容量产品则每页只有1K字节。主存储起的起始地址为0X08000000,B0、B1都接GND的时候,就从0X08000000开始运行代码。

信息块,该部分分为2个部分,其中启动程序代码,是用来存储ST自带的启动程序,用于下载,当B0接3.3V,B1接GND时,运行的就这部分代码,用户选择字节,则一般用于配置保护等功能。

闪存储器块,该部分用于控制闪存储器读取等,是整个闪存储器的控制机构。

1.3.3 STM32内存分析

 C/C++ 程序编译后的存储数据段:

     在了解如何使用内存管理之前,先得理解一下c++的内存划分:

(1)data段 (可读可写)

       数据段,储存已初始化且不为0的全局变量和静态变量(全局静态变量和局部静态变量)。 

(2)BSS段(可读可写)

        储存未初始化的,或初始化为0的全局变量和静态变量。 

(3)text段(只读)

         代码段,储存程序代码。也就是存放CPU执行的机器指令(machineinstructions)。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读。 在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。

(4)constdata

         储存只读常量。const修饰的常量。 把常量的字符串,数据等用const声明

(5)heap(堆)

        堆是用于存放进程运行中被动态分配的内存段。他的大小并不固定,可动态扩张或者缩减,由程序员使用malloc()和free()函数进行分配和释放。当调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)。 

  (6)stack(栈)

          栈又称堆栈,是用户存放程序临时创建的局部变量,由系统自动分配和释放。可存放局部变量、函数的参数和返回值。 除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。中断发生时能保存现场。

     对应STM32的内存分析,STM32的内存主要是FLASH区和SRAM区,根据数据的不同属性存放在两个不同的区域,与C++内存划分进行对比,如下图所示:

1.3.4 单片机和 x86CPU运行程序的不同 

      x86的pc机CPU在运行的时候程序是存储在内存中的,而单片机等嵌入式系统则是存于flash中。x86CPU和单片机读取程序的具体途径: pc机在运行程序的时候将程序从外存(硬盘)中,调入到内存中运行,cpu从内存中读取程序和数据,而单片机的程序则是固化在flash中,CPU运行时直接从flash中读取程序,从RAM中读取数据。

       原因分析 : x86构架的CPU是基于冯.诺依曼体系的,即数据和程序存储在一起,而且pc机的内存资源相当丰富,从几十M到几百M甚至是几个G,客观上能够承受大量的程序数据。
单片机的构架大多是哈弗体系的,即程序和数据分开存储,而且单片的片内RAM资源是相当有限的,内部的RAM过大会带来成本的大幅度提高。   

         冯.诺依曼体系与哈佛体系的区别: 二者的区别就是程序空间和数据空间是否是一体的。 早期的微处理器大多采用冯诺依曼结构,典型代表是Intel公司的X86微处理器。取指令和取操作数都在同一总线上,通过分时复用的方式进行的。缺点是在高速运行时,不能达到同时取指令和取操作数,从而形成了传输过程的瓶颈。哈佛总线技术应用是以DSP和ARM为代表的。采用哈佛总线体系结构的芯片内部程序空间和数据空间是分开的,这就允许同时取指令和取操作数,从而大大提高了运算能力。

二、STM32启动分析

2.1 启动模式

        我们知道的复位方式有三种:上电复位,硬件复位和软件复位。

复位可以理解为我们的板⼦开始从0x00000000地址处运行了。此处的0x00000000地址就是我们前面讲的内存映射4G地址空间。当产生复位,并且离开复位状态后,CM4 内核做的第一件事就是读取下列两个 32 位整数的值: (1)从地址 0x0000 0000 处取出堆栈指针 MSP 的初始值,该值就是栈顶地址。 (2)从地址 0x0000 0004 处取出程序计数器指针 PC 的初始值,该值指向复位后执行的第一条指令。

下面用示意图表示,如图所示。

      上述过程中,内核是从 0x0000 0000 和 0x0000 0004 两个的地址获取堆栈指针 SP 和程序计数器指针 PC。事实上,0x0000 0000 和 0x0000 0004 两个的地址可以被重映射到其他的地址空间。例如:我们将 0x0800 0000 映射到 0x0000 0000,即从内部 FLASH 启动,那么内核会从地址 0x0800 0000 处取出堆栈指针 MSP 的初始值,从地址 0x0800 0004 处取出程序计数器指针 PC 的初始值。CPU 会从 PC 寄存器指向的地址空间取出的第 1 条指令开始执行程序,就是开始执行复位中断服务程序 Reset_Handler。将 0x0000 0000 和 0x0000 0004 两个的地址重映射到其他地址空间,就是启动模式选择。对于 STM32F4 的启动模式(也称自举模式),我们看表进行分析。

注:启动引脚的电平:0:低电平;1:高电平;x:任意电平,即高低电平均可由表 可以看到,STM32F4 根据 BOOT 引脚的电平选择启动模式,这两个 BOOT 引脚根据外部施加的电平来决定芯片的启动地址。

(1)内部 FLASH 启动方式

         当芯片上电后采样到 BOOT0 引脚为低电平时,0x00000000 和 0x00000004 地址被映射到 内部 FLASH 的首地址 0x08000000 和 0x08000004。因此,内核离开复位状态后,读取内部 FLASH 的 0x08000000 地址空间存储的内容,赋值给栈指针 MSP,作为栈顶地址,再读取内部 FLASH 的 0x08000004 地址空间存储的内容,赋值给程序指针 PC,作为将要执行的第一条指令所在的地址。完成这两个操作后,内核就可以开始从 PC 指向的地址中读取指令执行了。

(2)内部 SRAM 启动方式

      类似于内部 Flash,当芯片上电后采样到 BOOT0 和 BOOT1 引脚均为高电平时,地址 0x00000000 和 0x00000004 被映射到内部 SRAM 的首地址 0x20000000 和 0x20000004,内核从 SRAM 空间获取内容进行自举。

(3)系统存储器启动方式

        当芯片上电后采样到 BOOT0=1,BOOT1=0 的组合时,内核将从系统存储器的 0x1FFFF000 及 0x1FFFF004 获取 MSP 及 PC 值进行自举。系统存储器是一段特殊的空间,用户不能访问, ST 公司在芯片出厂前就在系统存储器中固化了一段代码。因而使用系统存储器启动方式时,内核会执行该代码,该代码运行时,会为 ISP(In System Program)提供支持,在 STM32F4 上最常见的是检测 USART1 传输过来的信息,并根据这些信息更新自己内部 FLASH 的内容,达到升级产品应用程序的目的,因此这种启动方式也称为 ISP 启动方式。

2.2 启动文件分析

2.2.0 什么是启动文件

        ⾸先,对于嵌入式开发,⼀般使⽤的是C语言开发。⽽我们知道C语言都是从main函数开始 的,因此,对于处理器来说它是如何找到并执行main函数的,就需要用到启动文件,就是各种 startup_xxx.s文件。   对于我们STM32f407来说其启动⽂件为:startup_stm32f40_41xx.s 。启动文件由汇编编写,是系统上电复位后第一个执行的程序。主要做了以下工作:

启动文件主要做了以下工作:

1、初始化堆栈指针 SP = _initial_sp

2、初始化程序计数器指针 PC = Reset_Handler

3、设置堆和栈的大小

4、初始化中断向量表

5、配置外部 SRAM 作为数据存储器(可选)

6、配置系统时钟,通过调用 SystemInit 函数(可选)

7、调用 C 库中的 _main 函数初始化用户堆栈,最终调用 main 函数

2.2.1 启动文件中的一些指令


2.2.2 启动文件代码讲解

(1)栈空间的开辟

     栈空间的开辟,源码如图所示:

      源码含义:开辟一段大小为 0x0000 0400(1KB)的栈空间,段名为 STACK,NOINIT 表 示不初始化; READWRITE 表示可读可写;ALIGN=3,表示按照 2^3 对齐,即 8 字节对齐。 AREA 汇编一个新的代码段或者数据段。 SPACE 分配内存指令,分配大小为 Stack_Size 字节连续的存储单元给栈空间。 __initial_sp 紧挨着 SPACE 放置,表示栈的结束地址,栈是从高往低生长,所以结束地址就是栈顶地址。

      栈主要用于存放局部变量,函数形参等,属于编译器自动分配和释放的内存,栈的大小不能超过内部 SRAM 的大小。如果工程的程序量比较大,定义的局部变量比较多,那么就需要在 启动代码中修改栈的大小,即修改 Stack_Size 的值。如果程序出现了莫名其妙的错误,并进入 了 HardFault 的时候,你就要考虑下是不是栈空间不够大,溢出了的问题。

(2)堆空间的开辟

       堆空间的开辟,源码如图所示:

源码含义:开辟一段大小为 0x0000 0200(512 字节)的堆空间,段名为 HEAP,不初始 化,可读可写,8 字节对齐。 __heap_base 表示堆的起始地址,__heap_limit 表示堆的结束地址。堆和栈的生长方向相反 的,堆是由低向高生长,而栈是从高往低生长。 堆主要用于动态内存的分配,像 malloc()、calloc()和 realloc()等函数申请的内存就在堆上面。 堆中的内存一般由程序员分配和释放,若程序员不释放,程序结束时可能由操作系统回收。注意:由于正点原子提供了独立的内存管理实现方式(mymalloc,myfree 等),并不需要使用 C 库的 malloc 和 free 等函数,也就用不到堆空间,因此我们可以设置 Heap_Size 的大小为 0, 以节省内存空间。

堆和栈的属性都是可读可写的,执行上述代码会在SRAM区(位于0x2000 0000地址后)开辟相应的空间。

(3)中断向量表定义(简称:向量表)

        STM32F407 的中断向量表定义代码,如图所示。

__Vectors 为向量表起始地址, __Vectors_End 为向量表结束地址,__Vectors_Size 为向量 表大小,__Vectors_Size = __Vectors_End - __Vectors。 DCD:分配一个或者多个以字为单位的内存,以四字节对齐,并要求初始化这些内存。

       中断向量表被放置在代码段的最前面。例如:当我们的程序在 FLASH 运行时,那么向量表的起始地址是:0x0800 0000。结合图可以知道,地址 0x0800 0000 存放的是栈顶地址。 DCD:以四字节对齐分配内存,也就是下个地址是 0x0800 0004,存放的是 Reset_Handler 中断 函数入口地址。 从代码上看,向量表中存放的都是中断服务函数的函数名,所以 C 语言中的函数名对芯片来说实际上就是一个地址。

如何理解向量表?

       其实向量表的本质就是一个元素大小为4字节的数组,而这个数组里面的元素就是这些中断服务函数的名字(也就是中断服务函数的地址),而这张向量表默认就放在flash起始地址处,注意向量表的第一个存储的是栈顶指针(栈顶的地址),开发板上电复位时由CPU将这个栈顶地址赋给CPU的栈寄存器SP

重点:向量表有什么用呢?
      当中断来临时内核就会去向量表中找出对应的中断服务函数的地址,并将地址赋给PC寄存器,进而程序跳转去执行中断函数,而这个过程就是由硬件帮助我们完成的。

(4)复位程序

Reset handler函数内部会调用_main 函数,而_main调用到main函数进入到C语言的世界,但是_main 在调用main之前做了什么事情呢?初始化堆栈:

反正_main函数的最后会调用main函数,然后你就可以随意的写C代码了

(5) 中断服务程序

       在启动文件里面已经帮我们写好所有中断的中断服务函数,跟我们平时写的中断服务函数不一样的就是这些函数都是空的,真正的中断复服务程序需要我们在外部的 C 文件里面重新实现,这里只是提前占了一个位置而已,以防程序奔溃。

     如果我们开启了某个中断,但是忘记写对应的中断服务程序函数又或者把中断服务函数名 写错,那么中断发生时,程序就会跳转到启动文件预先写好的弱定义的中断服务程序中,并且 在 B 指令作用下跳转到一个‘.’中,无限循环。 这里的系统异常中断部分是内核的,外部中断部分是外设的。

2.3map文件分析

C语⾔的编译链接过程:

   MDK 编译工程,也会生成一些中间文件(如.o、.axf、.map 等),最终生成 hex 文件,以 便下载到 MCU 上面执行. 

map 文件是编译器链接时生成的一个文件,它主要包含了交叉链接信息。通过.map 文件, 我们可以知道整个工程的函数调用关系、FLASH 和 RAM 占用情况及其详细汇总信息,能具 体到单个源文件(.c/.s)的占用情况,根据这些信息,我们可以对代码进行优化。

     map 文件可 以分为以下 5 个组成部分:

1, 程序段交叉引用关系(Section Cross References)

2, 删除映像未使用的程序段(Removing Unused input sections from the image)

3, 映像符号表(Image Symbol Table)

4, 映像内存分布图(Memory Map of the image)

5, 映像组件大小(Image component sizes)

以上便是STM32启动过程分析的全部内容,如有兴趣,感谢点赞、关注、收藏,若有不正地方,还请各位大佬多多指教!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/605073.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

洛谷 P4148:简单题 ← KD-Tree模板题

【题目来源】https://www.luogu.com.cn/problem/P4148【题目描述】 你有一个 NN 的棋盘,每个格子内有一个整数,初始时的时候全部为 0,现在需要维护两种操作: ● 1 x y A → 1≤x,y≤N,A 是正整数。将格子 (x,y) 里的数…

【Shell脚本】Shell编程之条件语句

目录 一.条件测试 1.test命令 1.1.test命令是内部命令 1.2.格式一 1.3.格式二 2.文件测试 2.1.常用的测试操作符 3.整数值测试 3.1.常用的测试操作符 3.2.格式一 3.3.格式二 4.字符串比较 4.1.格式一 4.2.格式二 注意: 5.逻辑测试 5.1.常用的测试操…

机器学习 - 梯度下降算法推导

要逐步推导多变量线性回归的梯度计算过程,我们首先需要明确模型和损失函数的形式,然后逐步求解每个参数的偏导数。这是梯度下降算法核心部分,因为这些偏导数将指导我们如何更新每个参数以最小化损失函数。 模型和损失函数 考虑一个多变量线…

“人工智能+”推进新质生产力发展论坛暨工作室实践实训基地授牌仪式圆满结束

4月27日,由江西财经大学现代经济管理学院主办的“人工智能”推进新质生产力发展论坛暨“江财现经管泰迪数智技术”校企工作室实践实训基地授牌仪式在江西财经大学现代经济管理学院共青城校区举行,学院院长王金海,副院长丁美东,副院…

为什么选择ATECLOUD自动化测试平台?

在当今飞速发展的时代,一切都在不断进步与变革,电测行业也由手动测试逐步转向了自动化测试。但是随着科技的发展,对于产品的测试要求也越来越高,传统的自动化测试系统已经无法满足用户日益增长的测试需求,全新的ATE测试…

[沫忘录]MySQL储存对象

[沫忘录]MySQL储存对象 视图 视图本质是对原表(基表)显示上的裁剪,可以当作表进行操作,其操作的结果会直接反馈到原表上,即对视图的操作实质上是对原表的操作。 MySQL不仅支持为基表创建视图,同时也支持为视图创建视图。 基本语…

【C++】详解STL容器之一的 vector

目录 概述 迭代器 数据结构 优点和缺点 接口介绍 begin end rbegin rend resize reseve insert erase 其他一些接口 模拟实现 框架 获取迭代器 深浅拷贝 赋值重载 reseve resize 拷贝构造 构造 析构 insert erase 其他 概述 vector是STL的容器之一。…

用户页面触发点击事件和 js 执行点击事件的区别

文章目录 情景展示情况一:用户点击页面触发情况二:通过 js 触发点击 结果分析情况一情况二 其实这个谜底揭开之后,第一反应都是,哦~,非常简单,但是细节决定成败,我被这个细节毁掉了,…

[嵌入式系统-72]:RT-Thread-组件:单元测试框架utest

目录 utest 测试框架 ​编辑 测试用例定义 测试单元定义 utest 应用框图 2. utest API assert 宏 测试单元函数运行宏 测试用例导出宏 测试用例 LOG 输出接口 3. 配置使能 4. 应用范式 5. 测试用例运行要求 6. 运行测试用例 测试结果分析 7. 测试用例运行流程 …

RAG 场景对Milvus Cloud向量数据库的需求

虽然向量数据库成为了检索的重要方式,但随着 RAG 应用的深入以及人们对高质量回答的需求,检索引擎依旧面临着诸多挑战。这里以一个最基础的 RAG 构建流程为例:检索器的组成包括了语料的预处理如切分、数据清洗、embedding 入库等,然后是索引的构建和管理,最后是通过 vecto…

webpack从零到1 构建 vue3

为什么要手写webpack 不用cli (无的放矢)并不是 其实是为了加深我们对webpack 的了解方便以后灵活运用webpack 的技术 初始化项目结构(跟cli 结构保持一致) 新建 public src 等文件夹npm init -y 创建package.json文件tsc --init…

【Ubuntu20.04安装java-8-openjdk】

1 下载 官网下载链接: https://www.oracle.com/java/technologies/downloads/#java8 下载 最后一行 jdk-8u411-linux-x64.tar.gz,并解压: tar -zxvf jdk-8u411-linux-x64.tar.gz2 环境配置 1、打开~/.bashrc文件 sudo gedit ~/.bashrc2、…

NGINX App Protect现已支持NGINX开源版 全方位加强现代应用安全防护

近日,F5 NGINX 发布全新升级的NGINX App Protect 5.0版本,将先前专属于NGINX 商业版本NGINX Plus 的现代应用安全能力拓展至NGINX开源版中,为增强现代应用和API安全防护提供全方位支持。此次升级后,适用于云端及本地部署的NGINX A…

C++:位图和布隆过滤器

一,位图 1.1 位图的概念 究竟什么是位图呢??我们用一道问题来引入 问题:给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在 这40亿个数中。【腾讯】 根据这个问题&#x…

java——嵌套(二)

目录 一:方法的重写(覆盖/覆写) 1. 方法的重写的意义: 2. 重写(overide) 3. 案例 二:继承中构造方法的调用 1. 子类的构造方法会默认调用父类的构造方法; 2. super 关键字调用…

基于MPPT最大功率跟踪和SVPWM的光伏三相并网逆变器simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 基于MPPT最大功率跟踪和SVPWM的光伏三相并网逆变器simulink建模与仿真。包括PV模块,MPPT模块,SVPWM模块,电网模块等。 2.系统仿真结果 1不…

JavaScript异步编程——04-同源和跨域

同源和跨域 同源 同源策略是浏览器的一种安全策略,所谓同源是指,域名,协议,端口完全相同。 跨域问题的解决方案 从我自己的网站访问别人网站的内容,就叫跨域。 出于安全性考虑,浏览器不允许ajax跨域获取…

二总线,替代传统485总线通讯,主站设计

二总线通信设计专栏 《二总线,替代传统485总线通讯,选型及应用-CSDN博客》《二总线,替代传统485总线通讯,低成本直流载波方案实现及原理-CSDN博客》《二总线,替代传统485总线通讯,调试避坑指南之最大的电流…

基于控制工程的牛鞭效应simulink建模与仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 牛鞭效应”对供应链性能和绩效产生了严重的影响。基于控制理论建立了多级线性供应链的模型,分别利用噪声带宽和Matlab/Simulink对一个可扩…

【快捷部署】024_Hive(3.1.3)

📣【快捷部署系列】024期信息 编号选型版本操作系统部署形式部署模式复检时间024Hive3.1.3Ubuntu 20.04tar包单机2024-05-07 一、快捷部署 #!/bin/bash ################################################################################# # 作者:cx…