Contains Ayoub's Ranging and Custom interfaces for the VL53L3CX

53l3a2.c

Committer:
charlesmn
Date:
2021-07-21
Revision:
1:dae4cb24beec
Parent:
0:c1910e04fc6c

File content as of revision 1:dae4cb24beec:

/**
  ******************************************************************************
  * @file    53l3a2.c
  * @author  IMG SW Application Team
  * @brief   This file contains the X-NUCLEO-53L3A2 BSP implementation.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */

 /* Includes ------------------------------------------------------------------ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "53l3a2.h"
#include "spi_interface.h"


/** @addtogroup BSP
  * @{
  */

/** @addtogroup XNUCLEO_53L3A2
  * @{
  */

/** @addtogroup XNUCLEO_53L3A2_COMMON
  * @{
  */

/* This macro can be overloaded by the user to report error log messages with printf format */
#define VL53L3A2_ErrLog(...) (void)0

/* These macros can be overloaded by the user to enforce i2c sharing in RTOS context */
#define VL53L3A2_GetI2cBus(...) (void)0
#define VL53L3A2_PutI2cBus(...) (void)0

#define I2C_EXPANDER_ADDR0 ((int)(0x43*2))   /*!< Expander 0 i2c address[7..0] format */
#define I2C_EXPANDER_ADDR1 ((int)(0x42*2))   /*!< Expander 1 i2c address[7..0] format */

/**
  * GPIO monitor pin state register
  * 16 bit register LSB at lowest offset (little endian)
  */
#define GPMR    (0x10)
/**
  * STMPE1600 GPIO set pin state register
  * 16 bit register LSB at lowest offset (little endian)
  */
#define GPSR    (0x12)
/**
  * STMPE1600 GPIO set pin direction register
  * 16 bit register LSB at lowest offset
  */
#define GPDR    (0x14)

/**
  * @defgroup VL53L3A2_7Segment 7 segment display
  *
  * macro use for human readable segment building
  * @code
  *  --s0--
  *  s    s
  *  5    1
  *  --s6--
  *  s    s
  *  4    2
  *  --s3-- . s7 (dp)
  * @endcode
  *
  * @{
  */
#define DP (1U << 7)   /*!< decimal point bit mapping */
#define S0 (1U << 3)   /*!< segment s0 bit mapping */
#define S1 (1U << 5)   /*!< segment s1 bit mapping */
#define S2 (1U << 6)   /*!< segment s2 bit mapping */
#define S3 (1U << 4)   /*!< segment s3 bit mapping */
#define S4 (1U << 0)   /*!< segment s4 bit mapping */
#define S5 (1U << 1)   /*!< segment s5 bit mapping */
#define S6 (1U << 2)   /*!< segment s6 bit mapping */

/**
  * build a character by defining the non lighted segment (not one and no DP)
  *
  * @param  ... literal sum and or combine of any macro to define any segment #S0 .. #S6
  *
  * example '9' is all segment on but S4
  * @code
  *   ['9']=           NOT_7_NO_DP(S4),
  * @endcode
  */
#define NOT_7_NO_DP( ... ) (uint8_t) ~( __VA_ARGS__ + DP )

/**
  * Ascii to 7 segment  lookup table
  *
  * Most common character are supported and follow http://www.twyman.org.uk/Fonts/
  * few extra special \@ ^~ ... etc are present for specific demo purpose
  */
static const uint8_t ascii_to_display_lut[256] =
{
  [' '] =           0,
  ['-'] =           S6,
  ['_'] =           S3,
  ['='] =           S3 + S6,
  ['~'] =           S0 + S3 + S6, /* 3 h bar */
  ['^'] =           S0, /* use as top bar */

  ['?'] =           NOT_7_NO_DP(S5 + S3 + S2),
  ['*'] =           NOT_7_NO_DP(),
  ['['] =           S0 + S3 + S4 + S5,
  [']'] =           S0 + S3 + S2 + S1,
  ['@'] =           S0 + S3,

  ['0'] =           NOT_7_NO_DP(S6),
  ['1'] =           S1 + S2,
  ['2'] =           S0 + S1 + S6 + S4 + S3,
  ['3'] =           NOT_7_NO_DP(S4 + S5),
  ['4'] =           S5 + S1 + S6 + S2,
  ['5'] =           NOT_7_NO_DP(S1 + S4),
  ['6'] =           NOT_7_NO_DP(S1),
  ['7'] =           S0 + S1 + S2,
  ['8'] =           NOT_7_NO_DP(0),
  ['9'] =           NOT_7_NO_DP(S4),

  ['a'] =           S2 + S3 + S4 + S6,
  ['b'] =           NOT_7_NO_DP(S0 + S1),
  ['c'] =           S6 + S4 + S3,
  ['d'] =           NOT_7_NO_DP(S0 + S5),
  ['e'] =           NOT_7_NO_DP(S2),
  ['f'] =           S6 + S5 + S4 + S0, /* same as F */
  ['g'] =           NOT_7_NO_DP(S4), /* same as 9 */
  ['h'] =           S6 + S5 + S4 + S2,
  ['i'] =           S4,
  ['j'] =           S1 + S2 + S3 + S4,
  ['k'] =           S6 + S5 + S4 + S2, /* a h */
  ['l'] =           S3 + S4,
  ['m'] =           S0 + S4 + S2, /* same as  */
  ['n'] =           S2 + S4 + S6,
  ['o'] =           S6 + S4 + S3 + S2,
  ['p'] =           NOT_7_NO_DP(S3 + S2), /* same as P */
  ['q'] =           S0 + S1 + S2 + S5 + S6,
  ['r'] =           S4 + S6,
  ['s'] =           NOT_7_NO_DP(S1 + S4),
  ['t'] =           NOT_7_NO_DP(S0 + S1 + S2),
  ['u'] =           S4 + S3 + S2 + S5 + S1, /* U */
  ['v'] =           S4 + S3 + S2, /* is u but u use U */
  ['w'] =           S1 + S3 + S5,
  ['x'] =           NOT_7_NO_DP(S0 + S3), /* similar to H */
  ['y'] =           NOT_7_NO_DP(S0 + S4),
  ['z'] =           S0 + S1 + S6 + S4 + S3, /* same as 2 */

  ['A'] =           NOT_7_NO_DP(S3),
  ['B'] =           NOT_7_NO_DP(S0 + S1), /* as b  */
  ['C'] =           S0 + S3 + S4 + S5, /* same as [ */
  ['E'] =           NOT_7_NO_DP(S1 + S2),
  ['F'] =           S6 + S5 + S4 + S0,
  ['G'] =           NOT_7_NO_DP(S4), /* same as 9 */
  ['H'] =           NOT_7_NO_DP(S0 + S3),
  ['I'] =           S1 + S2,
  ['J'] =           S1 + S2 + S3 + S4,
  ['K'] =           NOT_7_NO_DP(S0 + S3), /* same as H */
  ['L'] =           S3 + S4 + S5,
  ['M'] =           S0 + S4 + S2, /* same as  m*/
  ['N'] =           S2 + S4 + S6, /* same as n*/
  ['O'] =           NOT_7_NO_DP(S6),
  ['P'] =           NOT_7_NO_DP(S3 + S2),
  ['Q'] =           NOT_7_NO_DP(S3 + S2),
  ['R'] =           S4 + S6,
  ['S'] =           NOT_7_NO_DP(S1 + S4), /* sasme as 5 */
  ['T'] =           NOT_7_NO_DP(S0 + S1 + S2), /* sasme as t */
  ['U'] =           NOT_7_NO_DP(S6 + S0),
  ['V'] =           S4 + S3 + S2, /* is u but u use U */
  ['W'] =           S1 + S3 + S5,
  ['X'] =           NOT_7_NO_DP(S0 + S3), /* similar to H */
  ['Y'] =           NOT_7_NO_DP(S0 + S4),
  ['Z'] =           S0 + S1 + S6 + S4 + S3, /* same as 2 */
};

#undef S0
#undef S1
#undef S2
#undef S3
#undef S4
#undef S5
#undef S6
#undef DP
/**
  * @}
  */


static uint32_t InitCounter = 0;

/* cache the full set of expanded GPIO values to avoid i2c reading */
static union CurIOVal_u
{
  uint8_t bytes[4];   /*!<  4 bytes array i/o view */
  uint32_t u32;       /*!<  single dword i/o view */
} CurIOVal; /* cache the extended IO values */


/** @defgroup XNUCLEO_53L3A2_COMMON_Private_Functions_Prototypes Private Functions Prototypes
  * @{
  */
static void _I2cFailRecover(void);
static int32_t _ExpanderRd(uint32_t I2cExpAddr, uint32_t index, uint8_t *data, uint32_t n_data);
static int32_t _ExpanderWR(uint32_t I2cExpAddr, uint32_t index, uint8_t *data, uint32_t n_data);
static int32_t _ExpandersSetAllIO(void);


/**
  * @brief Initialize X-NUCLEO-53L3A2 STM32 expansion board
  * @note All devices XSDN are asserted and display is turned off
  * @return 0 on success
  */
int32_t VL53L3A2_Init(void)
{
  int32_t status = 0;
  uint8_t ExpanderData[2];
  
  if (InitCounter++ == 0U)
  {
	  CurIOVal.u32 = 0x0U;

	  // setup expander   i/o direction  all output but exp1 bit 14
	  ExpanderData[0] = 0xFFU;
	  ExpanderData[1] = 0xFFU;

	  status = _ExpanderWR(I2C_EXPANDER_ADDR0, GPDR, ExpanderData, 2);

	  if (status)
	  {
		VL53L3A2_ErrLog("Set Expander @0x%02X DR", I2C_EXPANDER_ADDR0);
		goto done_err;
	  }

	  ExpanderData[0] = 0xFFU;
	  ExpanderData[1] = 0xBFU; /* all but bit 14-15 that is pb1 and xhurt */
	  status = _ExpanderWR(I2C_EXPANDER_ADDR1, GPDR, ExpanderData, 2);

	  if (status)
	  {
		VL53L3A2_ErrLog("Set Expander @0x%02X DR", I2C_EXPANDER_ADDR1);
		goto done_err;
	  }

	  /* shut down all segment and all device */
	  CurIOVal.u32 = 0x7FU + (0x7FU << 7) + (0x7FU << 16) + (0x7FU << (16 + 7));
	  
	  CurIOVal.bytes[3] = 0x0f;
	  CurIOVal.bytes[1] = 0x0f;
	  status = _ExpandersSetAllIO();

	  if (status)
	  {
		VL53L3A2_ErrLog("Set initial i/o ");
	  }
  }

done_err:
  return status;
}

/**
  * @brief De-initialize X-NUCLEO-53L3A2 STM32 expansion board
  * @return 0 on success
  */
int32_t VL53L3A2_DeInit(void)
{
  int32_t status = 0;

  if (InitCounter > 0U)
  {
	if (--InitCounter == 0U)
	{
//      status = VL53L3A2_I2C_DeInit();
	}
  }

  return status;
}

/**
  * @brief Set Reset (XSDN) state of a given "id" device
  * @param  DevNo The device number, use @ref VL53L3A2_dev_e.
  * @param  state  State of the device reset (xsdn) pin @warning reset pin is active low
  * i.e. xshut is raised to enable device
  * @return 0 on success
  */
  
//   VL53L3A2_DEV_LEFT    =  0,   /* !< left satellite device P21 header */
//   VL53L3A2_DEV_CENTER  =  1,   /* !< center (built-in) device */
//   VL53L3A2_DEV_RIGHT   =  2    /* !< Right satellite device P22 header */
int32_t VL53L3A2_ResetId(uint8_t DevNo, uint8_t state)
{
  int32_t status;
printf("VL53L3A2_ResetId %d %d %d %d \n",DevNo,state,CurIOVal.bytes[1],CurIOVal.bytes[3]);
  switch (DevNo)
  {
    case VL53L3A2_DEV_CENTER :
      CurIOVal.bytes[3] &= ~0x80U; /* bit 15 expander 1  => byte #3 */

      if (state)
      {
        CurIOVal.bytes[3] |= 0x80U;  /* bit 15 expander 1  => byte #3 */
      }

	  status = _ExpanderWR(I2C_EXPANDER_ADDR1, GPSR , &CurIOVal.bytes[3], 1);
      break;

    case VL53L3A2_DEV_LEFT :
	printf("VL53L3A2_DEV_LEFT \n");
      CurIOVal.bytes[1] &= ~0x40U; /* bit 14 expander 0 => byte #1*/

      if (state)
      {
        CurIOVal.bytes[1] |= 0x40U;  /* bit 14 expander 0 => byte #1*/
      }

      status = _ExpanderWR(I2C_EXPANDER_ADDR0, GPSR , &CurIOVal.bytes[1], 1);
      break;

    case VL53L3A2_DEV_RIGHT :
      CurIOVal.bytes[1] &= ~0x80U; /* bit 15 expander 0  => byte #1 */

      if (state)
      {
        CurIOVal.bytes[1] |= 0x80U;  /* bit 15 expander 0 => byte #1*/
      }

      status = _ExpanderWR(I2C_EXPANDER_ADDR0, GPSR , &CurIOVal.bytes[1], 1);
      break;

    default:
      VL53L3A2_ErrLog("Invalid DevNo %d", DevNo);
      status = -1;
      goto done;
  }

  /* error with valid id */
  if (status)
  {
    VL53L3A2_ErrLog("expander i/o error for DevNo %d state %d ", DevNo, state);
  }

done:
printf("VL53L3A2_ResetId %d %d %d %d\n",status,DevNo,CurIOVal.bytes[1],CurIOVal.bytes[3]);
  return status;
}

/**
  * @brief Set the 7 segments display
  * @param str  String to set on display
  * @warning When string is less than 4 digits, display is left-justified and lower digits are blanked.
  *          To display a 2 digits value, left justified on the 4 digits, use "%4d" formating
  * @warning When more than 4 char are present only first 4 are displayed
  * @note    Characters that do not have 7 segment font matching in ascii_to_display_lut are left blank
  * @return 0 on success
  */
int32_t VL53L3A2_SetDisplayString(const char *str)
{
  int32_t status;
  uint32_t BitPos;
  uint32_t i;
  uint32_t Segments;

  /* lookup table for for digit  to bit position in @a CurIOVal u32 */
  uint8_t DisplayBitPos[4] = {0, 7, 16, 16 + 7};

  for (i = 0; (i < 4U) && (str[i] != 0U); i++)
  {
    Segments = (uint32_t)ascii_to_display_lut[(uint8_t)str[i]];
    Segments = (~Segments) & 0x7FU;
    BitPos = DisplayBitPos[i];
    CurIOVal.u32 &= ~(0x7FU << BitPos);
    CurIOVal.u32 |= Segments << BitPos;
  }

  /* clear unused digit */
  for (; i < 4U; i++)
  {
    BitPos = DisplayBitPos[i];
    CurIOVal.u32 |= 0x7FU << BitPos;
  }

  status = _ExpandersSetAllIO();

  if (status)
  {
    VL53L3A2_ErrLog("Set i/o");
  }

  return status;
}

/** @defgroup XNUCLEO_53L3A2_COMMON_Private_Functions Private Functions
  * @{
  */

/**
  * @brief Expansion board i2c bus recovery
  * We may get reset in middle of an i2c access (h/w reset button, debug or f/w load)
  * hence some agent on bus may be in middle of a transaction and can create issue or even prevent starting (SDA is low)
  * this routine does use gpio to manipulate and recover i2c bus line in all cases.
  */
static void _I2cFailRecover()
{
	printf("_I2cFailRecover \n");
#if 0
  GPIO_InitTypeDef GPIO_InitStruct;
  uint8_t i, nRetry = 0;

  /* We can't assume bus state based on SDA and SCL state (we may be in a data or NAK bit so SCL=SDA=1)
   * by setting SDA high and toggling SCL at least 10 time we ensure whatever agent and state
   * all agent should end up seeing a "stop" and bus get back to an known idle i2c bus state */

  /* Enable I/O */
  __GPIOB_CLK_ENABLE();
  HAL_GPIO_WritePin(VL53L3A2_I2C_SCL_GPIO_PORT, VL53L3A2_I2C_SCL_GPIO_PIN, GPIO_PIN_SET);
  HAL_GPIO_WritePin(VL53L3A2_I2C_SDA_GPIO_PORT, VL53L3A2_I2C_SDA_GPIO_PIN, GPIO_PIN_SET);
  GPIO_InitStruct.Pin = VL53L3A2_I2C_SCL_GPIO_PIN | VL53L3A2_I2C_SDA_GPIO_PIN ;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* we could do this faster by not using HAL delay 1ms for clk timing */
  do
  {
    for (i = 0; i < 10U; i++)
    {
      HAL_GPIO_WritePin(VL53L3A2_I2C_SCL_GPIO_PORT, VL53L3A2_I2C_SCL_GPIO_PIN, GPIO_PIN_RESET);
      HAL_Delay(1);
      HAL_GPIO_WritePin(VL53L3A2_I2C_SCL_GPIO_PORT, VL53L3A2_I2C_SCL_GPIO_PIN, GPIO_PIN_SET);
      HAL_Delay(1);
    }

  } while ((HAL_GPIO_ReadPin(VL53L3A2_I2C_SDA_GPIO_PORT, VL53L3A2_I2C_SDA_GPIO_PIN) == 0) && (nRetry++ < 7U));

  if (HAL_GPIO_ReadPin(VL53L3A2_I2C_SCL_GPIO_PORT, VL53L3A2_I2C_SDA_GPIO_PIN) == 0)
  {
    /* We are still in a bad i2c state, block the program here 
     * A hardware reset is necessary */
    while (1);
  }
 #endif
}

/**
  * @brief Set all i2c expended gpio in one go
  * @return i/o operation status
  */
static int32_t _ExpandersSetAllIO(void)
{
  int32_t status;

  status = _ExpanderWR(I2C_EXPANDER_ADDR0, GPSR, &CurIOVal.bytes[0], 2);

  if (status)
  {
    goto done_err;
  }

  status = _ExpanderWR(I2C_EXPANDER_ADDR1, GPSR, &CurIOVal.bytes[2], 2);

done_err:
printf("_ExpandersSetAllIO end \n");
  return status;
}

/**
  * @brief STMPE1600 i2c Expander register read
  * @param I2cExpAddr Expander address
  * @param index      register index
  * @param data       read data buffer
  * @param n_data     number of byte to read
  * @return           of if ok else i2c I/O operation status
  */
static int32_t _ExpanderRd(uint32_t I2cExpAddr, uint32_t index, uint8_t *data, uint32_t n_data)
{
  int32_t status;
  uint8_t RegAddr;

  RegAddr = index;

  status = v53l1x_i2c_read_if(data,I2cExpAddr, index,2);

  return status;
}

/**
  * @brief STMPE1600 i2c Expander register write
  * @param I2cExpAddr Expander address
  * @param index      register index
  * @param data       data buffer
  * @param n_data     number of byte to write
  * @return           of if ok else i2c I/O operation status
  */
static int32_t _ExpanderWR(uint32_t I2cExpAddr, uint32_t index, uint8_t *data, uint32_t n_data)
{
  int32_t status = 0;
  uint8_t RegAddr[0x10];
  uint8_t i;
  for (i = 0 ; i < 0x10 ; i++)
  {
	   RegAddr[i] =0;
  }
// build packet to send
if (n_data == 1)
{
	RegAddr[0] = (uint8_t)index;  // the register in the chip we are sending to
	RegAddr[1]= 255; // the lower byte of the control word. We just set to FF
	RegAddr[2]= data[0];  //the byte that controls the xshut pins
}
else{
    RegAddr[0] = (uint8_t)index;  // the register in the chip we are sending to
    RegAddr[1]=data[0]; // the lower byte of the control word. We just set to FF
    RegAddr[2]=data[1];  //the byte that controls the xshut pins
}
  
//   	 printf("_ExpanderWR %d %d %d \n",data[0],data[1],n_data); 
// 	 printf("_ExpanderWR %d %d %d %d %d %d %d\n",I2cExpAddr,index,RegAddr[0],RegAddr[1],RegAddr[2],status,n_data+2); 
     status = v53l1x_i2c_write_direct(RegAddr,I2cExpAddr,n_data + 2);

 
 
 

  return (status);
}


/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/