본문 바로가기

Firmware/stm32

OV5642_LWIP_RTOS Project -2(Camera API)

실제 카메라 사진을 찍기 위한 API를 구현

Arducam에서 제공하는 예제소스를 참고하여 구현하였다.

 

카메라 및 LWIP 초기화

void StartDefaultTask(void *argument)
{
  /* init code for LWIP */
  MX_LWIP_Init();
  /* USER CODE BEGIN StartDefaultTask */
  set_format(JPEG);	
  initCAM();
  set_bit(0x03,0x02);
  clear_fifo_flag();
  write_reg(0x01,0x00); //VSYNC Active HIGH
  OV5642_set_JPEG_size(OV5642_1600x1200);
  
  TcpTaskHandle = osThreadNew(Tcp_Task, NULL, &TcpTask_attributes);
  CameraTaskHandle = osThreadNew(Camera_Task, NULL, &CameraTask_attributes);
  /* Infinite loop */
  for(;;)
  {
   osThreadTerminate(defaultTaskHandle);
      
  
  }
  /* USER CODE END StartDefaultTask */
}

StartDefaultTask 에서 LWIP 초기화 후  카메라를 초기화 해준다.

 

initCAM()

void initCAM ()
{
  
  uint16_t reg_val;
  wrSensorReg16_8 (0x3008, 0x80);
  wrSensorRegs16_8 (OV5642_QVGA_Preview);
  
  HAL_Delay (100);
  
  if (m_fmt == JPEG)
  {
    wrSensorRegs16_8 (OV5642_JPEG_Capture_QSXGA);
    wrSensorRegs16_8 (ov5642_320x240);
    HAL_Delay (100);
    wrSensorReg16_8 (0x3818, 0xa8);
    wrSensorReg16_8 (0x3621, 0x10);
    wrSensorReg16_8 (0x3801, 0xb0);
    wrSensorReg16_8 (0x4407, 0x04);
  }
  else
  {
    wrSensorReg16_8 (0x4740, 0x21);
    wrSensorReg16_8 (0x501e, 0x2a);
    wrSensorReg16_8 (0x5002, 0xf8);
    wrSensorReg16_8 (0x501f, 0x01);
    wrSensorReg16_8 (0x4300, 0x61);
    rdSensorReg16_8 (0x3818, (uint8_t*) &reg_val);
    wrSensorReg16_8 (0x3818, (reg_val | 0x60) & 0xff);
    rdSensorReg16_8 (0x3621, (uint8_t*) &reg_val);
    wrSensorReg16_8 (0x3621, reg_val & 0xdf);
  }
  
}

앞서 설정한 set_format으로 JPEG으로 카메라르 초기화 해준다.

http://www.arducam.com/downloads/modules/OV5642/OV5642_camera_module_software_application_notes_1.1.pdf

 

초기화 및 레지스터 설정은 첨부한 Application Note에 자세히 설명 되어있다.

 

Camera_Capture

void Camera_Capture(struct netconn *cmraconn)
{
  flush_fifo();
  clear_fifo_flag();
  HAL_Delay(1);
  fstart_capture();
  camera_flag = true;
  /****** Camera_flag***********/
  while (camera_flag)
  {
    if (get_bit(0x41, 0x08))
    {
#ifdef DEBUG
      printf("get_bit is true \n\r");
#endif
      Camera_Module_length = read_fifo_length();
      first_picture_data();
      second_picture_data(cmraconn);
      
      camera_flag = false;
      
    } 
  }
}

void flush_fifo (void)
{
  
  write_reg (0x04, 0x01);
  
}

void fstart_capture (void)
{
  
  write_reg (0x04, 0x02);
  
}

void clear_fifo_flag (void)
{
  
  write_reg (0x04, 0x01);
  
}

flush_fifo와 clear_fifo_flag는 같은 명령어이며 fifo buffer를 모두 clear 한다.

Camera Capture 명령어를 내리고 카메라가 사진이 찍혔으면 0x41 Address에 4번째 비트에 1이 setting 된다.

1이 set 된걸 확인 후 first_picture_data 함수와 second_picture_data 함수를 통해 buffer에 있는 데이터를 가지고 와

TCP로 전송한다.

 

fist_picture_data

void first_picture_data()
{
  
  uint8_t spi_dummy;
  
  cmra_flag = 0;
  Real_length = 0;
  cmra_buf[cmra_flag++] = 'T';
  cmra_buf[cmra_flag++] = 'E';
  cmra_buf[cmra_flag++] = 'S';
  cmra_buf[cmra_flag++] = 'T';
  
  set_fifo_burst();
  
  
  while (1)
  {
    temp_last = temp;
    
    HAL_SPI_TransmitReceive(&hspi3, (uint8_t*) &spi_dummy, &temp, 1, 1000);
    
    if ((temp == 0xD8) && (temp_last == 0xFF))
    {
      cmra_buf[cmra_flag++] = temp_last;
      Real_length++;
      cmra_buf[cmra_flag++] = temp;
      Real_length++;
      picture_flag = true;
      break;
      
    }
    
  }
}

First picture data를 통해 사진의 헤더를 찾는다 JPEG 포멧의 첫 header는 0xff 0xd8로 시작한다.

따라서 0xff와 0xd8이란 데이터가 나오기 전까지는 저장하지 않고 모두 버린다.

만약 0xff와 0xd8을 찾았다면 Cmra_buf에 데이터를 저장 후 함수를 종료한다.

 

second_picture_data

void second_picture_data(struct netconn *cmraconn)
{
  while (picture_flag)
  {
    
    temp_last = temp;
    
    HAL_SPI_TransmitReceive(&hspi3, (uint8_t*) &spi_dummy, &temp, 1, 1000);
    
    cmra_buf[cmra_flag++] = temp;
    Real_length++;
    
    if ((temp == 0xD9) && (temp_last == 0xFF))
    {
      picture_flag = false;
      cmra_buf[cmra_flag++] = 0xFF;
      cmra_buf[cmra_flag++] = 0xFF;
      cmra_buf[cmra_flag++] = 0xFF;
      cmra_buf[cmra_flag++] = 0xFF;
      cmra_buf[cmra_flag++] = Real_length >> 24;
      cmra_buf[cmra_flag++] = Real_length >> 16;
      cmra_buf[cmra_flag++] = Real_length >> 8;
      cmra_buf[cmra_flag++] = Real_length;
      
      clear_fifo_flag();
      netconn_write(cmraconn,cmra_buf,cmra_flag,NETCONN_COPY);
      cmra_flag = 0;
      
      
    }
    
    
    if (cmra_flag == SEND_SIZE)
    {
      netconn_write(cmraconn,cmra_buf,cmra_flag,NETCONN_COPY);
      cmra_flag = 0;
      osDelay(1);
    }
    
  }
  
}

 

second_picture_data 함수에서는 계속 데이터를 cmra_buf에 저장한다.

저장하다가 보내고자하는 buffer size 까지 다 차면 netconn_write 를 호출하여 데이터를 보낸 후 

다시 cmra_buf[0]부터 채워 나간다.

 

채우다가 jpeg의 마지막 패킷을 알리는 0xff 0xd9가 더이상 데이터를 저장하지 않고 0xff 4개와 사진 데이터 길이를 추가로 저장 후 tcp로 전송한다.

 

그리고 pitcutre_flag는 false가 되어 함수는 종료 된다.