(原創)LEON3入門教程(四):基於AMBA APB總線的七段數碼管IP核設計


摘要:這一小節將介紹下如何設計用戶自定義的APB IP,並將IP嵌入到SOPC中去。一個APB IP核的主要分為三個部分:邏輯單元、寄存器單元和接口單元。所設計的IP是一個簡單的七段數碼管顯示IP,只有一個寄存器ledindata_reg,實現數碼管顯示,比較簡單實用,可以類比到更多的寄存器設計中。IP設計后,對其進行仿真測試和軟件測試,驗證其功能。該IP沒有中斷功能,如果需要添加中斷請參考AMBA協議。

  更多更新請關注我的博客:@超群天晴 http://www.cnblogs.com/surpassal/

相關閱讀

(原創)LEON3入門教程(一):什么是LEON3?需要哪些開發工具和軟件?

(原創)LEON3入門教程(二):Cygwin和GRtools的安裝與配置

(原創)LEON3入門教程(三):基於LEON3的SOPC設計:HELLOWORLD和流水燈

 

一、AMBA APB總線和APB IP核

ARM研發的AMBA(Advanced Microcontroller Bus Architecture)提供一種特殊的機制,可將RISC處理器集成在其它IP芯核和外設中,2.0版AMBA標准定義了三組總線:AHB(AMBA高性能總線)、ASB(AMBA系統總線)、和APB(AMBA外設總線)。3.0版本將支持AXI。APB總線用於提供低帶寬的接口用作外圍總線,適合掛接一般的外圍設備。

圖1 是一個簡單的APB總線讀操作的時序圖。圖中第一個時鍾周期是SETUP周期,第二個時鍾周期是ENABLE周期,地址、控制信號在兩個周期內都是有效的。PENABLE信號在傳輸結束的時候將被置無效。PWRITE信號維持不變,直到不第同的讀寫傳輸發生的時候改變。寫操作的時序基本相同,只是PWDATA數據信號現在SETUP周期內和地址、控制信號一同給出。

圖1 APB總線的簡單讀操作時序

一個APB IP核的主要分為三個部分:邏輯單元、寄存器單元和接口單元。其中邏輯單元完成任務邏輯的實現。對於七段數碼管來說,就是完成對輸入數值的顯示;接口單元完成對AMBA APB總線協議的支持,包括讀寫協議、時序等;寄存器單元完成地址和寄存器的衍射,將AMBA APB上的地址空間對應到需要的寄存器上,這樣CPU對這些地址的操作,也就完成了對相應寄存器的操作,最終實現對邏輯單元的輸入輸出控制等。一個APB IP的結構框圖如圖2所示。

 圖 2 一個APB IP核的結構框圖 

二、 IP核的設計和測試

1 邏輯設計

由於DE2-70上的七段數碼管是共陽的,所以設計的是BCD輸碼入的共陽七段數碼管。實現代碼如下。

 1 --超群天晴 @ NEU
 2 library ieee; 
 3 use ieee.std_logic_1164.all; 
 4 use ieee.std_logic_unsigned.all; 
 5 
 6 ENTITY led IS
 7 PORT(
 8     indata:IN STD_LOGIC_VECTOR (3 DOWNTO 0);
 9     outdata:OUT STD_LOGIC_VECTOR (7 DOWNTO 0)
10     );
11 END led;
12 
13 ARCHITECTURE rtl OF led IS
14 BEGIN
15     process(indata)--
16     begin       
17         
18         --共陽
19         CASE indata IS---26 27 28 29---0000EDCB --100509
20             WHEN "0000"=>outdata<="11000000";--0
21             WHEN "0001"=>outdata<="11111001";--1
22             WHEN "0010"=>outdata<="10100100";--2
23             WHEN "0011"=>outdata<="10110000";--3
24             WHEN "0100"=>outdata<="10011001";--4
25             WHEN "0101"=>outdata<="10010010";--5
26             WHEN "0110"=>outdata<="10000010";--6
27             WHEN "0111"=>outdata<="11111000";--7
28             WHEN "1000"=>outdata<="10000000";--8
29             WHEN "1001"=>outdata<="10010000";--9
30             WHEN "1010"=>outdata<="10001000";--A
31             WHEN "1011"=>outdata<="10000011";--b
32             WHEN "1100"=>outdata<="11000110";--C
33             WHEN "1101"=>outdata<="10100001";--D
34             WHEN "1110"=>outdata<="10000110";--E
35             WHEN "1111"=>outdata<="10001110";--F
36             when others=>outdata<="11000000";--0;--0
37         END CASE;
38     END process;
39 end;

 

2  AMBA APB總線接口和寄存器設計

由於只需要對這個IP進行讀操作,也不需要添加中斷等其他功能,故只需要一個寄存器來存放輸入數據即可。這里定義ledindata_reg,是對於IP基地址偏移為0(也就是基地址)的寄存器,作為處理器寫數據的輸入。

 1 library ieee;
 2 use ieee.std_logic_1164.all;
 3 library grlib;
 4 use grlib.amba.all;
 5 use grlib.stdlib.all;
 6 use grlib.devices.all;
 7 
 8 
 9 entity apbseg is
10     generic (
11                 pindex    : integer := 1         ;-- slave bus index
12                 paddr    : integer := 16#240#;-- slave address
13                 pmask    : integer := 16#fff#; --choose the minimun size 256byte
14                 pirq    : integer := 0        ---interrupt index
15             );           
16     port     (
17                 rst     : in  std_ulogic;
18                 clk     : in  std_ulogic;
19                 apbi    : in  apb_slv_in_type;     -- APB slave inputs
20                 apbo    : out apb_slv_out_type;     -- APB slave outputs
21                 led_out    : out std_logic_vector(7 downto 0)
22             );
23 end entity;
24 
25 architecture rtl of apbseg is
26 
27 component led 
28 port(
29         indata:in std_logic_vector (3 downto 0);
30         outdata:out std_logic_vector (7 downto 0)
31     );
32 end component;
33 
34 constant REVISION : integer := 0;
35 constant pconfig : apb_config_type :=
36          (
37              0 => ahb_device_reg ( VENDOR_OPENCHIP, OPENCHIP_APBGPIO, 0, REVISION, pirq),
38              1 => apb_iobar(paddr, pmask)
39          );
40          
41 signal ledindata_reg :std_logic_vector(3 downto 0);
42 signal apb_write_reg :std_logic_vector(3 downto 0);
43 
44 begin
45 
46     --the main process
47     p:process(rst, apbi)
48     
49     --variable rdata : std_logic_vector(31 downto 0) := (others => '0');
50     variable write_temp: std_logic_vector(31 downto 0);--apb write data temp
51     
52     begin        
53     
54         -- reset operation
55         if rst = '0' then
56             write_temp:= (others => '0');
57         end if;
58             
59         --write
60         if (apbi.psel(pindex) and apbi.penable and apbi.pwrite) = '1' then -- 
61             case apbi.paddr(3 downto 2) is
62             when "00" =>
63                 write_temp:= apbi.pwdata;
64             when others =>
65                 null;
66             end case;
67             
68             apb_write_reg<=write_temp(3 downto 0);        
69 end if;
70 
71     end process;
72 
73     --clk process
74     regs : process(clk)
75     begin
76         if rising_edge(clk) then
77             ledindata_reg <= apb_write_reg;--一定要時鍾才會跟新數據
78         end if;
79     end process;
80     
81     --reconglise the vendor
82     apbo.pconfig <= pconfig;
83     
84     --instant the entity
85     led1:led
86     port map(
87                 indata=>ledindata_reg,
88                 outdata=>led_out
89             );
90     
91 end architecture;

 

3 仿真測試

為了確保所定義的IP核能按照設計的工作,在將IP核嵌入到SOPC之前,需要對IP核的功能經行仿真。如圖4所示(由於用的是Quartus II 9.0,並沒有使用modelsim仿真)。

當APB的寫信號有效后,APB數據線上的數據寫入到ledindata_reg寄存器中,輸出引腳輸出對應共陽數碼管的碼值。例如APB總線上的數據是15時,輸出引腳輸出的就是10001110;當APB 總線上的數據是10000000時,IP輸出引腳輸出的就是10000000。仿真測試說明這個定義的IP核能正常工作。

 

圖 4 IP核的仿真圖 

三、 將IP核嵌入到SOPC中

1 庫文件准備

1、添加自定義IP庫。為了方便IP核的管理和使用,需要添加自定義的IP庫。在lib目錄下新建文件夾,這里新建的是一個名為rcq的文件夾,作為自己的IP庫。再在rcq里面新建一個名為seg的文件夾,作為七段數碼管的IP庫。將前面編寫的led.vhd 和 apbseg.vhd放到seg中。

2、編寫包文件。在seg文件夾中新建名為seg.vhd文件作為包文件。seg.vhd的內容如下:

 1 library ieee;
 2 use ieee.std_logic_1164.all;
 3 library grlib;
 4 use grlib.amba.all;
 5 use grlib.stdlib.all;
 6 use grlib.devices.all;
 7 
 8 package seg is
 9 
10 type matrix_type is array (7 downto 0) of std_logic_vector (7 downto 0);
11 
12 component apbseg is
13     generic (
14                 pindex    : integer := 1         ;-- slave bus index
15                 paddr    : integer := 16#240#;-- slave address
16                 pmask    : integer := 16#fff#; --choose the minimun size 256byte
17                 pirq    : integer := 0        ---interrupt index
18             );           
19     port     (
20                 rst     : in  std_ulogic;
21                 clk     : in  std_ulogic;
22                 apbi    : in  apb_slv_in_type;     -- APB slave inputs
23                 apbo    : out apb_slv_out_type;     -- APB slave outputs
24                 led_out    : out std_logic_vector(7 downto 0)
25             );
26             
27 end component;
28 
29 end package;

 3、另外,還需要修改leon3mp.qsf文件。在leon3mp.qsf中添加如下三行語句:

1 set_global_assignment -name VHDL_FILE http://www.cnblogs.com/lib/rcq/seg/seg.vhd -library rcq
2 set_global_assignment -name VHDL_FILE http://www.cnblogs.com/lib/rcq/seg/apbseg.vhd -library rcq
3 set_global_assignment -name VHDL_FILE http://www.cnblogs.com/lib/rcq/seg/led.vhd -library rcq

這樣Quartus II 在綜合的時候,就能找到前面定義的rcq 庫中的所有設計文件。

2 添加IP

LEON 的配置和設計都是通過修改或者編寫源代碼來實現的。這里通過修改頂層文件的方式將IP添加到SOPC系統中。鑒於前面已經將一個簡單的SOPC系統成功運行起來,這里在前面的基礎上,只修改頂層leon3mp.vhd文件,將這個七段數碼管的IP添加進去。

自定義的IP符合AMBA APB 總線協議,所以將其添加到APB總線上很容易。需要添加8個數碼管,使用for generate語句生成。實現代碼如下:

 1 -----------------------------------------------------------------------
 2 ---  HEX                        ---------------------------------------
 3 -----------------------------------------------------------------------
 4     x:for i in 0 to 7
 5     generate
 6         hex:apbseg
 7         generic map(
 8                     pindex    => SEG_INDEX+i,-- slave bus index
 9                     paddr    => SEG_INDEX+i-- slave address
10                 )         
11         port map(
12                     rst     => rstn,
13                     clk     => clkm,
14                     apbi    => apbi,     -- APB slave inputs
15                     apbo    => apbo(SEG_INDEX+i),     -- APB slave outputs
16                     led_out    => hex_temp(i)
17                 );
18     end generate;
19         
20     hexo_d_pad:outpadv 
21         generic map (width =>7, tech => padtech) 
22         port map (oHEX0_D, hex_temp(0)(6 downto 0));    
23     hexo_dp_pad:outpad
24         generic map (tech => padtech) 
25         port map (oHEX0_DP, hex_temp(0)(7));    
26     
27     hex1_d_pad:outpadv 
28         generic map (width =>7, tech => padtech) 
29         port map (oHEX1_D, hex_temp(1)(6 downto 0));    
30     hex1_dp_pad:outpad
31         generic map (tech => padtech) 
32         port map (oHEX1_DP, hex_temp(1)(7));
33         
34     hex2_d_pad:outpadv 
35         generic map (width =>7, tech => padtech) 
36         port map (oHEX2_D, hex_temp(2)(6 downto 0));    
37     hex2_dp_pad:outpad
38         generic map (tech => padtech) 
39         port map (oHEX2_DP, hex_temp(2)(7));
40         
41     hex3_d_pad:outpadv 
42         generic map (width =>7, tech => padtech) 
43         port map (oHEX3_D, hex_temp(3)(6 downto 0));    
44     hex3_dp_pad:outpad
45         generic map (tech => padtech) 
46         port map (oHEX3_DP, hex_temp(3)(7));
47     
48     hex4_d_pad:outpadv 
49         generic map (width =>7, tech => padtech) 
50         port map (oHEX4_D, hex_temp(4)(6 downto 0));    
51     hex4_dp_pad:outpad
52         generic map (tech => padtech) 
53         port map (oHEX4_DP, hex_temp(4)(7));
54     
55     hex5_d_pad:outpadv 
56         generic map (width =>7, tech => padtech) 
57         port map (oHEX5_D, hex_temp(5)(6 downto 0));    
58     hex5_dp_pad:outpad
59         generic map (tech => padtech) 
60         port map (oHEX5_DP, hex_temp(5)(7));
61     
62     hex6_d_pad:outpadv 
63         generic map (width =>7, tech => padtech) 
64         port map (oHEX6_D, hex_temp(6)(6 downto 0));    
65     hex6_dp_pad:outpad
66         generic map (tech => padtech) 
67         port map (oHEX6_DP, hex_temp(6)(7));
68     
69     hex7_d_pad:outpadv 
70         generic map (width =>7, tech => padtech) 
71         port map (oHEX7_D, hex_temp(7)(6 downto 0));    
72     hex7_dp_pad:outpad
73         generic map (tech => padtech) 
74         port map (oHEX7_DP, hex_temp(7)(7));

注意:在AMBA設計的時候,默認APB 外設最多為16個,如果之前已經設計了很多APB 外設,在添加8個數碼管的IP的時候,會出現錯誤。這種情況下,就需要修改AMBA的設計文件了。

3 測試硬件

啟動Quartus II ,對修改后的工程進行編譯綜合、下載。

為了檢測新生成的SOPC系統是否是符合要求的,可以使用GRTools中的Grmon工具測試硬件。

啟動Grmon,在Action菜單下選擇Connect to target,連接到目標。

 圖 5 Grmon連接到目標

如果連接成功,就能看到控制台輸出如下信息:

 1 GRMON LEON debug monitor v1.1.35b evaluation version
 2 
 3  Copyright (C) 2004,2005 Gaisler Research - all rights reserved.
 4  For latest updates, go to http://www.gaisler.com/
 5  Comments or bug-reports to support@gaisler.com
 6 
 7  This evaluation version will expire on 27/5/2010
 8  using Altera JTAG cable
 9  Selected cable 1 - USB-Blaster [USB-0]
10 JTAG chain:
11 @1: EP2C70 (0x020B60DD)
12 
13  GRLIB build version: 4104
14 
15  initialising 
16  detected frequency:  50 MHz
17 
18  Component                            Vendor
19  LEON3 SPARC V8 Processor             Gaisler Research
20  Unknown device                       Gaisler Research
21  AHB/APB Bridge                       Gaisler Research
22  LEON3 Debug Support Unit             Gaisler Research
23  32-bit PC133 SDRAM Controller        Gaisler Research
24  Generic APB UART                     Gaisler Research
25  Multi-processor Interrupt Ctrl       Gaisler Research
26  Modular Timer Unit                   Gaisler Research
27  General purpose I/O port             Gaisler Research
28  General purpose I/O port             Gaisler Research
29  Unknown device                       Unknown vendor
30  Unknown device                       Unknown vendor
31  Unknown device                       Unknown vendor
32  Unknown device                       Unknown vendor
33  Unknown device                       Unknown vendor
34  Unknown device                       Unknown vendor
35  Unknown device                       Unknown vendor
36  Unknown device                       Unknown vendor
37 
38  Use command 'info sys' to print a detailed report of attached cores
39 
40 
41 Grmon>

 可以看到,系統中出現了8個 Unkown device,這個8個Unkown device就是自定義的8個數碼管IP核,由於是用戶自定義的,Vendor(提供商)和ID都是未知的,所以Grmon用 Unkown device 來表示。這表明我們自定義的數碼管IP核已經添加到這個SOPC中。這時如果輸入info sys 命令,獲取系統更多的信息。

 1 Grmon> info sys
 2 00.01:003   Gaisler Research  LEON3 SPARC V8 Processor (ver 0x0)
 3              ahb master 0
 4 01.01:01c   Gaisler Research  Unknown device (ver 0x1)
 5              ahb master 1
 6 01.01:006   Gaisler Research  AHB/APB Bridge (ver 0x0)
 7              ahb: 80000000 - 80100000
 8 02.01:004   Gaisler Research  LEON3 Debug Support Unit (ver 0x1)
 9              ahb: 90000000 - a0000000
10              AHB trace 128 lines, stack pointer 0x43fffff0
11              CPU#0 win 8, hwbp 2, itrace 128, V8 mul/div, lddel 1
12                    icache 2 * 8 kbyte, 32 byte/line lru
13                    dcache 2 * 4 kbyte, 16 byte/line lru
14 03.01:009   Gaisler Research  32-bit PC133 SDRAM Controller (ver 0x1)
15              ahb: 40000000 - 50000000
16              ahb: fff00100 - fff00200
17              32-bit sdram: 1 * 64 Mbyte @ 0x40000000, col 9, cas 2, ref 7.8 us
18 01.01:00c   Gaisler Research  Generic APB UART (ver 0x1)
19              irq 2
20              apb: 80000100 - 80000200
21              baud rate 38343
22 02.01:00d   Gaisler Research  Multi-processor Interrupt Ctrl (ver 0x3)
23              apb: 80000200 - 80000300
24 03.01:011   Gaisler Research  Modular Timer Unit (ver 0x0)
25              irq 8
26              apb: 80000300 - 80000400
27              8-bit scaler, 2 * 32-bit timers, divisor 50
28 05.01:01a   Gaisler Research  General purpose I/O port (ver 0x1)
29              apb: 80000500 - 80000600
30 06.01:01a   Gaisler Research  General purpose I/O port (ver 0x1)
31              apb: 80000600 - 80000700
32 08.07:001   Unknown vendor  Unknown device (ver 0x0)
33              apb: 80000800 - 80000900
34 09.07:001   Unknown vendor  Unknown device (ver 0x0)
35              apb: 80000900 - 80000a00
36 0a.07:001   Unknown vendor  Unknown device (ver 0x0)
37              apb: 80000a00 - 80000b00
38 0b.07:001   Unknown vendor  Unknown device (ver 0x0)
39              apb: 80000b00 - 80000c00
40 0c.07:001   Unknown vendor  Unknown device (ver 0x0)
41              apb: 80000c00 - 80000d00
42 0d.07:001   Unknown vendor  Unknown device (ver 0x0)
43              apb: 80000d00 - 80000e00
44 0e.07:001   Unknown vendor  Unknown device (ver 0x0)
45              apb: 80000e00 - 80000f00
46 0f.07:001   Unknown vendor  Unknown device (ver 0x0)
47              apb: 80000f00 - 80001000
48 
49 Grmon>

 這可更詳細地看到,這8個IP的地址,分別是0x80000800、0x80000900、0x80000a00…0x80000f00。這些地址對應的寄存器就是前面在定義IP時候定義的輸入數據寄存器。

四、 使用LEON IDE 測試IP核

知道了自定義IP核的地址和相關寄存器,就可以編程軟件測試程序使用定義的IP核了。由於我們定義的數碼管的IP核只有一個數據寄存器,只需要對它寫值就可以進行測試了。

1 新建工程

(原創)LEON3入門教程(三):基於LEON3的SOPC設計以及HELLOWORLD和流水燈介紹的一樣,我們使用LEON IDE建立測試工程,為Seg_test。添加一個main.c文件,內容為:

 1 /*
 2  * main.c
 3  *
 4  *  Created on: 2010-3-27
 5  *      Author: 超群天晴
 6  */
 7 
 8 
 9 // LED
10 #define LEDG_BASE 0x80000600
11 
12 // REG LEDG
13 #define LEDG_DATA_IN      (*(unsigned int volatile *)(LEDG_BASE            ))
14 #define LEDG_DATA_OUT      (*(unsigned int volatile *)(LEDG_BASE + 4        ))
15 #define LEDG_DIR          (*(unsigned int volatile *)(LEDG_BASE + 8        ))
16 #define LEDG_INT_MASK      (*(unsigned int volatile *)(LEDG_BASE + 0xC    ))
17 #define LEDG_INT_POL      (*(unsigned int volatile *)(LEDG_BASE + 0x10    ))
18 #define LEDG_INT_EDGE      (*(unsigned int volatile *)(LEDG_BASE + 0x14    ))
19 #define LEDG_BYPASS      (*(unsigned int volatile *)(LEDG_BASE + 0x18    ))
20 
21 
22 // HEX
23 #define HEX_BASE 0x80000800
24 
25 #define HEX0_DATA      (*(unsigned int volatile *)(HEX_BASE + 0x000))
26 #define HEX1_DATA      (*(unsigned int volatile *)(HEX_BASE + 0x100))
27 #define HEX2_DATA      (*(unsigned int volatile *)(HEX_BASE + 0x200))
28 #define HEX3_DATA      (*(unsigned int volatile *)(HEX_BASE + 0x300))
29 #define HEX4_DATA      (*(unsigned int volatile *)(HEX_BASE + 0x400))
30 #define HEX5_DATA      (*(unsigned int volatile *)(HEX_BASE + 0x500))
31 #define HEX6_DATA      (*(unsigned int volatile *)(HEX_BASE + 0x600))
32 #define HEX7_DATA      (*(unsigned int volatile *)(HEX_BASE + 0x700))
33 
34 
35 void delay1s(void);
36 int main(void)
37 {
38     unsigned char i=0;
39 
40     unsigned char led1=0;
41 
42     LEDG_DIR=0xffffffff;//output mode
43 
44     led1=0xf0;
45 
46     while(1)
47     {
48         for(i=0;i<16;i++)
49         {
50             LEDG_DATA_OUT=led1;
51 
52             HEX0_DATA=i;
53             HEX1_DATA=i;
54             HEX2_DATA=i;
55             HEX3_DATA=i;
56             HEX4_DATA=i;
57             HEX5_DATA=i;
58             HEX6_DATA=i;
59             HEX7_DATA=i;
60 
61             delay1s();
62 
63             led1=~led1;//    取反
64         }
65     }
66 
67     return 1;
68 }
69 
70 void delay1s(void)
71 {
72     int i,j;
73     for(i=0;i<1000;i++)
74         for(j=0;j<500;j++);
75 }

 

2 編譯、運行測試程序

程序運行后,可以看到8個數碼管交替顯示0~F

圖6 數碼管IP測試結果

 

 

=======================

完整工程和代碼可以從這里獲取:LEON3-lab2.rar

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM