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

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]
103   ////////////////////// Ethernet Interface ////////////////////////
104   ENET_DATA,          // DM9000A DATA bus 16Bits
105   ENET_CMD,           // DM9000A Command/Data Select, 0 = Command, 1 = Data
106   ENET_CS_N,          // DM9000A Chip Select
107   ENET_WR_N,          // DM9000A Write
108   ENET_RD_N,          // DM9000A Read
109   ENET_RST_N,         // DM9000A Reset
110   ENET_INT,           // DM9000A Interrupt
111   ENET_CLK,           // DM9000A Clock 25 MHz
112   ////////////////////// Audio CODEC ////////////////////////
113   AUD_ADCLRCK,        // Audio CODEC ADC LR Clock
114   AUD_ADCDAT,         // Audio CODEC ADC Data
115   AUD_DACLRCK,        // Audio CODEC DAC LR Clock
116   AUD_DACDAT,         // Audio CODEC DAC Data
117   AUD_BCLK,           // Audio CODEC Bit-Stream Clock
118   AUD_XCK,            // Audio CODEC Chip Clock
119   ////////////////////// TV Decoder ////////////////////////
120   TD_DATA,            //  TV Decoder Data bus 8 bits
121   TD_HS,              //  TV Decoder H_SYNC
122   TD_VS,              //  TV Decoder V_SYNC
123   TD_RESET,           //  TV Decoder Reset
124   ////////////////////// GPIO ////////////////////////////
125   GPIO_0,             // GPIO Connection 0
126   GPIO_1              // GPIO Connection 1
127 );
128 
129 ////////////////////////////// Clock Input ////////////////////////
130 input         CLOCK_27;     // 27 MHz
131 input         CLOCK_50;     // 50 MHz
132 input         EXT_CLOCK;    // External Clock
133 ////////////////////////////// Push Button ////////////////////////
134 input  [3:0]  KEY;          // Pushbutton[3:0]
135 ////////////////////////////// DPDT Switch ////////////////////////
136 input  [17:0] SW;           // Toggle Switch[17:0]
137 ////////////////////////////// 7-SEG Dispaly ////////////////////////
138 output [6:0]  HEX0;         // Seven Segment Digit 0
139 output [6:0]  HEX1;         // Seven Segment Digit 1
140 output [6:0]  HEX2;         // Seven Segment Digit 2
141 output [6:0]  HEX3;         // Seven Segment Digit 3
142 output [6:0]  HEX4;         // Seven Segment Digit 4
143 output [6:0]  HEX5;         // Seven Segment Digit 5
144 output [6:0]  HEX6;         // Seven Segment Digit 6
145 output [6:0]  HEX7;         // Seven Segment Digit 7
146 ////////////////////////////// LED ////////////////////////////
147 output [8:0]      LEDG;         // LED Green[8:0]
148 output [17:0] LEDR;         // LED Red[17:0]
149 ////////////////////////////// UART ////////////////////////////
150 output        UART_TXD;     // UART Transmitter
151 input         UART_RXD;     // UART Receiver
152 ////////////////////////////// IRDA ////////////////////////////
153 output        IRDA_TXD;     // IRDA Transmitter
154 input         IRDA_RXD;     // IRDA Receiver
155 ////////////////////////////// SDRAM Interface ////////////////////////
156 inout  [15:0] DRAM_DQ;      // SDRAM Data bus 16 Bits
157 output [11:0] DRAM_ADDR;    // SDRAM Address bus 12 Bits
158 output        DRAM_LDQM;    // SDRAM Low-byte Data Mask
159 output        DRAM_UDQM;    // SDRAM High-byte Data Mask
160 output        DRAM_WE_N;    // SDRAM Write Enable
161 output        DRAM_CAS_N;   // SDRAM Column Address Strobe
162 output        DRAM_RAS_N;   // SDRAM Row Address Strobe
163 output        DRAM_CS_N;    // SDRAM Chip Select
164 output        DRAM_BA_0;    // SDRAM Bank Address 0
165 output        DRAM_BA_1;    // SDRAM Bank Address 0
166 output        DRAM_CLK;     // SDRAM Clock
167 output        DRAM_CKE;     // SDRAM Clock Enable
168 ////////////////////////////// Flash Interface ////////////////////////
169 inout  [7:0]  FL_DQ;        // FLASH Data bus 8 Bits
170 output [21:0] FL_ADDR;      // FLASH Address bus 22 Bits
171 output        FL_WE_N;      // FLASH Write Enable
172 output        FL_RST_N;     // FLASH Reset
173 output        FL_OE_N;      // FLASH Output Enable
174 output        FL_CE_N;      // FLASH Chip Enable
175 ////////////////////////////// SRAM Interface ////////////////////////
176 inout  [15:0] SRAM_DQ;      // SRAM Data bus 16 Bits
177 output [17:0] SRAM_ADDR;    // SRAM Address bus 18 Bits
178 output        SRAM_UB_N;    // SRAM High-byte Data Mask
179 output        SRAM_LB_N;    // SRAM Low-byte Data Mask
180 output        SRAM_WE_N;    // SRAM Write Enable
181 output        SRAM_CE_N;    // SRAM Chip Enable
182 output        SRAM_OE_N;    // SRAM Output Enable
183 ////////////////////////////// ISP1362 Interface ////////////////////////
184 inout  [15:0] OTG_DATA;     // ISP1362 Data bus 16 Bits
185 output [1:0]  OTG_ADDR;     // ISP1362 Address 2 Bits
186 output        OTG_CS_N;     // ISP1362 Chip Select
187 output        OTG_RD_N;     // ISP1362 Write
188 output        OTG_WR_N;     // ISP1362 Read
189 output        OTG_RST_N;    // ISP1362 Reset
190 output        OTG_FSPEED;   // USB Full Speed, 0 = Enable, Z = Disable
191 output        OTG_LSPEED;   // USB Low Speed, 0 = Enable, Z = Disable
192 input         OTG_INT0;     // ISP1362 Interrupt 0
193 input         OTG_INT1;     // ISP1362 Interrupt 1
194 input         OTG_DREQ0;    // ISP1362 DMA Request 0
195 input         OTG_DREQ1;    // ISP1362 DMA Request 1
196 output        OTG_DACK0_N;  // ISP1362 DMA Acknowledge 0
197 output        OTG_DACK1_N;  // ISP1362 DMA Acknowledge 1
198 ////////////////////////////// LCD Module 16X2 ////////////////////////////
199 inout  [7:0]  LCD_DATA;     // LCD Data bus 8 bits
200 output        LCD_ON;       // LCD Power ON/OFF
201 output        LCD_BLON;     // LCD Back Light ON/OFF
202 output        LCD_RW;       // LCD Read/Write Select, 0 = Write, 1 = Read
203 output        LCD_EN;       // LCD Enable
204 output        LCD_RS;       // LCD Command/Data Select, 0 = Command, 1 = Data
205 ////////////////////////////// SD Card Interface ////////////////////////
206 inout         SD_DAT;       // SD Card Data
207 inout         SD_DAT3;      // SD Card Data 3
208 inout         SD_CMD;       // SD Card Command Signal
209 output        SD_CLK;       // SD Card Clock
210 ////////////////////////////// I2C ////////////////////////////////
211 inout         I2C_SDAT;     // I2C Data
212 output        I2C_SCLK;     // I2C Clock
213 ////////////////////////////// PS2 ////////////////////////////////
214 input         PS2_DAT;      // PS2 Data
215 input         PS2_CLK;      // PS2 Clock
216 ////////////////////////////// USB JTAG link ////////////////////////////
217 input         TDI;          // CPLD -> FPGA (data in)
218 input         TCK;          // CPLD -> FPGA (clk)
219 input         TCS;          // CPLD -> FPGA (CS)
220 output        TDO;          // FPGA -> CPLD (data out)
221 ////////////////////////////// VGA ////////////////////////////
222 output        VGA_CLK;      // VGA Clock
223 output        VGA_HS;       // VGA H_SYNC
224 output        VGA_VS;       // VGA V_SYNC
225 output        VGA_BLANK;    // VGA BLANK
226 output        VGA_SYNC;     // VGA SYNC
227 output [9:0]  VGA_R;        // VGA Red[9:0]
228 output [9:0]  VGA_G;        // VGA Green[9:0]
229 output [9:0]  VGA_B;        // VGA Blue[9:0]
230 ////////////////////////////// Ethernet Interface ////////////////////////////
231 inout  [15:0] ENET_DATA;    // DM9000A DATA bus 16Bits
232 output        ENET_CMD;     // DM9000A Command/Data Select, 0 = Command, 1 = Data
233 output        ENET_CS_N;    // DM9000A Chip Select
234 output        ENET_WR_N;    // DM9000A Write
235 output        ENET_RD_N;    // DM9000A Read
236 output        ENET_RST_N;   // DM9000A Reset
237 input         ENET_INT;     // DM9000A Interrupt
238 output        ENET_CLK;     // DM9000A Clock 25 MHz
239 ////////////////////////////// Audio CODEC ////////////////////////////
240 inout         AUD_ADCLRCK;  // Audio CODEC ADC LR Clock
241 input         AUD_ADCDAT;   // Audio CODEC ADC Data
242 inout         AUD_DACLRCK;  // Audio CODEC DAC LR Clock
243 output        AUD_DACDAT;   // Audio CODEC DAC Data
244 inout         AUD_BCLK;     // Audio CODEC Bit-Stream Clock
245 output        AUD_XCK;      // Audio CODEC Chip Clock
246 ////////////////////////////// TV Devoder ////////////////////////////
247 input  [7:0]  TD_DATA;      // TV Decoder Data bus 8 bits
248 input         TD_HS;        // TV Decoder H_SYNC
249 input         TD_VS;        // TV Decoder V_SYNC
250 output        TD_RESET;     // TV Decoder Reset
251 ////////////////////////////// GPIO ////////////////////////////////
252 inout  [35:0] GPIO_0;       // GPIO Connection 0
253 inout  [35:0] GPIO_1;       // GPIO Connection 1
254 
255 // Turn on all display
256 assign  LCD_ON      = 1'b1;
257 assign  LCD_BLON    = 1'b1;
258 
259 // All inout port turn to tri-state
260 assign  DRAM_DQ     = 16'hzzzz;
261 assign  FL_DQ       = 8'hzz;
262 assign  SRAM_DQ     = 16'hzzzz;
263 assign  OTG_DATA    = 16'hzzzz;
264 assign  LCD_DATA    = 8'hzz;
265 assign  SD_DAT      = 1'bz;
266 assign  ENET_DATA   = 16'hzzzz;
267 assign  AUD_ADCLRCK = 1'bz;
268 assign  AUD_DACLRCK = 1'bz;
269 assign  AUD_BCLK    = 1'bz;
270 assign  TD_RESET    = 1'b1;
271 
272 //////////////////////// For TFT LCD Module ///////////////////////
273 wire [7:0] LCM_DATA;  // LCM Data 8 Bits
274 wire       LCM_GRST;  // LCM Global Reset
275 wire       LCM_SHDB;  // LCM Sleep Mode
276 wire       LCM_DCLK;  // LCM Clcok
277 wire       LCM_HSYNC; // LCM HSYNC
278 wire       LCM_VSYNC; // LCM    VSYNC
279 wire       LCM_SCLK;  // LCM I2C Clock
280 wire       LCM_SDAT;  // LCM I2C Data
281 wire       LCM_SCEN;  // LCM I2C Enable
282 wire       CLK_18;
283 
284 assign GPIO_0[18] = LCM_DATA[6];
285 assign GPIO_0[19] = LCM_DATA[7];
286 assign GPIO_0[20] = LCM_DATA[4];
287 assign GPIO_0[21] = LCM_DATA[5];
288 assign GPIO_0[22] = LCM_DATA[2];
289 assign GPIO_0[23] = LCM_DATA[3];
290 assign GPIO_0[24] = LCM_DATA[0];
291 assign GPIO_0[25] = LCM_DATA[1];
292 assign GPIO_0[26] = LCM_VSYNC;
293 assign GPIO_0[28] = LCM_SCLK;
294 assign GPIO_0[29] = LCM_DCLK;
295 assign GPIO_0[30] = LCM_GRST;
296 assign GPIO_0[31] = LCM_SHDB;
297 assign GPIO_0[33] = LCM_SCEN;
298 assign GPIO_0[34] = LCM_SDAT;
299 assign GPIO_0[35] = LCM_HSYNC;
300 
301 //////////////////////// For CMOS Sensor 1 ///////////////////////
302 wire [9:0]  CCD_DATA;
303 wire        CCD_SDAT;
304 wire        CCD_SCLK;
305 wire        CCD_FLASH;
306 wire        CCD_FVAL;
307 wire        CCD_LVAL;
308 wire        CCD_PIXCLK;
309 reg         CCD_MCLK;  // CCD Master Clock
310 
311 wire [15:0] Read_DATA1;
312 wire [15:0] Read_DATA2;
313 wire [9:0]  mCCD_DATA;
314 wire        mCCD_DVAL;
315 wire        mCCD_DVAL_d;
316 wire [10:0] X_Cont;
317 wire [10:0] Y_Cont;
318 wire [9:0]  X_ADDR;
319 wire [31:0] Frame_Cont;
320 wire [9:0]  mCCD_R;
321 wire [9:0]  mCCD_G;
322 wire [9:0]  mCCD_B;
323 wire        DLY_RST_0;
324 wire        DLY_RST_1;
325 wire        DLY_RST_2;
326 wire        Read;
327 reg  [9:0]  rCCD_DATA;
328 reg         rCCD_LVAL;
329 reg         rCCD_FVAL;
330 wire [9:0]  sCCD_R;
331 wire [9:0]  sCCD_G;
332 wire [9:0]  sCCD_B;
333 wire        sCCD_DVAL;
334 
335 // add by oomusou
336 wire [2:0]  CCD_KEY;
337 wire [15:0] CCD_SW;
338 
339 
340 assign CCD_DATA[0] = GPIO_1[0];
341 assign CCD_DATA[1] = GPIO_1[1];
342 assign CCD_DATA[2] = GPIO_1[5];
343 assign CCD_DATA[3] = GPIO_1[3];
344 assign CCD_DATA[4] = GPIO_1[2];
345 assign CCD_DATA[5] = GPIO_1[4];
346 assign CCD_DATA[6] = GPIO_1[6];
347 assign CCD_DATA[7] = GPIO_1[7];
348 assign CCD_DATA[8] = GPIO_1[8];
349 assign CCD_DATA[9] = GPIO_1[9];
350 assign GPIO_1[11= CCD_MCLK;
351 assign GPIO_1[15= CCD_SDAT;
352 assign GPIO_1[14= CCD_SCLK;
353 assign CCD_FVAL    = GPIO_1[13];
354 assign CCD_LVAL    = GPIO_1[12];
355 assign CCD_PIXCLK  = GPIO_1[10];
356 
357 // edit by oomusou
358 assign LEDR        = CCD_SW;
359 assign LEDG        = Y_Cont;
360 
361 always@(posedge CLOCK_50)
362   CCD_MCLK <= CCD_MCLK;
363 
364 always@(posedge CCD_PIXCLK)
365 begin
366   rCCD_DATA <= CCD_DATA;
367   rCCD_LVAL <= CCD_LVAL;
368   rCCD_FVAL <= CCD_FVAL;
369 end
370 
371 LCM_PLL u0 (
372   .inclk0(CLOCK_27),
373   .c0(CLK_18)
374 );
375 
376 LCM_Controller u1 (
377   // Host Side
378   .iRed(Read_DATA2[9:2]),
379   .iGreen({Read_DATA1[14:10],Read_DATA2[14:12]}),
380   .iBlue(Read_DATA1[9:2]),
381   // LCM Side
382   .LCM_DATA(LCM_DATA),
383   .LCM_VSYNC(LCM_VSYNC),
384   .LCM_HSYNC(LCM_HSYNC),
385   .LCM_DCLK(LCM_DCLK),
386   .LCM_SHDB(LCM_SHDB),
387   .LCM_GRST(LCM_GRST),
388   // Control Signals
389   .oDATA_REQ(Read),
390   .iCLK(CLK_18),
391   .iRST_N(DLY_RST_2)
392 );
393 
394 Reset_Delay u2 (
395   .iCLK(CLOCK_50),
396   .iRST(KEY[0]),
397   .oRST_0(DLY_RST_0),
398   .oRST_1(DLY_RST_1),
399   .oRST_2(DLY_RST_2)
400 );
401 
402 CCD_Capture u3 (
403   .oDATA(mCCD_DATA),
404   .oDVAL(mCCD_DVAL),
405   .oX_Cont(X_Cont),
406   .oY_Cont(Y_Cont),
407   .oFrame_Cont(Frame_Cont),
408   .iDATA(rCCD_DATA),
409   .iFVAL(rCCD_FVAL),
410   .iLVAL(rCCD_LVAL),
411   .iSTART(!CCD_KEY[2]), // edit by oomusou
412   .iEND(!CCD_KEY[1]),   // edit by oomusou
413   .iCLK(CCD_PIXCLK),
414   .iRST(DLY_RST_1)
415 );
416 
417 RAW2RGB u4 (
418   .oRed(mCCD_R),
419   .oGreen(mCCD_G),
420   .oBlue(mCCD_B),
421   .oDVAL(mCCD_DVAL_d),
422   .iX_Cont(X_Cont),
423   .iY_Cont(Y_Cont),
424   .iDATA(mCCD_DATA),
425   .iDVAL(mCCD_DVAL),
426   .iCLK(CCD_PIXCLK),
427   .iRST(DLY_RST_1)
428 );
429 
430 SEG7_LUT_8 u5 (
431   .oSEG0(HEX0),
432   .oSEG1(HEX1),
433   .oSEG2(HEX2),
434   .oSEG3(HEX3),
435   .oSEG4(HEX4),
436   .oSEG5(HEX5),
437   .oSEG6(HEX6),
438   .oSEG7(HEX7),
439   .iDIG(Frame_Cont)
440 );
441 
442 Sdram_Control_4Port u6 (
443   // HOST Side
444   .REF_CLK(CLOCK_50),
445   .RESET_N(1'b1),
446   // FIFO Write Side 1
447   .WR1_DATA({sCCD_G[9:5], sCCD_B[9:0]}),
448   .WR1(sCCD_DVAL),
449   .WR1_ADDR(0),
450   .WR1_MAX_ADDR(320*256),
451   .WR1_LENGTH(9'h100),
452   .WR1_LOAD(!DLY_RST_0),
453   .WR1_CLK(CCD_PIXCLK),
454   // FIFO Write Side 2
455   .WR2_DATA( {sCCD_G[4:0], sCCD_R[9:0]}),
456   .WR2(sCCD_DVAL),
457   .WR2_ADDR(22'h100000),
458   .WR2_MAX_ADDR(22'h100000+320*256),
459   .WR2_LENGTH(9'h100),
460   .WR2_LOAD(!DLY_RST_0),
461   .WR2_CLK(CCD_PIXCLK),
462   // FIFO Read Side 1
463   .RD1_DATA(Read_DATA1),
464   .RD1(Read),
465   .RD1_ADDR(320*8),
466   .RD1_MAX_ADDR(320*248),
467   .RD1_LENGTH(9'h100),
468   .RD1_LOAD(!DLY_RST_0),
469   .RD1_CLK(CLK_18),
470   // FIFO Read Side 2
471   .RD2_DATA(Read_DATA2),
472   .RD2(Read),
473   .RD2_ADDR(22'h100000+320*8),
474   .RD2_MAX_ADDR(22'h100000+320*248),
475   .RD2_LENGTH(9'h100),
476   .RD2_LOAD(!DLY_RST_0),
477   .RD2_CLK(CLK_18),
478   // SDRAM Side
479   .SA(DRAM_ADDR),
480   .BA({DRAM_BA_1,DRAM_BA_0}),
481   .CS_N(DRAM_CS_N),
482   .CKE(DRAM_CKE),
483   .RAS_N(DRAM_RAS_N),
484   .CAS_N(DRAM_CAS_N),
485   .WE_N(DRAM_WE_N),
486   .DQ(DRAM_DQ),
487   .DQM({DRAM_UDQM,DRAM_LDQM}),
488   .SDR_CLK(DRAM_CLK)
489 );
490 
491 I2C_CCD_Config u7 (
492   // Host Side
493   .iCLK(CLOCK_50),
494   .iRST_N(CCD_KEY[0]),      // edit by oomusou
495   .iExposure(CCD_SW[15:0]), // edit by oomusou
496   // I2C Side
497   .I2C_SCLK(CCD_SCLK),
498   .I2C_SDAT(CCD_SDAT)
499 );
500 
501 I2S_LCM_Config u8 (
502   // Host Side
503   .iCLK(CLOCK_50),
504   .iRST_N(KEY[0]),
505   // I2C Side
506   .I2S_SCLK(LCM_SCLK),
507   .I2S_SDAT(LCM_SDAT),
508   .I2S_SCEN(LCM_SCEN)
509 );
510 
511 I2C_AV_Config u9 (
512   // Host Side
513   .iCLK(CLOCK_50),
514   .iRST_N(KEY[0]),
515   // I2C Side
516   .I2C_SCLK(I2C_SCLK),
517   .I2C_SDAT(I2C_SDAT)
518 );
519 
520 Mirror_Col u10 (
521   // Input Side
522   .iCCD_R(mCCD_R),
523   .iCCD_G(mCCD_G),
524   .iCCD_B(mCCD_B),
525   .iCCD_DVAL(mCCD_DVAL_d),
526   .iCCD_PIXCLK(CCD_PIXCLK),
527   .iRST_N(DLY_RST_1),
528   // Output Side
529   .oCCD_R(sCCD_R),
530   .oCCD_G(sCCD_G),
531   .oCCD_B(sCCD_B),
532   .oCCD_DVAL(sCCD_DVAL)
533 );
534 
535 nios_ii_system nios_ii (
536   .clk(CLOCK_50),
537   .reset_n(KEY[0]),
538   .in_port_to_the_key_pio(KEY[3:1]),
539   .in_port_to_the_sw_pio(SW),
540   .avs_s1_export_o_key_from_the_CCD_Controller_inst(CCD_KEY),
541   .avs_s1_export_o_sw_from_the_CCD_Controller_inst(CCD_SW)
542 );
543 
544 endmodule


535行

nios_ii_system nios_ii (
  .clk(CLOCK_50),
  .reset_n(KEY[
0]),
  .in_port_to_the_key_pio(KEY[
3:1]),
  .in_port_to_the_sw_pio(SW),
  .avs_s1_export_o_key_from_the_CCD_Controller_inst(CCD_KEY),
  .avs_s1_export_o_sw_from_the_CCD_Controller_inst(CCD_SW)
);


將我們剛剛所建立的nios_ii_system加入,或許你會疑問?我怎麼知道SOPC Builder為我們產生的nios_ii_system有哪些port?請參考nios_ii_system.v內nios_ii_system這個module。

clk和reset_n直接接上top module所定義的CLOCK_50和KEY[0]即可,這不是問題,由於我們就是要用軟體去攔截KEY和SW,所以in_port_to_the_key_pio與in_port_to_the_sw_pio要與硬體的KEY[3:1]與SW相接。

avs_s1_export_o_key_from_the_CCD_Controller_inst與avs_s1_export_o_sw_from_the_CCD_Controller_inst輸出我們經由avalon bus writedata解析後的KEY和SW,與自己加上CCD_KEY和CCD_SW這兩個wire相接,準備將這兩個wire和原來CCD和LCM的module相連。

335行

// add by oomusou
wire [2:0]  CCD_KEY;
wire [
15:0] CCD_SW;


宣告了新產生的wire

358行

assign LEDR        = CCD_SW;


由於LEDR會根據SW的on或off改變,原本接的是硬體SW,現在改接我們輸出的CCD_SW。

402行

CCD_Capture u3 (
  .oDATA(mCCD_DATA),
  .oDVAL(mCCD_DVAL),
  .oX_Cont(X_Cont),
  .oY_Cont(Y_Cont),
  .oFrame_Cont(Frame_Cont),
  .iDATA(rCCD_DATA),
  .iFVAL(rCCD_FVAL),
  .iLVAL(rCCD_LVAL),
  .iSTART(
!CCD_KEY[2]), // edit by oomusou
  .iEND(!CCD_KEY[1]),   // edit by oomusou
  .iCLK(CCD_PIXCLK),
  .iRST(DLY_RST_1)
);


iSTART和iEND原來也是直接硬體KEY和SW,現在改接自己的CCD_KEY和CCD_SW。

491行

I2C_CCD_Config u7 (
 
// Host Side
  .iCLK(CLOCK_50),
  .iRST_N(CCD_KEY[
0]),      // edit by oomusou
  .iExposure(CCD_SW[15:0]), // edit by oomusou
 
// I2C Side
  .I2C_SCLK(CCD_SCLK),
  .I2C_SDAT(CCD_SDAT)
);


.iRST與iExposure原來接的是硬體的KEY與SW,現在改接自己的CCD_KEY和CCD_SW。

使用Quartus II編譯Verilog
截至目前為止,SOPC和硬體部分已經完全,開始使用Quartus II編譯Verilog。Quartus II編譯需要一段時間,以我目前的配備Intel Core 2 Duo T7500,編譯還需要1分26秒。

de2_lcm_ccd_35

Fig.34 編譯Verilog

使用Programmer將DE2_LCM_CCD.sof燒進FPGA
編譯完產生DE2_LCM_CCD.sof,使用Programmer燒進F PGA後,完成硬體佈署。

 de2_lcm_ccd_36

Fig.35 啟動Programmer

按Start將DE2_LCM_CCD.sof燒進FPGA。

de2_lcm_ccd_37

Fig.36 按Start開始燒錄

開發Nios II軟體
硬體部分完成了,現在我們要開發Nios II軟體。

Step 1:
啟動Nios II EDS

de2_lcm_ccd_38

Fig.37 Nios II EDS

Step 2:
建立Nios II C/C++ Application

按滑鼠右鍵,New->Nios II C/C++ Application

de2_lcm_ccd_39

Fig.38 New Nios II C/C++ Application

選擇右側Hello World template,將SOPC Builder System PTF File指向DE2_LCM_CCD_onchip\nios_ii_system.ptf,這是由SOPC Builder所產生的檔案,描述著我們剛剛建立的Nios II System,最後直接按Finish。

de2_lcm_ccd_40

Fig. 40 New Project

Step 3:
修改hello_world.c

hello_world.c

1#include "system.h"
2#include <io.h>
3
4int main() {
5 
6  while(1) {
7    // read switch
8    unsigned char key = IORD(KEY_PIO_BASE, 0);
9    unsigned int  sw  = IORD(SW_PIO_BASE, 0);
10   
11    // write CCD
12    IOWR(CCD_CONTROLLER_INST_BASE, 1, sw);
13    IOWR(CCD_CONTROLLER_INST_BASE, 0, key);
14  }

15}


第8行

unsigned char key = IORD(KEY_PIO_BASE, 0);
unsigned
int  sw  = IORD(SW_PIO_BASE, 0);


使用IORD去讀取目前KEY和SW的狀態,IORD()和IOWR()定義在io.h當中,由Nios II所提供。

KEY_PIO_BASE和SW_PIO_BASE定義在system.h,你可以在\DE2_LCM_CCD_onchip\software\hello_world_0_syslib\Debug\system_description\system.h找到,當建立project時,Nios II EDS會根據nios_ii_system.ptf的內容自動產生system.h,主要記載著SOPC中各controller的base address,透過base address,我們就可以在軟體存取硬體了。

第二個參數0是address,填0即可。

11行

IOWR(CCD_CONTROLLER_INST_BASE, 1, sw);
IOWR(CCD_CONTROLLER_INST_BASE,
0, key);


將在軟體讀到的KEY和SW送進自己寫的CCD_Controller,CCD_CONTROLLER_INST_BASE定義在system.h中。為什麼傳sw時,第二個參數是1呢?而key是0呢?在CCD_Controller.v中,我們曾經這樣定義:

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
else if (avs_s1_address == 1'b1 && avs_s1_chipselect && avs_s1_write)
begin
  r_key
<= r_key;
  r_sw 
<= avs_s1_writedata;
end


address 0表示傳入KEY,address 1表示傳入SW,所以我們在軟體端必須遵照這個規則。

這樣整個軟硬體就大功告成了!!

完整程式碼下載
DE2_LCM_CCD_onchip.7z

Conclusion
這篇文章是我寫過最長的blog,用到的圖片達40張也破紀錄了,其實關鍵的觀念只有一個:『如何將自己寫的Verilog包成component加進Nios II?』,Altera在Quartus II 7.2 Handbook Volumn 4: SOPC Builder Ch.9 Developing Components for SOPC Builder提供了一個完整的範例:Checksm Master,可以參考拙作(原創) 如何在DE2執行Checksum Master範例? (中級) (IC Design) (DE2) (Quartus II) (Nios II) (SOPC Builder),本文也可當成一篇練習寫component的tutorial。

還缺什麼呢?

1.本篇作法雖然已經讓軟硬體整合,讓軟體控制Nios II硬體,不過嚴格來說還不算Driver,一般來說,還會提供HAL(Hardware Abstraction Layer),以API的方式讓軟體呼叫。

2.使用on-chip memory並不實際,實務上幾乎不會用on-chip memory,會用SRAM或SDRAM。

3.還沒有上OS。

下一篇(原創) 如何在DE2將CCD影像顯示在彩色LCD? (Nios II軟體篇 + μC/OS-II + SRAM + 驅動程式) (IC Design) (DE2) (Nios II) (μC/OS-II) (SOPC Builder),我將以這個專案為基礎下,繼續加上API和OS,並跑在SRAM,讓它更完整。

See Also
(原創) 如何在DE2執行Checksum Master範例? (中級) (IC Design) (DE2) (Quartus II) (Nios II) (SOPC Builder)
(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (純硬體篇) (IC Design) (DE2)
(原創) 如何在DE2將CCD影像顯示在彩色LCD? (Nios II軟體篇 + μC/OS-II + SRAM + 驅動程式) (IC Design) (DE2) (Nios II) (μC/OS-II) (SOPC Builder)
(原創) 如何加速Altera的EDA工具? (IC Design) (Quartus II) (Nios II) (SOPC Builder)
(原創) 深入探討Altera的Checksum Master範例 (SOC) (SOPC Builder) (Nios II) (DE2)

Reference
[1] Quartus II 7.2 Handbook Volumn 4 : SOPC Builder P.4-4
[2] Quartus II 7.2 Handbook Volumn 4 : SOPC Builder P.5-4

posted on 2008-01-29 00:42  真 OO无双  阅读(13674)  评论(69编辑  收藏  举报

导航