基于板厂给的模板,修改文件,实现以下功能:
PS端向PL端发送数据(写至BRAM),PL端对数据进行处理,处理后将数据写回BRAM,接着PS端读取BRAM并通过串口发送至win10,win10下使用串口接收数据并利用python导出数据保存。 1.原板厂例程https://download.csdn.net/download/wxkhturfun/77297149
内容包含vivado工程、vitis工程、说明文档
PL端的vivado工程没什么好讲的,厂家自己封了一个IP,这个IP自己可以改:
case(state) IDLE : begin if (start) begin state <= READ_RAM ; addr <= start_addr ; start_addr_tmp <= start_addr ; len_tmp <= len ; dout <= init_data ; en <= 1'b1 ; start_clr <= 1'b1 ; end if (intr_clr) intr <= 1'b0 ; end READ_RAM : begin if ((addr - start_addr_tmp) == len_tmp - 4) //read completed begin state <= READ_END ; en <= 1'b0 ; end else begin addr <= addr + 32'd4 ; //address is byte based, for 32bit data width, adding 4 end start_clr <= 1'b0 ; end READ_END : begin addr <= start_addr_tmp ; en <= 1'b1 ; we <= 4'hf ; state <= WRITE_RAM ; end WRITE_RAM : begin if ((addr - start_addr_tmp) == len_tmp - 4) //write completed begin state <= WRITE_END ; dout <= 32'd0 ; en <= 1'b0 ; we <= 4'd0 ; end else begin addr <= addr + 32'd4 ; dout <= dout + 32'd1 ; end end WRITE_END : begin addr <= 32'd0 ; intr <= 1'b1 ; state <= IDLE ; end default : state <= IDLE ; endcase end end
intr是中断,它与Zynq的中断信号相连,这里的READ_RAM是指PS端向BRAM写数据,WRITE_RAM是指PL端向BRAM写数据,read write是相对于PL端来讲的,总体控制代码很简单。synthesis->implementation->generate Bitstream
生成Bit流后,将硬件信息进行Export,具体 *** 作如下:
如果只用到PS端的话,只用pre-synthesis即可,这里用到了PL端,还是要include bitstream的
最后会生成一个 .xsa文件,用解压软件打开会发现如下内容,这个东西后续要交给vitis开发,即软件工程师的内容。
2018之后的vivado已经没有SDK这个选项了,所以放弃吧别找了,Xilinx把他给集成到Vitis里了。
之后按下列图选择(未出现的图自己默认起个文件名或直接点击next)
最后会生成一个Helloworld工程,自己可以基于这个模板写对就的PS端 *** 作,但是BRAM的相关 *** 作什么的一定要和vivado的地址等相关信息一致。
把helloworld.c进行魔改,改成板厂的提供的文件,在此基础上在进行些修订,方便后续 python串口处理
#include "xil_printf.h" #include "xil_printf.h" #include "xbram.h" #include#include "pl_bram_ctrl.h" #include "xscugic.h" #define BRAM_CTRL_base XPAR_AXI_BRAM_CTRL_0_S_AXI_baseADDR #define BRAM_CTRL_HIGH XPAR_AXI_BRAM_CTRL_0_S_AXI_HIGHADDR #define PL_RAM_base XPAR_PL_BRAM_CTRL_1_S00_AXI_baseADDR #define PL_RAM_CTRL PL_BRAM_CTRL_S00_AXI_SLV_REG0_OFFSET #define PL_RAM_INIT_DATA PL_BRAM_CTRL_S00_AXI_SLV_REG1_OFFSET #define PL_RAM_LEN PL_BRAM_CTRL_S00_AXI_SLV_REG2_OFFSET #define PL_RAM_ST_ADDR PL_BRAM_CTRL_S00_AXI_SLV_REG3_OFFSET #define START_MASK 0x00000001 #define INTRCLR_MASK 0x00000002 #define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID #define INTR_ID XPAR_FABRIC_PL_BRAM_CTRL_1_INTR_INTR #define TEST_START_VAL 0xC #define BRAM_BYTENUM 4 XScuGic INTCInst; int Len ; int Start_Addr ; int Intr_flag ; int bram_read_write() ; int IntrInitFuntion(u16 DeviceId); void IntrHandler(void *InstancePtr); int main() { int Status; Intr_flag = 1 ; IntrInitFuntion(INTC_DEVICE_ID) ; while(1) { if (Intr_flag) { Intr_flag = 0 ; printf("Please provide start addresstn") ; //scanf("%d", &Start_Addr) ; Start_Addr = 0; printf("Start address is %dtn", Start_Addr) ; printf("Please provide lengthtn") ; //scanf("%d", &Len) ; Len = 100; printf("Length is %dtn", Len) ; Status = bram_read_write() ; if (Status != XST_SUCCESS) { xil_printf("Bram Test Failed!rn") ; xil_printf("******************************************rn"); Intr_flag = 1 ; } } } } int bram_read_write() { u32 Write_Data = TEST_START_VAL ; int i ; if ((Start_Addr + Len) > (BRAM_CTRL_HIGH - BRAM_CTRL_base + 1)/4) { xil_printf("******************************************rn"); xil_printf("Error! Exceed Bram Control Address Range!rn"); return XST_FAILURE ; } for(i = BRAM_BYTENUM*Start_Addr ; i < BRAM_BYTENUM*(Start_Addr + Len) ; i += BRAM_BYTENUM) { XBram_WriteReg(XPAR_BRAM_0_baseADDR, i , Write_Data) ; Write_Data += 1 ; } //Set ram read and write length PL_BRAM_CTRL_mWriteReg(PL_RAM_base, PL_RAM_LEN , BRAM_BYTENUM*Len) ; //Set ram start address PL_BRAM_CTRL_mWriteReg(PL_RAM_base, PL_RAM_ST_ADDR , BRAM_BYTENUM*Start_Addr) ; //Set pl initial data //PL_BRAM_CTRL_mWriteReg(PL_RAM_base, PL_RAM_INIT_DATA , (Start_Addr+9)) ; PL_BRAM_CTRL_mWriteReg(PL_RAM_base, PL_RAM_INIT_DATA , (Start_Addr)) ; //Set ram start signal PL_BRAM_CTRL_mWriteReg(PL_RAM_base, PL_RAM_CTRL , START_MASK) ; return XST_SUCCESS ; } int IntrInitFuntion(u16 DeviceId) { XScuGic_Config *IntcConfig; int Status ; //check device id IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); //intialization Status = XScuGic_CfgInitialize(&INTCInst, IntcConfig, IntcConfig->CpubaseAddress) ; if (Status != XST_SUCCESS) return XST_FAILURE ; XScuGic_SetPriorityTriggerType(&INTCInst, INTR_ID, 0xA0, 0x3); Status = XScuGic_Connect(&INTCInst, INTR_ID, (Xil_ExceptionHandler)IntrHandler, (void *)NULL) ; if (Status != XST_SUCCESS) return XST_FAILURE ; XScuGic_Enable(&INTCInst, INTR_ID) ; Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, &INTCInst); Xil_ExceptionEnable(); return XST_SUCCESS ; } void IntrHandler(void *CallbackRef) { int Read_Data ; int i ; printf("Enter interrupttn"); //clear interrupt status PL_BRAM_CTRL_mWriteReg(PL_RAM_base, PL_RAM_CTRL , INTRCLR_MASK) ; for(i = BRAM_BYTENUM*Start_Addr ; i < BRAM_BYTENUM*(Start_Addr + Len) ; i += BRAM_BYTENUM) { Read_Data = XBram_ReadReg(XPAR_BRAM_0_baseADDR , i) ; printf("Address:@%d$%d@overtn", i/BRAM_BYTENUM ,Read_Data) ; } printf("^exit^n"); Intr_flag = 1 ; }
代码很简单,一次PS写BRAM、一次PL写BRAM,PL写完后引发Zynq中断。
4. win10端接收数据不需要数据导出的,直接在putty里看就行了:
安装驱动
将串口打开后,vitis将工程烧进FPGA(烧前,先编译)
以下是Helloworld
好吧,我需要将串口的数据导出到
环境:python 3.8.10 64-bits
pip3 install pyserial
我不是软件工程师,python写的很菜,好歹最后能用了。
因为接收到的是二进制数据,所以需要先进行utf-8转码,最后我要的16进制数据,所以还需要转一下(当然你也可以在printf中直接发送16进制数),在vitis中我在PL端最后一次写BRAM之后还printf("^ exit^n");,我也是根据是否接收到exit来决定是否跳出While循环.
因为串口接收的数据可能是跨行的,或者说不连续的,我无法确定是数据的相关连的,所以只好先将接收的数据通过:dataline = dataline + data全部拼接到一起,最后才处理,由于需要对字符进行split *** 作,为了方便起见,我在vitis工程的的printf函数中对数据的两端进行添加了若干符号:
printf("Address:@%d$%d@overtn", i/BRAM_BYTENUM ,Read_Data) ;//@与$就是我用来spilt的符号
以下是python3代码(由于各种原因,只能展示部分代码),并不难写,框架和思路我都写好的,自己处理导出数据就行了。
#此处略去部分代码 if __name__ == '__main__' #此处略去部分代码 #COM3 serial = serial.Serial('COM3', 115200)#serial = serial.Serial('COM3', 115200, timeout=0.01) print(serial) if serial.isOpen() : print("open success") else : print("open failed") ex = False while True: data =recv(serial) if data != b'' : dataline = dataline + data print("receive : ",data) #print("receive : ",data.decode('utf-8')) w_data = b'12rn' #serial.write(w_data) #数据写回 f_data = data.decode('utf-8') f_data = f_data.strip('n') #去掉列表中每一个元素的换行符 f_p_split = f_data.split('^') #按'@'进行切片 #此处略去部分代码 result = splitData(dataline,len) print(result) #此处略去部分代码
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)