Tải bản đầy đủ (.pdf) (15 trang)

ĐỒ ÁN CƠ SỞ Nghiên cứu VGA và xây dựng ứng dụng trên kit UP2_3 ppsx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (702.25 KB, 15 trang )

ĐỒ ÁN CƠ SỞ
Nghiên cứu VGA và xây dựng ứng
dụng trên kit UP2

2. KHỐI I2C_VIDEO_CONFIG
2.1 SƠ ĐỒ KHỐI

Hình 6.1: Sơ đồ khối I2C_Video_Config
Tên

Mô tả
ICLK

Xung Clock 50MHz từ kit DE2
RESET

Tín hiệu Reset hệ thống
I2C_SCLK
Ngõ ra ch

a xung Clock cung c

p
cho ADV7181B

I2C_DATA

Port 2 chiều để cấu hình các giá trị thanh ghi của
ADV7181B




Hình 6.2: Dạng sóng để truyền dữ liệu và cấu trúc ghi với giao thức I2C
2.2 MÔ TẢ
Vai trò của khối chỉ là ghi giá trị vào các thanh ghi của ADV7181B nên có
thể chọn xung clock làm việc của khối là 20KHz nhờ vào bộ chia tần số 50MHz.
Địa chỉ Slaver của ADV7181B là 40h nên ta sử dụng cách gán mI2C_DATA là
kiểu dữ liệu cần truyền trên Bus và LUT_DATA chứa địa chỉ của thanh ghi và giá
trị cần nạp.
Khi reset, bắt đầu cấu hình lại cho ADV7181B bằng cách xóa giá trị các bộ
đếm và cờ. Sau đó để nạp giá trị cho các thanh ghi ta sử dụng máy trạng thái sau:
always@(posedge mI2C_CTRL_CLK or negedge iRST_N)
begin
if (!iRST_N) begin
LUT_INDEX<= 0;
mSetup_ST <= 0;
mI2C_GO <= 0; end
else
begin
if(LUT_INDEX<LUT_SIZE)
//LUT_SIZE là số lần nạp giá trị cho các thanh ghi cần thiết
//LUT_INDEX là biến đếm để ánh xạ đến địa chỉ của các thanh ghi và giá trị cần
nạp.
begin
case(mSetup_ST)
0: begin
//nhập chuỗi dữ liệu cần truyền để đặt giá trị cho các thanh ghi
mI2C_DATA <= {8’h40,LUT_DATA};
mI2C_GO <= 1;
mSetup_ST <= 1;
end

1: begin
If(mI2C_END)
//mI2C_END là cờ báo khi truyền hết chuỗi dữ liệu
begin
//có xác nhận ACK là đã nạp xong giá trị cho một thanh ghi từ
//ADV thì nhảy tới trạng thái 2
if(!mI2C_ACK)
mSetup_ST <= 2;
//không có xác nhận thì nhảy về trạng thái 0
else
mSetup_ST <= 0;
mI2C_GO <= 0;
end
end
2: begin
//tăng LUT_INDEX lên 1 để nhảy đến thay ghi mới rồi quay về trạng thái
0
LUT_INDEX <= LUT_INDEX + 1;
mSetup_ST <= 0;
end
endcase
end
end
end
Ta chỉ cần đặt giá trị cho một thanh ghi cần thiết nên không thực hiện việc
tăng dần địa chỉ thanh ghi mà sẽ ánh xạ từ LUX_INDEX đến LUX_DATA nhờ
vào lệnh case, chẳng hạn như khi LUX_INDEX=27 để nạp giá trị 8’50 vào thanh
ghi địa chỉ 8’h00 ta có cấu trúc:
case(LUX_INDEX):
27: LUT_DATA <= 16’h0050;

Để AVD7181B có thể phát hiện chuẩn video NTSC thì ta sẽ nạp các giá trị
cho các thanh ghi theo bảng giá trị cài đặt ở phần mô tả ADV7181B. Tuy nhiên khi
truyền chuỗi này trên bus ta cần phải thêm các bit đồng bộ: 1 bit cho trạng thái
IDE, 2 bit để thiết lặp cờ START, 3 bit để chờ ACK cho ADV xác nhận, 3 bit để
thiết lặp cờ STOP và báo kết thúc chuỗi, vì vậy thực sự chuỗi dài 33 bit:
case(SD_COUNTER)
6’d0 : begin ACK1=0; ACK2=0; ACK3=0;
END=0;SDO=1;SCLK=1;end
//thiết lặp cờ START
6’d1 : begin SD=I2C_DATA;SDO=0;end
6’d2 : SCLK=0;
//địa chỉ SLAVER của ADV7181B
6’d3 : SDO=SD[23];
6’d4 : SDO=SD[22];
6’d5 : SDO=SD[21];
6’d6 : SDO=SD[20];
6’d7 : SDO=SD[19];
6’d8 : SDO=SD[18];
6’d9 : SDO=SD[17];
6’d10 : SDO=SD[16];
//thả nổi đường truyền nhập để ACK từ ADV7181B qua port 2 chiều
I2C_DATA
6’d20 : SDO=1’bz;
//giá trị cần ghi vào thanh ghi
6’d21 : begin SDO=SD[7]; ACK2=I2C_SDAT;end
6’d22 : SDO=SD[6];
6’d23 : SDO=SD[5];
6’d24 : SDO=SD[4];
6’d25 : SDO=SD[3];
6’d26 : SDO=SD[2];

6’d27 : SDO=SD[1];
6’d28 : SDO=SD[0];
//thả nổi đường truyền nhập ACK từ ADV7181B qua port 2 chiều
I2C_DATA
6’d29 : SDO=1’bz;
//thiết lặp cờ STOP và báo kết thúc chuỗi
6’d30 : begin SDO=1’b0; SCLK=1’b0; ACK3=I2C_SDAT;end
6’d31 : SCLK=1’b1;
6’d32 : begin SDO=1’b1;END=1;end
endcase
Trong đó SD_COUTER thực hiện đếm từ 0 đến 63, như vậy việc nạp cho
một thanh ghi chỉ thực hiện trong 33 chu kỳ đầu còn 30 chu kỳ sau thì bus ở trạng
thái IDE (SCLK=1 va SDO=1) để chờ chu kỳ tiếp theo. Đồng thời để đảm bảo
được yêu cầu về dạng sóng trên chân I2C_SCLK và xác nhận (ACK) đã nạp xong
thanh ghi, ta thực hiện:
wire I2C_SCLK = SCLK | (((SD_COUTER>=4) &
(SD_COUTER<=30))? ~CLOCK : 0 );
wire ACK=ACK1 | ACK2 | ACK3;
// khi xét xác nhận đã nạp xong thanh ghi ta sử dụng giá trị bù của
//ACK (tích cực mức thấp), chỉ xác nhận khi có đủ 3 xác nhận ACK1, //ACK2,
ACK3
Và dạng sóng thu được trên chân I2C_SCLK như sau (END từ 0 lên 1 chỉ ra
rằng đã nạp xong giá trị cho một thanh ghi):

Hình 6.4: dạng sóng mô phỏng trên chân I2C_SCLK
3. KHỐI TIMER TRÌ HOÃN BAN ĐẦU
3.1 SƠ ĐỒ KHỐI


Hình 7.1: Sơ đồ của khối timer trì hoãn ban đầu

Tên
Mô tả
ICLK
Xung clock 50Mhz t


kit DE2

VS
Tín hi

u VS (Vertical Sync) t


ADV7181B

HS
Tín hi

u HS (Horizontal Sync) t


ADV7181B
TD_Stable
Báo hi

u ADV7181b đ
ã ho

t đ


ng

n đ

nh

RST0, RST1, RST3
Ngõ ra cho phép các kh

i khác b

t đ

u
làm
việc

3.2 MÔ TẢ
Với cấu hình đã cài đặt ở phần trước, khi đã hoạt động ổn định, dạng sóng
do ADV7181B phát ra như sau:


Hình 7.2: Mô tả dạng sóng ADV7181B
Vì vậy để phát hiện xem chip mã hóa này đã hoạt động ổn định hay chưa
khối TD_DETEC tiến hành kiểm tra điều kiện: VS ở mức cao trong 9 chu kỳ liên
tiếp của HS rồi chuyển xuống mức thấp, nếu thỏa mãn thì đưa TD_Stable lên mức
cao. Khi tín hiệu TD_Stable lên mức cao, khối RESET_DELAY bắt đầu đếm lên
theo xung nhịp của ICLK (50MHz) để tính thời điểm xuất ra mức 1 trên các chân
RST0, RST1, RST2. Các tín hiệu này dùng để khởi động các khối khác theo trình

tự như sau:
a) Ban đầu xóa tất cả dữ liệu trong các khối.
b) Tính từ thời điểm TD_Stable lên 1 (đơn vị là chu kỳ clock 27MHz)
- Sau 1132461.5: tích cực RST0 để kích hoạt khối SDRAM BUFFER.
- Sau 1698692.5: tích cực RST1 để kích hoạt khối Desize Horizon.
- Sau 2264923.5: tích cực RST2 để kích hoạt khối xử lý ảnh YUV và
VGA controller.
c) Giữ nguyên giá trị ngõ ra cho đến khi có tín hiệu RESET hệ thống thì
lặp lại.
 Điểm cần chú ý ở đây là khi Desize Horizon hoạt động thì sẽ xuất
DATA_VALID cho phép ghi dữ liệu vào SDRAM BUFFER. Rồi phải chờ một
khoảng thời gian để ghi đủ số liệu cần thiết mới kích hoạt VGA Controller để xuất
dữ liệu từ SDRAM BUFFER. Như ta đã biết một frame ảnh do ADV7181B xuất ra
bao gồm 900900 byte (525 line, mỗi line có 1716 byte) hay để truyền hết một
frame sẽ mất 900900 chu kỳ. Do xung clock trên chân LLC để truyền các byte là
27MHz nên ta kiểm tra lại các thời điểm này như sau:
- Lấy gốc thời gian là khi bắt đầu frame đầu tiên.
- TD_Stable lên 1 khi Frame đầu tiên đã phát được 9 line: 9 x 1716 =
15444 chu kỳ.
- Frame thứ ba được bắt đầu tại thời điểm 2 x 900900 = 1801800
- Khối Desize Horizon được kích hoạt tại thời điểm 1714136.5
(= 15444 + 1698692.5) tức là trước khi frame thứ ba bắt đầu. Đảm bảo
rằng khối sẽ xuất ra DATA_VALID = 1 ở toàn bộ các Active Pixel của frame thứ
3.
- Khối VGA Controller được kích hoạt tại thời điểm 2280367.5(=15444
+ 2264923.5) nên oRequest được xuất ra tại thời điểm 2315727.5(= 2280376.5 +
35360). Với 35360 chu kỳ là khoảng thời gian từ khi khối được reset cho đến khi
oRequest lên 1. Vậy việc đọc từ SDRAM BUFFER được kích hoạt khi frame thứ 3
đã bắt đầu được một khoảng thời gian là 513927.5(= 2315727.5 – 1801800). Điều
này đảm bảo cho việc xuất ra đúng từng frame từ SDRAM BUFFER mà ta sẽ đề

cập kỹ hơn ở phần mô tả SDRAM BUFFER.
4. KHỐI DISIZE_HORIZON
4.1 SƠ ĐỒ KHỐI

Hình 8.1: Sơ đồ khối Disize_Horizon
Tên Mô tả
CLK_27 Xung clock 27MHz từ kit DE2
RST_N Reset hệ thống
TD_DATA[7:0] Dữ liệu hình ảnh từ ADV7181B
ACLR
Tín hiệu xóa bất đồng bộ do khối Timer trì hoãn
cung cấp
CLK
Xung clock 27MHz từ chân TD_CLK của
ADV7181B
Số chia = 9
Số chia cung cấp cho bộ chia do người thiết kế
nhập vào
TV_X[9:0]
Vị trí của Pixel trong hàng hiện hành đồng thời
cũng là số bị chia cung cấp cho bộ chia
Thương[9:0] Thương của phép chia TV_X cho 9
Số dư [9:0] Số dư của phép chia TV_X cho 9
DATA_VALID
Đồng bộ cho oYCbCr để đưa vào
SDRAM_Controller
oYCbCr[15:0] Chuỗi dữ liệu ảnh ngõ ra

DATA_VALID: ở mức 1 thì sẽ cho phép Pixel đi kèm được ghi vào
SDRAM thông qua SDRAM_Controller. Do frame mà ADV7181B xuất ra có

dạng 720 x 480 để đưa về chuẩn 640 x 480 mà hình ảnh không bị xén thì với mỗi 9
pixel liên tiếp ta sẽ loại bỏ Pixel đầu tiên: Không cho phép ghi vào SDRAM bằng
cách đưa DATA_VALID xuống mức 0 (lấy ra 8 Pixel trong 9 Pixel: 640 =


x 720
).
Đồng thời để đảm bảo được chuỗi đưa vào SDRAM_Controller vẫn có dạng
chuỗi C
b
Y
n
C
r
Y
n+1
liên tiếp thì phải hoán đổi giữa 2 thành phần Cb và Cr cứ sau 2
lần loại bỏ 1 Pixel.

Hình 8.2: Vị trí các Pixel trong chuỗi
Như ở hình trên X là vị trí các Pixel bị loại bỏ (bị bỏ qua khi hiển thị lên
màn hình), khi đó chuỗi Pixel tại S1 là Cb
4
Y
8
Cb
5
Y10 và tại E1 là Cr
8
Y

17
Cr
9
Y
19

vậy để đảm bảo chuỗi có dạng CbYCrY liên tiếp thì phải hoán đổi vị trí giữa Cb
và Cr trong khoảng Cb
5
Y
10
…Cr
8
Y
17.

4.2 MÔ TẢ
TD_DATA là chuỗi Pixel được phát ra theo chuẩn Video ITU656. Ta có thể
xem một frame thực sự bắt đầu với Odd Field khi bit F (bit 6 trong byte cuối của
trường SAV hay EAV) chuyển từ 1 về 0, vậy để xét điều kiện bắt đầu của một
frame ta phải đợi đến trường SAV hay EAV rồi mới kiểm tra giá trị của bit F:
Window <= {Window[15:0],iTD_DATA};
if (Window == 24’hFF0000)
//khi phát hiện trường SAV (EAV) thì gán giá trị bit V cho FVAL và bit F cho
//Field
begin
FVAL <= !iTD_DATA[5];
Field <= iTD_DATA[6];
end
//kiểm tra điều kiện bit F chuyển từ 1 về 0 để bắt đầu 1 frame như sau:

Pre_Field <= Field;
if ({ Pre_Field, Field } == 2’b10)
Start <= 1’b1;
//khởi động bộ đếm cont để xác định số byte của chuỗi Pixel trong 1 hàng
if (SAV)
begin
cont <= 18’h0;
Active_video <= 1’b0;
End
else if (cont < 1440)
cont <= cont+1’b1;
//cứ 2 byte 1 Pixel khi xác định vị trí Pixel trong hàng thì phải chia cont cho
2
assign oTV_X = cont>>1;
Để thực hiện phép chia oTV_X cho 9 ta sử dụng bộ chia từ thư viện của
quatus:
Phần Menu >> Tools >> MegaWizard Plug_in Manager…>>Create… tạo
custom mới đặt tên là DVI; chọn phần Arithmetic >> LPM_DEVIDE. Vì oTV_X ≤
720 nên chọn độ rộng bit của số bị chia (Numberator) là 10, độ rộng bit của số chia
(denominator) là 4, kiểu dữ liệu không dấu. Vì số chia cần nhập là 9 nên ta ghép
vào khối tổng thể như sau:
DIV u5 ( .aclr(!DLY0),
.clock(TD_CLK),
.denom(4’h9),
.number(TV_X),
.quotient(Quotient),
.remain(Remain));
Trong đó quotient, remain là thương và số dư, ta nhập các điều kiện oTV_X
có chia hết cho 9 và thương là số lẻ thông qua các chân iSkip và iSwap_CbCr bằng
cách khai báo:

Desize_Horizontal u4 ( .iTD_DATA(TD_DATA),
.oTV_X(TV_X),
.oYCbCr(YCbCr),
.oDVAL(TV_DVAL),
.iSwap_CbCr(Quotient[0]),
.iSkip(Remain==4'h0),
.iRST_N(DLY1),
.iCLK_27(TD_CLK) );
Sau đó ghép 1 Y với 1 Cr hay 1 Y với 1 Cb đồng thời hoán đổi vị trí của Cr
và Cb tại các vị trí cần thiết:
if(iSwap_CbCr)
begin
case(Cont[1:0]) //hoán đổi Cb và Cr
0: Cb <= iTD_DATA;
1: YCbCr <= {iTD_DATA,Cr};
2: Cr <= iTD_DATA;
3: YCbCr <= {iTD_DATA,Cb};
endcase
end
else
begin
case(Cont[1:0]) //không cần hoán đổi
0: Cb <= iTD_DATA;
1: YCbCr <= {iTD_DATA,Cb};
2: Cr <= iTD_DATA;
3: YCbCr <= {iTD_DATA,Cr};
endcase
end
Sau đó xét thêm điều kiện Cont[0] để đảm bảo việc ghép 1 byte Y với 1 byte
Cr hay 1 byte Y với 1 byte Cb đã hoàn thành để xuất DATA_VALID :

if(Start && FVAL && Active_Video && Cont[0] && !iSkip )
Data_Valid <= 1'b1;
else
Data_Valid <= 1'b0;
Như vậy Data_Valid chỉ lên 1 ở Active Pixel để điều khiển sự ghi vào
SDRAM BUFFER.
5. KHỐI SDRAM BUFFER
5.1 SƠ ĐỒ KHỐI
Gồm 2 khối PLL và SDRAM Controller:


×