(原創) 如何從Nios II讀出CMOS放在SDRAM中的影像? (SOC) (SOPC Builder) (Nios II) (DE2-70) (TRDB-D5M) (TRDB-LTM)
Abstract
本文提供一個CMOS Controller,讓Nios II可以藉由CMOS Controller控制CMOS,並能讀出CMOS放在SDRAM中的影像。
Introduction
使用環境:Quartus II 8.0 SP1 + Nios II EDS 8.0 SP1 + DE2-70 (Cyclone II EP2C70F896C6N) + TRDB-D5M + TRDB-LTM
(很多人問我為什麼這篇不寫完,並不是這篇做法不對,主要有兩個原因:1.這篇要寫完很長,有點懶,2.後來弄出了master架構的CMOS與LTM,比這個slave架構更好,因為正在測試中,等最後穩定了再發表,想到時候再一併補齊本文作比較,不過我已經先放了source code,有興趣的朋友可自行參考研究。)
利用DE2做電腦視覺應用的,大概分3種族群:第1種是做純硬的,把DE2當FPGA用,如(原創) 如何實現Real Time的Sobel Edge Detector? (SOC) (Verilog) (Image Processing) (DE2-70) (TRDB-D5M),完全拼Verilog與RTL;第2種是做純軟的,把DE2當成嵌入式Nios II平台,拼的是C語言與OS;第3種是軟硬體設計,Verilog與C通通來,軟體硬體都要弄。
DE2的DE2_CCD與DE2-70的DE2_70_D5M_LTM,都是純硬的範例,若要拿來做Nios II嵌入式與軟硬體設計,大家最常問的問題是:
『我該怎麼在Nios II去控制CMOS?』
『我該怎麼在Nios II讀出CMOS放在SDRAM中的影像?』
要讓Nios II去控制硬體,必須要透過controller,Altera與友晶科技都已經提供不少現成的controller,以前在Quartus II 6.1更有鼎鼎有名的Altera University IP Core可用,但無論是130萬像素的TRDB-DC2或者500萬像素的TRDB-D5M,目前都沒看到給Nios II用的CMOS controller,我在2008年初的3篇
(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (純硬體篇) (IC Design) (DE2)
(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder)
(原創) 如何在DE2將CCD影像顯示在彩色LCD? (Nios II軟體篇 + μC/OS-II + SRAM + 驅動程式) (IC Design) (DE2) (Nios II) (μC/OS-II) (SOPC Builder)
曾經試圖為130萬像素的TRDB-DC2寫一個給Nios II用的controller,不過當時功力有限,只能寫出控制CMOS的free run、capture、與exposure三個功能,讀出CMOS放在SDRAM中的影像從這部分一直弄不出來,期間試過很多方法,好幾次接近成功,雖然能從SDRAM讀出資料,不過讀出的資料卻始終是錯的。
以下這張圖片,並不是如(原創) 如何將CMOS所擷取的影像傳到PC端? (IC Design) (DE2)所言,利用友晶科技提供的Control Panel與Image Converter產生,而是在Nios II利用C語言,從SDRAM讀出每個pixel的RGB,自己fwrite()出800 * 400的bmp檔。
這代表什麼意義呢?
這表示在Nios II能正確地讀出CMOS放在SDRAM中的影像,進而利用C語言做更複雜的演算法處理!!。
系統架構圖
紫色部分是大家熟悉的DE2_CCD架構(DE2 + 130萬像素CMOS + 640 * 480 VGA),其他如DE2_LCM_CCD (DE2 + 130萬像素CMOS + 320 * 240 3.6" LCM)與DE2_70_D5M_LTM (DE2-70 + 500萬像素CMOS + 800 * 480 4.3" LTM) 基本上用的仍是這個架構。
I2C Sensor Configuration(I2C_CCD_Config.v)
負責設定CMOS的register。
CMOS Sensor Data Capture(CCD_Capture.v)
負責接收CMOS所傳來的Bayer Pattern格式資料。
Bayer Color Pattern Data to 30-Bit RGB (RAW2RGB.v)
負責將Bayer Pattern格式轉成RGB格式。
Multi-Port SDRAM Controller(Sdram_Control_4Port.v)
負責讀寫SDRAM。SDRAM為CMOS與VGA(LCM/LTM)之間的frame buffer,它一共有4個port:2 read port與2 write port,每個port為16 bit。
LTM Controller and Data Request(VGA_Controller.v/LCM_Controller.v/touch_tcon.v)
負責將SDRAM的RGB資料送進VGA(LCM/LTM)顯示。
這些Verilog的RTL code相當精采,我將會另開篇幅詳細討論每個module中的code。
加入Nios II所面臨的困難
1.無法在Nios II使用CMOS
無論是DE2_CCD、DE2_LCM_CCD或DE2_70_D5M_LTM範例,這些都是純硬的RTL code,若要讓純軟的C介入使用CMOS,就必須使用SOPC Builder加上Nios II CPU以及相關周邊的controller,在(原創) 哪裡有DE2-70的Nios II reference design可以參考? (SOC) (DE2-70) (Nios II) (SOPC Builder),我們在DE2-70已經可以用Nios II驅動絕大部分周邊,但因為缺少CMOS controller,所以目前我們還無法在Nios II使用CMOS。
2.無法在Nios II存取SDRAM
大家都知道CMOS所capture的影像放在SDRAM,理論上只要能在Nios II讀出CMOS放在SDRAM中的影像,就能用C做更複雜的演算法處理,但因為在DE2_CCD架構中,SDRAM已經被當成frame buffer,用的是Sdram_Control_4Port.v這個4 port的SDRAM controller,而Nios II用的是SOPC Builder上的SDRAM controller,因為兩者無法並存(請問top module的SDRAM port該接Sdram_Control_4Port?還是接Nios II?),所以目前我們還無法在Nios II存取SDRAM。
本文所提供的解決方案
如系統架構圖所示,本文的重點就是黃色部分:提供一個CMOS Controller,讓Nios II可以藉由CMOS Controller控制CMOS,並能讀出CMOS放在SDRAM中的影像,最後將這些影像資訊放在SSRAM中,讓C語言能做更複雜的演算法處理。
CMOS Controller
CMOS_Controller.v / Verilog
2 (C) OOMusou 2008 http://oomusou.cnblogs.com
3
4 Filename : CMOS_Controller.v
5 Compiler : Quartus II 7.2 SP3
6 Description : Demo how to write CMOS Controller
7 Release : 08/31/2008 1.0
8 */
9
10 module CMOS_Controller (
11 // Avalon clock interface siganals
12 input csi_clockreset_clk,
13 input csi_clockreset_reset_n,
14 // Signals for Avalon-MM slave port
15 input [1:0] avs_s1_address,
16 input avs_s1_chipselect,
17 input avs_s1_read,
18 output reg [31:0] avs_s1_readdata,
19 input avs_s1_write,
20 input [31:0] avs_s1_writedata,
21 // Signals export to top module
22 output avs_s1_export_clk,
23 output reg avs_s1_export_capture_start,
24 output reg avs_s1_export_capture_stop,
25 output reg avs_s1_export_capture_read,
26 input [31:0] avs_s1_export_capture_readdata
27 );
28
29 // Slave address constant
30 parameter CAPTURE_START = 2'h0;
31 parameter CAPTURE_STOP = 2'h1;
32 parameter CAPTURE_DATA = 2'h2;
33
34 assign avs_s1_export_clk = ~csi_clockreset_clk;
35
36 // write to export
37 always@(posedge csi_clockreset_clk, negedge csi_clockreset_reset_n) begin
38 if (!csi_clockreset_reset_n) begin
39 avs_s1_export_capture_start <= 1'b0;
40 avs_s1_export_capture_stop <= 1'b0;
41 end
42 else begin
43 if (avs_s1_chipselect && avs_s1_write) begin
44 case (avs_s1_address)
45 CAPTURE_START:
46 avs_s1_export_capture_start <= avs_s1_writedata[0];
47
48 CAPTURE_STOP:
49 avs_s1_export_capture_stop <= avs_s1_writedata[0];
50
51 default: begin
52 avs_s1_export_capture_start <= avs_s1_export_capture_start;
53 avs_s1_export_capture_stop <= avs_s1_export_capture_stop;
54 end
55 endcase
56 end
57 end
58 end
59
60 // read from export
61 always@(posedge csi_clockreset_clk, negedge csi_clockreset_reset_n) begin
62 if (!csi_clockreset_reset_n) begin
63 avs_s1_export_capture_read <= 1'b0;
64 avs_s1_readdata <= 32'hzzzzzzzz;
65 end
66 else begin
67 avs_s1_export_capture_read <= 1'b0;
68 avs_s1_readdata <= 32'hzzzzzzzz;
69
70 if (avs_s1_chipselect && avs_s1_read) begin
71 case (avs_s1_address)
72 CAPTURE_DATA: begin
73 avs_s1_export_capture_read <= 1'b1;
74 avs_s1_readdata <= avs_s1_export_capture_readdata;
75 end
76 default: begin
77 avs_s1_export_capture_read <= avs_s1_export_capture_read;
78 avs_s1_readdata <= avs_s1_readdata;
79 end
80 endcase
81 end
82 end
83 end
84
85 endmodule
11行
input csi_clockreset_clk,
input csi_clockreset_reset_n,
使用clock interface,定義controller所使用的clock與reset,由Avalon bus傳入。
14行
input [1:0] avs_s1_address,
input avs_s1_chipselect,
input avs_s1_read,
output reg [31:0] avs_s1_readdata,
input avs_s1_write,
input [31:0] avs_s1_writedata,
使用Avalon MM slave interface, 是CMOS controller與Avalon bus溝通所使用的port。
avs_s1_address
由Avalon bus傳入,是CMOS controller在SOPC Builder定址空間的offset,單位為word,用此address判斷readdata與writedata上的資料是什麼信號。
avs_s1_chipselect
由Avalon bus傳入,因為Avalon bus上會有很多master與slave,所以controller在writedata所收到信號,可能是要傳給其他slave的信號,而不是自己該處理的信號,因此Avalon bus會根據adress去decode,產生chipselect,所以slave就不需再對所有信號去decode,只需簡單判斷chipselect是否為1,就可確定是否屬於自己該處理的信號。
avs_s1_read
avs_s1_readdata
read由Avalon bus傳入,表示Avalon bus對slave有讀取資料的需求,然後slave會從SDRAM讀取資料,藉由readdata傳給Avalon bus。
avs_s1_write
avs_s1_writedata
write與writedata由Avalon bus傳入,表示Avalon bus對slave有寫入資料的需求,並藉由writedata將Nios II控制CMOS的capture start與capture stop的信號傳給slave。
21行
output avs_s1_export_clk,
output reg avs_s1_export_capture_start,
output reg avs_s1_export_capture_stop,
output reg avs_s1_export_capture_read,
input [31:0] avs_s1_export_capture_readdata
CMOS controller所扮演的腳色,本來就是Avalon bus與原本CCD_Capture、Sdram_Control_4Port之間的adapter,所以除了面對Avalon bus的port外,也要有能面對原本CCD_Capture與Sdram_Control_4Port的port,export就屬於這種port。
avs_s1_export_clk
傳出到top module,將此clock傳進Sdram_Control_4Port。
avs_s1_export_capture_start
傳出到top module,由Nios II傳入的capture start信號將由此port傳給CCD_Capture。
avs_s1_exort_capture_stop
傳出到top module,由Nios II傳入的capture stop信號將由此port傳給CCD_Capture。
avs_s1_export_capture_read
傳出到top module,由Avalon bus傳入的read信號將由此port傳給Sdram_Control_4Port的read enable。
avs_s1_export_capture_readdata
由top module傳入,SDRAM的資料藉由此port傳給slave,然後再由readdata傳回Nios II。
以上port的命名方式皆根據(筆記) Naming Convention for Avalon Signal Type (IC Design) (SOPC Builder)所建議的naming convention命名, 除了可讀性較高外,SOPC Builder也可以自動抓到signal type,不需再另外設定。
29行
parameter CAPTURE_START = 2'h0;
parameter CAPTURE_STOP = 2'h1;
parameter CAPTURE_DATA = 2'h2;
設定所有slave address會用到的位址常數,由於Avalon bus與slave交換資料皆靠readdata與writedata,以傳入slave的writedata為例,該如何判斷傳進來的是capture start?還是capture stop呢? 就是靠address判斷,若為2'h0,就是capture start,若為2'h1,則為capture stop。
在CMOS_Controller_HAL.h中,我們也可以看到完全相同的設定,供Nios II呼叫CMOS controller時使用。
#define CAPTURE_START 0x0
#define CAPTURE_STOP 0x1
#define CAPTURE_DATA 0x2
36行
always@(posedge csi_clockreset_clk, negedge csi_clockreset_reset_n) begin
if (!csi_clockreset_reset_n) begin
avs_s1_export_capture_start <= 1'b0;
avs_s1_export_capture_stop <= 1'b0;
end
else begin
if (avs_s1_chipselect && avs_s1_write) begin
case (avs_s1_address)
CAPTURE_START:
avs_s1_export_capture_start <= avs_s1_writedata[0];
CAPTURE_STOP:
avs_s1_export_capture_stop <= avs_s1_writedata[0];
default: begin
avs_s1_export_capture_start <= avs_s1_export_capture_start;
avs_s1_export_capture_stop <= avs_s1_export_capture_stop;
end
endcase
end
end
end
將從Avalon bus讀進的writedata資料,經過處理寫到export,最後傳給CCD_Capture。為什麼slave要做這些判斷呢?這要從slave write的timing diagram來理解。
以上是write wait為0時的timing diagram,這也是建立custom component時,SOPC Builder預設的write wait。
為什麼設定write wait為0,而不是1或2呢?
根據Altera Avalon Memory-Mapped Interface Specification p.35的解釋:
所謂的fundamental write,就是write wait為0,因為要寫進slave的對象是Nios II CPU,與slave就在同一個FPGA上,屬於on-chip peripherals,所以使用write wait為0即可。
更詳細的write wait與read wait討論,請參考(原創) 如何設定Avalon Slave Timing? (SOC) (SOPC Builder)。
always@(posedge csi_clockreset_clk, negedge csi_clockreset_reset_n) begin
if (!csi_clockreset_reset_n) begin
avs_s1_export_capture_read <= 1'b0;
avs_s1_readdata <= 32'h0000;
end
else begin
avs_s1_export_capture_read <= 1'b0;
avs_s1_readdata <= 32'hzzzzzzzz;
if (avs_s1_chipselect && avs_s1_read) begin
case (avs_s1_address)
CAPTURE_DATA: begin
avs_s1_export_capture_read <= 1'b1;
avs_s1_readdata <= avs_s1_export_capture_readdata;
end
default: begin
avs_s1_export_capture_read <= 1'b0;
avs_s1_readdata <= 32'hzzzzzzzz;
end
endcase
end
end
end
(未完...)
在DE2-70實現
證明此方案的正確性
實務上的應用
在DE2實現
其他方法
完整程式碼下載
DE2_70_D5M_LTM_NIOS_capture.7z
Conclusion
See Also
(原創) 如何實現Real Time的Sobel Edge Detector? (SOC) (Verilog) (Image Processing) (DE2-70) (TRDB-D5M)
(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (純硬體篇) (IC Design) (DE2)
(原創) 如何在DE2將CCD影像顯示在彩色LCD上? (Nios II軟體篇 + onchip memory) (IC Design) (DE2) (Nios II) (SOPC Builder)
(原創) 如何在DE2將CCD影像顯示在彩色LCD? (Nios II軟體篇 + μC/OS-II + SRAM + 驅動程式) (IC Design) (DE2) (Nios II) (μC/OS-II) (SOPC Builder)
(原創) 如何將CMOS所擷取的影像傳到PC端? (IC Design) (DE2)
(原創) 哪裡有DE2-70的Nios II reference design可以參考? (SOC) (DE2-70) (Nios II) (SOPC Builder)
(筆記) Naming Convention for Avalon Signal Type (IC Design) (SOPC Builder)
(筆記) Quartus II 7.x版的Avalon Memory-Mapped Interface Specification分享 (SOC) (SOPC Builder)
(原創) 如何設定Avalon Slave Timing? (SOC) (SOPC Builder)
(原創) 如何在Nios II EDS 8.0使用Host File System與Zip File System? (SOC) (Nios II)
Reference
Altera Avalon Memory-Mapped Interface Specification