ZYNQ PS讀寫PL BRAM

一、實驗室任務

????????本章的實驗任務是 PS 將數據寫入BRAM,然后從 BRAM 中讀出數據,并通過串口打印出來;與此同時,PL 從通過自定義ip核從BRAM中同樣讀出數據,并通過ILA 來觀察讀出的數據與串口打印的數據是否一致。這里是通過PS寫入進的只有數據信息,而無法讀數據,因此通過ILA觀察數據。

二、實驗整體架構

三、自定義ip寫進ram的控制ip核

? ? ? ? 這個ip核呢是將我們通過AXI輸入進BRAM的數據通過自定義的ip核轉為合適的ram接口信息接到ramip核上,這樣就可以通過ps端輸入的讀使能,讀地址讀數據長度信息轉化為ram的讀使能,讀地址,保證時序正確。

四、設計流程

一、自定義ip核。

1、創建IP管理器

2、選擇AXI接口的ip核,然后一直保持默認最后點擊完成,

3、編輯這個ip,右鍵ip核,然后選擇編輯選項,進入編輯頁面,然后默認ok就行

4、添加一個控制文件(.v)如下

????????為什么要寫這個模塊呢?為什么不能通過ps側輸入讀使能,讀數據直接連接到ram的ip核上呢?在我看來這是因為ps側的邏輯無法精準控制時鐘邏輯,也就是ps側無法做到像pl側的嚴格時序控制。pl側的邏輯是在每個時鐘內做自己的事情,每個時鐘周期都有嚴格的要求,因此我們在PS側無法做到如此嚴格的時序要求。所以通過一個自定義控制模塊對輸入的信號進行處理,使得時序要求滿足我們pl側的邏輯。

module ram_ip
(input 		 		 pl_rst_n		,input		 		 pl_clk			,input		 		 ps_read_en		,//開始讀的使能input		 [31:0]	 ps_start_addar	,//開始讀的起始地址input		 [31:0]	 ps_data_num	,//需要讀取的數量//bram接口output               ram_clk    	,//RAM時鐘input        [31:0]  ram_rd_data	,//RAM中讀出的數據,這個接口是讀出來的數據需要我們通過該控制器輸出到ps端。output  reg          ram_en     	,//RAM使能信號,這個接口是讀使能信號,需要根據我們ps側輸入的幾個信息給出合適的讀信號。output  reg  [31:0]  ram_addr   	,//RAM地址,這個也需要通過ps側輸入的起始地址和需要讀取的數量來生成的。output  reg  [3 :0]  ram_we     	,//RAM讀寫控制信號output  reg  [31:0]  ram_wr_data	,//RAM寫數據output               ram_rst     	 //RAM復位信號,高電平有效);assign ram_clk=pl_clk;
assign ram_rst=1'b0;always @(posedge pl_clk)
if(!pl_rst_n)ram_we<=4'd0;
else ram_we<=ram_we;always @(posedge pl_clk)
if(!pl_rst_n)ram_wr_data<=32'd0;
else ram_wr_data<=ram_wr_data;reg		ps_read_en_reg;
always @(posedge pl_clk)
if(!pl_rst_n)ps_read_en_reg<=1'b0;
else ps_read_en_reg<=ps_read_en;wire ps_read_en_pos=ps_read_en&~ps_read_en_reg;parameter 		A_EDA=3'd0,A_ADD=3'd1,A_DOW=3'd2;reg 	[2:0]	state;
always @(posedge pl_clk)if(!pl_rst_n)state<=A_EDA;else case(state)A_EDA:state<=(ps_read_en_pos)	?	A_ADD	:	A_EDA;A_ADD:state<=(ram_addr-ps_start_addar+2'd2==ps_data_num)	?	A_DOW	:	A_ADD;A_DOW:state<=A_EDA;default:state<=A_EDA;endcasealways @(posedge pl_clk)if(!pl_rst_n)ram_en<=1'b0;else case(state)A_EDA:if(ps_read_en_pos) ram_en<=1'b1;A_ADD:ram_en<=1'b1;default:ram_en<=1'b0; endcasealways @(posedge pl_clk)if(!pl_rst_n)ram_addr<=32'd0;else case(state)A_EDA:if(ps_read_en_pos) ram_addr<=ps_start_addar;A_ADD:ram_addr<=ram_addr+1'b1;default:ram_addr<=32'd0;endcaseendmodule

????????上面是我們的需要添加進我們ip核的verilog代碼。下面是systemverilog仿真代碼和仿真圖。由圖可知在我們的pl側受到來自ps的使能和讀數據信息時候,會產生一個高脈沖,然后通過狀態機完成對讀數據信息的轉化,轉化成我們pl側ram接口可以識別的信息,比如讀使能,使能對應的讀地址。由仿真圖也可以看出:當我們的pl側檢測到來自ps側的上升沿時就會立馬進入ram接口時序生成狀態,依據起始地址,讀數量等生成我們需要的接口時序。

`timescale 1ns/1ns
module ram_ip_sim();reg 	 	 	   pl_rst_n			;
reg		  		   pl_clk			;
reg		  		   ps_read_en		;
reg		  [31:0]   ps_start_addar	;
reg		  [31:0]   ps_data_num		;//bram接口
wire               ram_clk    		;
reg        [31:0]  ram_rd_data		;
wire               ram_en     		;
wire       [31:0]  ram_addr   		;
wire       [3 :0]  ram_we     		;
wire       [31:0]  ram_wr_data		;
wire               ram_rst     	    ;initial beginpl_clk<=1'b0;forever #10 pl_clk=~pl_clk;
endinitial beginpl_rst_n=1'b0;repeat(3) @(posedge pl_clk);pl_rst_n=1'b1;
endinitial beginps_read_en		=1'b0 ;ps_start_addar	=32'd0;ps_data_num		=32'd0;ram_rd_data		=32'd0;
endtask data_send;repeat(3) @(posedge pl_clk);ps_read_en		=1'b1  ;ps_start_addar	=32'd0 ;ps_data_num		=32'd10;repeat(15) @(posedge pl_clk);ps_read_en		=1'b0 ;ps_start_addar	=32'd0;ps_data_num		=32'd0;endtask :	data_send;initial beginwait(pl_rst_n);fork beginrepeat(1) @(posedge pl_clk);data_send;endjoin
endram_ip  ram_ip_un
(.pl_rst_n		(pl_rst_n		),.pl_clk			(pl_clk			),.ps_read_en		(ps_read_en		),//開始讀的使能.ps_start_addar	(ps_start_addar	),//開始讀的起始地址.ps_data_num	(ps_data_num	),//需要讀取的數量.ram_clk    	(ram_clk    	),//RAM時鐘.ram_rd_data	(ram_rd_data	),//RAM中讀出的數據,這個接口是讀出來的數據需要我們通過該控制器輸出到ps端。.ram_en     	(ram_en     	),//RAM使能信號,這個接口是讀使能信號,需要根據我們ps側輸入的幾個信息給出合適的讀信號。.ram_addr   	(ram_addr   	),//RAM地址,這個也需要通過ps側輸入的起始地址和需要讀取的數量來生成的。.ram_we     	(ram_we     	),//RAM讀寫控制信號.ram_wr_data	(ram_wr_data	),//RAM寫數據.ram_rst     	(ram_rst     	) //RAM復位信號,高電平有效);endmodule

?5、需要修改的地方

在頂層模塊添加輸出端口

在頂層例化的模塊添加例化模塊修改的端口。

在AXI接口模塊添加輸出接口,然后例化我們的bram控制器

在例化我們添加的模塊可知,我們例化模塊的使能信號,我存在寄存器0的第一位,因此我們需要在ps側C語言代碼中操作該寄存器就可以給該bram控制模塊輸出想要的信息,同理我們用到了寄存器1和2分別接收來自ps側的起始地址和讀數據量,然后由該信息就可以讓bram控制模塊輸出滿足時序要求的讀使能端口和讀地址。

6、點擊文件組,這里就是我們添加和修改文件后需要刷新

7、這里是常量刷新(如果你是替換的代碼就先進代碼隨便打個空格然后保存就會刷新)

8、按照如下操作分別將信號接口從時鐘和復位接口移出去ram_rst和ram_clk

9、這里有兩個警告,這是因為我們頂層的輸出端口沒有和其他的ip核端口和形成映射關系,因此這里會有警告不知道對應的接口是哪個,因此我們添加輸出端口映射。

10、添加輸出端口映射。右鍵隨便一個端口,然后點擊add bus interface。

11、先修改我們要對接的端口,這里我們選擇bram端口。然后添加該接口映射的總線名字,然后選擇主端口,因為這個模塊控制的是ram ip的讀數據信息。

12、添加端口映射,點一下需要映射的端口然后點擊映射即可,按照此流程將所有端口映射。這樣做的目的是為了我們軟件可以自動幫我們連線,不需要我們一個一個連。

13、將端口的屬性添加到自適應列。這樣我們連接端口時,端口的信號會自動和從機端口屬性保持一致,這樣不需要我們一個一個的設置。

14、點擊提示信息

15、點擊下面的生成ip核

二、IP組裝

1、先修改我們的最小系統IP,因為在hello_word實驗時將有些端口取消了,這里我們重新添加回來,如下:GP接口和時鐘復位添加進來

2、添加AXI bram控制器,并按照如圖修改

3、添加bram ip核,并按照如圖修改兩個地方

4、添加我們自己寫的ip控制器,不需要修改

5、點擊自動連接,然后全部選中,然后為這兩個ip核的端口設置連接的ip核接口,這樣這兩個ip核的接口就會自動連接到我們的雙端口bram上去,實現一個ip核寫,一個ip核讀。然后點擊確定后點擊重新布局。?

6、驗證設計,然后驗證無誤點擊ok即可。

7、修改ram容量大小,這里可以將兩個都改為4k也可以不改。

8、生成輸出文件,然后ok即可

9、生成頂層文件,這里需要記住的是在原來的hello的工程基礎上的頂層沒有改動,可以不生成,如果是重新建立的工程要生成頂層文件。以下是已經生成過的頂層文件重新生成,默認點擊ok即可

三、添加ILA

1、點擊綜合

2、點擊綜合設計->點擊step up debug

3、next后添加我們要探針的信號,如圖,導航到ram ip核的U0下添加我們要探查的信號

4、為探查信號添加時鐘,搜索選擇ALL_CLOCK,然后選擇下列時鐘后點擊🆗。重復剛才步驟為這三個信號都添加時鐘。然后一直默認點擊ok。

5、然后點擊實現,然后點擊生成bit流

6、導出設計文件,勾選bit流后點擊🆗即可,一定要勾選bit流,因為這里用到了pl端的設計。

7、打開SDK

四、SDK設計

1、新建空項目。

2、建立一個源文件,命名main.c

3、復制如下代碼

#include "stdio.h"
#include "xbram_hw.h"
#include "stdio.h"
#include "custom_pl_bram_ps.h"
#include "xparameters.h"
#include "sleep.h"#define PL_BRAM_START		CUSTOM_PL_BRAM_PS_S00_AXI_SLV_REG0_OFFSET//寄存器1輸出使能信號
#define PL_BRAM_START_ADDR	CUSTOM_PL_BRAM_PS_S00_AXI_SLV_REG1_OFFSET//寄存器2輸出起始地址
#define PL_BRAM_LEN			CUSTOM_PL_BRAM_PS_S00_AXI_SLV_REG2_OFFSET//寄存器3輸出數據長度#define PL_BRAM_BASE		XPAR_CUSTOM_PL_BRAM_PS_0_S00_AXI_BASEADDR //自定義ip的地址#define START_ADDAR			0//
#define PL_BRAM_DATA_LEN	4//每個bram的深度為4個字節char input_data[1024]="www.com.lzs"	;
int  num_data			;int main()
{//通過調試發現如果沒初值,那會將數據寫入到系統分配的初始地址位置。int wr_cnt=START_ADDAR;printf("test start!");sleep(5);//while(1)//{//scanf("please input data: %s",input_data);num_data=strlen(input_data);for(int i=START_ADDAR*PL_BRAM_DATA_LEN;i<(START_ADDAR+num_data)*PL_BRAM_DATA_LEN;i+=PL_BRAM_DATA_LEN){//第一個參數為寫入AXIip核的地址XBram_WriteReg(XPAR_BRAM_0_BASEADDR,i,input_data[wr_cnt]);printf("w_data:%c,odata : %d\n",input_data[wr_cnt],input_data[wr_cnt]);wr_cnt++;}//}//設備ip,ip映射(寄存器2),寫入數據的bram起始地址。其實就是像我們自定義的ip核里面的AXI寄存器寫入數據。//這個寄存器就是連接我們自己編寫的bram讀控制文件的輸入端口。CUSTOM_PL_BRAM_PS_mWriteReg(PL_BRAM_BASE,PL_BRAM_START_ADDR,START_ADDAR*PL_BRAM_DATA_LEN);//配置長度CUSTOM_PL_BRAM_PS_mWriteReg(PL_BRAM_BASE,PL_BRAM_LEN,(START_ADDAR+num_data)*PL_BRAM_DATA_LEN);//配置使能,讓我們的自定義ip采集上升沿CUSTOM_PL_BRAM_PS_mWriteReg(PL_BRAM_BASE,PL_BRAM_START,0x00000001);CUSTOM_PL_BRAM_PS_mWriteReg(PL_BRAM_BASE,PL_BRAM_START,0x00000000);printf("\naddares,data\n");int read_data;for(int i=START_ADDAR*PL_BRAM_DATA_LEN;i<(START_ADDAR+num_data)*PL_BRAM_DATA_LEN;i+=PL_BRAM_DATA_LEN){read_data=XBram_ReadReg(XPAR_BRAM_0_BASEADDR,i);printf("addares: %d, data: %c, odata : %d\n",i/PL_BRAM_DATA_LEN,read_data,read_data);}return 0;}

4、修改報錯信息,這里是因為系統生成的庫是按照我們自定義ip核名字生成的,如果你是按照我的步驟來的就復制最后修改好的代碼。

5、找到對應的庫文件,然后找到這幾個參數復制改變定義

6、找到這幾個庫文件的函數修改為以下函數

7、修改完后保存,如果你的自定義ip核的命名也為pl_ps_bram就可以直接復制下面的

#include "stdio.h"
#include "xbram_hw.h"
#include "stdio.h"
#include "pl_ps_bram.h"
#include "xparameters.h"
#include "sleep.h"#define PL_BRAM_START		PL_PS_BRAM_S00_AXI_SLV_REG0_OFFSET//寄存器1輸出使能信號
#define PL_BRAM_START_ADDR	PL_PS_BRAM_S00_AXI_SLV_REG1_OFFSET//寄存器2輸出起始地址
#define PL_BRAM_LEN			PL_PS_BRAM_S00_AXI_SLV_REG2_OFFSET//寄存器3輸出數據長度#define PL_BRAM_BASE		XPAR_PL_PS_BRAM_0_S00_AXI_BASEADDR //自定義ip的地址#define START_ADDAR			0//
#define PL_BRAM_DATA_LEN	4//每個bram的深度為4個字節char input_data[1024]="www.com.lzs"	;
int  num_data			;int main()
{//通過調試發現如果沒初值,那會將數據寫入到系統分配的初始地址位置。int wr_cnt=START_ADDAR;printf("test start!");sleep(5);//while(1)//{//scanf("please input data: %s",input_data);num_data=strlen(input_data);for(int i=START_ADDAR*PL_BRAM_DATA_LEN;i<(START_ADDAR+num_data)*PL_BRAM_DATA_LEN;i+=PL_BRAM_DATA_LEN){//第一個參數為寫入AXIip核的地址XBram_WriteReg(XPAR_BRAM_0_BASEADDR,i,input_data[wr_cnt]);printf("w_data:%c,odata : %d\n",input_data[wr_cnt],input_data[wr_cnt]);wr_cnt++;}//}//設備ip,ip映射(寄存器2),寫入數據的bram起始地址。其實就是像我們自定義的ip核里面的AXI寄存器寫入數據。//這個寄存器就是連接我們自己編寫的bram讀控制文件的輸入端口。PL_PS_BRAM_mWriteReg(PL_BRAM_BASE,PL_BRAM_START_ADDR,START_ADDAR*PL_BRAM_DATA_LEN);//配置長度PL_PS_BRAM_mWriteReg(PL_BRAM_BASE,PL_BRAM_LEN,(START_ADDAR+num_data)*PL_BRAM_DATA_LEN);//配置使能,讓我們的自定義ip采集上升沿PL_PS_BRAM_mWriteReg(PL_BRAM_BASE,PL_BRAM_START,0x00000001);PL_PS_BRAM_mWriteReg(PL_BRAM_BASE,PL_BRAM_START,0x00000000);printf("\naddares,data\n");int read_data;for(int i=START_ADDAR*PL_BRAM_DATA_LEN;i<(START_ADDAR+num_data)*PL_BRAM_DATA_LEN;i+=PL_BRAM_DATA_LEN){read_data=XBram_ReadReg(XPAR_BRAM_0_BASEADDR,i);printf("addares: %d, data: %c, odata : %d\n",i/PL_BRAM_DATA_LEN,read_data,read_data);}return 0;}

五、SDK驗證

1、打開板子供電、連接串口

2、右鍵項目,打開運行配置

3、雙擊GDB,打開燒錄bit流和復位

4、點擊運行

5、我們發現AXIbram控制器ip核讀寫一致

六、ILA驗證

????????這里我們需要注意,由于我的設計用不了scanf輸入函數,因此我加了一個延遲然后馬上回到ILA界面運行,等待enb拉高,觸發邏輯分析儀。如果你的scanf能用就不用加延遲,就可以通過串口輸入寫入信息后,SDK程序會立馬運行到拉高enb的信號函數。

還有一點就是如果你調不出ILA界面請點擊以下鏈接,查看原因和解決方法

vivado 下載程序后沒有ILA界面

1、點擊設備管理器后點擊自動連接,進入ila界面

2、設置觸發條件,選擇enb,選擇上升沿觸發。

3、回到SDK燒錄界面,燒錄后馬上回到ILA界面點擊運行。這里一定要馬上回到這個界面點運行,然后等待觸發。前面說過如果你的scanf能用就可以在SDK 終端輸入后這里就會觸發。而這里由于我的scanf用不了,我就加了個延遲,等幾秒鐘后會按順序執行到SDK設置上升沿的使能程序。然后ILA界面就會觸發,如下圖

4、對比寫入數據。將數據以ASCLL碼的形式展現

5、對比發現我們邏輯分析儀捕捉到的自定義ip核讀數據轉為ASCLL碼后和我們SDK PS側寫進PS側RAM的數據是一致的。因此我們的設計正確。

?

?

?

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/96867.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/96867.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/96867.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

LinuxC++項目開發日志——高并發內存池(5-page cache框架開發)

PageCachepage cache 設計邏輯一、PageCache 的核心定位&#xff1a;理解它與 CentralCache 的本質區別二、PageCache 的內存分配流程&#xff1a;從 “精確匹配” 到 “拆分適配”三、PageCache 的內存釋放流程&#xff1a;合并小 Span&#xff0c;解決內存碎片問題page cache…

Matplotlib:繪制你的第一張折線圖與散點圖

Matplotlib入門&#xff1a;繪制你的第一張折線圖與散點圖導語 歡迎來到 Matplotlib 的世界&#xff01;對于任何使用 Python 進行數據分析或機器學習的人來說&#xff0c;數據可視化都是一項至關重要的技能。Matplotlib 是 Python 中最流行、最基礎的可視化庫&#xff0c;它功…

MySQL保姆級安裝教程

MySQL 安裝詳細文檔&#xff0c;適用于 Windows、macOS 和 Linux 系統&#xff0c;包含了從下載到驗證安裝的完整步驟&#xff1a; 一、Windows 系統安裝 MySQL 1. 下載 MySQL 安裝包 訪問 MySQL 官方下載頁&#xff1a;https://dev.mysql.com/downloads/installer/選擇 “MySQ…

重塑你的大腦:從理解突觸到掌控人生

重塑你的大腦&#xff1a;從理解突觸到掌控人生你是否曾對自己的某些行為感到無力&#xff1f;明知應該早睡&#xff0c;卻總忍不住刷手機&#xff1b;下定決心要鍛煉&#xff0c;卻常常半途而廢。這些困擾我們的習慣&#xff0c;并非簡單的意志力問題&#xff0c;其根源深深植…

《C++進階之STL》【哈希表】

【哈希表】目錄前言------------概念介紹------------1. 什么是哈希&#xff1f;------------核心術語------------一、哈希函數1. 哈希函數的核心特點是什么&#xff1f;2. 哈希函數的設計目標是什么&#xff1f;3. 常見的哈希函數有哪些&#xff1f;直接定址法除法散列法乘法…

機器學習-模型驗證

驗證泛化誤差 在一個數據集上估計誤差&#xff0c;數據集只能使用一次驗證數據集&#xff1a;可以被使用多次 基本是訓練數據集中的一部分 當使用“test”時&#xff0c;大多數時候指的是驗證數據集 生成驗證數據集方法 1、數據隨機分入訓練集或驗證集 總是隨機選n%的數據作為驗…

Qt中自定義控件的三種實現方式

Qt中自定義控件的三種實現方式 在 Qt 應用開發中&#xff0c;標準控件往往無法滿足所有需求。自定義控件允許開發者創建具有特定功能和外觀的控件&#xff0c;提高代碼復用性和界面一致性。Qt 提供了多種方式來開發自定義控件&#xff0c;從簡單的組合現有控件到完全自定義繪制…

少兒舞蹈小程序(14)在線預約

目錄1 創建數據模型2 搭建預約按鈕3 搭建表單4 搭建管理功能整體效果總結目前我們的首頁已經開發完畢了&#xff0c;包含輪播圖、機構介紹、校區展示、作品與活動展示功能。家長在小程序了解了機構的基本情況之后&#xff0c;下一步就是參加試聽&#xff0c;在線下真實體驗一下…

TDengine 數據寫入詳細用戶手冊

TDengine 數據寫入用戶手冊 概述 TDengine 提供了多種靈活的數據寫入方式&#xff0c;以滿足不同應用場景的需求。本手冊將以智能電表場景為例&#xff0c;向初學者詳細介紹各種數據寫入方法的使用。 智能電表場景設定 假設我們需要為智能電表系統建立數據庫&#xff1a; …

PTA 天梯賽 7-43:字符串關鍵字的散列映射

【題目來源】 https://pintia.cn/problem-sets/15/exam/problems/type/7?problemSetProblemId890 【題目描述】 給定一系列由大寫英文字母組成的字符串關鍵字和素數 P&#xff0c;用移位法定義的散列函數 H(Key) 將關鍵字 Key 中的最后 3 個字符映射為整數&#xff0c;每個字…

Python核心技術開發指南(065)——with語句

版權聲明 本文原創作者:谷哥的小弟 作者博客地址:http://blog.csdn.net/lfdfhl with語句定義 with語句是Python中用于簡化資源管理的語法結構,通過上下文管理器(實現__enter__()和__exit__()方法的對象)確保資源在使用完畢后被正確釋放,無論代碼塊是否發生異常。其核心作…

從基礎到高級:一文快速認識MySQL UPDATE 語句

在數據庫日常運維與開發中&#xff0c;數據更新是與數據查詢同等重要的核心操作。MySQL 的 UPDATE 語句憑借其靈活的語法結構和強大的功能&#xff0c;能夠滿足從簡單字段修改到復雜關聯表更新的各類需求。然而&#xff0c;若使用不當&#xff0c;不僅可能導致數據一致性問題&a…

材料基因組計劃(MGI)入門:高通量計算與數據管理最佳實踐

點擊 “AladdinEdu&#xff0c;同學們用得起的【H卡】算力平臺”&#xff0c;注冊即送-H卡級別算力&#xff0c;80G大顯存&#xff0c;按量計費&#xff0c;靈活彈性&#xff0c;頂級配置&#xff0c;學生更享專屬優惠。 摘要 材料基因組計劃&#xff08;Materials Genome Ini…

Vision Transformer (ViT) :Transformer在computer vision領域的應用(一)

在圖像領域,CNN卷積神經網絡結構已經成為了標配,所有的模型都是基于CNN來構造的。 而在NLP領域,自從Transformer橫空出世之后,基本上也統治了NLP的各個領域。 基于Transformer的強大,一些論文的工作都是將Transformer也應用到CV領域,在這篇論文:AN IMAGE IS WORTH 16X1…

自動駕駛中的傳感器技術45——Radar(6)

本文詳細介紹4D雷達相關解決方案&#xff0c;4D雷達關鍵詞&#xff1a;4D Imaging Radar 1、4D雷達特點 圖1 4D雷達 vs 3D雷達圖2 4D雷達虛擬通道數量不斷增加圖3 4D雷達 vs 3D雷達 vs 攝像頭和激光雷達圖4 毫米波雷達在不同駕駛等級下的應用需求Ref&#xff1a;https://pdf.d…

瀏覽器調試工具詳解

個人簡介 &#x1f440;個人主頁&#xff1a; 前端雜貨鋪 &#x1f64b;?♂?學習方向&#xff1a; 主攻前端方向&#xff0c;正逐漸往全干發展 &#x1f4c3;個人狀態&#xff1a; 研發工程師&#xff0c;現效力于中國工業軟件事業 &#x1f680;人生格言&#xff1a; 積跬步…

代碼審計-PHP專題原生開發SQL注入1day分析構造正則搜索語句執行監控功能定位

挖掘技巧&#xff1a; -語句監控-數據庫SQL監控排查可利用語句定向分析 -功能追蹤-功能點文件SQL執行代碼函數調用鏈追蹤 -正則搜索-(update|select|insert|delete|).*?where.* 如何快速的在多個文件代碼里面找脆弱&#xff1a; 1、看文件路徑 2、看代碼里面的變量&#…

Linux中:調試器gdb/cgdb的使用

引言在追尋光的路上不斷前行&#xff0c;詳細介紹Linux下gdb/cgdb的使用。一、準備? 程序的發布方式有兩種&#xff0c;默認是 debug 模式和 release 模式。Linux gcc/g編譯出來的二進制程序默認是release模式? 要使用gdb調試&#xff0c;必須在源代碼生成?進制程序的時候加…

【算法】【鏈表】148.排序鏈表--通俗講解

算法通俗講解推薦閱讀 【算法–鏈表】83.刪除排序鏈表中的重復元素–通俗講解 【算法–鏈表】刪除排序鏈表中的重復元素 II–通俗講解 【算法–鏈表】86.分割鏈表–通俗講解 【算法】92.翻轉鏈表Ⅱ–通俗講解 【算法–鏈表】109.有序鏈表轉換二叉搜索樹–通俗講解 【算法–鏈表…

計算機組成原理:存儲系統概述

&#x1f4cc;目錄&#x1f4be; 存儲系統概述&#xff1a;計算機的“記憶中樞”&#x1f3d7;? 一、存儲系統的層次結構&#xff1a;速度與容量的“黃金平衡”&#xff08;一&#xff09;經典存儲層次金字塔&#xff08;二&#xff09;層次結構的設計原則&#xff08;三&…