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

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 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將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第1张图片

Fig.1 SOPC Builder圖示

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

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第2张图片 

Fig.2 設定System名稱

Step 3:
啟動Component Editor

 (原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第3张图片

Fig.3 SOPC Builder

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

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第4张图片

Fig.4 Component Editor

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第5张图片 

Fig.5 加入CCD_Controller.v

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

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第6张图片

Fig.6 CCD_Controller.v編譯成功

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

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第7张图片 

Fig.7 Component Editor : Signals

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

 (原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第8张图片

Fig.8 Component Editor:Interfaces

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

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第9张图片

Fig.9 Component Editor:Interfaces 2

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

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第10张图片 

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將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第11张图片

Fig.11 確定產生CCD_Controller_hw.tcl

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第12张图片

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將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第13张图片

Fig.13 加入Nios II Processor

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

 (原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第14张图片

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將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第15张图片

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將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第16张图片

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將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第17张图片

Fig.17 加入JTAG UART

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第18张图片

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將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第19张图片

Fig.19 加入System ID Peripheral

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第20张图片

Fig.20 System ID Peripheral window

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

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

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第21张图片

Fig.21 加入CCD_Controller

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第22张图片

Fig.22 CCD_Controller window

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

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

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第23张图片

Fig.23 加入PIO

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

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第24张图片

Fig.24 PIO window

更名為key_pio

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第25张图片

Fig.25 更名為key_pio

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

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

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第26张图片

Fig.25 加入PIO

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

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第27张图片

Fig.26 PIO window

更名為sw_pio

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第28张图片

Fig.27 更名為sw_pio

Step 8:
設定reset和exception vector

在右側CPU用滑鼠點兩下。

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第29张图片

Fig.28 設定reset與exception

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

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第30张图片

Fig.29 將reset和exception設在onchip_mem

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

選擇System->Auto-Assign Base Address

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第31张图片

Fig.30 Auto-Assign Base Address

Step 10:
產生Nios II System

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

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第32张图片

Fig.31 Generate System

按Save對Nios II System存檔。

 (原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第33张图片

Fig.32 Save system

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

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第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將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第35张图片

Fig.34 編譯Verilog

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

 (原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第36张图片

Fig.35 啟動Programmer

按Start將DE2_LCM_CCD.sof燒進FPGA。

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第37张图片

Fig.36 按Start開始燒錄

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

Step 1:
啟動Nios II EDS

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第38张图片

Fig.37 Nios II EDS

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

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

(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第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將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ..._第40张图片

Fig. 40 New Project

Step 3:
修改hello_world.c

hello_world.c

1 #include " system.h "
2 #include < io.h >
3
4 ExpandedBlockStart.gifContractedBlock.gif int main() {
5 
6ExpandedSubBlockStart.gifContractedSubBlock.gif  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

你可能感兴趣的:((原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder) ...)