/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file X-WL55_WLE5_53L0X.c * @author Yunhorn (r) Technology Limited Application Team * @brief implement X-WL55_WLE5_53L0X BSP ****************************************************************************** * @attention * * Copyright (c) 2023 Yunhorn Technology Limited. * Copyright (c) 2023 Shenzhen Yunhorn Technology Co., Ltd. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ #include #include "X-WL55_WLE5_53L0X.h" #include "stm32wlxx_hal.h" #include "main.h" #ifndef HAL_I2C_MODULE_ENABLED #define HAL_I2C_MODULE_ENABLED #pragma message("hal conf should enable i2c") #endif /* when not customized by application define dummy one */ #ifndef XNUCLEO53L1A1_GetI2cBus /** * macro that can be overloaded by user to enforce i2c sharing in RTOS context */ #define XNUCLEO53L1A1_GetI2cBus(...) (void)0 #endif #ifndef XNUCLEO53L1A1_PutI2cBus /** macro can be overloaded by user to enforce i2c sharing in RTOS context */ # define XNUCLEO53L1A1_PutI2cBus(...) (void)0 #endif /**************************************************** *@defgroup XNUCLEO53L1A1_globals *@{ */ /** * i2c handle to be use of all i2c access * end user shall provide it to * can be @a XNUCLEO53L1A1_I2C1Configure() @sa XNUCLEO53L1A1_usage * @warning do not use any XNUCLEO53L1A1_xxx prior to a first init with valid i2c handle */ I2C_HandleTypeDef XNUCLEO53L1A1_hi2c; /** * 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(){ GPIO_InitTypeDef GPIO_InitStruct; int 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 PME_ON; // Enable I/O __GPIOA_CLK_ENABLE(); HAL_GPIO_WritePin(I2C2_SCL_PORT, I2C2_SCL_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(I2C2_SDA_PORT, I2C2_SDA_PIN, GPIO_PIN_SET); GPIO_InitStruct.Pin = I2C2_SCL_PIN|I2C2_SDA_PIN ; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(I2C2_SDA_PORT, &GPIO_InitStruct); //TODO we could do this faster by not using HAL delay 1ms for clk timing do{ for( i=0; i<10; i++){ HAL_GPIO_WritePin(I2C2_SCL_PORT, I2C2_SCL_PIN, GPIO_PIN_RESET); HAL_Delay(1); HAL_GPIO_WritePin(I2C2_SCL_PORT, I2C2_SCL_PIN, GPIO_PIN_SET); HAL_Delay(1); } // if( HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_9) == 0 ){ // static int RetryRecover; // RetryRecover++; // } }while(HAL_GPIO_ReadPin(I2C2_SDA_PORT, I2C2_SDA_PIN) == 0 && nRetry++<7); if( HAL_GPIO_ReadPin(I2C2_SDA_PORT, I2C2_SDA_PIN) == 0 ){ __GPIOA_CLK_ENABLE(); //We are still in bad i2c state warm user by blinking led but stay here GPIO_InitStruct.Pin = LED1_Pin ; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(LED1_GPIO_Port, &GPIO_InitStruct); do{ HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET); HAL_Delay(33); HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET); HAL_Delay(33); HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET); HAL_Delay(33); HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET); HAL_Delay(33*20); }while(0); } } int XWL55_WLE5_53L0X_I2C2Configure() { int status; GPIO_InitTypeDef GPIO_InitStruct; _I2cFailRecover(); /* Peripheral clock enable */ __GPIOA_CLK_ENABLE(); __I2C2_CLK_ENABLE(); /**I2C1 GPIO Configuration\n PB8 ------> I2C1_SCL\n PB9 ------> I2C1_SDA *I2C2 GPIO configuration PA12 -------> I2C2_SCL PA11 -------> I2C2_SDA */ GPIO_InitStruct.Pin = I2C2_SCL_PIN | I2C2_SDA_PIN; GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF4_I2C2; HAL_GPIO_Init(I2C2_SDA_PORT, &GPIO_InitStruct); XNUCLEO53L1A1_hi2c.Instance = I2C2; //XNUCLEO53L1A1_hi2c.Init.Timing = 0x00300F38; /* set 400KHz fast mode i2c*/ //XNUCLEO53L1A1_hi2c.Init.Timing = I2C2_FAST_400K; //UPDATE 2024-07-09 XNUCLEO53L1A1_hi2c.Init.Timing = I2C2_STANDARD_100K; // UPDATE 2024-07-12 //XNUCLEO53L1A1_hi2c.Init.Timing = 0x2010091A; //0x2010091A = 400K Fast Mode, 0x20303E5D, 100K Standard mode, 0x20000209 Fast Mode Plus, 1Mbps XNUCLEO53L1A1_hi2c.Init.OwnAddress1 = 0; XNUCLEO53L1A1_hi2c.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; XNUCLEO53L1A1_hi2c.Init.DualAddressMode = I2C_DUALADDRESS_DISABLED; XNUCLEO53L1A1_hi2c.Init.OwnAddress2 = 0; XNUCLEO53L1A1_hi2c.Init.GeneralCallMode = I2C_GENERALCALL_DISABLED; XNUCLEO53L1A1_hi2c.Init.NoStretchMode = I2C_NOSTRETCH_DISABLED; status = HAL_I2C_Init(&XNUCLEO53L1A1_hi2c); return status; } int XWL55_WLE5_53L0X_SetIntrStateId(int EnableIntr, int DevNo) { int status; IRQn_Type IntrNo; int IntrPin; switch (DevNo){ case 1: IntrNo = VL53L0X_GPIO1_L_INTx; IntrPin= VL53L0X_GPIO1_L_GPIO_PIN; break; case 0: IntrNo = VL53L0X_GPIO1_C_INTx; IntrPin= VL53L0X_GPIO1_C_GPIO_PIN; break; case 2: IntrNo = VL53L0X_GPIO1_R_INTx; IntrPin= VL53L0X_GPIO1_R_GPIO_PIN; break; default: break; } /* IntrNo = VL53L0X_GPIO1_C_INTx; IntrPin= VL53L0X_GPIO1_C_GPIO_PIN; */ status = 0; if( EnableIntr ){ __HAL_GPIO_EXTI_CLEAR_IT(IntrPin); NVIC_ClearPendingIRQ(IntrNo); HAL_NVIC_EnableIRQ(IntrNo); /** * @note When enabling interrupt end user shall check actual state of the line and soft trigger event if active * Alternatively user can use API and device feature to clear device Interrupt status to possibly generates a new edge. * on shared pin configuration this must be repeated for all device. * The same shall be done after clearing a condition in device and interrupt remain active. */ } else{ HAL_NVIC_DisableIRQ(IntrNo); __HAL_GPIO_EXTI_CLEAR_IT(IntrPin); NVIC_ClearPendingIRQ(IntrNo); } return status; } int XWL55_WLE5_53L0X_Init(void) { int status; status = XWL55_WLE5_53L0X_I2C2Configure(); return status; } void XWL55_WLE5_53L0X_ResetId(uint8_t DevNo, int state) { switch(DevNo) { case XNUCLEO53L0X_LEFT: #if defined(TOF_2) HAL_GPIO_WritePin(TOF_L_XSHUT_GPIO_Port, TOF_L_XSHUT_Pin, ((state == 1)?GPIO_PIN_SET:GPIO_PIN_RESET)); #endif break; #if defined(TOF_1) case XNUCLEO53L0X_CENTER: HAL_GPIO_WritePin(TOF_C_XSHUT_GPIO_Port, TOF_C_XSHUT_Pin, ((state == 1)?GPIO_PIN_SET:GPIO_PIN_RESET)); break; #endif case XNUCLEO53L0X_RIGHT: #if defined(TOF_3) HAL_GPIO_WritePin(TOF_R_XSHUT_GPIO_Port, TOF_R_XSHUT_Pin, ((state == 1)?GPIO_PIN_SET:GPIO_PIN_RESET)); #endif break; default: break; } } /** * * @} X-WL55_WLE5_53L0X_top */