cancel
Showing results for 
Search instead for 
Did you mean: 

VL53L5CX _start_ranging() fails with 255 error

ALohr.1
Associate II

Hi all,

For the last several days I have been battling this API for the VL53L5CX and finally reached the point where the initialisation passes every time. I proceed to set some of the configuration parameters (mostly resetting to the default values suggested in the application note). These functions also return status = 0.

Then I start a ranging session. The problem is that checking the status/error output shows me that the function is failing with a 255 error. Further investigation with a debugger has yielded that the final if() check in the function sets the status too 255. This means that the data_read_size check has failed. see screenshot below for reference.

0693W00000aIQYxQAO.pngI should note that, every single function and I2C transaction passes with no error. In other words, status = 0, the whole time, until this if statement. It is the physical value of the variables that does not match. Has anyone else had this error? or can offer some suggestions as to what is happening and how to fix it?

Thanks

13 REPLIES 13
kappa182
Associate II

Hi 

i have similar issue using driver VL53L5CX_ULD_driver_2.0.0 on my STM32WB5MM. 

I disabled all outputs except "Distance mm" and "Target status"; when i read temp_buffer using vl53l5cx_dci_read_data i have  temp_buffer[0x8] == 56 but data_read_size == 60 and sensor doesn't work.

Can someone help me?

Thanks in advance

Davide

you need 'number of valid targets' as well. 

To determine a range, the logic is:

If (the number of targets is greater than 0, AND the RangeStatus is 5, 6, 9 or sometimes 12) then use the range for that zone. 

But to do this, you do need 'number of valid targets'.

At least I think so. I replied just yesterday to a similar question, but I have not heard back if it solved the issue. 

My assumption is that we never checked this case, as we knew it was invalid. 

- john


If this or any post solves your issue, please mark them as 'Accept as Solution' It really helps. And if you notice anything wrong do not hesitate to 'Report Inappropriate Content'. Someone will review it.
kappa182
Associate II

I John 

thanks for your reply

i'm new using VL53L5CX and i would start a simple ranging example.

I have setted VL53L5CX_NB_TARGET_PER_ZONE == 1 and i'm using the the example in the folder.

The init function is ok but i'm unable to start ranging. Below our schematic and my code

kappa182_1-1725025594130.png

uint8_t vl53l5cx_init(I2C_HandleTypeDef *p_i2c)
{
  uint8_t tmp;
  uint8_t pipe_ctrl[] = { VL53L5CX_NB_TARGET_PER_ZONE, 0x00, 0x01, 0x00 };
  uint32_t single_range = 0x01;
  uint8_t isAlive;
  uint8_t status = VL53L5CX_STATUS_OK;

//  Wake-up: The device is set in HP idle (high power), waiting for instructions.
//  • Sleep: The device is set in LP idle (low power), the low power state. The device cannot be used until set in
//  wake-up mode. This mode retains the firmware and the configuration.

//  vl53l5cx_set_power_mode(VL53L5CX_Configuration *p_dev,
//  				uint8_t power_mode)

  g_dev.platform.address = VL53L5CX_DEFAULT_I2C_ADDRESS;

  g_dev.platform.serif = p_i2c;

  VL53L5CX_Reset_Sensor();

  status = vl53l5cx_is_alive(&g_dev, &isAlive);

  if(!isAlive)
  {
    printf("VL53L5CXV0 not detected at requested address (0x%x)\n",
	   g_dev.platform.address);
    return 255;
  }
  printf("Sensor initializing, please wait few seconds\n");

  g_dev.default_xtalk = (uint8_t*)VL53L5CX_DEFAULT_XTALK;
  g_dev.default_configuration = (uint8_t*)VL53L5CX_DEFAULT_CONFIGURATION;
  g_dev.is_auto_stop_enabled = (uint8_t)0x0;

  /* SW reboot sequence */
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x7fff, 0x00);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x0009, 0x04);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x000F, 0x40);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x000A, 0x03);
  status |= VL53L5CX_RdByte(&(g_dev.platform), 0x7FFF, &tmp);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x000C, 0x01);

  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x0101, 0x00);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x0102, 0x00);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x010A, 0x01);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x4002, 0x01);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x4002, 0x00);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x010A, 0x03);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x0103, 0x01);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x000C, 0x00);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x000F, 0x43);
  status |= VL53L5CX_WaitMs(&(g_dev.platform), 1);

  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x000F, 0x40);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x000A, 0x01);
  status |= VL53L5CX_WaitMs(&(g_dev.platform), 100);

  /* Wait for sensor booted (several ms required to get sensor ready ) */
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x7fff, 0x00);
  status |= _vl53l5cx_poll_for_answer(&g_dev, 1, 0, 0x06, 0xff, 1);
  if(status != (uint8_t)0)
  {
    goto exit;
  }

  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x000E, 0x01);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x7fff, 0x02);

  /* Enable FW access */
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x03, 0x0D);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x7fff, 0x01);
  status |= _vl53l5cx_poll_for_answer(&g_dev, 1, 0, 0x21, 0x10, 0x10);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x7fff, 0x00);

  /* Enable host access to GO1 */
  status |= VL53L5CX_RdByte(&(g_dev.platform), 0x7fff, &tmp);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x0C, 0x01);

  /* Power ON status */
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x7fff, 0x00);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x101, 0x00);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x102, 0x00);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x010A, 0x01);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x4002, 0x01);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x4002, 0x00);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x010A, 0x03);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x103, 0x01);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x400F, 0x00);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x21A, 0x43);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x21A, 0x03);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x21A, 0x01);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x21A, 0x00);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x219, 0x00);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x21B, 0x00);

  /* Wake up MCU */
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x7fff, 0x00);
  status |= VL53L5CX_RdByte(&(g_dev.platform), 0x7fff, &tmp);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x0C, 0x00);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x7fff, 0x01);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x20, 0x07);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x20, 0x06);

  /* Download FW into VL53L5 */
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x7fff, 0x09);
  status |= VL53L5CX_WrMulti(&(g_dev.platform), 0,
			     (uint8_t*)&VL53L5CX_FIRMWARE[0], 0x8000);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x7fff, 0x0a);
  status |= VL53L5CX_WrMulti(&(g_dev.platform), 0,
			     (uint8_t*)&VL53L5CX_FIRMWARE[0x8000], 0x8000);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x7fff, 0x0b);
  status |= VL53L5CX_WrMulti(&(g_dev.platform), 0,
			     (uint8_t*)&VL53L5CX_FIRMWARE[0x10000], 0x5000);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x7fff, 0x01);

  /* Check if FW correctly downloaded */
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x7fff, 0x02);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x03, 0x0D);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x7fff, 0x01);
  status |= _vl53l5cx_poll_for_answer(&g_dev, 1, 0, 0x21, 0x10, 0x10);
  if(status != (uint8_t)0)
  {
    goto exit;
  }

  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x7fff, 0x00);
  status |= VL53L5CX_RdByte(&(g_dev.platform), 0x7fff, &tmp);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x0C, 0x01);

  /* Reset MCU and wait boot */
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x7FFF, 0x00);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x114, 0x00);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x115, 0x00);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x116, 0x42);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x117, 0x00);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x0B, 0x00);
  status |= VL53L5CX_RdByte(&(g_dev.platform), 0x7fff, &tmp);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x0C, 0x00);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x0B, 0x01);
  status |= _vl53l5cx_poll_for_mcu_boot(&g_dev);
  if(status != (uint8_t)0)
  {
    goto exit;
  }

  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x7fff, 0x02);

  /* Get offset NVM data and store them into the offset buffer */
  status |= VL53L5CX_WrMulti(&(g_dev.platform), 0x2fd8,
			     (uint8_t*)VL53L5CX_GET_NVM_CMD,
			     sizeof(VL53L5CX_GET_NVM_CMD));
  status |= _vl53l5cx_poll_for_answer(&g_dev, 4, 0,
  VL53L5CX_UI_CMD_STATUS,
				      0xff, 2);
  status |= VL53L5CX_RdMulti(&(g_dev.platform), VL53L5CX_UI_CMD_START,
			     (uint8_t*)&g_dev.temp_buffer,
			     VL53L5CX_NVM_DATA_SIZE);
  (void)memcpy(&g_dev.offset_data, &g_dev.temp_buffer,
  VL53L5CX_OFFSET_BUFFER_SIZE);
  status |= _vl53l5cx_send_offset_data(&g_dev, VL53L5CX_RESOLUTION_4X4);

  /* Set default Xtalk shape. Send Xtalk to sensor */
  (void)memcpy(&g_dev.xtalk_data, (uint8_t*)VL53L5CX_DEFAULT_XTALK,
  VL53L5CX_XTALK_BUFFER_SIZE);
  status |= _vl53l5cx_send_xtalk_data(&g_dev, VL53L5CX_RESOLUTION_4X4);

  /* Send default configuration to VL53L5CX firmware */
  status |= VL53L5CX_WrMulti(&(g_dev.platform), 0x2c34,
			     (uint8_t*)&g_dev.default_configuration,
			     sizeof(VL53L5CX_DEFAULT_CONFIGURATION));
  status |= _vl53l5cx_poll_for_answer(&g_dev, 4, 1,
  VL53L5CX_UI_CMD_STATUS,
				      0xff, 0x03);

  status |= vl53l5cx_dci_write_data(&g_dev, (uint8_t*)&pipe_ctrl,
  VL53L5CX_DCI_PIPE_CONTROL,
				    (uint16_t)sizeof(pipe_ctrl));
#if VL53L5CX_NB_TARGET_PER_ZONE != 1
	tmp = VL53L5CX_NB_TARGET_PER_ZONE;
	status |= vl53l5cx_dci_replace_data(&g_dev, &(g_dev.temp_buffer[0]),
		VL53L5CX_DCI_FW_NB_TARGET, 16,
	(uint8_t*)&tmp, 1, 0x0C);
#endif

  status |= vl53l5cx_dci_write_data(&g_dev, (uint8_t*)&single_range,
  VL53L5CX_DCI_SINGLE_RANGE,
				    (uint16_t)sizeof(single_range));

  tmp = (uint8_t)1;
  status |= vl53l5cx_dci_replace_data(&g_dev, g_dev.temp_buffer,
  VL53L5CX_GLARE_FILTER,
				      40, (uint8_t*)&tmp, 1, 0x26);
  status |= vl53l5cx_dci_replace_data(&g_dev, g_dev.temp_buffer,
  VL53L5CX_GLARE_FILTER,
				      40, (uint8_t*)&tmp, 1, 0x25);

  status |= vl53l5cx_set_ranging_frequency_hz(&g_dev, 15); // Set 30Hz ranging frequency

  uint8_t power_mode = 0;
  status |= vl53l5cx_get_power_mode(&g_dev, &power_mode);

  uint32_t time_ms = 0;

  time_ms = 10;

  vl53l5cx_set_integration_time_ms(&g_dev, time_ms);

  status |= vl53l5cx_get_integration_time_ms(&g_dev, &time_ms);

  uint8_t resolution = 0;
  status |= vl53l5cx_set_resolution(&g_dev, VL53L5CX_RESOLUTION_4X4);
  status |= vl53l5cx_get_resolution(&resolution);

  status |= vl53l5cx_set_ranging_mode(&g_dev, VL53L5CX_RANGING_MODE_CONTINUOUS);

  VL53L5CX_DetectionThresholds thresholds[VL53L5CX_NB_THRESHOLDS];

  /* Set all values to 0 */
  memset(&thresholds, 0, sizeof(thresholds));

  /* Add thresholds for all zones (16 zones in resolution 4x4, or 64 in 8x8) */
  for(uint8_t i = 0; i < 16; i++)
  {
    /* The first wanted thresholds is GREATER_THAN mode. Please note that the
     * first one must always be set with a mathematic_operation
     * VL53L5CX_OPERATION_NONE.
     * For this example, the signal thresholds is set to 150 kcps/spads
     * (the format is automatically updated inside driver)
     */
    thresholds[2 * i].zone_num = i;
    thresholds[2 * i].measurement = VL53L5CX_SIGNAL_PER_SPAD_KCPS;
    thresholds[2 * i].type = VL53L5CX_GREATER_THAN_MAX_CHECKER;
    thresholds[2 * i].mathematic_operation = VL53L5CX_OPERATION_NONE;
    thresholds[2 * i].param_low_thresh = 150;
    thresholds[2 * i].param_high_thresh = 150;

    /* The second wanted checker is IN_WINDOW mode. We will set a
     * mathematical thresholds VL53L5CX_OPERATION_OR, to add the previous
     * checker to this one.
     * For this example, distance thresholds are set between 200mm and
     * 400mm (the format is automatically updated inside driver).
     */
    thresholds[2 * i + 1].zone_num = i;
    thresholds[2 * i + 1].measurement = VL53L5CX_DISTANCE_MM;
    thresholds[2 * i + 1].type = VL53L5CX_IN_WINDOW;
    thresholds[2 * i + 1].mathematic_operation = VL53L5CX_OPERATION_OR;
    thresholds[2 * i + 1].param_low_thresh = 200;
    thresholds[2 * i + 1].param_high_thresh = 400;
  }

  /* The last thresholds must be clearly indicated. As we have 32
   * checkers (16 zones x 2), the last one is the 31 */
  thresholds[31].zone_num = VL53L5CX_LAST_THRESHOLD | thresholds[31].zone_num;

  /* Send array of thresholds to the sensor */
  status |= vl53l5cx_set_detection_thresholds(&g_dev, thresholds);

  /* Enable detection thresholds */
  status |= vl53l5cx_set_detection_thresholds_enable(&g_dev, 1);

exit: return status;

 

uint8_t vl53l5cx_start_ranging()
{
  uint8_t resolution;
  uint16_t tmp;
  uint32_t i;
  uint32_t header_config[2] = { 0, 0 };
  uint8_t status = VL53L5CX_STATUS_OK;

  union Block_header *bh_ptr;
  uint8_t cmd[] = { 0x00, 0x03, 0x00, 0x00 };

  status |= vl53l5cx_get_resolution(&resolution);
  g_dev.data_read_size = 0;
  g_dev.streamcount = 255;

  status = VL53L5CX_STATUS_OK;

  /* Enable mandatory output (meta and common data) */
  uint32_t output_bh_enable[] = { 0x00000007U, 0x00000000U, 0x00000000U,
      0xC0000000U };

  /* Send addresses of possible output */
  uint32_t output[] = { VL53L5CX_START_BH,
  VL53L5CX_METADATA_BH,
  VL53L5CX_COMMONDATA_BH,
  VL53L5CX_AMBIENT_RATE_BH,
  VL53L5CX_SPAD_COUNT_BH,
  VL53L5CX_NB_TARGET_DETECTED_BH,
  VL53L5CX_SIGNAL_RATE_BH,
  VL53L5CX_RANGE_SIGMA_MM_BH,
  VL53L5CX_DISTANCE_BH,
  VL53L5CX_REFLECTANCE_BH,
  VL53L5CX_TARGET_STATUS_BH,
  VL53L5CX_MOTION_DETECT_BH };

  /* Enable selected outputs in the 'platform.h' file */
#ifndef VL53L5CX_DISABLE_AMBIENT_PER_SPAD
  output_bh_enable[0] += (uint32_t)8;
#endif
#ifndef VL53L5CX_DISABLE_NB_SPADS_ENABLED
  output_bh_enable[0] += (uint32_t)16;
#endif
#ifndef VL53L5CX_DISABLE_NB_TARGET_DETECTED
  output_bh_enable[0] += (uint32_t)32;
#endif
#ifndef VL53L5CX_DISABLE_SIGNAL_PER_SPAD
  output_bh_enable[0] += (uint32_t)64;
#endif
#ifndef VL53L5CX_DISABLE_RANGE_SIGMA_MM
  output_bh_enable[0] += (uint32_t)128;
#endif
#ifndef VL53L5CX_DISABLE_DISTANCE_MM
  output_bh_enable[0] += (uint32_t)256;
#endif
#ifndef VL53L5CX_DISABLE_REFLECTANCE_PERCENT
  output_bh_enable[0] += (uint32_t)512;
#endif
#ifndef VL53L5CX_DISABLE_TARGET_STATUS
  output_bh_enable[0] += (uint32_t)1024;
#endif
#ifndef VL53L5CX_DISABLE_MOTION_INDICATOR
  output_bh_enable[0] += (uint32_t)2048;
#endif

  /* Update data size */
  for(i = 0; i < (uint32_t)(sizeof(output) / sizeof(uint32_t)); i++)
  {
    if((output[i] == (uint8_t)0)
	|| ((output_bh_enable[i / (uint32_t)32]
	    & ((uint32_t)1 << (i % (uint32_t)32))) == (uint32_t)0))
    {
      continue;
    }

    bh_ptr = (union Block_header*)&(output[i]);
    if(((uint8_t)bh_ptr->type >= (uint8_t)0x1)
	&& ((uint8_t)bh_ptr->type < (uint8_t)0x0d))
    {
      if((bh_ptr->idx >= (uint16_t)0x54d0)
	  && (bh_ptr->idx < (uint16_t)(0x54d0 + 960)))
      {
	bh_ptr->size = resolution;
      }
      else
      {
	bh_ptr->size = (uint16_t)((uint16_t)resolution
	    * (uint16_t)VL53L5CX_NB_TARGET_PER_ZONE);
      }
      g_dev.data_read_size += bh_ptr->type * bh_ptr->size;
    }
    else
    {
      g_dev.data_read_size += bh_ptr->size;
    }
    g_dev.data_read_size += (uint32_t)4;
  }
  g_dev.data_read_size += (uint32_t)24;

  status |= vl53l5cx_dci_write_data(&g_dev, (uint8_t*)&(output),
  VL53L5CX_DCI_OUTPUT_LIST,
				    (uint16_t)sizeof(output));

  header_config[0] = g_dev.data_read_size;
  header_config[1] = i + (uint32_t)1;

  status |= vl53l5cx_dci_write_data(&g_dev, (uint8_t*)&(header_config),
  VL53L5CX_DCI_OUTPUT_CONFIG,
				    (uint16_t)sizeof(header_config));

  status |= vl53l5cx_dci_write_data(&g_dev, (uint8_t*)&(output_bh_enable),
  VL53L5CX_DCI_OUTPUT_ENABLES,
				    (uint16_t)sizeof(output_bh_enable));

  /* Start xshut bypass (interrupt mode) */
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x7fff, 0x00);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x09, 0x05);
  status |= VL53L5CX_WrByte(&(g_dev.platform), 0x7fff, 0x02);

  /* Start ranging session */
  status |= VL53L5CX_WrMulti(&(g_dev.platform),
  VL53L5CX_UI_CMD_END - (uint16_t)(4 - 1),
			     (uint8_t*)cmd, sizeof(cmd));
  status |= _vl53l5cx_poll_for_answer(&g_dev, 4, 1,
  VL53L5CX_UI_CMD_STATUS,
				      0xff, 0x03);

  /* Read ui range data content and compare if data size is the correct one */
  status |= vl53l5cx_dci_read_data(&g_dev, (uint8_t*)g_dev.temp_buffer, 0x5440,
				   12);
//  vl53l5cx_test_i2c(&g_dev);

  (void)memcpy(&tmp, &(g_dev.temp_buffer[0x8]), sizeof(tmp));
  if(tmp != g_dev.data_read_size)
  {
    status |= VL53L5CX_STATUS_ERROR;
  }

  return status;
}

 

I can't read output data and inside the function vl53l5cx_check_data_ready the buffer g_dev.temp_buffer == {255,4,2,1}

Thanks

 

John E KVAM
ST Employee

Did you perhaps change the section in platform.h to reduce the number of bytes:

My recommended minimum is:

// #define VL53L8CX_DISABLE_AMBIENT_PER_SPAD
 #define VL53L8CX_DISABLE_NB_SPADS_ENABLED
// #define VL53L8CX_DISABLE_NB_TARGET_DETECTED
 #define VL53L8CX_DISABLE_SIGNAL_PER_SPAD
 #define VL53L8CX_DISABLE_RANGE_SIGMA_MM
// #define VL53L8CX_DISABLE_DISTANCE_MM
 #define VL53L8CX_DISABLE_REFLECTANCE_PERCENT
// #define VL53L8CX_DISABLE_TARGET_STATUS
 #define VL53L8CX_DISABLE_MOTION_INDICATOR

Technically you don't need ambient - but it's only 8 extra bytes and it might come in handy. 

This reduces the max output of 4095 bytes down to 1327 which is the minimum. 

To verify a valid target you need NB_Target_Detected >1 AND Target_Status =(5,6,9 or sometimes 12). With that you can print Distance_MM.

- john


If this or any post solves your issue, please mark them as 'Accept as Solution' It really helps. And if you notice anything wrong do not hesitate to 'Report Inappropriate Content'. Someone will review it.