발생한 문제
카메라가 BSP_CAMERA_LineEventCallback을 통해서 각 라인을 처리하도록 구성했을 때, 해당 인터럽트가 BSP_CAMERA_Suspend(0)를 걸었음에도 발생하는 문제가 생겼다.
이에 더불어 원래 캔버스의 크기에 맞게 디스플레이를 처리하고 출력할 경우 화면이 반정도 이전 프레임 같아 보이는 것을 처리하는 것을 발견했다. 이에 대한 원인과 해결 방안을 정리해보고자 한다.
추측되는 원인
내가 카메라 데이터를 처리하는 로직을 살펴보자.
void BSP_CAMERA_FrameEventCallback(uint32_t Instance)
{
BSP_CAMERA_Suspend(0);
...
}
void BSP_CAMERA_LineEventCallback(uint32_t Instance) {
cur_idx++;
}
// main loop
while (1)
{
if (cur_idx > ii)
ii++;
if (ii > 0 && ii < 480)
ProcessFrame_Line(&srcLine, &dstLine, xsize);
}라인 이벤트가 발생했다면, 라인을 처리하는 것을 구상했으며, ii변수는 현재 처리된 라인을 의미한다.
이때, 문제점이 BSP_CAMERA_FrameEventCallback에서 BSP_CAMERA_Suspend(0)를 한다고 해서 카메라가 즉시 정지하지 않는다는 점이다.
아래의 코드를 살펴보자.
HAL_StatusTypeDef HAL_DCMI_Suspend(DCMI_HandleTypeDef *hdcmi)
{
uint32_t count = HAL_TIMEOUT_DCMI_STOP * (SystemCoreClock / 8U / 1000U);
HAL_StatusTypeDef status = HAL_OK;
/* Process locked */
__HAL_LOCK(hdcmi);
if (hdcmi->State == HAL_DCMI_STATE_BUSY)
{
/* Change DCMI state */
hdcmi->State = HAL_DCMI_STATE_SUSPENDED;
/* Disable Capture */
hdcmi->Instance->CR &= ~(DCMI_CR_CAPTURE);
/* Check if the DCMI capture effectively disabled */
do
{
count-- ;
if (count == 0U)
{
/* Update error code */
hdcmi->ErrorCode |= HAL_DCMI_ERROR_TIMEOUT;
/* Change DCMI state */
hdcmi->State = HAL_DCMI_STATE_READY;
status = HAL_TIMEOUT;
break;
}
}
while ((hdcmi->Instance->CR & DCMI_CR_CAPTURE) != 0U);
}
/* Process Unlocked */
__HAL_UNLOCK(hdcmi);
/* Return function status */
return status;
}내부적으로 동작하는 정지코드를 볼 수 있는데, 이 신호가 카메라에 도달하고 이를 정지하고 다시 프로세서의 레지스터에 입력되어야 비로소 루프를 빠져나온다. 즉, 정지까지 시간이 소요된다. 이때, 프레임이 완성되었더라도 카메라 데이터는 곧바로 다음 데이터를 준비하므로 ‘라인 인터럽트’가 발생한다.
카메라 속도가 빠른것이 독이될 수 있다는 것.
DMA 또한 특별히 정지시키지 않으므로, 카메라에서 데이터를 생산한다면 이를 곧바로 메모리로 옮기게된다.
결론적으로, 위 문제를 동기화 시켜주지 않았기에 발생한 문제라고 추측된다.
해결 방안
카메라와 처리의 동기화가 이루어져야한다.
즉, 카메라의 프레임 시작 위치와 정지 위치를 일치시켜야한다.
그러기 위해서는 아래의 사실을 알아야한다.
- 전송 완료 후, DMA는 어디에 카메라의 첫 프레임을 담는가?
- 그냥 뒷 부분만 처리가 잘되나? 그러니까 240 이후 프레임? 왜?
처음 프레임이 덮어진다. 이유가 뭘까? 인터럽트를 받았다고 해서 데이터가 다 찬게 아니라는게 아닐까? 그러니까 인터럽트가 보다 빨리 도달하여 데이터는 차지 않은거지. 그럼 어떻게 확인하지?
- 라인을 전송하고 비워버릴까?
- 프레임 처리가 끝나고 카메라 버퍼를 비웠더니 절반의 데이터가 이전 프레임의 데이터였고. 이를 처리하면서 문제가 되었던 것으로 보인다.
- 인터럽트와 DMA의 속도가 이렇게 심한 차이를 가지는걸까?
위 방안을 테스트 후, 이어서 작성하도록 한다.