1. Title
Upscaling Image, OV7670
2. Category
"Video Processing"
3. Key Concepts
320 x 240 size의 QVGA를 업스케일링 하여 VGA 화면에 맞게 출력하고,
OV7670을 사용하기 위한 인터페이스 (SCCB)를 구현한다.
4. Setup
QVGA(320x240)를 VGA(640x480)로 업스케일링하는 방식은 두 가지 접근을 고려할 수 있다.
- 양쪽 픽셀 평균 내는 방식 (Bilinear Interpolation)
- 픽셀 사이사이의 값을 좌/우 인접 픽셀의 평균으로 삽입
- 단순 복사
- QVGA(320x240) → VGA(640x480)는 정확히 가로, 세로 2배씩 크기 차이가 난다. 그래서 각 QVGA 픽셀을 X, Y 방향으로 각각 2배로 복사해주면 VGA 사이즈로 맞출 수 있다.
image_rom U_Image_ROM (
.addr(y_pixel * 320 + x_pixel;),
.data(image_565)
);
// 기존 코드
image_rom U_IMAGE_ROM(
.addr(rom_addr),
.data(image_565)
);
image_upscaler U_IMAGE_UPSCALER(
.x_pixel(x_pixel),
.y_pixel(y_pixel),
.rom_addr(rom_addr)
);
module image_upscaler (
input logic [9:0] x_pixel,
input logic [9:0] y_pixel,
output logic [16:0] rom_addr
);
always @(*) begin
rom_addr = ((y_pixel >> 1) * 320) + (x_pixel >> 1);
end
endmodule
// pixel마다 rom에 접근하는 address가 반복되게 설정
OV7670을 Basys-3와 연동시키기 위한 간단한 블록 다이어그램을 그려보자면 다음과 같다.
- OV7670 Controller
- PCLK에 맞춰 HREF, VSYNC 감지
- HREF HIGH 동안만 D[7:0] 데이터 유효 확인
- VSYNC으로 Frame Reset 처리
- Pixel 데이터를 Frame Buffer에 쓰기
- Frame Buffer
- Write Port: OV7670 Controller에서 들어오는 Data 저장
- Read Port: VGA Controller가 VGA 클럭에 맞춰 읽기
- VGA Controller
- h_counter, v_counter로 VGA 타이밍 생성
- Pixel 위치에 맞춰 Frame Buffer로부터 데이터 읽어오기
- VGA HSYNC, VSYNC, RGB 데이터 출력
- STM32-F411RE
- OV7670 동작에 필요한 SDA, SCL 신호 생성
OV7670는 25MHz, 50%의 듀티사이클 주파수로 동작하게 된다. 또한 다양한 포맷으로 이미지 데이터를 출력할 수 있다.
OV7670은 HREF (Horizontal Reference)는 한 줄(ROW) 데이터 전송 유효 구간을 나타낸다. HIGH 상태에서 유효한 한 줄의 pixel data 전송하며, 한 프레임의 모든 데이터가 전송이 완료되면 VSYNC (Vertical Sync) 를 통해 프레임의 끝이라는 신호를 출력한다.
우선 ov7670으로부터 RGB 565 데이터를 받는 경우를 생각해보자. ov7670으로 부터 들어오는 픽셀 정보는 두개의 바이트로 나뉘어져 들어오게 된다. 따라서 320개의 픽셀 데이터를 얻기 위해서는 640번의 데이터 바이트를 읽어야한다.
5. Code Review
module vga_controller (
input logic clk,
input logic reset,
output logic h_sync,
output logic v_sync,
output logic [9:0] x_pixel,
output logic [9:0] y_pixel,
output logic display_enable
);
logic pclk;
logic [9:0] h_counter, v_counter;
pixel_clk_gen U_Pxl_Clk_Gen (
.clk (clk),
.reset(reset),
.pclk (pclk)
);
pixel_counter U_Pxl_Counter (
.pclk (pclk),
.reset (reset),
.h_counter(h_counter),
.v_counter(v_counter)
);
vga_decoder U_VGA_Decoder (
.h_counter (h_counter),
.v_counter (v_counter),
.h_sync (h_sync),
.v_sync (v_sync),
.x_pixel (x_pixel),
.y_pixel (y_pixel),
.display_enable(display_enable)
);
endmodule
module ov7670_controller (
pclk,
reset,
href,
v_sync,
ov7670_data,
we,
waddr,
wdata
);
input logic pclk;
input logic reset;
input logic href;
input logic v_sync;
input logic [7:0] ov7670_data;
output logic we;
output logic [16:0] waddr;
output logic [11:0] wdata;
logic [ 9:0] h_counter;
logic [7:0] v_counter;
logic [11:0] temp_cam_data;
assign waddr = v_counter * 320 + h_counter [9:1];
assign wdata = temp_cam_data;
always_ff @(posedge pclk, posedge reset) begin
if (reset) begin
h_counter <= 0;
end else begin
if (href == 1'b0) begin
h_counter <= 0;
end else begin
h_counter <= h_counter + 1;
end
end
end
always_ff @(posedge pclk, posedge reset) begin
if (reset) begin
temp_cam_data <= 0;
we <= 1'b0;
end else begin
if (href == 1'b0) begin
we <= 1'b0;
end else begin
if (h_counter[0] == 1'b0) begin
temp_cam_data[11:8] <= ov7670_data[7:4];
temp_cam_data[7:5] <= ov7670_data[2:0];
we <= 1'b0;
end else begin
temp_cam_data[4] <= ov7670_data[7];
temp_cam_data[3:0] <= ov7670_data[4:1];
we <= 1'b1;
end
end
end
end
always_ff @( posedge pclk, posedge reset ) begin
if(reset) begin
v_counter <= 0;
end else begin
if(v_sync == 1'b0) begin
if(h_counter == 640 - 1) begin
v_counter <= v_counter + 1;
end
end else begin
v_counter <= 0;
end
end
end
endmodule
화면이 이상하게 나오는 이유는 pclk의 불안정함과 SCCB 인터페이스 설정이 올바르지 않아서인데.. 이 문제에 대해서는 다음 게시글에서 다루도록 하겠다.
'AI SOC COURSE > 영상 처리' 카테고리의 다른 글
Video Course Review - 05. CDC (Clock Domain Crossing) (0) | 2025.03.28 |
---|---|
Video Course Review - 04. OV7670 SCCB (0) | 2025.03.20 |
Video Course Review - 02. Display Image (Lenna) (0) | 2025.03.18 |
Video Course Review - 01. VGA Port (0) | 2025.03.17 |