cancel
Showing results for 
Search instead for 
Did you mean: 

IMX335_ReadID fails to read ID value correctly

VitorWagner
Associate II

Hello ST Community!

I've been trying to recreate the DCMIPP_ContinuousMode example with STM32CubeIDE, but have been running into some issues with the IMX335_Probe function, the ID read by the I2C bus never matches the expected define IMX335_CHIP_ID. The original example runs completely fine in the STM32N6570-DK.

- AXISRAM3 (0x34200000) is being used as the address for the DCMIPP CSI Pipe.
- ISP Middleware does not return any errors in initialization.
- All files regarding IMX335 registers and functions match with the original examples. Same for all the BSP drivers.
- RIF has been configured for all peripherals involved.
- AXISRAM3 has been enabled in the CubeMX configurations, and it's clock has also been enabled.

static void IMX335_Probe(uint32_t Resolution, uint32_t PixelFormat)
{
  IMX335_IO_t              IOCtx;
  uint32_t                 id;

  /* Configure the camera driver */
  IOCtx.Address     = CAMERA_IMX335_ADDRESS;
  IOCtx.Init        = BSP_I2C1_Init;
  IOCtx.DeInit      = BSP_I2C1_DeInit;
  IOCtx.ReadReg     = BSP_I2C1_ReadReg16;
  IOCtx.WriteReg    = BSP_I2C1_WriteReg16;
  IOCtx.GetTick     = BSP_GetTick;

  if (IMX335_RegisterBusIO(&IMX335Obj, &IOCtx) != IMX335_OK)
  {
    Error_Handler();
  }
  else if (IMX335_ReadID(&IMX335Obj, &id) != IMX335_OK)
  {
    Error_Handler();
  }
  else
  {
    if (id != (uint32_t) IMX335_CHIP_ID)
    {
      Error_Handler();
    }
    else
    {
      if (IMX335_Init(&IMX335Obj, Resolution, PixelFormat) != IMX335_OK)
      {
        Error_Handler();
      }
      else if(IMX335_SetFrequency(&IMX335Obj, IMX335_INCK_24MHZ)!= IMX335_OK)
      {
        Error_Handler();
      }
      else
      {
        return;
      }
    }
  }
}


In debug, the execution runs as follows:

  IOCtx.Address     = CAMERA_IMX335_ADDRESS;
  IOCtx.Init        = BSP_I2C1_Init;
  IOCtx.DeInit      = BSP_I2C1_DeInit;
  IOCtx.ReadReg     = BSP_I2C1_ReadReg16;
  IOCtx.WriteReg    = BSP_I2C1_WriteReg16;
  IOCtx.GetTick     = BSP_GetTick;


The IMX335_IO_t temporary variable for the IMX335Obj records the addresses of all the BSP functions correctly, confirmed by running a dissasembly.

  if (IMX335_RegisterBusIO(&IMX335Obj, &IOCtx) != IMX335_OK)
  {
    Error_Handler();
  }


IMX335_RegisterBusIO records the correct addresses into the IMX335Obj from the temporary IMX335_IO_t variable, and BSP_I2C1_Init does not return any errors.

  else if (IMX335_ReadID(&IMX335Obj, &id) != IMX335_OK)
  {
    Error_Handler();
  }


Now here is where the main issue occurs, again, the pointer in the IMX335Obj is used to initialize I2C, which does not return any errors.

imx335_read_reg(&pObj->Ctx, IMX335_REG_ID, &tmp, 1)


The read register function is then called, which is actually just a wrapper with a return that points to another function.

static int32_t IMX335_ReadRegWrap(void *handle, uint16_t Reg, uint8_t* pData, uint16_t Length)
{
  IMX335_Object_t *pObj = (IMX335_Object_t *)handle;

  return pObj->IO.ReadReg(pObj->IO.Address, Reg, pData, Length);
}


Finally, the return of IMX335_ReadRegWrap calls a BSP Wrapper of I2C functions:

int32_t BSP_I2C1_ReadReg16(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length)
{
  int32_t ret;
#if defined(BSP_USE_CMSIS_OS)
  /* Get semaphore to prevent multiple I2C access */
  osSemaphoreWait(BspI2cSemaphore, osWaitForever);
#endif /* BSP_USE_CMSIS_OS */
  if (I2C1_ReadReg(DevAddr, Reg, I2C_MEMADD_SIZE_16BIT, pData, Length) == 0)
  {
    ret = BSP_ERROR_NONE;
  }
  else
  {
    if (HAL_I2C_GetError(&hbus_i2c1) == HAL_I2C_ERROR_AF)
    {
      ret = BSP_ERROR_BUS_ACKNOWLEDGE_FAILURE;
    }
    else
    {
      ret = BSP_ERROR_PERIPH_FAILURE;
    }
  }
#if defined(BSP_USE_CMSIS_OS)
  /* Release semaphore to prevent multiple I2C access */
  osSemaphoreRelease(BspI2cSemaphore);
#endif /* BSP_USE_CMSIS_OS */
  return ret;
}


No error is returned in the HAL_I2C_Mem_Read which is called by I2C1_ReadReg, and the recieved value is '3' instead of 0, making the decimal equivalent of the ID 51 instead of 0.

That said, I could just force the ReadID to be 0, but obviously that would just result in the camera not working.

Is there another parameter related to security I should worry about when using the I2C apart from the RIF? All of the registers and values returned point to this being a security related issue, but at this point I don't know what else to enable.

If anyone has been able to recreate the example in a STM32CubeIDE enviroment I would be grateful if you could share with me your project.


1 ACCEPTED SOLUTION

Accepted Solutions
VitorWagner
Associate II

Hello once again,

By discussing with ST, the issue has been solved. For anyone that wants to recreate the DCMIPP Continuous Mode, here are some things to keep in mind:

 

The NRST and ENABLE pins that connect the STM32N6570-DK to the MB1854B board are not configured by default, so you need to configure the pins as GPIO Outputs and to the context of your project. Keep in mind that NRST is active low as well.

VitorWagner_0-1761567745473.png

When using the DCMIPP with CSI, you won't actually see it in the clock tree, but the CSI requires a correct clock configuration as well, which is connected to IC18, you should configure it's frequency to, at maximum 20MHz, if I'm not mistaken.

You can assure your IC18 configuration is correct by looking at the hal_msp.c file after CubeMX code generation.

void HAL_DCMIPP_MspInit(DCMIPP_HandleTypeDef* hdcmipp)
{
  RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
  if(hdcmipp->Instance==DCMIPP)
  {
    /* USER CODE BEGIN DCMIPP_MspInit 0 */

    /* USER CODE END DCMIPP_MspInit 0 */

  /** Initializes the peripherals clock
  */
    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_DCMIPP|RCC_PERIPHCLK_CSI;
    PeriphClkInitStruct.DcmippClockSelection = RCC_DCMIPPCLKSOURCE_IC17;
    PeriphClkInitStruct.ICSelection[RCC_IC17].ClockSelection = RCC_ICCLKSOURCE_PLL3;
    PeriphClkInitStruct.ICSelection[RCC_IC17].ClockDivider = 4;
    PeriphClkInitStruct.ICSelection[RCC_IC18].ClockSelection = RCC_ICCLKSOURCE_PLL4;
    PeriphClkInitStruct.ICSelection[RCC_IC18].ClockDivider = 80;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
    {
      Error_Handler();
    }

    /* Peripheral clock enable */
    __HAL_RCC_DCMIPP_CLK_ENABLE();
    __HAL_RCC_CSI_CLK_ENABLE();
    __HAL_RCC_CSI_FORCE_RESET();
    __HAL_RCC_CSI_RELEASE_RESET();
    /* DCMIPP interrupt Init */
    HAL_NVIC_SetPriority(DCMIPP_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(DCMIPP_IRQn);
    HAL_NVIC_SetPriority(CSI_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(CSI_IRQn);
    /* USER CODE BEGIN DCMIPP_MspInit 1 */

    /* USER CODE END DCMIPP_MspInit 1 */

  }

}


If you have correctly configured the CSI clock and enabled the camera module, your IMX335_ReadID function should return the correct ID of the camera, or you can just use your own functions with I2C to read the ID as well.

Most of the other specifications are not hard to figure out, but in order to keep it short, I only included my main issue here, if anyone reading encounters other issues by trying to recreate the project, I most likely have found them and solved them in my project, so i'd be happy to lend a hand.

Thanks to ST for the guidance! :D

View solution in original post

5 REPLIES 5
VitorWagner
Associate II

Update, I have also confirmed that the value in the physical register of I2C1 differs in my application and the original example, by reading the value from 0x50005424 onwards (I2C1 base address + RX offset).

Billy OWEN
ST Employee

Hi @VitorWagner 

 

This post has been escalated to the ST Online Support Team for additional assistance.  We'll contact you directly.

 

Regards,

Billy

VitorWagner
Associate II

Hello once again,

By discussing with ST, the issue has been solved. For anyone that wants to recreate the DCMIPP Continuous Mode, here are some things to keep in mind:

 

The NRST and ENABLE pins that connect the STM32N6570-DK to the MB1854B board are not configured by default, so you need to configure the pins as GPIO Outputs and to the context of your project. Keep in mind that NRST is active low as well.

VitorWagner_0-1761567745473.png

When using the DCMIPP with CSI, you won't actually see it in the clock tree, but the CSI requires a correct clock configuration as well, which is connected to IC18, you should configure it's frequency to, at maximum 20MHz, if I'm not mistaken.

You can assure your IC18 configuration is correct by looking at the hal_msp.c file after CubeMX code generation.

void HAL_DCMIPP_MspInit(DCMIPP_HandleTypeDef* hdcmipp)
{
  RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
  if(hdcmipp->Instance==DCMIPP)
  {
    /* USER CODE BEGIN DCMIPP_MspInit 0 */

    /* USER CODE END DCMIPP_MspInit 0 */

  /** Initializes the peripherals clock
  */
    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_DCMIPP|RCC_PERIPHCLK_CSI;
    PeriphClkInitStruct.DcmippClockSelection = RCC_DCMIPPCLKSOURCE_IC17;
    PeriphClkInitStruct.ICSelection[RCC_IC17].ClockSelection = RCC_ICCLKSOURCE_PLL3;
    PeriphClkInitStruct.ICSelection[RCC_IC17].ClockDivider = 4;
    PeriphClkInitStruct.ICSelection[RCC_IC18].ClockSelection = RCC_ICCLKSOURCE_PLL4;
    PeriphClkInitStruct.ICSelection[RCC_IC18].ClockDivider = 80;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
    {
      Error_Handler();
    }

    /* Peripheral clock enable */
    __HAL_RCC_DCMIPP_CLK_ENABLE();
    __HAL_RCC_CSI_CLK_ENABLE();
    __HAL_RCC_CSI_FORCE_RESET();
    __HAL_RCC_CSI_RELEASE_RESET();
    /* DCMIPP interrupt Init */
    HAL_NVIC_SetPriority(DCMIPP_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(DCMIPP_IRQn);
    HAL_NVIC_SetPriority(CSI_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(CSI_IRQn);
    /* USER CODE BEGIN DCMIPP_MspInit 1 */

    /* USER CODE END DCMIPP_MspInit 1 */

  }

}


If you have correctly configured the CSI clock and enabled the camera module, your IMX335_ReadID function should return the correct ID of the camera, or you can just use your own functions with I2C to read the ID as well.

Most of the other specifications are not hard to figure out, but in order to keep it short, I only included my main issue here, if anyone reading encounters other issues by trying to recreate the project, I most likely have found them and solved them in my project, so i'd be happy to lend a hand.

Thanks to ST for the guidance! :D

Dear @VitorWagner,

We are currently undertaking an effort to replicate the DCMIPP_Continuous Mode example, as found in the STM32N6 example section. Our objective is to achieve live camera feed from the IMX335 camera onto the display, as demonstrated in the example. While we have successfully displayed images on the display, we are encountering difficulties in establishing a connection with the camera and displaying the live feed. We would greatly appreciate any guidance you could offer on implementing the I2C communication and ensuring a fully functional system.

Hello @JaiGanesh,

By displaying images on the display you probably mean using HAL_LTDC_SetAddress() to an array of a custom image or something of the sort right? If so that's a great first step.

While I cannot go into great details of my application, following this checklist should help:

- Configure the CSI-2 frequency to 20MHz

- If you are using CubeMX, check if your NRST and ENABLE pins of the camera are in the right context (FSBL or Application)

- Ensure your Pixel Pipe Patch matches the resolution you are trying to display, by default if you are going for 800 width, it should be configured to 1600.

- Ensure your downsize configuration also matches the resolution, if you search for the downsize section in the STM32N657xx manual you can find the formula, but if you follow the values in the example, you will end up with a downsize of 2592x1944 (original camera resolution) to 800x480.

- Be absolutely sure your flat cable is correctly connected to the camera module, I myself had some issues with it's delicate pins, so use a multimeter or something of the sort to make sure your pins from the board are connected to the camera module.

- Use the BSP drivers located in the example, even though you could recreate the example without them, it makes the journey alot easier, and you can also just copy and paste the example if your enviroment is correctly configured for a quick test as well.

- Enable your SRAMs if you are using the same memory address as the example, 0x34200000 if I am not mistaken, by default their enable register comes disabled, and you won't be able to read or write in that address if the memory is not enabled.

- Make sure your peripherals are configured in the RIF section, so they have privelege when accessing memory sections, especially the CSI and DCMIPP, if you are using the LTDC with the address directly configured to that memory section, you might have to enable it for the LTDC as well, I am not 100% sure.

Those are the points I can remember from the top of my head, feel free to send me DMs, some people have already contacted me regarding that example so I might make a forum post sharing a repo if I am allowed to do so, eitherway, if your problems are connected to simply recreating the example, I can lend a hand once I have some free time.