1. 程式人生 > >PYNQ上手筆記 | ⑥HDL設計IP核

PYNQ上手筆記 | ⑥HDL設計IP核

1.實驗目的

用HDL語言+Vivado建立一個掛載在AXI總線上的自定義IP核

2.實驗步驟

2.1.建立一個新的專案

2.2.呼叫Create and Package IP Wizard,建立一個新的AXI-Lite從機ip

選擇Tools->Create and Package IP

編輯建立的IP

  • led_controller_v1_0.v — 例項化了所有的AXI-Lite介面,在這種情況下,只有一個介面存在
  • led_controller_v1_0_S00_AXI.v — 包含了處理PL外設與PS端軟體的AXI4-Lite介面功能
    開啟led_controller_v1_0_S00_AXI.v
    檔案,找到Users to add ports here,然後在其後新增需要的埠:

然後在檔案最後,找到Add user logic here,然後在其後新增邏輯功能程式碼:

儲存檔案,開啟led_controller_v1_0.v檔案,找到Users to add ports here,新增埠:

在頂層檔案中例化剛剛我們新增的埠,儲存檔案:

更新IP核

打包IP核

然後關閉這個工程即可,ip核建立成功。

2.3.新增ip核到Block Design中進行設計

建立Block Design:

點選Add IP,搜尋led,新增led_controller

IP:

因為LEDs_out要連線板載LED,所以點選引腳,按下ctrl+t匯出引腳:

新增Zynq ps核,自動連線:

按下F6驗證設計:

建立Block Design 的HDL檔案:

新增LED引腳約束檔案:

在這裡插入圖片描述

##LEDs
set_property -dict { PACKAGE_PIN R14   IOSTANDARD LVCMOS33 } [get_ports { LEDs_out_0[0] }]; #IO_L6N_T0_VREF_34 Sch=LEDs_out_0[0]
set_property -dict { PACKAGE_PIN P14   IOSTANDARD LVCMOS33 }
[get_ports { LEDs_out_0[1] }]; #IO_L6P_T0_34 Sch=LEDs_out_0[1] set_property -dict { PACKAGE_PIN N16 IOSTANDARD LVCMOS33 } [get_ports { LEDs_out_0[2] }]; #IO_L21N_T3_DQS_AD14N_35 Sch=LEDs_out_0[2] set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 } [get_ports { LEDs_out_0[3] }]; #IO_L23P_T3_35 Sch=LEDs_out_0[3]

2.4.生成Bitstream,開啟實現設計,匯出硬體檔案,執行SDK

2.5.建立一個空的應用工程

File->New->Application Project,選擇建立一個空工程:

2.6.新增驅動庫

游標選中led_test_bsp之後再進行下面的操作!!!

選擇Xilinx->Repositories
在這裡插入圖片描述

新增ip核所在目錄,新增完了之後SDK會自動掃描所新增的目錄,然後重新編譯工程來新增新的驅動檔案:

檢查一下庫有沒有被分派到LED_Controller外設,開啟system.mss檔案,可以看到外設驅動中存在led_controller_0:

點選最上面modify this BSP's Setting檢查驅動設定:

至此,led_controlerip核的硬體設計完畢,BSP驅動新增完畢,可以開始寫應用測試程式了。

2.7.編寫應用程式碼

先在src資料夾下建立一個C檔案:

/**
 * @file 	led_test.c
 * @brief	led_controler ip test
 * @author  mculover666
 * @date	2018/11/10
 * */
#include "xparameters.h"
#include "xil_io.h"			//led_controller.h中用到了Xil_Out32
#include "led_controller.h"
#include "xil_printf.h"


#define LED_BASE_ADDR	XPAR_LED_CONTROLLER_0_S00_AXI_BASEADDR
#define LED_REG0		0

#define	DELAY 50000000

int main()
{
	int temp = 0;
	int led_value = 0;
	int i = 0;

    xil_printf("led_controller ip test\r\n");
    xil_printf("----------------------\r\n");

   while(1)
	{
	   	/* write reg0 */
		LED_CONTROLLER_mWriteReg(LED_BASE_ADDR,LED_REG0,led_value);

		/* read reg0 */
		temp = LED_CONTROLLER_mReadReg (LED_BASE_ADDR,LED_REG0);

		/* show value */
		xil_printf("led = %d",led_value);
		xil_printf("\ttemp = %d\r\n",temp);

		if(led_value < 15)
			led_value++;
		else
			led_value = 0;

		for(i=0;i<DELAY;i++);

	}
}

2.9.配置執行,觀察結果

3.實驗總結

這個實驗做了很長時間,最後看著燈思考了很長時間:

  • 從實驗的角度來說說:用HDL建立一個掛載在AXI總線上的ip核去控制LED,然後在儲存器對映下這個ip核的四個暫存器會有自己的地址,CPU靠這個地址來訪問暫存器,為了操作簡單,一般會有一個基地址,其餘暫存器是相對這個基地址的偏移,所以控制程式碼只需要讀寫暫存器就可以了;
  • 從嵌入式原理的角度來說,其實設計都是基於暫存器的,硬體靠暫存器的資料來工作,暫存器掛載在總線上,所以暫存器會有一個地址(暫存器對映),我們通過指標就可以訪問記憶體空間中這個地址處的資料;
  • 從嵌入式發展的角度來說,通常暫存器地址對映都是由廠商出廠時候對映好的,我們只需要檢視晶片參考手冊去程式設計,現在整個硬體可以自己設計,暫存器地址對映只是在一個固定的區間段內(AXI 從機地址1G),變的更加靈活了,也說明了整個數字系統的設計正在由板上設計轉入片上設計,原來由一塊板子才能搞定的任務,現在只需要一個晶片即可~