STM32CubeWL/Drivers/BSP/B-WL5M-SUBG/b_wl5m_subg_bus.c

1122 lines
30 KiB
C

/**
******************************************************************************
* @file b_wl5m_subg_bus.c
* @author MCD Application Team
* @brief This file provides a set of firmware functions to manage bus
* available on B-WL5M-SUBG board (MB1779) from
* STMicroelectronics.
******************************************************************************
* @attention
*
* Copyright (c) 2022 STMicroelectronics.
* 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.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "b_wl5m_subg_bus.h"
/** @addtogroup BSP
* @{
*/
/** @addtogroup B_WL5M_SUBG
* @{
*/
/** @defgroup B_WL5M_SUBG_BUS B-WL5M-SUBG BUS
* @{
*/
/** @defgroup B_WL5M_SUBG_BUS_Private_Defines B-WL5M-SUBG BUS Private Defines
* @{
*/
#define I2C_SPEED_FREQ_STANDARD 0U /* 100 kHz */
#define I2C_SPEED_FREQ_FAST 1U /* 400 kHz */
#define I2C_SPEED_FREQ_FAST_PLUS 2U /* 1 MHz */
#define I2C_ANALOG_FILTER_DELAY_MIN 50U /* ns */
#define I2C_ANALOG_FILTER_DELAY_MAX 260U /* ns */
#define I2C_USE_ANALOG_FILTER 1U
#define I2C_DIGITAL_FILTER_COEF 0U
#define I2C_VALID_TIMING_NBR 128U
#define I2C_PRESC_MAX 16U
#define I2C_SCLDEL_MAX 16U
#define I2C_SDADEL_MAX 16U
#define I2C_SCLH_MAX 256U
#define I2C_SCLL_MAX 256U
#define SEC2NSEC 1000000000UL
/**
* @}
*/
/** @defgroup B_WL5M_SUBG_BUS_Private_Types B-WL5M-SUBG BUS Private Types
* @{
*/
typedef struct
{
uint32_t freq; /* Frequency in Hz */
uint32_t freq_min; /* Minimum frequency in Hz */
uint32_t freq_max; /* Maximum frequency in Hz */
uint32_t hddat_min; /* Minimum data hold time in ns */
uint32_t vddat_max; /* Maximum data valid time in ns */
uint32_t sudat_min; /* Minimum data setup time in ns */
uint32_t lscl_min; /* Minimum low period of the SCL clock in ns */
uint32_t hscl_min; /* Minimum high period of SCL clock in ns */
uint32_t trise; /* Rise time in ns */
uint32_t tfall; /* Fall time in ns */
uint32_t dnf; /* Digital noise filter coefficient */
} I2C_Charac_t;
typedef struct
{
uint32_t presc; /* Timing prescaler */
uint32_t tscldel; /* SCL delay */
uint32_t tsdadel; /* SDA delay */
uint32_t sclh; /* SCL high period */
uint32_t scll; /* SCL low period */
} I2C_Timings_t;
/**
* @}
*/
/** @defgroup B_WL5M_SUBG_BUS_Private_Constants B-WL5M-SUBG BUS Private Constants
* @{
*/
static const I2C_Charac_t I2C_Charac[] =
{
[I2C_SPEED_FREQ_STANDARD] =
{
.freq = 100000,
.freq_min = 80000,
.freq_max = 120000,
.hddat_min = 0,
.vddat_max = 3450,
.sudat_min = 250,
.lscl_min = 4700,
.hscl_min = 4000,
.trise = 640,
.tfall = 20,
.dnf = I2C_DIGITAL_FILTER_COEF,
},
[I2C_SPEED_FREQ_FAST] =
{
.freq = 400000,
.freq_min = 320000,
.freq_max = 480000,
.hddat_min = 0,
.vddat_max = 900,
.sudat_min = 100,
.lscl_min = 1300,
.hscl_min = 600,
.trise = 250,
.tfall = 100,
.dnf = I2C_DIGITAL_FILTER_COEF,
},
[I2C_SPEED_FREQ_FAST_PLUS] =
{
.freq = 1000000,
.freq_min = 800000,
.freq_max = 1200000,
.hddat_min = 0,
.vddat_max = 450,
.sudat_min = 50,
.lscl_min = 500,
.hscl_min = 260,
.trise = 60,
.tfall = 100,
.dnf = I2C_DIGITAL_FILTER_COEF,
},
};
/**
* @}
*/
/** @defgroup B_WL5M_SUBG_BUS_Private_Variables B-WL5M-SUBG BUS Private Variables
* @{
*/
static uint32_t I2c2InitCounter = 0U;
#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1)
static uint32_t Bus_IsI2c2MspCbValid = 0U;
#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */
static I2C_Timings_t I2c_valid_timing[I2C_VALID_TIMING_NBR];
static uint32_t I2c_valid_timing_nbr = 0U;
#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1)
static uint32_t IsSpi1MspCbValid = 0U;
#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */
/**
* @}
*/
/** @defgroup B_WL5M_SUBG_BUS_Exported_Variables B-WL5M-SUBG BUS Exported Variables
* @{
*/
I2C_HandleTypeDef hbus_i2c2 = {0};
#if defined(HAL_SPI_MODULE_ENABLED)
SPI_HandleTypeDef hbus_spi1 = {0};
#endif /* HAL_SPI_MODULE_ENABLED */
/**
* @}
*/
/** @defgroup B_WL5M_SUBG_BUS_Private_Function_Prototypes B-WL5M-SUBG BUS Private Function Prototypes
* @{
*/
static void I2C2_MspInit(I2C_HandleTypeDef *hI2c);
static void I2C2_MspDeInit(I2C_HandleTypeDef *hI2c);
static int32_t I2C2_WriteReg(uint16_t DevAddr, uint16_t MemAddSize, uint16_t Reg, uint8_t *pData, uint16_t Length);
static int32_t I2C2_ReadReg(uint16_t DevAddr, uint16_t MemAddSize, uint16_t Reg, uint8_t *pData, uint16_t Length);
static uint32_t I2C_GetTiming(uint32_t clock_src_freq, uint32_t i2c_freq);
static uint32_t I2C_Compute_SCLL_SCLH(uint32_t clock_src_freq, uint32_t I2C_speed);
static void I2C_Compute_PRESC_SCLDEL_SDADEL(uint32_t clock_src_freq, uint32_t I2C_speed);
#if defined(HAL_SPI_MODULE_ENABLED)
static void SPI1_MspInit(SPI_HandleTypeDef *hspi);
static void SPI1_MspDeInit(SPI_HandleTypeDef *hspi);
static uint32_t SPI_GetPrescaler(uint32_t clk_src_hz, uint32_t baudfreq_mbps);
#endif /* HAL_SPI_MODULE_ENABLED */
/**
* @}
*/
/** @defgroup B_WL5M_SUBG_BUS_Exported_Functions B_WL5M_SUBG BUS Exported Functions
* @{
*/
/**
* @brief Initialize BSP I2C2.
* @note Initialize could be long causing by the call of I2C_GetTiming which computes
* the best I2C configuration
* @retval BSP status.
*/
int32_t BSP_I2C2_Init(void)
{
int32_t status = BSP_ERROR_NONE;
hbus_i2c2.Instance = BUS_I2C2;
if (I2c2InitCounter == 0U)
{
if (HAL_I2C_GetState(&hbus_i2c2) == HAL_I2C_STATE_RESET)
{
#if (USE_HAL_I2C_REGISTER_CALLBACKS == 0)
/* Init the I2C2 Msp */
I2C2_MspInit(&hbus_i2c2);
/* Note: I2C_GetTiming could take a long time to compute the best I2C configuration */
if (MX_I2C2_Init(&hbus_i2c2, I2C_GetTiming(HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_I2C2),
BUS_I2C2_FREQUENCY)) != HAL_OK)
{
status = BSP_ERROR_BUS_FAILURE;
}
#else
if (Bus_IsI2c2MspCbValid == 0U)
{
if (BSP_I2C2_RegisterDefaultMspCallbacks() != BSP_ERROR_NONE)
{
status = BSP_ERROR_MSP_FAILURE;
}
}
if (status == BSP_ERROR_NONE)
{
if (MX_I2C2_Init(&hbus_i2c2, I2C_GetTiming(HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_I2C2),
BUS_I2C2_FREQUENCY)) != HAL_OK)
{
status = BSP_ERROR_BUS_FAILURE;
}
}
#endif /* (USE_HAL_I2C_REGISTER_CALLBACKS == 0) */
}
}
if (I2c2InitCounter < 0xFFFFFFFFU)
{
I2c2InitCounter++;
}
return status;
}
/**
* @brief DeInitialize BSP I2C2.
* @retval BSP status.
*/
int32_t BSP_I2C2_DeInit(void)
{
int32_t status = BSP_ERROR_NONE;
if (I2c2InitCounter > 0U)
{
I2c2InitCounter--;
if (I2c2InitCounter == 0U)
{
#if (USE_HAL_I2C_REGISTER_CALLBACKS == 0)
I2C2_MspDeInit(&hbus_i2c2);
#endif /* (USE_HAL_I2C_REGISTER_CALLBACKS == 0) */
/* De-Init the I2C */
if (HAL_I2C_DeInit(&hbus_i2c2) != HAL_OK)
{
status = BSP_ERROR_PERIPH_FAILURE;
}
}
}
return status;
}
/**
* @brief Write 8bit values in registers of the device through BUS.
* @param DevAddr Device address on Bus.
* @param Reg The target register start address to write.
* @param pData Pointer to data buffer.
* @param Length Number of data.
* @retval BSP status.
*/
int32_t BSP_I2C2_WriteReg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length)
{
return I2C2_WriteReg(DevAddr, Reg, I2C_MEMADD_SIZE_8BIT, pData, Length);
}
/**
* @brief Read a 8bit values in registers of the device through BUS.
* @param DevAddr Device address on Bus.
* @param Reg The target register start address to read.
* @param pData Pointer to data buffer.
* @param Length Number of data.
* @retval BSP status
*/
int32_t BSP_I2C2_ReadReg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length)
{
return I2C2_ReadReg(DevAddr, Reg, I2C_MEMADD_SIZE_8BIT, pData, Length);
}
/**
* @brief Write 16bit values in registers of the device through BUS.
* @param DevAddr Device address on Bus.
* @param Reg The target register start address to write.
* @param pData Pointer to data buffer.
* @param Length Number of data.
* @retval BSP status.
*/
int32_t BSP_I2C2_WriteReg16(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length)
{
return I2C2_WriteReg(DevAddr, Reg, I2C_MEMADD_SIZE_16BIT, pData, Length);
}
/**
* @brief Read a 16bit values in registers of the device through BUS.
* @param DevAddr Device address on Bus.
* @param Reg The target register start address to read.
* @param pData Pointer to data buffer.
* @param Length Number of data.
* @retval BSP status
*/
int32_t BSP_I2C2_ReadReg16(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length)
{
return I2C2_ReadReg(DevAddr, Reg, I2C_MEMADD_SIZE_16BIT, pData, Length);
}
/**
* @brief Checks if target device is ready for communication.
* @param DevAddr Target device address.
* @param Trials Number of trials.
* @retval BSP status
*/
int32_t BSP_I2C2_IsReady(uint16_t DevAddr, uint32_t Trials)
{
int32_t status = BSP_ERROR_NONE;
if (HAL_I2C_IsDeviceReady(&hbus_i2c2, DevAddr, Trials, BUS_I2C2_TIMEOUT) != HAL_OK)
{
status = BSP_ERROR_BUSY;
}
return status;
}
#if defined(HAL_SPI_MODULE_ENABLED)
/**
* @brief Initializes SPI HAL.
* @retval BSP status
*/
int32_t BSP_SPI1_Init(void)
{
int32_t ret = BSP_ERROR_NONE;
hbus_spi1.Instance = BUS_SPI1_INSTANCE;
if (HAL_SPI_GetState(&hbus_spi1) == HAL_SPI_STATE_RESET)
{
#if (USE_HAL_SPI_REGISTER_CALLBACKS == 0)
/* Init the SPI Msp */
SPI1_MspInit(&hbus_spi1);
#else
if (IsSpi1MspCbValid == 0U)
{
if (BSP_SPI1_RegisterDefaultMspCallbacks() != BSP_ERROR_NONE)
{
return BSP_ERROR_MSP_FAILURE;
}
}
#endif /* (USE_HAL_SPI_REGISTER_CALLBACKS == 0) */
/* Init the SPI */
if (MX_SPI1_Init(&hbus_spi1, SPI_GetPrescaler(HAL_RCC_GetPCLK1Freq(), BUS_SPI1_BAUDRATE)) != HAL_OK)
{
ret = BSP_ERROR_BUS_FAILURE;
}
}
return ret;
}
/**
* @brief DeInitializes SPI HAL.
* @retval BSP status
*/
int32_t BSP_SPI1_DeInit(void)
{
int32_t ret = BSP_ERROR_NONE;
#if (USE_HAL_SPI_REGISTER_CALLBACKS == 0)
SPI1_MspDeInit(&hbus_spi1);
#endif /* (USE_HAL_SPI_REGISTER_CALLBACKS == 0) */
/* DeInit the SPI*/
if (HAL_SPI_DeInit(&hbus_spi1) == HAL_OK)
{
ret = BSP_ERROR_BUS_FAILURE;
}
return ret;
}
/**
* @brief Initializes MX SPI1 HAL.
* @param phspi SPI handler
* @param BaudratePrescaler prsecaler to set for SPI baudrate
* @retval HAL status
*/
__weak HAL_StatusTypeDef MX_SPI1_Init(SPI_HandleTypeDef *phspi, uint32_t BaudratePrescaler)
{
HAL_StatusTypeDef ret = HAL_OK;
phspi->Init.Mode = SPI_MODE_MASTER;
phspi->Init.Direction = SPI_DIRECTION_2LINES;
phspi->Init.DataSize = SPI_DATASIZE_8BIT;
phspi->Init.CLKPolarity = SPI_POLARITY_HIGH;
phspi->Init.CLKPhase = SPI_PHASE_1EDGE;
phspi->Init.NSS = SPI_NSS_SOFT;
phspi->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
phspi->Init.FirstBit = SPI_FIRSTBIT_MSB;
phspi->Init.TIMode = SPI_TIMODE_DISABLE;
phspi->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
phspi->Init.CRCPolynomial = 7;
if (HAL_SPI_Init(phspi) != HAL_OK)
{
ret = HAL_ERROR;
}
return ret;
}
/**
* @brief Write Data through SPI BUS.
* @param pData Pointer to data buffer to send
* @param Length Length of data in byte
* @retval BSP status
*/
int32_t BSP_SPI1_Send(uint8_t *pData, uint16_t Length)
{
int32_t ret = BSP_ERROR_NONE;
if (HAL_SPI_Transmit(&hbus_spi1, pData, Length, BUS_SPI1_TIMEOUT) == HAL_OK)
{
ret = BSP_ERROR_NONE;
}
return ret;
}
/**
* @brief Receive Data from SPI BUS
* @param pData Pointer to data buffer to receive
* @param Length Length of data in byte
* @retval BSP status
*/
int32_t BSP_SPI1_Recv(uint8_t *pData, uint16_t Length)
{
int32_t ret = BSP_ERROR_UNKNOWN_FAILURE;
uint32_t tx_data = 0xFFFFFFFFU;
if (HAL_SPI_TransmitReceive(&hbus_spi1, (uint8_t *)&tx_data, pData, Length, BUS_SPI1_TIMEOUT) == HAL_OK)
{
ret = BSP_ERROR_NONE;
}
return ret;
}
/**
* @brief Send and Receive data to/from SPI BUS (Full duplex)
* @param pTxData Pointer to data buffer to send
* @param pRxData Pointer to data buffer to receive
* @param Length Length of data in byte
* @retval BSP status
*/
int32_t BSP_SPI1_SendRecv(uint8_t *pTxData, uint8_t *pRxData, uint16_t Length)
{
int32_t ret = BSP_ERROR_UNKNOWN_FAILURE;
if (HAL_SPI_TransmitReceive(&hbus_spi1, pTxData, pRxData, Length, BUS_SPI1_TIMEOUT) == HAL_OK)
{
ret = BSP_ERROR_NONE;
}
return ret;
}
#endif /* HAL_SPI_MODULE_ENABLED */
#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1)
/**
* @brief Register Default I2C2 Bus Msp Callbacks
* @retval BSP status
*/
int32_t BSP_I2C2_RegisterDefaultMspCallbacks(void)
{
int32_t ret = BSP_ERROR_NONE;
__HAL_I2C_RESET_HANDLE_STATE(&hbus_i2c2);
/* Register default MspInit/MspDeInit Callback */
if (HAL_I2C_RegisterCallback(&hbus_i2c2, HAL_I2C_MSPINIT_CB_ID, I2C2_MspInit) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_I2C_RegisterCallback(&hbus_i2c2, HAL_I2C_MSPDEINIT_CB_ID, I2C2_MspDeInit) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
Bus_IsI2c2MspCbValid = 1U;
}
/* BSP status */
return ret;
}
/**
* @brief Register I2C2 Bus Msp Callback registering
* @param Callbacks pointer to I2C2 MspInit/MspDeInit callback functions
* @retval BSP status
*/
int32_t BSP_I2C2_RegisterMspCallbacks(BSP_I2C_Cb_t *Callback)
{
int32_t ret = BSP_ERROR_NONE;
__HAL_I2C_RESET_HANDLE_STATE(&hbus_i2c2);
/* Register MspInit/MspDeInit Callbacks */
if (HAL_I2C_RegisterCallback(&hbus_i2c2, HAL_I2C_MSPINIT_CB_ID, Callback->pMspI2cInitCb) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_I2C_RegisterCallback(&hbus_i2c2, HAL_I2C_MSPDEINIT_CB_ID, Callback->pMspI2cDeInitCb) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
Bus_IsI2c2MspCbValid = 1U;
}
/* BSP status */
return ret;
}
#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */
/**
* @brief Return system tick in ms
* @retval Current HAL time base time stamp
*/
int32_t BSP_GetTick(void)
{
return HAL_GetTick();
}
#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1)
/**
* @brief Register Default SPI1 Bus Msp Callbacks
* @retval BSP status
*/
int32_t BSP_SPI1_RegisterDefaultMspCallbacks(void)
{
__HAL_SPI_RESET_HANDLE_STATE(&hbus_spi1);
/* Register MspInit Callback */
if (HAL_SPI_RegisterCallback(&hbus_spi1, HAL_SPI_MSPINIT_CB_ID, SPI1_MspInit) != HAL_OK)
{
return BSP_ERROR_PERIPH_FAILURE;
}
/* Register MspDeInit Callback */
if (HAL_SPI_RegisterCallback(&hbus_spi1, HAL_SPI_MSPDEINIT_CB_ID, SPI1_MspDeInit) != HAL_OK)
{
return BSP_ERROR_PERIPH_FAILURE;
}
IsSpi1MspCbValid = 1;
return BSP_ERROR_NONE;
}
/**
* @brief Register SPI1 Bus Msp Callback registering
* @param Callbacks pointer to SPI1 MspInit/MspDeInit callback functions
* @retval BSP status
*/
int32_t BSP_SPI1_RegisterMspCallbacks(BSP_SPI1_Cb_t *Callbacks)
{
__HAL_SPI_RESET_HANDLE_STATE(&hbus_spi1);
/* Register MspInit Callback */
if (HAL_SPI_RegisterCallback(&hbus_spi1, HAL_SPI_MSPINIT_CB_ID, Callbacks->pMspSpiInitCb) != HAL_OK)
{
return BSP_ERROR_PERIPH_FAILURE;
}
/* Register MspDeInit Callback */
if (HAL_SPI_RegisterCallback(&hbus_spi1, HAL_SPI_MSPDEINIT_CB_ID, Callbacks->pMspSpiDeInitCb) != HAL_OK)
{
return BSP_ERROR_PERIPH_FAILURE;
}
IsSpi1MspCbValid = 1;
return BSP_ERROR_NONE;
}
#endif /* (USE_HAL_SPI_REGISTER_CALLBACKS == 1) */
/**
* @brief MX I2C1 initialization.
* @param hI2c I2C handle.
* @param timing I2C timing.
* @retval HAL status.
*/
__weak HAL_StatusTypeDef MX_I2C2_Init(I2C_HandleTypeDef *hI2c, uint32_t timing)
{
HAL_StatusTypeDef status = HAL_OK;
hI2c->Init.Timing = timing;
hI2c->Init.OwnAddress1 = 0;
hI2c->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hI2c->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hI2c->Init.OwnAddress2 = 0;
hI2c->Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hI2c->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hI2c->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(hI2c) != HAL_OK)
{
status = HAL_ERROR;
}
else
{
uint32_t analog_filter;
analog_filter = (I2C_USE_ANALOG_FILTER == 1U) ? I2C_ANALOGFILTER_ENABLE : I2C_ANALOGFILTER_DISABLE;
if (HAL_I2CEx_ConfigAnalogFilter(hI2c, analog_filter) != HAL_OK)
{
status = HAL_ERROR;
}
else
{
if (HAL_I2CEx_ConfigDigitalFilter(hI2c, I2C_DIGITAL_FILTER_COEF) != HAL_OK)
{
status = HAL_ERROR;
}
}
}
return status;
}
#if defined(HAL_SPI_MODULE_ENABLED)
/**
* @brief Initializes SPI MSP.
* @param hspi SPI handler
* @retval None
*/
static void SPI1_MspInit(SPI_HandleTypeDef *hspi)
{
UNUSED(hspi);
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable SPIx clock */
BUS_SPI1_CLOCK_ENABLE();
/* enable SPIx gpio clock */
BUS_SPI1_GPIO_CLKA_ENABLE();
/* configure SPIx SCK, MOSI */
GPIO_InitStructure.Pin = BUS_SPI1_MOSI_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pull = GPIO_PULLDOWN;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStructure.Alternate = BUS_SPI1_AF;
HAL_GPIO_Init(BUS_SPI1_GPIO_PORTA, &GPIO_InitStructure);
GPIO_InitStructure.Pin = BUS_SPI1_SCK_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pull = GPIO_PULLDOWN;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStructure.Alternate = BUS_SPI1_AF;
HAL_GPIO_Init(BUS_SPI1_GPIO_PORTA, &GPIO_InitStructure);
}
/**
* @brief DeInitializes SPI MSP.
* @param hspi SPI handler
* @retval None
*/
static void SPI1_MspDeInit(SPI_HandleTypeDef *hspi)
{
UNUSED(hspi);
GPIO_InitTypeDef gpio_init_structure;
/* Peripheral clock disable */
__HAL_RCC_SPI1_CLK_DISABLE();
/* DeInitialize Peripheral GPIOs */
/* SCK GPIO */
gpio_init_structure.Pin = BUS_SPI1_SCK_PIN;
HAL_GPIO_DeInit(BUS_SPI1_GPIO_PORTA, gpio_init_structure.Pin);
/* MOSI GPIO */
gpio_init_structure.Pin = BUS_SPI1_MOSI_PIN;
HAL_GPIO_DeInit(BUS_SPI1_GPIO_PORTA, gpio_init_structure.Pin);
}
#endif /* HAL_SPI_MODULE_ENABLED */
/**
* @}
*/
/** @defgroup B_WL5M_SUBG_BUS_Private_Functions B-WL5M-SUBG BUS Private Functions
* @{
*/
/**
* @brief Initialize I2C2 MSP.
* @param hI2c I2C handler
* @retval None
*/
static void I2C2_MspInit(I2C_HandleTypeDef *hI2c)
{
GPIO_InitTypeDef gpio_init_structure;
/* Prevent unused argument(s) compilation warning */
UNUSED(hI2c);
/*** Configure the GPIOs ***/
/* Enable GPIO clock */
BUS_I2C2_GPIO_CLK_ENABLE();
/* Configure I2C SCL as alternate function */
gpio_init_structure.Pin = BUS_I2C2_SCL_GPIO_PIN;
gpio_init_structure.Mode = GPIO_MODE_AF_OD;
gpio_init_structure.Pull = GPIO_NOPULL;
gpio_init_structure.Speed = GPIO_SPEED_FREQ_HIGH;
gpio_init_structure.Alternate = BUS_I2C2_SCL_GPIO_AF;
HAL_GPIO_Init(BUS_I2C2_SCL_GPIO_PORT, &gpio_init_structure);
/* Configure I2C SDA as alternate function */
gpio_init_structure.Pin = BUS_I2C2_SDA_GPIO_PIN;
gpio_init_structure.Alternate = BUS_I2C2_SDA_GPIO_AF;
HAL_GPIO_Init(BUS_I2C2_SDA_GPIO_PORT, &gpio_init_structure);
/*** Configure the I2C peripheral ***/
/* Enable I2C clock */
BUS_I2C2_CLK_ENABLE();
/* Force the I2C peripheral clock reset */
BUS_I2C2_FORCE_RESET();
/* Release the I2C peripheral clock reset */
BUS_I2C2_RELEASE_RESET();
}
/**
* @brief DeInitialize I2C MSP.
* @param hI2c I2C handler
* @retval None
*/
static void I2C2_MspDeInit(I2C_HandleTypeDef *hI2c)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hI2c);
/* De-initialiaze I2C SCL and SDA */
HAL_GPIO_DeInit(BUS_I2C2_SCL_GPIO_PORT, BUS_I2C2_SCL_GPIO_PIN);
HAL_GPIO_DeInit(BUS_I2C2_SDA_GPIO_PORT, BUS_I2C2_SDA_GPIO_PIN);
/* Disable I2C clock */
BUS_I2C2_CLK_DISABLE();
}
/**
* @brief Write values in registers of the device through BUS.
* @param DevAddr Device address on Bus.
* @param Reg The target register start address to write.
* @param MemAddSize Size of internal memory address.
* @param pData The target register values to be written.
* @param Length Number of data.
* @retval BSP status.
*/
static int32_t I2C2_WriteReg(uint16_t DevAddr, uint16_t Reg, uint16_t MemAddSize, uint8_t *pData, uint16_t Length)
{
int32_t status = BSP_ERROR_NONE;
uint32_t hal_error;
if (HAL_I2C_Mem_Write(&hbus_i2c2, DevAddr, Reg, MemAddSize, pData, Length, BUS_I2C2_TIMEOUT) != HAL_OK)
{
hal_error = HAL_I2C_GetError(&hbus_i2c2);
if ((hal_error & HAL_I2C_ERROR_BERR) != 0U)
{
status = BSP_ERROR_BUS_PROTOCOL_FAILURE;
}
else if ((hal_error & HAL_I2C_ERROR_ARLO) != 0U)
{
status = BSP_ERROR_BUS_ARBITRATION_LOSS;
}
else if ((hal_error & HAL_I2C_ERROR_AF) != 0U)
{
status = BSP_ERROR_BUS_ACKNOWLEDGE_FAILURE;
}
else if (((hal_error & HAL_I2C_ERROR_TIMEOUT) != 0U) || ((hal_error & HAL_I2C_ERROR_SIZE) != 0U))
{
status = BSP_ERROR_BUS_TRANSACTION_FAILURE;
}
else
{
status = BSP_ERROR_PERIPH_FAILURE;
}
}
return status;
}
/**
* @brief Read values in registers of the device through BUS.
* @param DevAddr Device address on Bus.
* @param Reg The target register start address to read.
* @param MemAddSize Size of internal memory address.
* @param pData The target register values to be read.
* @param Length Number of data.
* @retval BSP status.
*/
static int32_t I2C2_ReadReg(uint16_t DevAddr, uint16_t Reg, uint16_t MemAddSize, uint8_t *pData, uint16_t Length)
{
int32_t status = BSP_ERROR_NONE;
uint32_t hal_error;
if (HAL_I2C_Mem_Read(&hbus_i2c2, DevAddr, Reg, MemAddSize, pData, Length, BUS_I2C2_TIMEOUT) != HAL_OK)
{
hal_error = HAL_I2C_GetError(&hbus_i2c2);
if ((hal_error & HAL_I2C_ERROR_BERR) != 0U)
{
status = BSP_ERROR_BUS_PROTOCOL_FAILURE;
}
else if ((hal_error & HAL_I2C_ERROR_ARLO) != 0U)
{
status = BSP_ERROR_BUS_ARBITRATION_LOSS;
}
else if ((hal_error & HAL_I2C_ERROR_AF) != 0U)
{
status = BSP_ERROR_BUS_ACKNOWLEDGE_FAILURE;
}
else if (((hal_error & HAL_I2C_ERROR_TIMEOUT) != 0U) || ((hal_error & HAL_I2C_ERROR_SIZE) != 0U))
{
status = BSP_ERROR_BUS_TRANSACTION_FAILURE;
}
else
{
status = BSP_ERROR_PERIPH_FAILURE;
}
}
return status;
}
/**
* @brief Compute I2C timing according current I2C clock source and required I2C clock.
* @param clock_src_freq I2C clock source in Hz.
* @param i2c_freq Required I2C clock in Hz.
* @retval I2C timing or 0 in case of error.
*/
static uint32_t I2C_GetTiming(uint32_t clock_src_freq, uint32_t i2c_freq)
{
uint32_t ret = 0;
uint32_t speed;
uint32_t idx;
if ((clock_src_freq != 0U) && (i2c_freq != 0U))
{
for (speed = 0U ; speed <= (uint32_t)I2C_SPEED_FREQ_FAST_PLUS ; speed++)
{
if ((i2c_freq >= I2C_Charac[speed].freq_min) &&
(i2c_freq <= I2C_Charac[speed].freq_max))
{
I2C_Compute_PRESC_SCLDEL_SDADEL(clock_src_freq, speed);
idx = I2C_Compute_SCLL_SCLH(clock_src_freq, speed);
if (idx < I2C_VALID_TIMING_NBR)
{
ret = ((I2c_valid_timing[idx].presc & 0x0FU) << 28) | \
((I2c_valid_timing[idx].tscldel & 0x0FU) << 20) | \
((I2c_valid_timing[idx].tsdadel & 0x0FU) << 16) | \
((I2c_valid_timing[idx].sclh & 0xFFU) << 8) | \
((I2c_valid_timing[idx].scll & 0xFFU) << 0);
}
break;
}
}
}
return ret;
}
/**
* @brief Compute PRESC, SCLDEL and SDADEL.
* @param clock_src_freq I2C source clock in HZ.
* @param I2C_speed I2C frequency (index).
* @retval None.
*/
static void I2C_Compute_PRESC_SCLDEL_SDADEL(uint32_t clock_src_freq, uint32_t I2C_speed)
{
uint32_t prev_presc = I2C_PRESC_MAX;
uint32_t ti2cclk;
int32_t tsdadel_min;
int32_t tsdadel_max;
int32_t tscldel_min;
uint32_t presc;
uint32_t scldel;
uint32_t sdadel;
uint32_t tafdel_min;
uint32_t tafdel_max;
ti2cclk = (SEC2NSEC + (clock_src_freq / 2U)) / clock_src_freq;
tafdel_min = (I2C_USE_ANALOG_FILTER == 1U) ? I2C_ANALOG_FILTER_DELAY_MIN : 0U;
tafdel_max = (I2C_USE_ANALOG_FILTER == 1U) ? I2C_ANALOG_FILTER_DELAY_MAX : 0U;
/* tDNF = DNF x tI2CCLK
tPRESC = (PRESC+1) x tI2CCLK
SDADEL >= {tf +tHD;DAT(min) - tAF(min) - tDNF - [3 x tI2CCLK]} / {tPRESC}
SDADEL <= {tVD;DAT(max) - tr - tAF(max) - tDNF- [4 x tI2CCLK]} / {tPRESC} */
tsdadel_min = (int32_t)I2C_Charac[I2C_speed].tfall + (int32_t)I2C_Charac[I2C_speed].hddat_min -
(int32_t)tafdel_min - (int32_t)(((int32_t)I2C_Charac[I2C_speed].dnf + 3) * (int32_t)ti2cclk);
tsdadel_max = (int32_t)I2C_Charac[I2C_speed].vddat_max - (int32_t)I2C_Charac[I2C_speed].trise -
(int32_t)tafdel_max - (int32_t)(((int32_t)I2C_Charac[I2C_speed].dnf + 4) * (int32_t)ti2cclk);
/* {[tr+ tSU;DAT(min)] / [tPRESC]} - 1 <= SCLDEL */
tscldel_min = (int32_t)I2C_Charac[I2C_speed].trise + (int32_t)I2C_Charac[I2C_speed].sudat_min;
if (tsdadel_min <= 0)
{
tsdadel_min = 0;
}
if (tsdadel_max <= 0)
{
tsdadel_max = 0;
}
for (presc = 0U; presc < I2C_PRESC_MAX; presc++)
{
for (scldel = 0U; scldel < I2C_SCLDEL_MAX; scldel++)
{
/* TSCLDEL = (SCLDEL+1) * (PRESC+1) * TI2CCLK */
uint32_t tscldel = (scldel + 1U) * (presc + 1U) * ti2cclk;
if (tscldel >= (uint32_t)tscldel_min)
{
for (sdadel = 0; sdadel < I2C_SDADEL_MAX; sdadel++)
{
/* TSDADEL = SDADEL * (PRESC+1) * TI2CCLK */
uint32_t tsdadel = (sdadel * (presc + 1U)) * ti2cclk;
if ((tsdadel >= (uint32_t)tsdadel_min) && (tsdadel <= (uint32_t)tsdadel_max))
{
if (presc != prev_presc)
{
I2c_valid_timing[I2c_valid_timing_nbr].presc = presc;
I2c_valid_timing[I2c_valid_timing_nbr].tscldel = scldel;
I2c_valid_timing[I2c_valid_timing_nbr].tsdadel = sdadel;
prev_presc = presc;
I2c_valid_timing_nbr ++;
if (I2c_valid_timing_nbr >= I2C_VALID_TIMING_NBR)
{
return;
}
}
}
}
}
}
}
}
/**
* @brief Calculate SCLL and SCLH and find best configuration.
* @param clock_src_freq I2C source clock in HZ.
* @param I2C_speed I2C frequency (index).
* @retval config index (0 to I2C_VALID_TIMING_NBR], 0xFFFFFFFF for no valid config.
*/
static uint32_t I2C_Compute_SCLL_SCLH(uint32_t clock_src_freq, uint32_t I2C_speed)
{
uint32_t ret = 0xFFFFFFFFU;
uint32_t ti2cclk;
uint32_t ti2cspeed;
uint32_t prev_error;
uint32_t dnf_delay;
uint32_t clk_min;
uint32_t clk_max;
uint32_t scll;
uint32_t sclh;
uint32_t tafdel_min;
ti2cclk = (SEC2NSEC + (clock_src_freq / 2U)) / clock_src_freq;
ti2cspeed = (SEC2NSEC + (I2C_Charac[I2C_speed].freq / 2U)) / I2C_Charac[I2C_speed].freq;
tafdel_min = (I2C_USE_ANALOG_FILTER == 1U) ? I2C_ANALOG_FILTER_DELAY_MIN : 0U;
/* tDNF = DNF x tI2CCLK */
dnf_delay = I2C_Charac[I2C_speed].dnf * ti2cclk;
clk_max = SEC2NSEC / I2C_Charac[I2C_speed].freq_min;
clk_min = SEC2NSEC / I2C_Charac[I2C_speed].freq_max;
prev_error = ti2cspeed;
for (uint32_t count = 0U; count < I2c_valid_timing_nbr; count++)
{
/* tPRESC = (PRESC+1) x tI2CCLK*/
uint32_t tpresc = (I2c_valid_timing[count].presc + 1U) * ti2cclk;
for (scll = 0; scll < I2C_SCLL_MAX; scll++)
{
/* tLOW(min) <= tAF(min) + tDNF + 2 x tI2CCLK + [(SCLL+1) x tPRESC ] */
uint32_t tscl_l = tafdel_min + dnf_delay + (2U * ti2cclk) + ((scll + 1U) * tpresc);
/* The I2CCLK period tI2CCLK must respect the following conditions:
tI2CCLK < (tLOW - tfilters) / 4 and tI2CCLK < tHIGH */
if ((tscl_l > I2C_Charac[I2C_speed].lscl_min) && (ti2cclk < ((tscl_l - tafdel_min - dnf_delay) / 4U)))
{
for (sclh = 0; sclh < I2C_SCLH_MAX; sclh++)
{
/* tHIGH(min) <= tAF(min) + tDNF + 2 x tI2CCLK + [(SCLH+1) x tPRESC] */
uint32_t tscl_h = tafdel_min + dnf_delay + (2U * ti2cclk) + ((sclh + 1U) * tpresc);
/* tSCL = tf + tLOW + tr + tHIGH */
uint32_t tscl = tscl_l + tscl_h + I2C_Charac[I2C_speed].trise + I2C_Charac[I2C_speed].tfall;
if ((tscl >= clk_min) && (tscl <= clk_max)
&& (tscl_h >= I2C_Charac[I2C_speed].hscl_min) && (ti2cclk < tscl_h))
{
int32_t error = (int32_t)tscl - (int32_t)ti2cspeed;
if (error < 0)
{
error = -error;
}
/* look for the timings with the lowest clock error */
if ((uint32_t)error < prev_error)
{
prev_error = (uint32_t)error;
I2c_valid_timing[count].scll = scll;
I2c_valid_timing[count].sclh = sclh;
ret = count;
}
}
}
}
}
}
return ret;
}
#if defined(HAL_SPI_MODULE_ENABLED)
/**
* @brief Convert the SPI baudfreq into tpresc.
* @param clock_src_freq : SPI source clock in HZ.
* @param baudfreq_mbps : SPI baud freq in mbps.
* @retval Prescaler divisor
*/
static uint32_t SPI_GetPrescaler(uint32_t clock_src_freq, uint32_t baudfreq_mbps)
{
uint32_t divisor = 0U;
uint32_t spi_clk = clock_src_freq;
uint32_t presc = 0U;
static const uint32_t baudfreq[] =
{
SPI_BAUDRATEPRESCALER_2,
SPI_BAUDRATEPRESCALER_4,
SPI_BAUDRATEPRESCALER_8,
SPI_BAUDRATEPRESCALER_16,
SPI_BAUDRATEPRESCALER_32,
SPI_BAUDRATEPRESCALER_64,
SPI_BAUDRATEPRESCALER_128,
SPI_BAUDRATEPRESCALER_256,
};
while (spi_clk > baudfreq_mbps)
{
presc = baudfreq[divisor];
if (++divisor > 7U)
{
break;
}
spi_clk = (spi_clk >> 1U);
}
return presc;
}
#endif /* HAL_SPI_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/