cancel
Showing results for 
Search instead for 
Did you mean: 

Changing Hue, Saturation, and Brightness on SMT32H747I-Disco Board, Application Code from Model Zoo

rt_ecyhg1
Associate III

Hi @Julian E. , I want to change the Hue, Saturation, and Brightness of the B-Cams OMV camera all at once while running the image classification application code from the Model Zoo. However, when I run my code, only the last value gets captured and reflected on the board. For example, if my code is 

 

void Camera_StartNewFrameAcquisition(AppConfig_TypeDef *App_Config_Ptr)
{ 
  App_Config_Ptr->new_frame_ready = 0;
  Camera_Set_HueDegree(App_Config_Ptr->mirror_flip);
  Camera_Set_Saturation(App_Config_Ptr->mirror_flip);
  Camera_Set_Brightness(App_Config_Ptr->mirror_flip);

  /***Resume the camera capture in NOMINAL mode****/
  BSP_CAMERA_Resume(0);

}

 

Only the Brightness gets changed and not Hue or Saturation. I've made changes to the apps_camera.c only as shown above. I've also included a copy of the version I'm using.  I would really really appreciate if anyone can guide me on how to change all three features at once. I am very desperate.

1 ACCEPTED SOLUTION

Accepted Solutions

Hello @rt_ecyhg1,

 

Yes, but you probably need to edit the 2 other functions for hue and saturation to make sure that they are not editing the same registers. 

The important part in the example correction is the end of the function where we added bit masking. Here is a video that explains it.

https://youtu.be/Ew2QnDeTCCE?feature=shared 

 

The idea is that if you use the brightness function and set a value in OV5640_SDE_CTRL8, the other functions that also edit this register must use bit masking to edit some bits without changing the bits already changed with the brightness function.

 

Make sure to use the datasheet of the camera that explains which bits and registers are being edited to apply the good masks.

OV5640_datasheet.pdf

 

I am not very knowledgeable about that kind of things but if you can probably ask for help in another forum board like the STM32 MCUs Embedded software - STMicroelectronics Community to receive help creating your masks.

 

Have a good day,

Julian

 

 

 


In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.

View solution in original post

7 REPLIES 7
rt_ecyhg1
Associate III

I'm really desperate to make it work, please if anyone has any solution to try please share it

Hello @rt_ecyhg1 ,

 

I have asked internally, I am waiting for answers.

I'll update you as soon as I know more.

 

Have a good day,

Julian


In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.

Hi Julian.

Thank you so much.

Hello @rt_ecyhg1 ,

 

After some digging, we found out that it is the driver of the ov5640 camera that are the issue.

They edit the register without using masks, so for example when using the brightness and saturation function, the last one prevails.

 

The functions you use to edit the brightness, saturation and hue ultimately call the drivers functions in Drivers\BSP\Components\ov5640\ov5640.c

 

If we look at the drivers function for brightness and saturation, you can see that they both edit the OV5640_SDE_CTRL0 and OV5640_SDE_CTRL8 registers:

int32_t OV5640_SetBrightness(OV5640_Object_t *pObj, int32_t Level)
{
  int32_t ret;
  const uint8_t brightness_level[] = {0x40U, 0x30U, 0x20U, 0x10U, 0x00U, 0x10U, 0x20U, 0x30U, 0x40U};
  uint8_t tmp;
 
  tmp = 0xFF;
  ret = ov5640_write_reg(&pObj->Ctx, OV5640_ISP_CONTROL01, &tmp, 1);
 
  if (ret == OV5640_OK)
  {
    tmp = brightness_level[Level + 4];
    ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL7, &tmp, 1);
  }
  if (ret == OV5640_OK)
  {
    tmp = 0x04;
    ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL0, &tmp, 1);
  }
 
  if (ret == OV5640_OK)
  {
    if (Level < 0)
    {
      tmp = 0x01;
      if (ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL8, &tmp, 1) != OV5640_OK)
      {
        ret = OV5640_ERROR;
      }
    }
    else
    {
      tmp = 0x09;
      if (ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL8, &tmp, 1) != OV5640_OK)
      {
        ret = OV5640_ERROR;
      }
    }
  }
 
  return ret;
}
 
int32_t OV5640_SetSaturation(OV5640_Object_t *pObj, int32_t Level)
{
  int32_t ret;
  const uint8_t saturation_level[] = {0x00U, 0x10U, 0x20U, 0x30U, 0x80U, 0x70U, 0x60U, 0x50U, 0x40U};
  uint8_t tmp;
 
  tmp = 0xFF;
  ret = ov5640_write_reg(&pObj->Ctx, OV5640_ISP_CONTROL01, &tmp, 1);
 
  if (ret == OV5640_OK)
  {
    tmp = saturation_level[Level + 4];
    ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL3, &tmp, 1);
  }
  if (ret == OV5640_OK)
  {
    ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL4, &tmp, 1);
  }
  if (ret == OV5640_OK)
  {
    tmp = 0x02;
    ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL0, &tmp, 1);
  }
 
  if (ret == OV5640_OK)
  {
    tmp = 0x41;
    ret = ov5640_write_reg(&pObj->Ctx, OV5640_SDE_CTRL8, &tmp, 1);
  }
 
  if (ret != OV5640_OK)
  {
    ret = OV5640_ERROR;
  }
 
  return ret;
}

 

Here is the doc of the camera from sparkfun:

JulianE_1-1742467249205.png

OV5640_datasheet.pdf

OV5640_SetBrightness: write 0x01 / 0x09

OV5640_SetSaturation: write 0x41

 

The call to OV5640_SetSaturation therefore overwrites bit[3], the sign of the contrast value, to zero.

 

The correct way to do it should be something like this (it is reformatted, but the important point is the masks):

int32_t OV5640_SetBrightness(OV5640_Object_t *pObj, int32_t Level)
{
        int32_t ret = OV5640_OK;
        const uint8_t brightness_level[] =
            { 0x40U, 0x30U, 0x20U, 0x10U, 0x00U, 0x10U, 0x20U, 0x30U, 0x40U };
        uint8_t tmp;
        uint8_t val = 0;
        ov5640_ctx_t *ctx = &pObj->Ctx;

        if (pObj == NULL)
                return OV5640_ERROR;

        /* Ensure Level is within valid range (-4 to +4) */
        if ((Level < -4) || (Level > 4))
                return OV5640_ERROR;

        tmp = 0xFF;
        ret = ov5640_write_reg(ctx, OV5640_ISP_CONTROL01, &tmp, 1);
        if (ret != OV5640_OK)
                return ret;

        /* Set brightness level value */
        tmp = brightness_level[Level + 4];
        ret = ov5640_write_reg(ctx, OV5640_SDE_CTRL7, &tmp, 1);
        if (ret != OV5640_OK)
                return ret;

        /* Enable manual brightness control */
        ret = ov5640_read_reg(ctx, OV5640_SDE_CTRL0, &val, 1);
        if (ret != OV5640_OK)
                return ret;

        val |= 0x04U;

        ret = ov5640_write_reg(ctx, OV5640_SDE_CTRL0, &val, 1);
        if (ret != OV5640_OK)
                return ret;

        /* Configure brightness direction based on Level sign */
        ret = ov5640_read_reg(ctx, OV5640_SDE_CTRL8, &val, 1);
        if (ret != OV5640_OK)
                return ret;

        if (Level < 0)
                val |= 0x80;
        else
                val &= ~0x80;

        ret = ov5640_write_reg(ctx, OV5640_SDE_CTRL8, &val, 1);

        return ret;
}

 

We are looking internally who to contact to correct these, but it will most likely take time.

 

Additionally, in your app_camera.c, you should not use your function in each frame: Camera_StartNewFrameAcquisition but in the Camera_Init function (see line 81 to 83 in the example below): 

void Camera_Init(AppConfig_TypeDef *App_Config_Ptr)
{


  __HAL_RCC_MDMA_CLK_ENABLE();

  /* Init MDMA for camera line buffer to frame buffer copy */
  hmdma.Instance = MDMA_Channel0;
  hmdma.Init.Request                  = MDMA_REQUEST_SW;
  hmdma.Init.TransferTriggerMode      = MDMA_BLOCK_TRANSFER;
  hmdma.Init.Priority                 = MDMA_PRIORITY_HIGH;
  hmdma.Init.Endianness               = MDMA_LITTLE_ENDIANNESS_PRESERVE;
  hmdma.Init.SourceInc                = MDMA_SRC_INC_WORD;
  hmdma.Init.DestinationInc           = MDMA_DEST_INC_WORD;
  hmdma.Init.SourceDataSize           = MDMA_SRC_DATASIZE_WORD;
  hmdma.Init.DestDataSize             = MDMA_DEST_DATASIZE_WORD;
  hmdma.Init.DataAlignment            = MDMA_DATAALIGN_PACKENABLE;
  hmdma.Init.SourceBurst              = MDMA_DEST_BURST_SINGLE;
  hmdma.Init.DestBurst                = MDMA_DEST_BURST_16BEATS;
  hmdma.Init.BufferTransferLength     = 128;
  hmdma.Init.SourceBlockAddressOffset = 0;
  hmdma.Init.DestBlockAddressOffset   = 0;

#if ASPECT_RATIO_MODE == ASPECT_RATIO_PADDING
  uint8_t *camera_capture_buffer = App_Config_Ptr->camera_capture_buffer_no_borders;
#else
  uint8_t *camera_capture_buffer = App_Config_Ptr->camera_capture_buffer;
#endif
  if (HAL_MDMA_Init(&hmdma) != HAL_OK)
  {
    Error_Handler();
  }

  /* NVIC configuration for MDMA transfer complete interrupt */
  HAL_NVIC_SetPriority(MDMA_IRQn, 15U, 0);
  HAL_NVIC_EnableIRQ(MDMA_IRQn);

  /* Reset and power down camera to be sure camera is Off prior start */
  BSP_CAMERA_PwrDown(0);
  
  /* Wait delay */ 
  HAL_Delay(200);
  
  /* Initialize the Camera */
  if (BSP_CAMERA_Init(0, CAMERA_RESOLUTION, CAMERA_PF_RGB565) != BSP_ERROR_NONE)
  {
    Error_Handler();
  }





#ifdef TEST_MODE
  Camera_Enable_TestBar_Mode();
#endif
  
  /* Modify DMA2_Stream3 configuration so to increase its priority and its 
  memory transfer size: purpose is to avoid DCMI overflow */
  MODIFY_REG(DMA2_Stream3->CR, DMA_SxCR_PL, DMA_PRIORITY_VERY_HIGH);
  MODIFY_REG(DMA2_Stream3->CR, DMA_SxCR_MBURST, DMA_MBURST_INC4);
  
  /* Set OV5640 pixel clock (PCLK) to 48MHz and get a 30fps camera frame rate */
  if (Camera_Ctx[0].CameraId == OV5640_ID)
  {
    OV5640_Object_t *pObj = Camera_CompObj;
    // original tmp vlaue is tmp = 0xC0; /* Bits[7:0]: PLL multiplier */ for 30fps.
    // can try to change it to  15fps (0x60) so the board can access the dram faster
    uint8_t tmp = 0xC0; /* Bits[7:0]: PLL multiplier */
    if (ov5640_write_reg(&pObj->Ctx, OV5640_SC_PLL_CONTRL2,  &tmp, 1) != OV5640_OK)
    {
      while(1);
    }


  }

  /* Set camera mirror / flip configuration */
  Camera_Set_MirrorFlip(App_Config_Ptr->mirror_flip);

  Camera_Set_HueDegree(-4);
  Camera_Set_Saturation(0);
  Camera_Set_Brightness(-4);
  

  HAL_Delay(100);

#if ASPECT_RATIO_MODE == ASPECT_RATIO_CROP
  /* Center-crop the 320x240 frame to 240x240 */
  const uint32_t x0 = (CAM_RES_WIDTH - CAM_RES_HEIGHT) / 2;
  const uint32_t y0 = 0;
  
  /* Note: 1 px every 2 DCMI_PXCLK (8-bit interface in RGB565) */
  HAL_DCMI_ConfigCrop(&hcamera_dcmi,
                      x0 * 2,
                      y0,
                      CAM_RES_WIDTH * 2 - 1,
                      CAM_RES_HEIGHT - 1);
  
  HAL_DCMI_EnableCrop(&hcamera_dcmi);
  /* Wait for the camera initialization after HW reset */ 
  HAL_Delay(200);
#endif
  
  /*
  * Start the Camera Capture
  * Using intermediate line buffer in D2-AHB domain to support high pixel clocks.
  */
  if (HAL_DCMIEx_Start_DMA_MDMA(&hcamera_dcmi, CAMERA_MODE_CONTINUOUS,
                                camera_capture_buffer,
                                CAM_LINE_SIZE, CAM_RES_HEIGHT) != HAL_OK)
  {
    while(1);
  }
  
  /* Wait for the camera initialization after HW reset */
  HAL_Delay(200);
}

 

Have a good day

Julian


In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.

Hi @Julian E.,

Thank you for getting back to me regarding the issue, I really appreciate it. If I wanted to use all three settings could I use the corrected function you provided above? 

Thank you for your help! 

Hello @rt_ecyhg1,

 

Yes, but you probably need to edit the 2 other functions for hue and saturation to make sure that they are not editing the same registers. 

The important part in the example correction is the end of the function where we added bit masking. Here is a video that explains it.

https://youtu.be/Ew2QnDeTCCE?feature=shared 

 

The idea is that if you use the brightness function and set a value in OV5640_SDE_CTRL8, the other functions that also edit this register must use bit masking to edit some bits without changing the bits already changed with the brightness function.

 

Make sure to use the datasheet of the camera that explains which bits and registers are being edited to apply the good masks.

OV5640_datasheet.pdf

 

I am not very knowledgeable about that kind of things but if you can probably ask for help in another forum board like the STM32 MCUs Embedded software - STMicroelectronics Community to receive help creating your masks.

 

Have a good day,

Julian

 

 

 


In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.

Hi @Julian E. ,

 

Thank you for the clarification!