luckybag

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) (TRDB-LCM)

2013年07月13日 ⁄ 综合 ⁄ 共 12687字 ⁄ 字号    ⁄ 评论关闭
 

Abstract
前一篇(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (純硬體篇) (IC Design) (DE2) 討論了使用Verilog純硬體的方式實作簡易的數位相機,為了實現SOC和軟硬體整合,本文我們將加上Nios II CPU,透過軟體的方式去控制CCD和彩色LCD。

使用環境:Quartus II 7.2 SP1 + Nios II 7.2 SP1 + DE2(Cyclone II EP2C35F627C6) + TRDB_LCM + TRDB_DC2

Introduction
若就功能面而言,使用Verilog純硬體實作的數位相機已經達到功能了,唯一的缺憾是他是『純硬體』,我們無法使用C語言軟體的方式去控制CCD和LCD,所以我們打算加上Nios II CPU,透過記憶體定址的方式去控制硬體。

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (純硬體篇) (IC Design) (DE2)中,我們使用了KEY和SW作為輸入的介面,這些KEY和SW直接與硬體的module相接,這是純硬體的方式。若要用軟體,我們勢必得用軟體去攔截KEY和SW輸入的結果,然後再將結果送到控制CCD和LCD的module。由於要使用軟體,一定需要一顆CPU,Nios II softcore CPU剛好可扮演這個角色,而軟體一定得載入記憶體執行,所以還需要一塊記憶體,DE2上有很多種記憶體可用,除了FPGA上的onchip-memory外,還有SRAM、SDRAM、Flash,為了簡化問題,本文先討論最單純的onchip-memory,後續會繼續討論使用SRAM等其他記憶體。

該如何攔截KEY和SW呢?Nios II提供了PIO的方式,可以輕易的攔截KEY和SW,這問題不大,但該如何用軟體去控制CCD和LCD呢?這就是本文的重點了。

Nios II提供了Avalon Bus,所有的周邊要和Nios II CPU溝通,都得透過這個bus,當然也必須遵守Avalon Bus的協定才能順利與Nios II溝通,所以必須將原來純硬體的Verilog程式碼,再多加上一個Adapter(是的,就是Design Pattern那個Adapter Pattern),讓原來的硬體能掛上Avalon Bus和Nios II溝通,只要能掛上Avalon Bus後,Nios II就能對這個Adapter做記憶體定址,只要有記憶體位址,C語言就能靠著記憶體位址對Adapter作存取了,也因此間接控制了CCD和LCD。

建立DE2_LCM_CCD_onchip專案
Step 1:

建立DE2_LCM_CCD_onchip目錄,將原本用Verilog純硬體的DE2_LCM_CCD.7z下載,將解壓縮後DE2_LCM_CCD下所有的檔案放到DE2_LCM_CCD_onchip下。

Step 2:
在DE2_LCM_CCD_onchip下建立ip子目錄。

要使SOPC Builder抓到你自己寫的controller,在Quartus II 7.2和以前版本有些不同,有兩種方法[1]:

1.將自己寫的controller放在專案目錄的ip子目錄下,這樣SOPC Builder在啟動時就會自動載入。這種方式適合controller只有這個專案會用到,而且期望你將專案複製給其他人時,不用設定就能抓到controller。

2.將controller放在獨立目錄,然後在SOPC Builder的Tools->Options->IP Search Path加入controller目錄,讓SOPC Builder可以找的到,這種方式適合多個專案要共用一個controller,不過若將專案複製給其他人時,對方還得自己設定controller路徑。

SOPC Builder更詳細的運作方式,請參閱(原創) 如何加速Altera的EDA工具? (IC Design) (Quartus II) (Nios II) (SOPC Builder) 。

本文採用的是第一種方法。

Step 3:
在ip目錄下建立CCD_Controller子目錄。

將CCD_Controller的Verilog code放在CCD_Controller目錄下。


撰寫CCD_Controller

CCD_Controller.v

1 module CCD_Controller (
2   // Avalon clock interface siganals
3   csi_clockreset_clk,
4   csi_clockreset_reset_n,
5   // Signals for Avalon-MM slave port
6   avs_s1_address,
7   avs_s1_chipselect,
8   avs_s1_write,
9   avs_s1_writedata,
10   // export
11   avs_s1_export_o_key,
12   avs_s1_export_o_sw
13 );
14 
15 input         csi_clockreset_clk;
16 input         csi_clockreset_reset_n;
17 
18 input         avs_s1_address;
19 input         avs_s1_chipselect;
20 input         avs_s1_write;
21 input  [15:0] avs_s1_writedata;
22 
23 output [2:0]  avs_s1_export_o_key;
24 output [15:0] avs_s1_export_o_sw;
25 
26 reg    [2:0]  r_key;
27 reg    [15:0] r_sw;
28 
29 // write to export
30 always@(posedge csi_clockreset_clk or negedge csi_clockreset_reset_n)
31 begin
32   if (!csi_clockreset_reset_n)
33   begin
34     r_key <= 4\'b1111;
35     r_sw <= 16\'b0000_0000_0000_0000;
36   end
37   else
38   begin
39     if (avs_s1_address == 1\'b0 && avs_s1_chipselect && avs_s1_write)
40     begin
41       r_key <= avs_s1_writedata[2-:3];
42       r_sw  <= r_sw;
43     end
44     else if (avs_s1_address == 1\'b1 && avs_s1_chipselect && avs_s1_write)
45     begin
46       r_key <= r_key;
47       r_sw  <= avs_s1_writedata;
48     end
49   end
50 end
51 
52 assign avs_s1_export_o_key = r_key;
53 assign avs_s1_export_o_sw  = r_sw;
54 
55 endmodule

這個CCD_Controller.v主要的目的在做什麼?由於CCD_Controller.v需要掛在Avalon Bus上,所以必須遵守Avalon-MM slave的規定,如clk、reset_n、address、chip_select、write、writedata這些port,尤其若要將資料送進CCD_Controller,Nios II是將資料送進writedata中,所以我們必須將writedata的資料進行解析,然後export出來,與CCD和LCD相關module相連。在Quartus II早期的版本,在port命名並沒有規定naming convention,所以在Component Editor的Signals還必須手動指定Signal Type,但在Quartus II 5.1以後增加了以下規定:

<interface_type>_<interface name>_<signal type>

Interface Type Meaning
avs Avalon-MM Slave
avm Avalon-MM Master
ats Avalon-MM Tristate Slave
atm Avalon-MM Tristate Master
aso Avalon-ST Source
asi Avalon-ST Sink
cso Clock Output
csi Clock Input
inr Interrupt Receiver
ins Interupt Sender
cos Conduit Start
coe Conduit End
ncm Nios II Custom Instruction Master
ncs Nios II Custom Instruction Slave
csi_clockreset_clk Clock Reset
csi_clockreset_reset_n Clock Reset N

Table.1 Interface type value meaning [2]

20行

input  [15:0] avs_s1_writedata;

為什麼avs_s1_writedata要設定16 bit寬呢?因為這個controller主要的input為KEY和SW,KEY[0]由於作為硬體reset用,所以軟體就不加以攔截了,所以只有KEY[1]、KEY[2]、KEY[3]共3 bit,SW為16 bit,所以由最大的16 bit決定writedata寬度。

23行、24行

output [2:0]  avs_s1_export_o_key;
output [15:0] avs_s1_export_o_sw;

如前段所解釋,因為KEY只有3 bit,所以export用的avs_s1_export_key也只有3 bit,同理,avs_s1_export_o_sw也只有如SW的16 bit。

39行到43行

if (avs_s1_address == 1\'b0 && avs_s1_chipselect && avs_s1_write)
begin
  r_key <= avs_s1_writedata[2-:3];
  r_sw  <= r_sw;
end

目的是將writedata資料解析為KEY,address的功用是做什麼呢?由於所有輸入的訊號都由writedata進來,我該怎麼分辨進來的訊號是KEY還是SW?就是靠address!!由於本controller只須分辨KEY和SW兩種訊號,所以address只需1 bit分辨0與1即可,並且規定1\'b0為KEY,1\'b1為SW,除此之外,Avalon Bus還規定chipselect和write為1時訊號才有效,所以必須增加判斷。

為什麼只抓writedata[2-:3]呢?由於writedata為16 bit,但KEY只有3 bit,所以只需writedata低3bit的資料即可,[2-:3]為Verilog專屬語法,表是從3bit開始往下抓3 bit。

44行到48行解析SW同理,由於SW和writedata同寬,只需用assign vector的方式即可。

最後必須將CCD_Controller.v存到DE2_LCM_CCD_onchip\ip\CCD_Controller\hdl\目錄下。

使用Component Editor建立CCD_Controller
Verilog程式寫好還不夠,還必須使用Component Editor將CCD_Controller.v包裝成SOPC Builder能用的controller。

Step 1:
按右上角圖示啟動SOPC Builder。

 de2_lcm_ccd_04

Fig.1 SOPC Builder圖示

Step 2:
設定System名稱,輸入nios_ii_system。

de2_lcm_ccd_04a 

Fig.2 設定System名稱

Step 3:
啟動Component Editor

 de2_lcm_ccd_05

Fig.3 SOPC Builder

Step 4:
按下Add HDL File,加入CCD_Controller.v

de2_lcm_ccd_06

Fig.4 Component Editor

de2_lcm_ccd_06a 

Fig.5 加入CCD_Controller.v

加入後,Component Editor會對CCD_Controller.v作及時編譯,若Verilog語法有錯會顯示出來,若成功將出現以下畫面。

de2_lcm_ccd_07

Fig.6 CCD_Controller.v編譯成功

Step 5:
設定Signals
由於CCD_Controller.v已經依照naming convention寫了,所以就不用再設定Signal Type,Component Editor會自動抓到。

de2_lcm_ccd_08 

Fig.7 Component Editor : Signals

Step 6:
設定Interfaces
Component Editor預設多抓了export_0這個interface(原因不明),須手動按Remove Interfaces With No Signals將其刪除。

 de2_lcm_ccd_09

Fig.8 Component Editor:Interfaces

移除export_0後,將s1的Associated Clock選擇clockreset,Slave Addressing選擇NATIVE。

de2_lcm_ccd_10

Fig.9 Component Editor:Interfaces 2

Step 7:
填入Controller資訊
這些資訊可依你的需要自行修改,不會影響功能,最後按下Finish。

de2_lcm_ccd_11 

Fig.10 Component Editor:Component Wizard

Step 8:
完成CCD_Controller
按下Yes, Save後,Component Editor會為你在DE2_LCM_CCD_onchip\ip\CCD_Controller\hdl下產生CCD_Controller_hw.tcl。

de2_lcm_ccd_12

Fig.11 確定產生CCD_Controller_hw.tcl

de2_lcm_ccd_13

Fig.12 SOPC Builder出現CCD_Controller

建立Nios II System
接著我們要使用SOPC Builder產生以Nios II為基礎的SOC

Step 1:
加入Nios II Processor
選擇左側Altera SOPC Builder->Nios II Processor,滑鼠按兩下加入

de2_lcm_ccd_14

Fig.13 加入Nios II Processor

選擇Nios II/e,因為本專案要使用on-chip memory,所以只好選Nios II/e以節省logic element,讓on-chip memory能開到最大。

 de2_lcm_ccd_15

Fig.14 選用Nios II/e

Step 2:
加入on-chip memory
由於要使用軟體,所以必須使用記憶體載入程式,為了簡化問題,所以本專案選擇最單純的on-chip memory,將記憶體直接放在FPGA內。

選擇左側Altera SOPC Builder->Memories and Memory Controller->On-Chip->On-Chip Memory(RAM or ROM),滑鼠按兩下加入

de2_lcm_ccd_16

Fig.15 加入on-chip memory

設定on-chip memory大小為35KB。
為什麼只設定35KB,而不設定其他數值呢?Cyclone II(EP2C35F672C6)的Nios II,若取最單純的設定:Nios II/e + on-chip memory + JTAG UART + System ID Peripheral,且不包含任何自己寫的Verilog,極限可設定on-chip memory 49KB,且可正常編譯,以本例而言,由於CCD和LCD已經寫了不少Verilog,所以已經占了FPGA不少logic element,導致on-chip memory的極限只能設定到36KB,若更大則Quartus II無法正常編譯,這裡取35KB只因為剛好為整數,且對本系統已經夠用。

 de2_lcm_ccd_17

Fig.16 on-chip memory size

Step 3:
加入JTAG UART
本專案雖然不需在Console顯示文字,不過在Console使用printf()仍為最常用的debug方式,所以建議還是加上JTAG UART。

在左側SOPC Builder->Interface Protocols->Serial下找到JTAG UART,滑鼠點兩下加入,接受預設值即可,按Finish。

de2_lcm_ccd_18

Fig.17 加入JTAG UART

de2_lcm_ccd_19

Fig.18 JTAG UART window

Step 4:
加入System ID Peripheral
System ID Peripheral可以用來辨識硬體,雖然沒有加入也能執行,不過Altera原廠手冊仍建議加入此controller。

在左側Altera SOPC Builder->Peripherals->Debug and Performance下找到System ID Peripheral,滑鼠按兩下加入,接受預設值即可,按Finish。

de2_lcm_ccd_20

Fig.19 加入System ID Peripheral

de2_lcm_ccd_21

Fig.20 System ID Peripheral window

Step 5:
加入CCD_Controller
現在要加入剛剛自己寫好的CCD_Controller。

在左側Altera SOPC Builder->My Controller下找到CCD_Controller,滑鼠按兩下加入,接受預設值即可,按Finish。

de2_lcm_ccd_22

Fig.21 加入CCD_Controller

de2_lcm_ccd_23

Fig.22 CCD_Controller window

Step 6:
加入KEY PIO
由於我們要用軟體攔截KEY的輸入,所以要加上PIO。

在左側Altera SOPC Builder->Peripherals->Microcontroller Peripherals下找到PIO(Parallel I/O),滑鼠按兩下加入,接受預設值即可,按Finish。

de2_lcm_ccd_24

Fig.23 加入PIO

由於KEY[0]是reset,因此軟體不攔,只用軟體攔KEY[1]、KEY[2]與KEY[3]而已,所以Width填3 bit。因為只是讀取KEY的輸入值,所以選Input ports only。

de2_lcm_ccd_25

Fig.24 PIO window

更名為key_pio

de2_lcm_ccd_26

Fig.25 更名為key_pio

Step 7:
加入SW PIO
由於我們要用軟體攔截SW的輸入,所以要加上PIO。

在左側Altera SOPC Builder->Peripherals->Microcontroller Peripherals下找到PIO(Parallel I/O),滑鼠按兩下加入,接受預設值即可,按Finish。

de2_lcm_ccd_24

Fig.25 加入PIO

由於SW為16 bit,所以Width填3 bit。因為只是讀取SW的輸入值,所以選Input ports only。

de2_lcm_ccd_27

Fig.26 PIO window

更名為sw_pio

de2_lcm_ccd_28

Fig.27 更名為sw_pio

Step 8:
設定reset和exception vector

在右側CPU用滑鼠點兩下。

de2_lcm_ccd_29

Fig.28 設定reset與exception

將reset和exception vector設在onchip_mem,這也是本專案唯一的記憶體。

de2_lcm_ccd_30

Fig.29 將reset和exception設在onchip_mem

Step 9:
重新設定Base Address
由下方的錯誤訊息得知,有些元件所分配的base address衝突了,所以必須重新指定base address。

選擇System->Auto-Assign Base Address

de2_lcm_ccd_31

Fig.30 Auto-Assign Base Address

Step 10:
產生Nios II System

截至目前為止,整個Nios II System已經設定完成,按Generate產生nios_ii_system.ptf,這需要一點時間,非常依賴CPU運算速度。

de2_lcm_ccd_32

Fig.31 Generate System

按Save對Nios II System存檔。

 de2_lcm_ccd_33

Fig.32 Save system

經過一段時間後,值到右下方出現Generate,表是建立完成,按Exit回到Quartus II。

de2_lcm_ccd_34

Fig.33 Generate complete

修改Top mudule:DE2_LCM_CCD.v
雖然SOPC Builder和Component Editor自動產生了很多Verilog程式碼,為我們省下不少工夫,但Top module還是得手動自己改,主要為了連接Nios II System和原本純硬體的CCD和LCD。

DE2_LCM_CCD.V

  1 module DE2_LCM_CCD (
  2   ////////////////////// Clock Input ////////////////////
  3   CLOCK_27,           // 27 MHz
  4   CLOCK_50,           // 50 MHz
  5   EXT_CLOCK,          // External Clock
  6   ////////////////////// Push Button ////////////////////
  7   KEY,                // Pushbutton[3:0]
  8   //////////////////// DPDT Switch ////////////////////
  9   SW,                 // Toggle Switch[17:0]
10   ////////////////////// 7-SEG Dispaly ////////////////////
11   HEX0,               // Seven Segment Digit 0
12   HEX1,               // Seven Segment Digit 1
13   HEX2,               // Seven Segment Digit 2
14   HEX3,               // Seven Segment Digit 3
15   HEX4,               // Seven Segment Digit 4
16   HEX5,               // Seven Segment Digit 5
17   HEX6,               // Seven Segment Digit 6
18   HEX7,               // Seven Segment Digit 7
19   ////////////////////// LED ////////////////////////
20   LEDG,               // LED Green[8:0]
21   LEDR,               // LED Red[17:0]
22   ////////////////////// UART ////////////////////////
23   UART_TXD,           // UART Transmitter
24   UART_RXD,           // UART Receiver
25   ////////////////////// IRDA ////////////////////////
26   IRDA_TXD,           // IRDA Transmitter
27   IRDA_RXD,           // IRDA Receiver
28   ////////////////////// SDRAM Interface ////////////////
29   DRAM_DQ,            // SDRAM Data bus 16 Bits
30   DRAM_ADDR,          // SDRAM Address bus 12 Bits
31   DRAM_LDQM,          // SDRAM Low-byte Data Mask 
32   DRAM_UDQM,          // SDRAM High-byte Data Mask
33   DRAM_WE_N,          // SDRAM Write Enable
34   DRAM_CAS_N,         // SDRAM Column Address Strobe
35   DRAM_RAS_N,         // SDRAM Row Address Strobe
36   DRAM_CS_N,          // SDRAM Chip Select
37   DRAM_BA_0,          // SDRAM Bank Address 0
38   DRAM_BA_1,          // SDRAM Bank Address 0
39   DRAM_CLK,           // SDRAM Clock
40   DRAM_CKE,           // SDRAM Clock Enable
41   ////////////////////// Flash Interface ////////////////
42   FL_DQ,              // FLASH Data bus 8 Bits
43   FL_ADDR,            // FLASH Address bus 22 Bits
44   FL_WE_N,            // FLASH Write Enable
45   FL_RST_N,           // FLASH Reset
46   FL_OE_N,            // FLASH Output Enable
47   FL_CE_N,            // FLASH Chip Enable
48   ////////////////////// SRAM Interface ////////////////
49   SRAM_DQ,            // SRAM Data bus 16 Bits
50   SRAM_ADDR,          // SRAM Address bus 18 Bits
51   SRAM_UB_N,          // SRAM High-byte Data Mask 
52   SRAM_LB_N,          // SRAM Low-byte Data Mask 
53   SRAM_WE_N,          // SRAM Write Enable
54   SRAM_CE_N,          // SRAM Chip Enable
55   SRAM_OE_N,          // SRAM Output Enable
56   ////////////////////// ISP1362 Interface ////////////////
57   OTG_DATA,           // ISP1362 Data bus 16 Bits
58   OTG_ADDR,           // ISP1362 Address 2 Bits
59   OTG_CS_N,           // ISP1362 Chip Select
60   OTG_RD_N,           // ISP1362 Write
61   OTG_WR_N,           // ISP1362 Read
62   OTG_RST_N,          // ISP1362 Reset
63   OTG_FSPEED,         // USB Full Speed, 0 = Enable, Z = Disable
64   OTG_LSPEED,         // USB Low Speed, 0 = Enable, Z = Disable
65   OTG_INT0,           // ISP1362 Interrupt 0
66   OTG_INT1,           // ISP1362 Interrupt 1
67   OTG_DREQ0,          // ISP1362 DMA Request 0
68   OTG_DREQ1,          // ISP1362 DMA Request 1
69   OTG_DACK0_N,        // ISP1362 DMA Acknowledge 0
70   OTG_DACK1_N,        // ISP1362 DMA Acknowledge 1
71   ////////////////////// LCD Module 16X2 ////////////////
72   LCD_ON,             // LCD Power ON/OFF
73   LCD_BLON,           // LCD Back Light ON/OFF
74   LCD_RW,             // LCD Read/Write Select, 0 = Write, 1 = Read
75   LCD_EN,             // LCD Enable
76   LCD_RS,             // LCD Command/Data Select, 0 = Command, 1 = Data
77   LCD_DATA,           // LCD Data bus 8 bits
78   ////////////////////// SD_Card Interface ////////////////
79   SD_DAT,             // SD Card Data
80   SD_DAT3,            // SD Card Data 3
81   SD_CMD,             // SD Card Command Signal
82   SD_CLK,             // SD Card Clock
83   ////////////////////// USB JTAG link    ////////////////////
84   TDI,                // CPLD -> FPGA (data in)
85   TCK,                // CPLD -> FPGA (clk)
86   TCS,                // CPLD -> FPGA (CS)
87   TDO,                // FPGA -> CPLD (data out)
88   ////////////////////// I2C ////////////////////////////
89   I2C_SDAT,           // I2C Data
90   I2C_SCLK,           // I2C Clock
91   ////////////////////// PS2 ////////////////////////////
92   PS2_DAT,            // PS2 Data
93   PS2_CLK,            // PS2 Clock
94   ////////////////////// VGA ////////////////////////////
95   VGA_CLK,            // VGA Clock
96   VGA_HS,             // VGA H_SYNC
97   VGA_VS,             // VGA V_SYNC
98   VGA_BLANK,          // VGA BLANK
99   VGA_SYNC,           // VGA SYNC
100   VGA_R,              // VGA Red[9:0]
101   VGA_G,              // VGA Green[9:0]
102   VGA_B,              // VGA Blue[9:0]

分类:

技术点:

相关文章:

  • 2021-10-21
  • 2022-01-22
  • 2021-08-11
  • 2021-11-27
  • 2021-04-14
  • 2022-01-11
  • 2021-09-12
  • 2021-08-30
猜你喜欢
  • 2021-11-01
  • 2021-11-01
  • 2021-11-01
  • 2021-11-01
  • 2021-11-14
  • 2021-10-14
  • 2021-06-14
相关资源
相似解决方案