Raspberry Pi 3B 모델에 PCAM5C 카메라를 연결하려고 디바이스 트리, 드라이버 수정해보았다.
도저히 안 붙는다 싶어서 파이카메라는 원래 어떻게 작동하였는지 알아보았음.
결과적으로 다른 카메라를 연결하는데는 실패하였지만
왜 안되는지 생각해보면서 작성한 글이다.
아래는 핀과 케이블 규격이 호환되는 PCAM5C라는 제품(OV5640기반)을
PiCam과 비교하여 붙일 수 있는지 체크한 내용이다.
카메라가 받아오는 클럭의 소스를 라즈베리파이 AP가 아닌 카메라 보드 위의 24MHz 크리스탈에서 받아오고있다.
라즈베리파이 AP에서 받아올 수 있다면 디바이스드라이버나 트리수준에서 제어한 뒤에 클럭을 제어할 수 있어보인다..
12MHz 클럭을 보드에서 받아옴.
I2C, MIPI 핀맵 구성은 같다.
PCAM5C를 라즈베리파이의 CSI포트에 연결할 경우 클럭을 넣어줄 수 없음.
작동 방식을 분석하여 핀맵을 변경하던 드라이버를 수정하던 뭔가 진행해서 클럭을 따로 넣어줄 수 있는지 알아봐야 할 것 같음.
카메라를 사용하기위해 raspi-config의 camera enable 과정을 확인해보았다.
대체 뭘 했길래 카메라가 설정되는지 알고싶었기 때문에 raspi-config 스크립트를 열어보았고,
아래는 스크립트를 보면서 이해하는데 필요한 부분을 일부 발췌한 내용을 옮겨적었다.
:<<'HIDDEN_PARAMS'
CONFIG=/boot/config.txt
INTERACTIVE=True
...
HIDDEN_PARAMS
:<<'HIDDEN_METHODS'
set_config_var() {
lua - "$1" "$2" "$3" <<EOF > "$3.bak"
local key=assert(arg[1])
local value=assert(arg[2])
local fn=assert(arg[3])
local file=assert(io.open(fn))
local made_change=false
for line in file:lines() do
if line:match("^#?%s*"..key.."=.*$") then
line=key.."="..value
made_change=true
end
print(line)
end
if not made_change then
print(key.."="..value)
end
EOF
mv "$3.bak" "$3"
}
get_config_var() {
# lua script.
lua - "$1" "$2" <<EOF
local key=assert(arg[1])
local fn=assert(arg[2])
local file=assert(io.open(fn))
local found=false
for line in file:lines() do
local val = line:match("^%s*"..key.."=(.*)$")
if (val ~= nil) then
print(val)
found=true
break
end
end
if not found then
print(0)
end
EOF
}
get_camera() {
CAM=$(get_config_var start_x $CONFIG)
if [ $CAM -eq 1 ]; then
echo 0
else
echo 1
fi
}
HIDDEN_METHODS
do_camera() {
# -e : if 조건; 해당 파일이 있으면 true
# whiptail : 인터페이스 생성에 필요함.
# start_x.elf 파일이 있는지 확인함.
if [ ! -e /boot/start_x.elf ]; then
whiptail --msgbox "Your firmware appears to be out of date (no start_x.elf). Please update" 20 60 2
return 1
fi
sed $CONFIG -i -e "s/^startx/#startx/"
sed $CONFIG -i -e "s/^fixup_file/#fixup_file/"
# whiptail option (default no)
DEFAULT=--defaultno
CURRENT=0
# -eq 값이 같으면 참.
# camera 못찾으면 0 그 이외에는 0이아닌 다른값.
# 카메라 못찾으면 여기로 들어감.
if [ $(get_camera) -eq 0 ]; then
DEFAULT=
CURRENT=1
fi
# 정상종료 : $?==0 / 실패 등 비정상종료 : $?==1
if [ "$INTERACTIVE" = True ]; then
whiptail --yesno "Would you like the camera interface to be enabled?" $DEFAULT 20 60 2
RET=$?
else
RET=$1
fi
# 카메라 찾은경우
# DEFAULT=--defaultno
# CURRENT=0
# 카메라 활성화 여부
# 활성화; RET=0 / 비활성화; RET=1
# 카메라 찾은 상태에서 활성화; 재부팅 플래그 활성화
if [ $RET -eq $CURRENT ]; then
ASK_TO_REBOOT=1
fi
# 카메라 활성화시
if [ $RET -eq 0 ]; then
# /boot/config.txt 내부의 start_x 속성 값을 1로 변경
set_config_var start_x 1 $CONFIG
# /boot/config.txt 내부의 gpu_mem 속성 값을 가져옴.
CUR_GPU_MEM=$(get_config_var gpu_mem $CONFIG)
# -z 문자열의 길이가 0이면 참
# -n 문자열의 길이가 0이 아니면 참
# -lt 값1 < 값2 , -le 값1 <= 값2
# -gt 값1 > 값2 , -ge 값1 >= 값2
# 받아온 gpu_mem 속성 값이 nil이거나 128보다 작을 경우
if [ -z "$CUR_GPU_MEM" ] || [ "$CUR_GPU_MEM" -lt 128 ]; then
# /boot/config.txt의 gpu_mem 속성 값을 128로 변경함.
set_config_var gpu_mem 128 $CONFIG
fi
STATUS=enabled
# 카메라 비활성화시
elif [ $RET -eq 1 ]; then
# /boot/config.txt의 start_x 속성 값을 0으로 변경
set_config_var start_x 0 $CONFIG
sed $CONFIG -i -e "s/^start_file/#start_file/"
STATUS=disabled
# undefined, 아무것도 안함.
else
return $RET
fi
# 활성/비활성 결과 메시지 보여줌.
if [ "$INTERACTIVE" = True ]; then
whiptail --msgbox "The camera interface is $STATUS" 20 60 1
fi
}
raspi-config에서 Camera 활성화시 /boot/config.txt의 start_x와 gpu_mem 속성 값이 변경됨.
config.txt는 뭘까?
Raspberry pi boot process
대략 GPU가 /boot/config.txt를 읽고나서 일련의 작업이 구성되고 CPU(및 OS)가 초기화 된다는 맥락인 것 같다.
RPi의 VideoCore와 PiCam 사이에 뭔가 인터페이스가 있거나 직접 통신을 하거나 둘중 하나임.
뭔가 있을 것 같아서 VideoCore이 주변 페리퍼럴에 어떤 상호작용을 하는지 알아보기 위해 블록 다이어그램을 찾았지만 못찾았다.
그러다가 포럼 게시물 하나를 읽게되었음.
이쯤되면 차라리 라즈베리파이를 안쓰고 카메라관련 프로세싱 과정이 오픈되어있는 다른 SBC를 사용 해 볼 생각도 든다.
비디오프로세싱 전용 코어가 있고 우린 그걸 제어할 수 없지..!
내부 직원이 아닌이상 못하지않을까...
라즈베리파이의 부팅과정 중 GPU가 초기화되는 단계가 있고, 이 때 boot 파티션의 start_x.elf 파일에 있는 카메라 조작 관련 코드를 실행시킴.
근데 그 내용은 비공개 상태이며 앞으로도 공개될 가능성이 상당히 낮다.
(공식적으로 브로드컴과 라즈베리파이제단에서 공개하지 않는다고 하는 항목 중 하나)
심지어 이게 I2C 등으로 제어될 줄 알았는데 VideoCore에 직접 연결되어있다.