본문 바로가기

Firmware/stm32

OV5642_LWIP_RTOS Project -2(Camera Interface 구현 )

Project에 사용 된 OV5642 는 DCMI or MIPI Interface가 아닌 SPI, I2C ineterface를 통해 사진데이터를 출력한다.

 

https://www.devicemart.co.kr/goods/view?no=1383721

(https://www.arducam.com/downloads/shields/ArduCAM_Camera_Shield_Software_Application_Note.pdf)

 

먼저 카메라의 SPI  하기 위한 Timing Diagram이다.

코드 구현

uint8_t bus_write (int address, int value)
{
  
  GPIOC->BSRR = CS_Pin << 16;
  
  HAL_SPI_Transmit (&hspi3, (uint8_t*) &address, 1, 1000);   //Command phase
  HAL_SPI_Transmit (&hspi3, (uint8_t*) &value, 1, 1000);     //Data phase
  
  GPIOC->BSRR = CS_Pin;
  
  return 1;
  
}

void write_reg (uint8_t addr, uint8_t data)
{
  
  bus_write (addr | 0x80, data);   // Write address = address | 0x80
  
}

 SPI는 통신을 통해 데이터를 Write 할려면, CS Pin을 내려준 다음 Address에 MSB에 1로 set 해야만

데이터를 쓸 수 있다. write_reg함수는 or연산을 통해 MSB에 1로 set해주고 bus_write 는 실제 SPI 통신한다.

 

아래 파형은 0x00에 0x55 값을 넣었을 시 출력 되는 파형이다.

 

SPI Read timing

실제 코드 구현

uint8_t bus_read (int address)
{
  uint8_t value;
  int dummy = 0x00;
  
  GPIOC->BSRR = CS_Pin << 16;
  
  HAL_SPI_Transmit (&hspi3, (uint8_t*) &address, 1, 1000); //Command Phase
  
  HAL_SPI_TransmitReceive (&hspi3, (uint8_t*) &dummy, &value, 1, 1000); // Data Phase
  
  GPIOC->BSRR = CS_Pin;
  
  return value;
}

uint8_t read_reg (uint8_t addr)
{
  uint8_t data;
  
  data = bus_read (addr & 0x7F);
  
  return data;
}

SPI 통신을 통해 데이터를 Read 할려면 Write와 반대로 MSB를 0으로 set 해야 한다.

read_reg 함수는 arg 통해 받아온 address를 and 연산을 통해 MSB를 0으로 set 한다.

bus_read는 실제 SPI 통신을 통해 데이터를 읽기 위해 구현한 함수이다.

 

아래 파형은 Address 에 0x55를 쓴 다음  read_reg를 호출하여 읽어 오는 파형이다.

 


I2C 타이밍

코드 구현

void wrSensorReg16_8 (uint16_t tx_addr, unsigned char rx_buf)
{
  
  if(HAL_I2C_Mem_Write (&hi2c1, 0x78, tx_addr, 2, &rx_buf, 1, 1000) != HAL_OK)
  {
#ifdef DEBUG
    printf("I2c Write Problem \n\r");
#endif
    
  }
  HAL_Delay (1);
  
}

void rdSensorReg16_8 (uint16_t tx_addr, uint8_t* rx_buf)
{
  
  if((HAL_I2C_Mem_Read(&hi2c1, 0x78, tx_addr, 2, rx_buf, 1, 1000))!= HAL_OK)
  {
#ifdef DEBUG
    printf("I2c Read Problem \n\r");
#endif
  }
  HAL_Delay (1);
  
}

I2C는 SPI와 다르게 MSB가 아닌 LSB값이 0이냐 1이냐를 확인하여  Read Address 인지 Write Address인지 판단한다.

 

앞서 SPI는 코드에서 and or 연산을 통해 set 해주었지만 I2C는 따로 set 해줄 필요 없이 I2C API 함수 안에서 자동으로 set 한다.

 

실제 HAL_I2C_Mem_Read(&hi2c1,0x78,tx_addr,2, rx_buf,1,1000); 실행 후 찍은 파형

앞서 올린 데이터시트 타이밍대로 자동으로 0x79가 되어 데이터 값을 읽어 온다.

 

다만 주의할 점은 Cortex M4로 할 경우 i2c read or Write 후 에는 Delay를 줘야 Camera가 i2c 처리할

시간을 줘야한다.

 

실제 Delay를 추가한 코드 

int wrSensorRegs16_8 (const struct sensor_reg reglist[])
{
  
  unsigned int reg_addr = 0;
  unsigned char reg_val = 0;
  const struct sensor_reg *next = reglist;
  
  while ((reg_addr != 0xffff) | (reg_val != 0xff))
  {
    reg_addr = next->reg;
    reg_val = next->val;
    
    if((HAL_I2C_Mem_Write(&hi2c1, 0x78, reg_addr, 2, &reg_val, 1, 1000))!= HAL_OK)
    {
#ifdef DEBUG
      printf("I2c Write Problem \n\r");
#endif
    }
    next++;
    
    HAL_Delay (1); //없을 시 log 창에 I2c Write Problem 문구를 볼 수 있다.
    
  }
  return 1;
  
}