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

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

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 (501.21 KB, 17 trang )

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


Hình 9.1: Sơ đồ khối SDRAM BUFFER
Tên Mô tả
RESET Tín hiệu reset hệ thống
CLK_27 Xung clock 27MHz từ kit DE2

CLK

Xung clock 81MHz PLL đưa ra cho các ngõ vào
CLK của khối SDRAM Controller ( chính là tần
số đọc của SDRAM WRITE FIFO, ghi của
SDRAM READ FIFO1 và SDRAM READ
FIFO2)

SDR_CLK Xuất xung clock 81MHz cho SDRAM
WR_LOAD
RD1_LOAD
RD2_LOAD

Lần lượt là tín hiệu để xóa bất đồng bộ SDRAM
WRITE FIFO, SDRAM READ FIFO1 và
SDRAM READ FIFO2 lấy từ chân RST0 của
khối Timer trì hoãn ban đầu.

WR_DATA

Dữ liệu ảnh đưa vào SDRAM WRITE FIFO do


Desize horizon cấp

WR

Cho phép ghi vào SDRAM WRITE FIFO lấy từ
chân DATA_VALID của khối Desize horizon

WR_CLK

Xung clock 27MHz từ chân LLC(TD_CLK) của
ADV7181B

RD_WRFIFO

Cho phép đọc dữ liệu từ SDRAM WRITE FIFO

WRITE_SIDE[8:0]


Số từ (Word) hiện có trong SDRAM WRITE
FIFO

DATA_IN

Dữ liệu từ SDRAM WRITE FIFO đưa vào
Control Center để ghi SDRAM.

DATA_OUT[15:0]



Dữ liệu Control Center đọc từ SDRAM để xuất ra
ngoài qua 1 trong 2 FIFO: SDRAM READ
FIFO1, SDRAM READ FIFO2

RD1
RD2

RD1 = ~ RD2: Lần lượt cho phép đọc dữ liệu từ
SDRAM READ FIFO1, SDRAM READ FIFO2
với sự điều khiển của khối VGA Cotroller thông
qua chân Request và VGA_Y.

RD1_CLK
RD2_CLK

Tần số đọc của SDRAM READ FIFO1 và
SDRAM READ FIFO2 được là 27MHz từ KIT
DE2


READ_SIDE1[8:0]
Số từ (Word) hiện có trong SDRAM READ
FIFO1
READ_SIDE2[8:0]

Số từ (Word) hiện có trong SDRAM READ
FIFO2
WR_RDFIFO1 Cho phép ghi dữ liệu SDRAM READ FIFO1
WR_RDFIFO2 Cho phép ghi dữ liệu SDRAM READ FIFO2
RD1_DATA[15:0]

RD2_DATA[15:0]
Dữ liệu ngõ ra cung cấp cho khối xử lý ảnh YUV

Các chân DQ[15:0], SA[11:0], CKE, CAS_N, RAS_N, SDR_CLK, WE_N,
BA[1:0], CS_N[1:0], DQM[1:0] thì được nối tương ứng vào chip SDRAM có sẵn
trên kit DE2.
2.1 MÔ TẢ
Như ta đã biết 1 frame ảnh theo chuẩn ITU656 bao gồm Odd Field và Even
Field: khi xuất ra màn hình thì các line thuộc Odd Field sẽ được hiển thị ở hàng lẻ,
còn các line thuộc Even là hàng chẵn. Nên các line của 2 Field này phải được xuất
xen kẽ nhau nhưng trong chuỗi video ITU656 do ADV7181B xuất ra thì 2 Field
được xuất liên tục: xuất xong Odd Field rồi mới tới Even Field (các frame khi ghi
vào SDRAM thì thành 2 Field liên tục) nên để xuất ra các line xen kẽ thì ta phải
tuần tự xuất 1 line từ địa chỉ mà Odd Field được lưu giữ rồi lại xuất tiếp 1 line từ
địa chỉ mà Even Field được lưu giữ.
Dữ liệu trong một frame ảnh sẽ được ghi lần lượt vào SDRAM từ địa chỉ 0
đến địa chỉ 324480 (324480 = 640 x 507, 507 chính là số line của frame được ghi
vào SDRAM ,ta bỏ qua 18 line có bit V =1 ), lúc này phần dữ liệu cần xuất ra từ
SDRAM chia thành 2 phần (trong 1 frame theo chuẩn ITU656 thực sự có tới 487
active line, ta xén bớt 7 active line để giảm số line về chuẩn hiển thị là 480):
 Phần 1: Từ địa chỉ 8320 (640 x 13) đến 161920 (640 x 253) sẽ là các
Pixel thuộc Odd Field. Đây chính là 240 line từ 23 đến 262 trong frame gốc.
 Phần 2: Từ địa chỉ 170880 (640 x 267) đến 324480 (640 x 507) là các
Pixel thuộc Even Field. Đây chính là 240 line từ 286 đến 525 trong frame gốc.
SDRAM hỗ trợ chế độ truy cập dữ liệu theo từng khối (Burst) với chiều dài
khối có thể thay đổi được nhờ vào cài đặt giá trị 3 bit cuối (BL) của thanh ghi
mode register bằng cách truy cập chế độ load mode rồi nhập giá trị cho thanh ghi
này qua các chân địa chỉ:

Ở đây đọc và ghi theo từng khối 128 word 16 bit nên nhập BL = 111:

chiều dài của Burts là full page (tức là 256 word với việc sử dụng SDRAM dưới
dạng 4M x 16); WT=0: truy xuất tuần tự (Sequential) dữ liệu trong khối;
LTMODE = 011: thời gian chờ (latency) cho tín hiệu RAS là 3 chu kỳ;
Các Burst dữ liệu của 2 phần trên sẽ được xuất xen kẽ nhau. Ta khởi tạo
và chi xuất địa chỉ cho các phần này như sau:
if(!RESET_N)
begin
rWR_ADDR <= 0;
rWR_MAX_ADDR <= 640*507;
rRD1_ADDR <= 640*13;
rRD1_MAX_ADDR <= 640*253;
rRD2_ADDR <= 640*267;
rRD2_MAX_ADDR <= 640*507;
//chiều dài của khối cần truy xuất
rWR_LENGTH <= 128;
rRD1_LENGTH <= 128;
rRD2_LENGTH <= 128;
end
else
begin
//nếu đã thực hiện xong tác vụ mWR_DONE, mRD_DONE và có cờ
báo thực hiện tác vụ mới đối với một khối WR_MASK[0], RD_MASK[0],
RD_MASK[1] thì tăng địa chỉ khối lên 1 khối và lặp lại cho đến khi vượt
quá địa chỉ tối đa thì quay về địa chỉ ban đầu.
//ghi vào SDRAM
if(WR_LOAD)
begin
rWR_ADDR <= WR1_ADDR;
rWR_LENGTH <= WR1_LENGTH;
end

else if(mWR_DONE&WR_MASK[0])
begin
if(rWR_ADDR<rWR_MAX_ADDR-rWR_LENGTH)
rWR_ADDR <= rWR_ADDR+rWR_LENGTH;
else
rWR_ADDR <= WR_ADDR;
end
//đọc dữ liệu từ phần 1
if(RD1_LOAD)
begin
rRD1_ADDR <= RD1_ADDR;
rRD1_LENGTH <= RD1_LENGTH;
end
else if(mRD_DONE&RD_MASK[0])
begin
if(rRD1_ADDR<rRD1_MAX_ADDR-rRD1_LENGTH)
rRD1_ADDR <= rRD1_ADDR+rRD1_LENGTH;
else
rRD1_ADDR <= RD1_ADDR;
end
//đọc dữ liệu từ phần 2
if(RD2_LOAD)
begin
rRD2_ADDR <= RD2_ADDR;
rRD2_LENGTH <= RD2_LENGTH;
end
else if(mRD_DONE&RD_MASK[1])
begin
if(rRD2_ADDR<rRD2_MAX_ADDR-rRD2_LENGTH)
rRD2_ADDR <= rRD2_ADDR+rRD2_LENGTH;

else
rRD2_ADDR <= RD2_ADDR;
end
end
Trước hết cần tạo một khối điều khiển việc ghi và đọc SDRAM xen kẽ nhau,
mỗi lần đọc hay ghi dữ liệu sẽ thao tác trên từng Burst có chiều dài là 128 từ
(Word) theo thứ tự ưu tiên (chờ thao tác hiện thời hoàn thành rồi mới thực hiện
thao tác tiếp theo):
- Đọc 1 khối từ SDRAM rồi ghi vào SDRAM READ FIFO1 để xuất
chuỗi Pixel thuộc Odd Frame.
- Đọc 1 khối từ SDRAM rồi ghi vào SDRAM READ FIFO2 để xuất
chuỗi Pixel thuộc Even Frame.
- Ghi 1 khối từ SDRAM WRITE FIFO vào SDRAM.
Ở trên ta thực hiện 3 thao tác xen kẽ nhau, vì vậy để dữ liệu có thể đồng bộ
nhập, xuất dữ liệu với các khối khác thì phải cung cấp tần số làm việc cho SDRAM
và tần số truy xuất dữ liệu giữa các khối FIFO và SDRAM gấp 3 lần tần số clock
của các khối khác. Để tạo các xung clock này ta sử dụng thư viện của Quartus để
tạo khối PLL :
Phần Menu >> Tools >> MegaWizard Plug_in Manager… >> Create… tạo
một custom mới, đặt tên là SDRAM_PLL, chọn phần I/O >> ALTCLKILOCK, ta
không sử dụng các chân đồng bộ mà chỉ nhập các thông số cho tần số ngõ vào và
tần số ngõ ra như sau: inclk0 là 27MHz; c0 chọn tần số là 81MHz với pha ban đầu
là 0; c1 tần số là 81 MHz với pha ban đầu trễ 3ns (bù trừ với khảng thời gian điều
khiển các tín hiệu đồng bộ để truy cập SDRAM).
Chân c0 sẽ cung cấp tần số đọc tần số cho SDRAM WRITE FIFO để ghi dữ
liệu vào SDRAM, tần số ghi cho SDRAM READ FIFO1 và SDRAM READ
FIFO2 để ghi dữ liệu được xuất ra từ SDRAM. Chân c1 cung cấp tần số làm việc
cho SDRAM.
Đồng thời khi thực hiện 1 tác vụ ta cần phải trì hoãn các tác vụ khác một
khoảng thời gian được mô tả theo giãn đồ sau (chưa xét tác động của RD1 và

RD2):

Hình 9.2: Giản đồ định thì cho chu kỳ truy xuất giữa SDRAM và các FIFO
Vì vậy để đảm bảo truy xuất đúng dữ liệu thì cần phải có các FIFO có chiều
dài 384 ( tức là 128 x 3 ). Tuy nhiên trong thư viện của Quarus chỉ có FIFO dài
384 Word nên sẽ tạo một FIFO dài 512 Word như sau:
Phần Menu >> Tools >> MegaWizard Plug_in Manager… >> Create … tạo
một custom mới, đặt tên là SDRAM_WRITE_FIFO, chọn phần Memory Compiler
>> FIFO chọn độ rộng dữ liệu là 16bit, chiều dài ( deep ) là 512 Words. Làm tương
tự để tạo các khối SDRAM_READ_FIFO1 và SDRAM_READ_FIFO2.
Khi sử dụng FIFO dài 512 Word ta phải có 1 số thay đổi trong thiết kế, tuy
nhiên các thay đổi này tương đối đơn giản như tăng tần số xung clock lên 108
MHz, sử dụng thêm 1 tác vụ ghi trống (WR2) để đảm bảo dữ liệu xuất ra đung
theo yêu cầu.
Thực hiện ghi và xuất từng khối dữ liệu xen kẽ từ SDRAM như sau:
//ghi vào SDRAM READ FIFO1 các Pixel thuộc line Odd frame
if( (READ_SIDE1< rRD1_LENGTH) )
begin
mADDR <= rRD1_ADDR;
mLENGTH <= rRD1_LENGTH;
WR_MASK <= 2'b00;
RD_MASK <= 2'b01;
mWR <= 0;
mRD <= 1;
end
//ghi vào SDRAM READ FIFO2 các Pixel thuộc line Even frame
else if( (READ_SIDE2< rRD2_LENGTH) )
begin
mADDR <= rRD2_ADDR;
mLENGTH <= rRD2_LENGTH;

WR_MASK <= 2'b00;
RD_MASK <= 2'b10;
mWR <= 0;
mRD <= 1;
end
//đọc dữ liệu từ SDRAM WRITE FIFO và ghi vào SDRAM
else if( (WRITE_SIDE>= rWR_LENGTH)&& (rWR_LENGTH!=0) )
begin
mADDR <= rWR_ADDR;
mLENGTH <= rWR_LENGTH;
WR_MASK <= 2'b01;
RD_MASK <= 2'b00;
mWR <= 1;
mRD <= 0;
end
end
if(mWR_DONE)
begin
WR_MASK <= 0;
mWR <= 0;
end
if(mRD_DONE)
begin
RD_MASK <= 0;
mRD <= 0;
end
Xét điều kiện số Word có trong các FIFO để khởi tạo lệnh đọc và ghi
SDRAM. Rồi dùng biến đếm ST (bắt đầu từ 0) để thiết lập khoảng thời gian cần
thiết cho 1 tác vụ bao gồm: thời gian chờ bus đảm bảo rảnh hoàn (đối với lệnh đọc
là SC_CL+SC_RCD+1, ghi là SC_CL-1, phụ thuộc vào cấu trúc của SDRAM:

SC_CL = SC_RCD = 3 được khai báo trong tập tin Sdram_Params.h ), thời gian
thực hiện tác vụ (mLENGTH = 128).Tạo tín hiệu điều khiển việc ghi đọc các FIFO
và cờ báo đã đọc hay ghi xong như sau:
if(Read)
begin
//OUT_VALID là tín hiệu dùng để điều khiển cho phép ghi vào các
SDRAM //READ FIFO
if(ST==SC_CL+SC_RCD+1)
OUT_VALID <= 1;
else if(ST==SC_CL+SC_RCD+mLENGTH+1)
begin
OUT_VALID <= 0;
Read <= 0;
mRD_DONE <= 1;
end
end
else
mRD_DONE <= 0;
if(Write)
begin
//IN_REQ là tín hiệu dùng để điều khiển cho phép đọc từ SDRAM WRITE
//FIFO
if(ST==SC_CL-1)
IN_REQ <= 1;
else if(ST==SC_CL+mLENGTH-1)
IN_REQ <= 0;
else if(ST==SC_CL+SC_RCD+mLENGTH)
begin
Write <= 0;
mWR_DONE <= 1;

end
end
else
mWR_DONE<= 0;
với chu kỳ truy xuất như giản đồ trên thì lượng dữ liệu xuất ra sẽ gấp 2 lần
lượng dữ liệu ghi vào SDRAM. Tuy nhiên quá trình trên còn chịu ảnh hưởng của
các ngõ vào RD1 và RD2, (tác động đến các giá trị READ_SIDE1 và
READ_SIDE2) sẽ điều khiển các thao tác xuất dữ liệu từ SDRAM vào SDRAM
READ FIFO như sau:
- RD1 = ~RD2 = 1: ngừng tác vụ xuất dữ liệu từ SDRAM vào SDRAM
READ FIFO2 tức là chỉ xuất các line của Odd Field.
- RD1 = ~RD2 = 0: ngừng tác vụ xuất dữ liệu từ SDRAM vào SDRAM
READ FIFO1 tức là chỉ xuất các line của Even Field.
Do RD1, RD2 được tích cực lần lượt sau 640 chu kỳ (tương đương với 1
line) nên các line sẽ được xuất xen kẽ nhau. Như vậy trong 1 chu kỳ truy xuất thực
sự chỉ có 128 Word được xuất vào 1 FIFO, đảm bảo được sự đồng bộ dữ liệu của
SDRAM với hệ thống.
Vấn đề cuối cùng cần phải giải quyết là xác định các thời điểm truy xuất
SDRAM BUFFER tức là tính toán khoảng thời gian kể từ khi bắt đầu ghi dữ liệu
vào(WR=1) và tới khi bắt đầu xuất chúng ra để đảm bảo các pixel được xuất ra là
cùng thuộc 1 frame:
- Nếu khoảng thời gian này không đủ lớn: chân RD2 tích cực bắt đầu
truy xuất dữ liệu của Even Field từ địa chỉ 170880 cho đến 324480, mà dữ liệu
trong các địa chỉ này lại chưa được cập nhật nên dẫn đến các line xuất ra sẽ không
có giá trị hoặc là các line của frame trước.
- Nếu khoảng thời gian này quá lớn: do tốc độ tăng địa chỉ của quá trình
ghi gấp đôi quá trình đọc (do địa chỉ ghi được tăng liên tục còn chỉ đọc lần lượt là
địa chỉ để xuất xen kẽ các line thuộc Odd Field và Even Field nên cũng chỉ được
tăng lần lượt), nên xảy ra trường hợp khi đang xuất dữ liệu thuộc 1 frame thì quá
trình ghi đã nhập dữ liệu của frame tiếp theo vào SDRAM BUFFER, khi đó RD1

tích cực thì có thể xuất ra 1 line thuộc frame mới này chứ không phải là line của
frame hiện hành.
Như đã nói trong phần mô tả khối Timer trì hoãn ban đầu, việc đọc từ
SDRAM BUFFER được kích hoạt sau 1 khoảng thời gian là 513927.5 chu kỳ tính
từ khi frame thứ 3 bắt đầu: khi các Pixel trên line thứ 300 của frame gốc (
513872.5 ÷ 1716; với1716 là số byte của 1 line trong frame gốc) tương đương với
line thứ 282 (bỏ qua18 line có bit V =1) đang được ghi vào SDRAM BUFFER, thì
bắt đầu xuất xen kẽ các line. Điều kiện RD2 truy xuất đúng Even frame được thỏa
mãn, xét các line mà RD1 xuất ra:
- Khi WR ghi liên tục từ line 282 đến line 507 vào SDRAM BUFFER
thì hiển nhiên là RD1 truy xuất đúng. Lúc này line mà RD1 đang xuất là 13 + (507
- 282) ÷ 2 = 125.5
- Xét frame tiếp theo: phải chờ hết 9 line đầu tiên mới bắt đầu ghi từ
line 0. Lúc đó RD1 sẽ truy xuất line thứ 125.5 + 9 : 2 = 130; như vậy cho đến khi
RD1 xuất line xong line thứ 253 thì WR mới chỉ ghi tới line (253-130)×2 = 246.
Đảm bảo dữ liêu được xuất vẫn là của frame hiện thời.
Ngoài ra trong khối Control Center còn có các khối command, control
interface để tạo và đồng bộ các lệnh làm tươi (refresh), tích nạp (Precharge), chọn
chế độ đọc, ghi, truyền khối, đồng thời mã hóa và giải mã lệnh cho SDRAM theo
mô tả các chế độ truy cập SDRAM ở Bảng 1.2 với cấu trúc khá phức tạp. Trong
khuôn khổ đồ án này không đề cập đến mà chỉ tham khảo và sử dụng code verilog
từ công ty Altera và hãng sản xuất KIT DE2 là Terasic.
Khi ghép vào trong khối tổng thể ta sẽ dùng cấu trúc để xuất dữ liệu như
sau: .RD1_DATA(m1YCbCr), .RD2_DATA(m2YCbCr), rồi chọn dữ liệu để đưa
vào khối xử lý ảnh YUV : assign mYCbCr_d = !VGA_Y[0]? m1YcbCr :
m2YCbCr; với !VGA_Y[0] là do khối VGA Controller đưa ra cho biết line đang
xuất trên màn hình ở vị trí lẻ hay chẵn để chọn dữ liệu xuất ra tương ứng.

×