전체적인 프로그램의 구조에 대하여 이야기하였으니 카메라를 제어하는 방법에 대하여 말씀드리겠습니다.
기본적으로 OjOcamStereo에서 사용하는 MT9M111 마이크론 카메라에는 많은 레지스터들이 있습니다.
레지스터에 적절한 값을 읽거나 써서 카메라를 제어하는 것이지요.
보통 카메라의 레지스터를 읽거나 쓰기위해서는 I2C 인터페이스를 이용합니다.
아시는 분은 아시겠지만 I2C 인터페이스는 스펙상 256개의 주소만을 지정할 수 있습니다.
MT9M111에는 256개 보다 더 많은 레지스터가 있기 때문에
MT9M111에서는 페이지란 개념을 이용하여 더 많은 레지스터를 제어합니다.
즉, 한번에 256개의 주소를 지정할 수 있는 페이지를 여러개 만들어 페이지를 변경해가며 레지스터를 이용하는 것입니다.
여러개의 페이지 중 원하는 페이지로 변경하기 위해서는 0xf0(240)번지에 원하는 페이지 번호를 쓰면 됩니다.
모든 페이지의 0xf0번 주소는 페이지를 변경하는 레지스터로 사용되기 때문에
어떤 페이지에서 건 0xf0번지에 페이지 번호를 쓰면 페이지가 변경되는 것이지요.
MT9M111에는 3개의 페이지가 있고 페이지당 대략 200여개의 레지스터가 있지만
우리가 주로 사용하는 레지스터는 그렇게 많지 않습니다.
우선, 중요한 레지스터로는 1번 페이지의 6번 레지스터인 "Operation Mode Control" 레지스터가 있습니다.
이 레지스터는 AutoExp를 On/Off 시키는 레지스터로 0x700E를 적으면 AutoExp On이 되고,
0x300C를 적으면 AutoExp가 off됩니다.
(각 비트에 대한 자세한 내용은 메뉴얼 MT9M111.pdf 22 페이지에 보면 나와 있습니다.)
1번 페이지에 있기 때문에 아래와 같이 동작시켜야겠지요.
I2C_Write(0xf0, 1); // 1 번페이지로변경합니다.
I2C_Write(0x06, 0x700E); // auto exposure on
혹은
I2C_Write(0xf0, 1); // 1 번페이지로변경합니다.
I2C_Write(0x06, 0x300C); // auto exposure off
AutoExp를 off로 하여야 셔터 스피드와 게인값을 설정하는 것이 가능해집니다.
AutoExp를 on으로 하면 카메라가 자동으로 카메라 레지스터 값을 변경하기 때문에
프로그램상에서 수동으로 레지스터 값을 설정하는 것이 의미가 없어집니다.
셔터 스피드의 경우는 0번 페이지 9번 레지스터입니다.
마찬가지로 셔터 스피드의 값을 바꾸기 위해서는 아래와 같이 해야겠지요.
I2C_Write(0xf0, 0); // 0 번페이지로변경합니다.
I2C_Write(0x09, shutter); // shutter speed 값을 바꿉니다.
게인 값은 0번 페이지 43(0x2B) ~ 47(0x2F)번 레지스터입니다.
이 레지스터를 보면, R, G1, G2, B, Global 게인을 설정할 수 있습니다.
위의 레지스터를 보면 R, G, B중 G가 두개입니다.
이것은 칼라 CMOS 센서가 아래와 같이 생겼기 때문입니다.


즉, 한점에서 칼라를 표현하기 위해서는 RGB가 모두 있어야 하지만 모든 픽셀마다 RGB 센서를 만들면
해상도가 낮아지기 때문에 위와 같이 RGB를 번갈아가면서 만들어서 센서의 효율을 높이는 것입니다.
(RGB를 번갈아가면서 만든다기 보다는 동일한 센서위에 RGB 칼라 필터를 장착하는 것이랍니다.)
사람의 시신경의 경우 G에 민감하기 때문에 G를 2개 사용한다고 하네요.
(진화론적으로 자연 환경이 거의 G로 되어 있기 때문이겠죠?)
위와 같은 패턴을 베이어 패턴(Bayer Pattern)이라고 합니다. 카메라 센서 MT9M111에서는
위와 같은 데이터로부터 각 픽셀당 RGB 값을 계산하고, RGB 값을 다시 밝기 정보(Y)와 색상 정보(UV)를 갖는
YUV 값으로 변경하여 최종 출력합니다.
최종적으로는 YUV422 포맷으로 전송되는데 이것은 밝기값 2개에 색상값을 1개씩만 보내는 것입니다.
이것도 역시 사람의 눈이 밝기 정보에는 예민하고 색상 정보에는 둔감하기 때문으로
색상에 대한 해상도는 절반으로 줄어들게 됩니다.
이렇게 해서 카메라 레지스터를 설정하는 부분에 대하여는 대략 설명이 되었고,
두개의 카메라의 동기를 맞추는 법에 대하여 설명 드리도록 하겠습니다.
OjOcamStereo는 기본적으로 카메라가 2개 있기 때문에
처음에는 FPGA에서 I2C 포트를 2개 만들어 각 카메라 별로 제어하려고 했습니다.
하지만 카메라의 동기를 맞추려고 보니 양쪽 카메라에 같은 시각에 동일한 명령을 내려야하는 경우가 발생하였습니다.
그래서 어떻게 할까 고민하다가 아래와 같이 I2C 회로를 구성하였습니다.

I2C는 Data와 클럭의 두개의 라인으로 되어 있는데,
이중 데이터는 공유를 하고 클럭은 FPGA에서 선택하여 각각의 카메라를 제어하는 것입니다.
이렇게 하면 FPGA를 통하여 카메라를 개별적으로 제어할 수도, 동시에 같이 제어할 수도 있게 됩니다.
FPGA에서 어떤 카메라를 제어할 것인가를 결정하는 함수가 아래의 함수입니다.
Bus_Write(3, Value);
Value에 0번 비트는 0번 카메라에 해당하고 1번 비트는 1번 카메라에 해당합니다.
따라서 Value에 1을 쓰면 0번 카메라를, 2를 쓰면 1번 카메라를 3을 쓰면 양쪽 카메라를 동시에 제어할 수 있습니다.
그래서, Bus_Write() 함수와 I2C_Write() 함수를 이용하여 카메라의 동기를 맞추는 방법은 아래와 같습니다 .
우선, AutoExp를 off 시킵니다.
AutoExp가 On되어 있으면 한프레임을 받는데 걸리는 시간이 양쪽 카메라가 다르기 때문에
동기를 맞추어도 계속 틀어지게 됩니다.
AutoExp를 off 시킨 후 양쪽 카메라에 셔터 스피드등 원하는 파라메터값을 설정합니다.
(셔터 스피드는 영상을 받는데 걸리는 시간이므로 동일하게 설정하여야 하며, 게인은 양쪽 카메라가
다르게 설정되어도 상관없습니다.)
그리고 나서 양쪽 카메라에 동시에 Restart를 하면
양쪽 카메라에 동일한 클럭이 들어가기 때문에 그때부터는 양쪽 카메라에서는 동기가 맞는
영상 데이터가 출력 됩니다.
이렇게 하면 픽셀 레벨에서 동기가 맞게됩니다.
Bus_Write(3, 3); // 양쪽 카메라를 동시에 제어합니다.
I2C_Write(0xf0, 1); // 1 번페이지로변경합니다.
I2C_Write(0x06, 0x300C); // auto exposure off
Bus_Write(3, 1); // 0 번 카메라를 제어합니다.
I2C_Write(); // 필요한 값 설정
...
Bus_Write(3, 2); // 1 번 카메라를 제어합니다.
I2C_Write(); // 필요한 값 설정
...
Bus_Write(3, 3); // 양쪽 카메라를 동시에 제어합니다.
I2C_Write(0xf0, 0); // 0 번페이지로변경합니다.
I2C_Write(0x0d, 0x0a); // restart
MT9M111.pdf