Contains Ayoub's Ranging and Custom interfaces for the VL53L3CX
Diff: 53l3a2.c
- Revision:
- 0:c1910e04fc6c
- Child:
- 1:dae4cb24beec
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/53l3a2.c Wed Jul 21 14:19:31 2021 +0000 @@ -0,0 +1,605 @@ +/** + ****************************************************************************** + * @file 53l3a2.c + * @author IMG SW Application Team + * @brief This file contains the X-NUCLEO-53L3A2 BSP implementation. + ****************************************************************************** + * @attention + * + * <h2><center>© 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 +/** + * @} + */ + +/** @defgroup XNUCLEO_53L3A2_COMMON_Private_Variables Private Variables + * @{ + */ +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) + { +// _I2cFailRecover(); + +//// VL53L3A2_I2C_Init(); + +//// status = _ExpanderRd(I2C_EXPANDER_ADDR0, 0, ExpanderData, 2); + +// if ((status != 0) || (ExpanderData[0] != 0x00U) || (ExpanderData[1] != 0x16U)) +// { + // VL53L3A2_ErrLog("I2C Expander @0x%02X not detected", (int)I2C_EXPANDER_ADDR0); + // goto done_err; +// } + +// status = _ExpanderRd(I2C_EXPANDER_ADDR1, 0, ExpanderData, 2); + +// if ((status != 0) || (ExpanderData[0] != 0x00U) || (ExpanderData[1] != 0x16U)) +// { +// printf("ExpanderData %d %d %d\n",status,ExpanderData[0],ExpanderData[1]); +// VL53L3A2_ErrLog("I2C Expander @0x%02X not detected", (int)I2C_EXPANDER_ADDR1); +// goto done_err; +// } + + 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; + // VL53L3A2_GetI2cBus(); + // printf("_ExpanderRd %d %d %d %d\n",I2cExpAddr,index,RegAddr,status); + // status = v53l1x_i2c_write_if(data,I2cExpAddr, index,n_data); + + + status = v53l1x_i2c_read_if(RegAddr,I2cExpAddr, index,2); + + + //// do + //// { + //// status = HAL_I2C_Master_Transmit(&VL53L3A2_hi2c, I2cExpAddr, &RegAddr, 1, 100); + + //// if (status) + //// { + //// break; + //// } + + //// status = HAL_I2C_Master_Receive(&VL53L3A2_hi2c, I2cExpAddr, data, n_data, n_data * 100); + //// } while (0); + + // VL53L3A2_PutI2cBus(); + + 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****/ +