(原創) 如何從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_capture00

這代表什麼意義呢?
這表示在Nios II能正確地讀出CMOS放在SDRAM中的影像,進而利用C語言做更複雜的演算法處理!!

系統架構圖

nios_capture01

紫色部分是大家熟悉的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_CCDDE2_LCM_CCDDE2_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

1  /*  
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行

// Avalon clock interface siganals
input                csi_clockreset_clk,
input                csi_clockreset_reset_n,


使用clock interface,定義controller所使用的clock與reset,由Avalon bus傳入。

14行

// Signals for Avalon-MM slave port
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行

// Signals export to top module
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行

// Slave address constant
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時使用。

// slave address
#define CAPTURE_START      0x0
#define CAPTURE_STOP       0x1
#define CAPTURE_DATA       0x2


36行

// write to export
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來理解。

nios_capture02

以上是write wait為0時的timing diagram,這也是建立custom component時,SOPC Builder預設的write wait。

為什麼設定write wait為0,而不是1或2呢?
根據Altera Avalon Memory-Mapped Interface Specification p.35的解釋:

The fundamental write transfer is generally appropriate for synchronous , on-chip peripherals that can capture data in a single clock cycle. Peripherals that cannot capture data in one clock cycle must use wait-states.


所謂的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)

// read from export
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

 

 

assign avs_s1_export_clk =   ~ csi_clockreset_clk;

 

 

(未完...)

在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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值