diff --git a/calib_board/Core/Inc/spi.h b/calib_board/Core/Inc/spi.h new file mode 100644 index 0000000..030130a --- /dev/null +++ b/calib_board/Core/Inc/spi.h @@ -0,0 +1,55 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file spi.h + * @brief This file contains all the function prototypes for + * the spi.c file + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 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. + * + ****************************************************************************** + */ +/* USER CODE END Header */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __SPI_H__ +#define __SPI_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +extern SPI_HandleTypeDef hspi1; + +extern SPI_HandleTypeDef hspi2; + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_SPI1_Init(void); +void MX_SPI2_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __SPI_H__ */ + diff --git a/calib_board/Core/Src/spi.c b/calib_board/Core/Src/spi.c new file mode 100644 index 0000000..ba63b41 --- /dev/null +++ b/calib_board/Core/Src/spi.c @@ -0,0 +1,196 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file spi.c + * @brief This file provides code for the configuration + * of the SPI instances. + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 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. + * + ****************************************************************************** + */ +/* USER CODE END Header */ +/* Includes ------------------------------------------------------------------*/ +#include "spi.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +SPI_HandleTypeDef hspi1; +SPI_HandleTypeDef hspi2; + +/* SPI1 init function */ +void MX_SPI1_Init(void) +{ + + /* USER CODE BEGIN SPI1_Init 0 */ + + /* USER CODE END SPI1_Init 0 */ + + /* USER CODE BEGIN SPI1_Init 1 */ + + /* USER CODE END SPI1_Init 1 */ + hspi1.Instance = SPI1; + hspi1.Init.Mode = SPI_MODE_MASTER; + hspi1.Init.Direction = SPI_DIRECTION_2LINES; + hspi1.Init.DataSize = SPI_DATASIZE_8BIT; + hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; + hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; + hspi1.Init.NSS = SPI_NSS_SOFT; + hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; + hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; + hspi1.Init.TIMode = SPI_TIMODE_DISABLE; + hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; + hspi1.Init.CRCPolynomial = 10; + if (HAL_SPI_Init(&hspi1) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN SPI1_Init 2 */ + + /* USER CODE END SPI1_Init 2 */ + +} +/* SPI2 init function */ +void MX_SPI2_Init(void) +{ + + /* USER CODE BEGIN SPI2_Init 0 */ + + /* USER CODE END SPI2_Init 0 */ + + /* USER CODE BEGIN SPI2_Init 1 */ + + /* USER CODE END SPI2_Init 1 */ + hspi2.Instance = SPI2; + hspi2.Init.Mode = SPI_MODE_MASTER; + hspi2.Init.Direction = SPI_DIRECTION_2LINES; + hspi2.Init.DataSize = SPI_DATASIZE_8BIT; + hspi2.Init.CLKPolarity = SPI_POLARITY_LOW; + hspi2.Init.CLKPhase = SPI_PHASE_1EDGE; + hspi2.Init.NSS = SPI_NSS_SOFT; + hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; + hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB; + hspi2.Init.TIMode = SPI_TIMODE_DISABLE; + hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; + hspi2.Init.CRCPolynomial = 10; + if (HAL_SPI_Init(&hspi2) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN SPI2_Init 2 */ + + /* USER CODE END SPI2_Init 2 */ + +} + +void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle) +{ + + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if(spiHandle->Instance==SPI1) + { + /* USER CODE BEGIN SPI1_MspInit 0 */ + + /* USER CODE END SPI1_MspInit 0 */ + /* SPI1 clock enable */ + __HAL_RCC_SPI1_CLK_ENABLE(); + + __HAL_RCC_GPIOA_CLK_ENABLE(); + /**SPI1 GPIO Configuration + PA5 ------> SPI1_SCK + PA6 ------> SPI1_MISO + PA7 ------> SPI1_MOSI + */ + GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF5_SPI1; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /* USER CODE BEGIN SPI1_MspInit 1 */ + + /* USER CODE END SPI1_MspInit 1 */ + } + else if(spiHandle->Instance==SPI2) + { + /* USER CODE BEGIN SPI2_MspInit 0 */ + + /* USER CODE END SPI2_MspInit 0 */ + /* SPI2 clock enable */ + __HAL_RCC_SPI2_CLK_ENABLE(); + + __HAL_RCC_GPIOB_CLK_ENABLE(); + /**SPI2 GPIO Configuration + PB13 ------> SPI2_SCK + PB14 ------> SPI2_MISO + PB15 ------> SPI2_MOSI + */ + GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF5_SPI2; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /* USER CODE BEGIN SPI2_MspInit 1 */ + + /* USER CODE END SPI2_MspInit 1 */ + } +} + +void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle) +{ + + if(spiHandle->Instance==SPI1) + { + /* USER CODE BEGIN SPI1_MspDeInit 0 */ + + /* USER CODE END SPI1_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_SPI1_CLK_DISABLE(); + + /**SPI1 GPIO Configuration + PA5 ------> SPI1_SCK + PA6 ------> SPI1_MISO + PA7 ------> SPI1_MOSI + */ + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7); + + /* USER CODE BEGIN SPI1_MspDeInit 1 */ + + /* USER CODE END SPI1_MspDeInit 1 */ + } + else if(spiHandle->Instance==SPI2) + { + /* USER CODE BEGIN SPI2_MspDeInit 0 */ + + /* USER CODE END SPI2_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_SPI2_CLK_DISABLE(); + + /**SPI2 GPIO Configuration + PB13 ------> SPI2_SCK + PB14 ------> SPI2_MISO + PB15 ------> SPI2_MOSI + */ + HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15); + + /* USER CODE BEGIN SPI2_MspDeInit 1 */ + + /* USER CODE END SPI2_MspDeInit 1 */ + } +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ diff --git a/calib_board/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_spi.h b/calib_board/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_spi.h new file mode 100644 index 0000000..d7997a3 --- /dev/null +++ b/calib_board/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_spi.h @@ -0,0 +1,729 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_spi.h + * @author MCD Application Team + * @brief Header file of SPI HAL module. + ****************************************************************************** + * @attention + * + * Copyright (c) 2016 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef STM32F4xx_HAL_SPI_H +#define STM32F4xx_HAL_SPI_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal_def.h" + +/** @addtogroup STM32F4xx_HAL_Driver + * @{ + */ + +/** @addtogroup SPI + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ +/** @defgroup SPI_Exported_Types SPI Exported Types + * @{ + */ + +/** + * @brief SPI Configuration Structure definition + */ +typedef struct +{ + uint32_t Mode; /*!< Specifies the SPI operating mode. + This parameter can be a value of @ref SPI_Mode */ + + uint32_t Direction; /*!< Specifies the SPI bidirectional mode state. + This parameter can be a value of @ref SPI_Direction */ + + uint32_t DataSize; /*!< Specifies the SPI data size. + This parameter can be a value of @ref SPI_Data_Size */ + + uint32_t CLKPolarity; /*!< Specifies the serial clock steady state. + This parameter can be a value of @ref SPI_Clock_Polarity */ + + uint32_t CLKPhase; /*!< Specifies the clock active edge for the bit capture. + This parameter can be a value of @ref SPI_Clock_Phase */ + + uint32_t NSS; /*!< Specifies whether the NSS signal is managed by + hardware (NSS pin) or by software using the SSI bit. + This parameter can be a value of @ref SPI_Slave_Select_management */ + + uint32_t BaudRatePrescaler; /*!< Specifies the Baud Rate prescaler value which will be + used to configure the transmit and receive SCK clock. + This parameter can be a value of @ref SPI_BaudRate_Prescaler + @note The communication clock is derived from the master + clock. The slave clock does not need to be set. */ + + uint32_t FirstBit; /*!< Specifies whether data transfers start from MSB or LSB bit. + This parameter can be a value of @ref SPI_MSB_LSB_transmission */ + + uint32_t TIMode; /*!< Specifies if the TI mode is enabled or not. + This parameter can be a value of @ref SPI_TI_mode */ + + uint32_t CRCCalculation; /*!< Specifies if the CRC calculation is enabled or not. + This parameter can be a value of @ref SPI_CRC_Calculation */ + + uint32_t CRCPolynomial; /*!< Specifies the polynomial used for the CRC calculation. + This parameter must be an odd number between Min_Data = 1 and Max_Data = 65535 */ +} SPI_InitTypeDef; + +/** + * @brief HAL SPI State structure definition + */ +typedef enum +{ + HAL_SPI_STATE_RESET = 0x00U, /*!< Peripheral not Initialized */ + HAL_SPI_STATE_READY = 0x01U, /*!< Peripheral Initialized and ready for use */ + HAL_SPI_STATE_BUSY = 0x02U, /*!< an internal process is ongoing */ + HAL_SPI_STATE_BUSY_TX = 0x03U, /*!< Data Transmission process is ongoing */ + HAL_SPI_STATE_BUSY_RX = 0x04U, /*!< Data Reception process is ongoing */ + HAL_SPI_STATE_BUSY_TX_RX = 0x05U, /*!< Data Transmission and Reception process is ongoing */ + HAL_SPI_STATE_ERROR = 0x06U, /*!< SPI error state */ + HAL_SPI_STATE_ABORT = 0x07U /*!< SPI abort is ongoing */ +} HAL_SPI_StateTypeDef; + +/** + * @brief SPI handle Structure definition + */ +typedef struct __SPI_HandleTypeDef +{ + SPI_TypeDef *Instance; /*!< SPI registers base address */ + + SPI_InitTypeDef Init; /*!< SPI communication parameters */ + + uint8_t *pTxBuffPtr; /*!< Pointer to SPI Tx transfer Buffer */ + + uint16_t TxXferSize; /*!< SPI Tx Transfer size */ + + __IO uint16_t TxXferCount; /*!< SPI Tx Transfer Counter */ + + uint8_t *pRxBuffPtr; /*!< Pointer to SPI Rx transfer Buffer */ + + uint16_t RxXferSize; /*!< SPI Rx Transfer size */ + + __IO uint16_t RxXferCount; /*!< SPI Rx Transfer Counter */ + + void (*RxISR)(struct __SPI_HandleTypeDef *hspi); /*!< function pointer on Rx ISR */ + + void (*TxISR)(struct __SPI_HandleTypeDef *hspi); /*!< function pointer on Tx ISR */ + + DMA_HandleTypeDef *hdmatx; /*!< SPI Tx DMA Handle parameters */ + + DMA_HandleTypeDef *hdmarx; /*!< SPI Rx DMA Handle parameters */ + + HAL_LockTypeDef Lock; /*!< Locking object */ + + __IO HAL_SPI_StateTypeDef State; /*!< SPI communication state */ + + __IO uint32_t ErrorCode; /*!< SPI Error code */ + +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + void (* TxCpltCallback)(struct __SPI_HandleTypeDef *hspi); /*!< SPI Tx Completed callback */ + void (* RxCpltCallback)(struct __SPI_HandleTypeDef *hspi); /*!< SPI Rx Completed callback */ + void (* TxRxCpltCallback)(struct __SPI_HandleTypeDef *hspi); /*!< SPI TxRx Completed callback */ + void (* TxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi); /*!< SPI Tx Half Completed callback */ + void (* RxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi); /*!< SPI Rx Half Completed callback */ + void (* TxRxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi); /*!< SPI TxRx Half Completed callback */ + void (* ErrorCallback)(struct __SPI_HandleTypeDef *hspi); /*!< SPI Error callback */ + void (* AbortCpltCallback)(struct __SPI_HandleTypeDef *hspi); /*!< SPI Abort callback */ + void (* MspInitCallback)(struct __SPI_HandleTypeDef *hspi); /*!< SPI Msp Init callback */ + void (* MspDeInitCallback)(struct __SPI_HandleTypeDef *hspi); /*!< SPI Msp DeInit callback */ + +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ +} SPI_HandleTypeDef; + +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) +/** + * @brief HAL SPI Callback ID enumeration definition + */ +typedef enum +{ + HAL_SPI_TX_COMPLETE_CB_ID = 0x00U, /*!< SPI Tx Completed callback ID */ + HAL_SPI_RX_COMPLETE_CB_ID = 0x01U, /*!< SPI Rx Completed callback ID */ + HAL_SPI_TX_RX_COMPLETE_CB_ID = 0x02U, /*!< SPI TxRx Completed callback ID */ + HAL_SPI_TX_HALF_COMPLETE_CB_ID = 0x03U, /*!< SPI Tx Half Completed callback ID */ + HAL_SPI_RX_HALF_COMPLETE_CB_ID = 0x04U, /*!< SPI Rx Half Completed callback ID */ + HAL_SPI_TX_RX_HALF_COMPLETE_CB_ID = 0x05U, /*!< SPI TxRx Half Completed callback ID */ + HAL_SPI_ERROR_CB_ID = 0x06U, /*!< SPI Error callback ID */ + HAL_SPI_ABORT_CB_ID = 0x07U, /*!< SPI Abort callback ID */ + HAL_SPI_MSPINIT_CB_ID = 0x08U, /*!< SPI Msp Init callback ID */ + HAL_SPI_MSPDEINIT_CB_ID = 0x09U /*!< SPI Msp DeInit callback ID */ + +} HAL_SPI_CallbackIDTypeDef; + +/** + * @brief HAL SPI Callback pointer definition + */ +typedef void (*pSPI_CallbackTypeDef)(SPI_HandleTypeDef *hspi); /*!< pointer to an SPI callback function */ + +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ +/** + * @} + */ + +/* Exported constants --------------------------------------------------------*/ +/** @defgroup SPI_Exported_Constants SPI Exported Constants + * @{ + */ + +/** @defgroup SPI_Error_Code SPI Error Code + * @{ + */ +#define HAL_SPI_ERROR_NONE (0x00000000U) /*!< No error */ +#define HAL_SPI_ERROR_MODF (0x00000001U) /*!< MODF error */ +#define HAL_SPI_ERROR_CRC (0x00000002U) /*!< CRC error */ +#define HAL_SPI_ERROR_OVR (0x00000004U) /*!< OVR error */ +#define HAL_SPI_ERROR_FRE (0x00000008U) /*!< FRE error */ +#define HAL_SPI_ERROR_DMA (0x00000010U) /*!< DMA transfer error */ +#define HAL_SPI_ERROR_FLAG (0x00000020U) /*!< Error on RXNE/TXE/BSY Flag */ +#define HAL_SPI_ERROR_ABORT (0x00000040U) /*!< Error during SPI Abort procedure */ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) +#define HAL_SPI_ERROR_INVALID_CALLBACK (0x00000080U) /*!< Invalid Callback error */ +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ +/** + * @} + */ + +/** @defgroup SPI_Mode SPI Mode + * @{ + */ +#define SPI_MODE_SLAVE (0x00000000U) +#define SPI_MODE_MASTER (SPI_CR1_MSTR | SPI_CR1_SSI) +/** + * @} + */ + +/** @defgroup SPI_Direction SPI Direction Mode + * @{ + */ +#define SPI_DIRECTION_2LINES (0x00000000U) +#define SPI_DIRECTION_2LINES_RXONLY SPI_CR1_RXONLY +#define SPI_DIRECTION_1LINE SPI_CR1_BIDIMODE +/** + * @} + */ + +/** @defgroup SPI_Data_Size SPI Data Size + * @{ + */ +#define SPI_DATASIZE_8BIT (0x00000000U) +#define SPI_DATASIZE_16BIT SPI_CR1_DFF +/** + * @} + */ + +/** @defgroup SPI_Clock_Polarity SPI Clock Polarity + * @{ + */ +#define SPI_POLARITY_LOW (0x00000000U) +#define SPI_POLARITY_HIGH SPI_CR1_CPOL +/** + * @} + */ + +/** @defgroup SPI_Clock_Phase SPI Clock Phase + * @{ + */ +#define SPI_PHASE_1EDGE (0x00000000U) +#define SPI_PHASE_2EDGE SPI_CR1_CPHA +/** + * @} + */ + +/** @defgroup SPI_Slave_Select_management SPI Slave Select Management + * @{ + */ +#define SPI_NSS_SOFT SPI_CR1_SSM +#define SPI_NSS_HARD_INPUT (0x00000000U) +#define SPI_NSS_HARD_OUTPUT (SPI_CR2_SSOE << 16U) +/** + * @} + */ + +/** @defgroup SPI_BaudRate_Prescaler SPI BaudRate Prescaler + * @{ + */ +#define SPI_BAUDRATEPRESCALER_2 (0x00000000U) +#define SPI_BAUDRATEPRESCALER_4 (SPI_CR1_BR_0) +#define SPI_BAUDRATEPRESCALER_8 (SPI_CR1_BR_1) +#define SPI_BAUDRATEPRESCALER_16 (SPI_CR1_BR_1 | SPI_CR1_BR_0) +#define SPI_BAUDRATEPRESCALER_32 (SPI_CR1_BR_2) +#define SPI_BAUDRATEPRESCALER_64 (SPI_CR1_BR_2 | SPI_CR1_BR_0) +#define SPI_BAUDRATEPRESCALER_128 (SPI_CR1_BR_2 | SPI_CR1_BR_1) +#define SPI_BAUDRATEPRESCALER_256 (SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_BR_0) +/** + * @} + */ + +/** @defgroup SPI_MSB_LSB_transmission SPI MSB LSB Transmission + * @{ + */ +#define SPI_FIRSTBIT_MSB (0x00000000U) +#define SPI_FIRSTBIT_LSB SPI_CR1_LSBFIRST +/** + * @} + */ + +/** @defgroup SPI_TI_mode SPI TI Mode + * @{ + */ +#define SPI_TIMODE_DISABLE (0x00000000U) +#define SPI_TIMODE_ENABLE SPI_CR2_FRF +/** + * @} + */ + +/** @defgroup SPI_CRC_Calculation SPI CRC Calculation + * @{ + */ +#define SPI_CRCCALCULATION_DISABLE (0x00000000U) +#define SPI_CRCCALCULATION_ENABLE SPI_CR1_CRCEN +/** + * @} + */ + +/** @defgroup SPI_Interrupt_definition SPI Interrupt Definition + * @{ + */ +#define SPI_IT_TXE SPI_CR2_TXEIE +#define SPI_IT_RXNE SPI_CR2_RXNEIE +#define SPI_IT_ERR SPI_CR2_ERRIE +/** + * @} + */ + +/** @defgroup SPI_Flags_definition SPI Flags Definition + * @{ + */ +#define SPI_FLAG_RXNE SPI_SR_RXNE /* SPI status flag: Rx buffer not empty flag */ +#define SPI_FLAG_TXE SPI_SR_TXE /* SPI status flag: Tx buffer empty flag */ +#define SPI_FLAG_BSY SPI_SR_BSY /* SPI status flag: Busy flag */ +#define SPI_FLAG_CRCERR SPI_SR_CRCERR /* SPI Error flag: CRC error flag */ +#define SPI_FLAG_MODF SPI_SR_MODF /* SPI Error flag: Mode fault flag */ +#define SPI_FLAG_OVR SPI_SR_OVR /* SPI Error flag: Overrun flag */ +#define SPI_FLAG_FRE SPI_SR_FRE /* SPI Error flag: TI mode frame format error flag */ +#define SPI_FLAG_MASK (SPI_SR_RXNE | SPI_SR_TXE | SPI_SR_BSY | SPI_SR_CRCERR\ + | SPI_SR_MODF | SPI_SR_OVR | SPI_SR_FRE) +/** + * @} + */ + +/** + * @} + */ + +/* Exported macros -----------------------------------------------------------*/ +/** @defgroup SPI_Exported_Macros SPI Exported Macros + * @{ + */ + +/** @brief Reset SPI handle state. + * @param __HANDLE__ specifies the SPI Handle. + * This parameter can be SPI where x: 1, 2, or 3 to select the SPI peripheral. + * @retval None + */ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) +#define __HAL_SPI_RESET_HANDLE_STATE(__HANDLE__) do{ \ + (__HANDLE__)->State = HAL_SPI_STATE_RESET; \ + (__HANDLE__)->MspInitCallback = NULL; \ + (__HANDLE__)->MspDeInitCallback = NULL; \ + } while(0) +#else +#define __HAL_SPI_RESET_HANDLE_STATE(__HANDLE__) ((__HANDLE__)->State = HAL_SPI_STATE_RESET) +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ + +/** @brief Enable the specified SPI interrupts. + * @param __HANDLE__ specifies the SPI Handle. + * This parameter can be SPI where x: 1, 2, or 3 to select the SPI peripheral. + * @param __INTERRUPT__ specifies the interrupt source to enable. + * This parameter can be one of the following values: + * @arg SPI_IT_TXE: Tx buffer empty interrupt enable + * @arg SPI_IT_RXNE: RX buffer not empty interrupt enable + * @arg SPI_IT_ERR: Error interrupt enable + * @retval None + */ +#define __HAL_SPI_ENABLE_IT(__HANDLE__, __INTERRUPT__) SET_BIT((__HANDLE__)->Instance->CR2, (__INTERRUPT__)) + +/** @brief Disable the specified SPI interrupts. + * @param __HANDLE__ specifies the SPI handle. + * This parameter can be SPIx where x: 1, 2, or 3 to select the SPI peripheral. + * @param __INTERRUPT__ specifies the interrupt source to disable. + * This parameter can be one of the following values: + * @arg SPI_IT_TXE: Tx buffer empty interrupt enable + * @arg SPI_IT_RXNE: RX buffer not empty interrupt enable + * @arg SPI_IT_ERR: Error interrupt enable + * @retval None + */ +#define __HAL_SPI_DISABLE_IT(__HANDLE__, __INTERRUPT__) CLEAR_BIT((__HANDLE__)->Instance->CR2, (__INTERRUPT__)) + +/** @brief Check whether the specified SPI interrupt source is enabled or not. + * @param __HANDLE__ specifies the SPI Handle. + * This parameter can be SPI where x: 1, 2, or 3 to select the SPI peripheral. + * @param __INTERRUPT__ specifies the SPI interrupt source to check. + * This parameter can be one of the following values: + * @arg SPI_IT_TXE: Tx buffer empty interrupt enable + * @arg SPI_IT_RXNE: RX buffer not empty interrupt enable + * @arg SPI_IT_ERR: Error interrupt enable + * @retval The new state of __IT__ (TRUE or FALSE). + */ +#define __HAL_SPI_GET_IT_SOURCE(__HANDLE__, __INTERRUPT__) ((((__HANDLE__)->Instance->CR2\ + & (__INTERRUPT__)) == (__INTERRUPT__)) ? SET : RESET) + +/** @brief Check whether the specified SPI flag is set or not. + * @param __HANDLE__ specifies the SPI Handle. + * This parameter can be SPI where x: 1, 2, or 3 to select the SPI peripheral. + * @param __FLAG__ specifies the flag to check. + * This parameter can be one of the following values: + * @arg SPI_FLAG_RXNE: Receive buffer not empty flag + * @arg SPI_FLAG_TXE: Transmit buffer empty flag + * @arg SPI_FLAG_CRCERR: CRC error flag + * @arg SPI_FLAG_MODF: Mode fault flag + * @arg SPI_FLAG_OVR: Overrun flag + * @arg SPI_FLAG_BSY: Busy flag + * @arg SPI_FLAG_FRE: Frame format error flag + * @retval The new state of __FLAG__ (TRUE or FALSE). + */ +#define __HAL_SPI_GET_FLAG(__HANDLE__, __FLAG__) ((((__HANDLE__)->Instance->SR) & (__FLAG__)) == (__FLAG__)) + +/** @brief Clear the SPI CRCERR pending flag. + * @param __HANDLE__ specifies the SPI Handle. + * This parameter can be SPI where x: 1, 2, or 3 to select the SPI peripheral. + * @retval None + */ +#define __HAL_SPI_CLEAR_CRCERRFLAG(__HANDLE__) ((__HANDLE__)->Instance->SR = (uint16_t)(~SPI_FLAG_CRCERR)) + +/** @brief Clear the SPI MODF pending flag. + * @param __HANDLE__ specifies the SPI Handle. + * This parameter can be SPI where x: 1, 2, or 3 to select the SPI peripheral. + * @retval None + */ +#define __HAL_SPI_CLEAR_MODFFLAG(__HANDLE__) \ + do{ \ + __IO uint32_t tmpreg_modf = 0x00U; \ + tmpreg_modf = (__HANDLE__)->Instance->SR; \ + CLEAR_BIT((__HANDLE__)->Instance->CR1, SPI_CR1_SPE); \ + UNUSED(tmpreg_modf); \ + } while(0U) + +/** @brief Clear the SPI OVR pending flag. + * @param __HANDLE__ specifies the SPI Handle. + * This parameter can be SPI where x: 1, 2, or 3 to select the SPI peripheral. + * @retval None + */ +#define __HAL_SPI_CLEAR_OVRFLAG(__HANDLE__) \ + do{ \ + __IO uint32_t tmpreg_ovr = 0x00U; \ + tmpreg_ovr = (__HANDLE__)->Instance->DR; \ + tmpreg_ovr = (__HANDLE__)->Instance->SR; \ + UNUSED(tmpreg_ovr); \ + } while(0U) + +/** @brief Clear the SPI FRE pending flag. + * @param __HANDLE__ specifies the SPI Handle. + * This parameter can be SPI where x: 1, 2, or 3 to select the SPI peripheral. + * @retval None + */ +#define __HAL_SPI_CLEAR_FREFLAG(__HANDLE__) \ + do{ \ + __IO uint32_t tmpreg_fre = 0x00U; \ + tmpreg_fre = (__HANDLE__)->Instance->SR; \ + UNUSED(tmpreg_fre); \ + }while(0U) + +/** @brief Enable the SPI peripheral. + * @param __HANDLE__ specifies the SPI Handle. + * This parameter can be SPI where x: 1, 2, or 3 to select the SPI peripheral. + * @retval None + */ +#define __HAL_SPI_ENABLE(__HANDLE__) SET_BIT((__HANDLE__)->Instance->CR1, SPI_CR1_SPE) + +/** @brief Disable the SPI peripheral. + * @param __HANDLE__ specifies the SPI Handle. + * This parameter can be SPI where x: 1, 2, or 3 to select the SPI peripheral. + * @retval None + */ +#define __HAL_SPI_DISABLE(__HANDLE__) CLEAR_BIT((__HANDLE__)->Instance->CR1, SPI_CR1_SPE) + +/** + * @} + */ + +/* Private macros ------------------------------------------------------------*/ +/** @defgroup SPI_Private_Macros SPI Private Macros + * @{ + */ + +/** @brief Set the SPI transmit-only mode. + * @param __HANDLE__ specifies the SPI Handle. + * This parameter can be SPI where x: 1, 2, or 3 to select the SPI peripheral. + * @retval None + */ +#define SPI_1LINE_TX(__HANDLE__) SET_BIT((__HANDLE__)->Instance->CR1, SPI_CR1_BIDIOE) + +/** @brief Set the SPI receive-only mode. + * @param __HANDLE__ specifies the SPI Handle. + * This parameter can be SPI where x: 1, 2, or 3 to select the SPI peripheral. + * @retval None + */ +#define SPI_1LINE_RX(__HANDLE__) CLEAR_BIT((__HANDLE__)->Instance->CR1, SPI_CR1_BIDIOE) + +/** @brief Reset the CRC calculation of the SPI. + * @param __HANDLE__ specifies the SPI Handle. + * This parameter can be SPI where x: 1, 2, or 3 to select the SPI peripheral. + * @retval None + */ +#define SPI_RESET_CRC(__HANDLE__) do{CLEAR_BIT((__HANDLE__)->Instance->CR1, SPI_CR1_CRCEN);\ + SET_BIT((__HANDLE__)->Instance->CR1, SPI_CR1_CRCEN);}while(0U) + +/** @brief Check whether the specified SPI flag is set or not. + * @param __SR__ copy of SPI SR register. + * @param __FLAG__ specifies the flag to check. + * This parameter can be one of the following values: + * @arg SPI_FLAG_RXNE: Receive buffer not empty flag + * @arg SPI_FLAG_TXE: Transmit buffer empty flag + * @arg SPI_FLAG_CRCERR: CRC error flag + * @arg SPI_FLAG_MODF: Mode fault flag + * @arg SPI_FLAG_OVR: Overrun flag + * @arg SPI_FLAG_BSY: Busy flag + * @arg SPI_FLAG_FRE: Frame format error flag + * @retval SET or RESET. + */ +#define SPI_CHECK_FLAG(__SR__, __FLAG__) ((((__SR__) & ((__FLAG__) & SPI_FLAG_MASK)) == \ + ((__FLAG__) & SPI_FLAG_MASK)) ? SET : RESET) + +/** @brief Check whether the specified SPI Interrupt is set or not. + * @param __CR2__ copy of SPI CR2 register. + * @param __INTERRUPT__ specifies the SPI interrupt source to check. + * This parameter can be one of the following values: + * @arg SPI_IT_TXE: Tx buffer empty interrupt enable + * @arg SPI_IT_RXNE: RX buffer not empty interrupt enable + * @arg SPI_IT_ERR: Error interrupt enable + * @retval SET or RESET. + */ +#define SPI_CHECK_IT_SOURCE(__CR2__, __INTERRUPT__) ((((__CR2__) & (__INTERRUPT__)) == \ + (__INTERRUPT__)) ? SET : RESET) + +/** @brief Checks if SPI Mode parameter is in allowed range. + * @param __MODE__ specifies the SPI Mode. + * This parameter can be a value of @ref SPI_Mode + * @retval None + */ +#define IS_SPI_MODE(__MODE__) (((__MODE__) == SPI_MODE_SLAVE) || \ + ((__MODE__) == SPI_MODE_MASTER)) + +/** @brief Checks if SPI Direction Mode parameter is in allowed range. + * @param __MODE__ specifies the SPI Direction Mode. + * This parameter can be a value of @ref SPI_Direction + * @retval None + */ +#define IS_SPI_DIRECTION(__MODE__) (((__MODE__) == SPI_DIRECTION_2LINES) || \ + ((__MODE__) == SPI_DIRECTION_2LINES_RXONLY) || \ + ((__MODE__) == SPI_DIRECTION_1LINE)) + +/** @brief Checks if SPI Direction Mode parameter is 2 lines. + * @param __MODE__ specifies the SPI Direction Mode. + * @retval None + */ +#define IS_SPI_DIRECTION_2LINES(__MODE__) ((__MODE__) == SPI_DIRECTION_2LINES) + +/** @brief Checks if SPI Direction Mode parameter is 1 or 2 lines. + * @param __MODE__ specifies the SPI Direction Mode. + * @retval None + */ +#define IS_SPI_DIRECTION_2LINES_OR_1LINE(__MODE__) (((__MODE__) == SPI_DIRECTION_2LINES) || \ + ((__MODE__) == SPI_DIRECTION_1LINE)) + +/** @brief Checks if SPI Data Size parameter is in allowed range. + * @param __DATASIZE__ specifies the SPI Data Size. + * This parameter can be a value of @ref SPI_Data_Size + * @retval None + */ +#define IS_SPI_DATASIZE(__DATASIZE__) (((__DATASIZE__) == SPI_DATASIZE_16BIT) || \ + ((__DATASIZE__) == SPI_DATASIZE_8BIT)) + +/** @brief Checks if SPI Serial clock steady state parameter is in allowed range. + * @param __CPOL__ specifies the SPI serial clock steady state. + * This parameter can be a value of @ref SPI_Clock_Polarity + * @retval None + */ +#define IS_SPI_CPOL(__CPOL__) (((__CPOL__) == SPI_POLARITY_LOW) || \ + ((__CPOL__) == SPI_POLARITY_HIGH)) + +/** @brief Checks if SPI Clock Phase parameter is in allowed range. + * @param __CPHA__ specifies the SPI Clock Phase. + * This parameter can be a value of @ref SPI_Clock_Phase + * @retval None + */ +#define IS_SPI_CPHA(__CPHA__) (((__CPHA__) == SPI_PHASE_1EDGE) || \ + ((__CPHA__) == SPI_PHASE_2EDGE)) + +/** @brief Checks if SPI Slave Select parameter is in allowed range. + * @param __NSS__ specifies the SPI Slave Select management parameter. + * This parameter can be a value of @ref SPI_Slave_Select_management + * @retval None + */ +#define IS_SPI_NSS(__NSS__) (((__NSS__) == SPI_NSS_SOFT) || \ + ((__NSS__) == SPI_NSS_HARD_INPUT) || \ + ((__NSS__) == SPI_NSS_HARD_OUTPUT)) + +/** @brief Checks if SPI Baudrate prescaler parameter is in allowed range. + * @param __PRESCALER__ specifies the SPI Baudrate prescaler. + * This parameter can be a value of @ref SPI_BaudRate_Prescaler + * @retval None + */ +#define IS_SPI_BAUDRATE_PRESCALER(__PRESCALER__) (((__PRESCALER__) == SPI_BAUDRATEPRESCALER_2) || \ + ((__PRESCALER__) == SPI_BAUDRATEPRESCALER_4) || \ + ((__PRESCALER__) == SPI_BAUDRATEPRESCALER_8) || \ + ((__PRESCALER__) == SPI_BAUDRATEPRESCALER_16) || \ + ((__PRESCALER__) == SPI_BAUDRATEPRESCALER_32) || \ + ((__PRESCALER__) == SPI_BAUDRATEPRESCALER_64) || \ + ((__PRESCALER__) == SPI_BAUDRATEPRESCALER_128) || \ + ((__PRESCALER__) == SPI_BAUDRATEPRESCALER_256)) + +/** @brief Checks if SPI MSB LSB transmission parameter is in allowed range. + * @param __BIT__ specifies the SPI MSB LSB transmission (whether data transfer starts from MSB or LSB bit). + * This parameter can be a value of @ref SPI_MSB_LSB_transmission + * @retval None + */ +#define IS_SPI_FIRST_BIT(__BIT__) (((__BIT__) == SPI_FIRSTBIT_MSB) || \ + ((__BIT__) == SPI_FIRSTBIT_LSB)) + +/** @brief Checks if SPI TI mode parameter is in allowed range. + * @param __MODE__ specifies the SPI TI mode. + * This parameter can be a value of @ref SPI_TI_mode + * @retval None + */ +#define IS_SPI_TIMODE(__MODE__) (((__MODE__) == SPI_TIMODE_DISABLE) || \ + ((__MODE__) == SPI_TIMODE_ENABLE)) + +/** @brief Checks if SPI CRC calculation enabled state is in allowed range. + * @param __CALCULATION__ specifies the SPI CRC calculation enable state. + * This parameter can be a value of @ref SPI_CRC_Calculation + * @retval None + */ +#define IS_SPI_CRC_CALCULATION(__CALCULATION__) (((__CALCULATION__) == SPI_CRCCALCULATION_DISABLE) || \ + ((__CALCULATION__) == SPI_CRCCALCULATION_ENABLE)) + +/** @brief Checks if SPI polynomial value to be used for the CRC calculation, is in allowed range. + * @param __POLYNOMIAL__ specifies the SPI polynomial value to be used for the CRC calculation. + * This parameter must be a number between Min_Data = 0 and Max_Data = 65535 + * @retval None + */ +#define IS_SPI_CRC_POLYNOMIAL(__POLYNOMIAL__) (((__POLYNOMIAL__) >= 0x1U) && \ + ((__POLYNOMIAL__) <= 0xFFFFU) && \ + (((__POLYNOMIAL__)&0x1U) != 0U)) + +/** @brief Checks if DMA handle is valid. + * @param __HANDLE__ specifies a DMA Handle. + * @retval None + */ +#define IS_SPI_DMA_HANDLE(__HANDLE__) ((__HANDLE__) != NULL) + +/** + * @} + */ + +/* Exported functions --------------------------------------------------------*/ +/** @addtogroup SPI_Exported_Functions + * @{ + */ + +/** @addtogroup SPI_Exported_Functions_Group1 + * @{ + */ +/* Initialization/de-initialization functions ********************************/ +HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi); +HAL_StatusTypeDef HAL_SPI_DeInit(SPI_HandleTypeDef *hspi); +void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi); +void HAL_SPI_MspDeInit(SPI_HandleTypeDef *hspi); + +/* Callbacks Register/UnRegister functions ***********************************/ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) +HAL_StatusTypeDef HAL_SPI_RegisterCallback(SPI_HandleTypeDef *hspi, HAL_SPI_CallbackIDTypeDef CallbackID, + pSPI_CallbackTypeDef pCallback); +HAL_StatusTypeDef HAL_SPI_UnRegisterCallback(SPI_HandleTypeDef *hspi, HAL_SPI_CallbackIDTypeDef CallbackID); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ +/** + * @} + */ + +/** @addtogroup SPI_Exported_Functions_Group2 + * @{ + */ +/* I/O operation functions ***************************************************/ +HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout); +HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout); +HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, + uint32_t Timeout); +HAL_StatusTypeDef HAL_SPI_Transmit_IT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_SPI_Receive_IT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_SPI_TransmitReceive_IT(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, + uint16_t Size); +HAL_StatusTypeDef HAL_SPI_Transmit_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_SPI_Receive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_SPI_TransmitReceive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, + uint16_t Size); +HAL_StatusTypeDef HAL_SPI_DMAPause(SPI_HandleTypeDef *hspi); +HAL_StatusTypeDef HAL_SPI_DMAResume(SPI_HandleTypeDef *hspi); +HAL_StatusTypeDef HAL_SPI_DMAStop(SPI_HandleTypeDef *hspi); +/* Transfer Abort functions */ +HAL_StatusTypeDef HAL_SPI_Abort(SPI_HandleTypeDef *hspi); +HAL_StatusTypeDef HAL_SPI_Abort_IT(SPI_HandleTypeDef *hspi); + +void HAL_SPI_IRQHandler(SPI_HandleTypeDef *hspi); +void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi); +void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi); +void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi); +void HAL_SPI_TxHalfCpltCallback(SPI_HandleTypeDef *hspi); +void HAL_SPI_RxHalfCpltCallback(SPI_HandleTypeDef *hspi); +void HAL_SPI_TxRxHalfCpltCallback(SPI_HandleTypeDef *hspi); +void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi); +void HAL_SPI_AbortCpltCallback(SPI_HandleTypeDef *hspi); +/** + * @} + */ + +/** @addtogroup SPI_Exported_Functions_Group3 + * @{ + */ +/* Peripheral State and Error functions ***************************************/ +HAL_SPI_StateTypeDef HAL_SPI_GetState(SPI_HandleTypeDef *hspi); +uint32_t HAL_SPI_GetError(SPI_HandleTypeDef *hspi); +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* STM32F4xx_HAL_SPI_H */ + diff --git a/calib_board/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_spi.c b/calib_board/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_spi.c new file mode 100644 index 0000000..62d5d65 --- /dev/null +++ b/calib_board/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_spi.c @@ -0,0 +1,3915 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_spi.c + * @author MCD Application Team + * @brief SPI HAL module driver. + * This file provides firmware functions to manage the following + * functionalities of the Serial Peripheral Interface (SPI) peripheral: + * + Initialization and de-initialization functions + * + IO operation functions + * + Peripheral Control functions + * + Peripheral State functions + ****************************************************************************** + * @attention + * + * Copyright (c) 2016 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. + * + ****************************************************************************** + @verbatim + ============================================================================== + ##### How to use this driver ##### + ============================================================================== + [..] + The SPI HAL driver can be used as follows: + + (#) Declare a SPI_HandleTypeDef handle structure, for example: + SPI_HandleTypeDef hspi; + + (#)Initialize the SPI low level resources by implementing the HAL_SPI_MspInit() API: + (##) Enable the SPIx interface clock + (##) SPI pins configuration + (+++) Enable the clock for the SPI GPIOs + (+++) Configure these SPI pins as alternate function push-pull + (##) NVIC configuration if you need to use interrupt process + (+++) Configure the SPIx interrupt priority + (+++) Enable the NVIC SPI IRQ handle + (##) DMA Configuration if you need to use DMA process + (+++) Declare a DMA_HandleTypeDef handle structure for the transmit or receive Stream/Channel + (+++) Enable the DMAx clock + (+++) Configure the DMA handle parameters + (+++) Configure the DMA Tx or Rx Stream/Channel + (+++) Associate the initialized hdma_tx(or _rx) handle to the hspi DMA Tx or Rx handle + (+++) Configure the priority and enable the NVIC for the transfer complete interrupt on the DMA Tx or Rx Stream/Channel + + (#) Program the Mode, BidirectionalMode , Data size, Baudrate Prescaler, NSS + management, Clock polarity and phase, FirstBit and CRC configuration in the hspi Init structure. + + (#) Initialize the SPI registers by calling the HAL_SPI_Init() API: + (++) This API configures also the low level Hardware GPIO, CLOCK, CORTEX...etc) + by calling the customized HAL_SPI_MspInit() API. + [..] + Circular mode restriction: + (#) The DMA circular mode cannot be used when the SPI is configured in these modes: + (##) Master 2Lines RxOnly + (##) Master 1Line Rx + (#) The CRC feature is not managed when the DMA circular mode is enabled + (#) When the SPI DMA Pause/Stop features are used, we must use the following APIs + the HAL_SPI_DMAPause()/ HAL_SPI_DMAStop() only under the SPI callbacks + [..] + Master Receive mode restriction: + (#) In Master unidirectional receive-only mode (MSTR =1, BIDIMODE=0, RXONLY=1) or + bidirectional receive mode (MSTR=1, BIDIMODE=1, BIDIOE=0), to ensure that the SPI + does not initiate a new transfer the following procedure has to be respected: + (##) HAL_SPI_DeInit() + (##) HAL_SPI_Init() + [..] + Callback registration: + + (#) The compilation flag USE_HAL_SPI_REGISTER_CALLBACKS when set to 1U + allows the user to configure dynamically the driver callbacks. + Use Functions HAL_SPI_RegisterCallback() to register an interrupt callback. + + Function HAL_SPI_RegisterCallback() allows to register following callbacks: + (++) TxCpltCallback : SPI Tx Completed callback + (++) RxCpltCallback : SPI Rx Completed callback + (++) TxRxCpltCallback : SPI TxRx Completed callback + (++) TxHalfCpltCallback : SPI Tx Half Completed callback + (++) RxHalfCpltCallback : SPI Rx Half Completed callback + (++) TxRxHalfCpltCallback : SPI TxRx Half Completed callback + (++) ErrorCallback : SPI Error callback + (++) AbortCpltCallback : SPI Abort callback + (++) MspInitCallback : SPI Msp Init callback + (++) MspDeInitCallback : SPI Msp DeInit callback + This function takes as parameters the HAL peripheral handle, the Callback ID + and a pointer to the user callback function. + + + (#) Use function HAL_SPI_UnRegisterCallback to reset a callback to the default + weak function. + HAL_SPI_UnRegisterCallback takes as parameters the HAL peripheral handle, + and the Callback ID. + This function allows to reset following callbacks: + (++) TxCpltCallback : SPI Tx Completed callback + (++) RxCpltCallback : SPI Rx Completed callback + (++) TxRxCpltCallback : SPI TxRx Completed callback + (++) TxHalfCpltCallback : SPI Tx Half Completed callback + (++) RxHalfCpltCallback : SPI Rx Half Completed callback + (++) TxRxHalfCpltCallback : SPI TxRx Half Completed callback + (++) ErrorCallback : SPI Error callback + (++) AbortCpltCallback : SPI Abort callback + (++) MspInitCallback : SPI Msp Init callback + (++) MspDeInitCallback : SPI Msp DeInit callback + + [..] + By default, after the HAL_SPI_Init() and when the state is HAL_SPI_STATE_RESET + all callbacks are set to the corresponding weak functions: + examples HAL_SPI_MasterTxCpltCallback(), HAL_SPI_MasterRxCpltCallback(). + Exception done for MspInit and MspDeInit functions that are + reset to the legacy weak functions in the HAL_SPI_Init()/ HAL_SPI_DeInit() only when + these callbacks are null (not registered beforehand). + If MspInit or MspDeInit are not null, the HAL_SPI_Init()/ HAL_SPI_DeInit() + keep and use the user MspInit/MspDeInit callbacks (registered beforehand) whatever the state. + + [..] + Callbacks can be registered/unregistered in HAL_SPI_STATE_READY state only. + Exception done MspInit/MspDeInit functions that can be registered/unregistered + in HAL_SPI_STATE_READY or HAL_SPI_STATE_RESET state, + thus registered (user) MspInit/DeInit callbacks can be used during the Init/DeInit. + Then, the user first registers the MspInit/MspDeInit user callbacks + using HAL_SPI_RegisterCallback() before calling HAL_SPI_DeInit() + or HAL_SPI_Init() function. + + [..] + When the compilation define USE_HAL_PPP_REGISTER_CALLBACKS is set to 0 or + not defined, the callback registering feature is not available + and weak (surcharged) callbacks are used. + + [..] + Using the HAL it is not possible to reach all supported SPI frequency with the different SPI Modes, + the following table resume the max SPI frequency reached with data size 8bits/16bits, + according to frequency of the APBx Peripheral Clock (fPCLK) used by the SPI instance. + + @endverbatim + + Additional table : + + DataSize = SPI_DATASIZE_8BIT: + +----------------------------------------------------------------------------------------------+ + | | | 2Lines Fullduplex | 2Lines RxOnly | 1Line | + | Process | Transfer mode |---------------------|----------------------|----------------------| + | | | Master | Slave | Master | Slave | Master | Slave | + |==============================================================================================| + | T | Polling | Fpclk/2 | Fpclk/2 | NA | NA | NA | NA | + | X |----------------|----------|----------|-----------|----------|-----------|----------| + | / | Interrupt | Fpclk/4 | Fpclk/8 | NA | NA | NA | NA | + | R |----------------|----------|----------|-----------|----------|-----------|----------| + | X | DMA | Fpclk/2 | Fpclk/2 | NA | NA | NA | NA | + |=========|================|==========|==========|===========|==========|===========|==========| + | | Polling | Fpclk/2 | Fpclk/2 | Fpclk/64 | Fpclk/2 | Fpclk/64 | Fpclk/2 | + | |----------------|----------|----------|-----------|----------|-----------|----------| + | R | Interrupt | Fpclk/8 | Fpclk/8 | Fpclk/64 | Fpclk/2 | Fpclk/64 | Fpclk/2 | + | X |----------------|----------|----------|-----------|----------|-----------|----------| + | | DMA | Fpclk/2 | Fpclk/2 | Fpclk/64 | Fpclk/2 | Fpclk/128 | Fpclk/2 | + |=========|================|==========|==========|===========|==========|===========|==========| + | | Polling | Fpclk/2 | Fpclk/4 | NA | NA | Fpclk/2 | Fpclk/64 | + | |----------------|----------|----------|-----------|----------|-----------|----------| + | T | Interrupt | Fpclk/2 | Fpclk/4 | NA | NA | Fpclk/2 | Fpclk/64 | + | X |----------------|----------|----------|-----------|----------|-----------|----------| + | | DMA | Fpclk/2 | Fpclk/2 | NA | NA | Fpclk/2 | Fpclk/128| + +----------------------------------------------------------------------------------------------+ + + DataSize = SPI_DATASIZE_16BIT: + +----------------------------------------------------------------------------------------------+ + | | | 2Lines Fullduplex | 2Lines RxOnly | 1Line | + | Process | Transfer mode |---------------------|----------------------|----------------------| + | | | Master | Slave | Master | Slave | Master | Slave | + |==============================================================================================| + | T | Polling | Fpclk/2 | Fpclk/2 | NA | NA | NA | NA | + | X |----------------|----------|----------|-----------|----------|-----------|----------| + | / | Interrupt | Fpclk/4 | Fpclk/4 | NA | NA | NA | NA | + | R |----------------|----------|----------|-----------|----------|-----------|----------| + | X | DMA | Fpclk/2 | Fpclk/2 | NA | NA | NA | NA | + |=========|================|==========|==========|===========|==========|===========|==========| + | | Polling | Fpclk/2 | Fpclk/2 | Fpclk/64 | Fpclk/2 | Fpclk/32 | Fpclk/2 | + | |----------------|----------|----------|-----------|----------|-----------|----------| + | R | Interrupt | Fpclk/4 | Fpclk/4 | Fpclk/64 | Fpclk/2 | Fpclk/64 | Fpclk/2 | + | X |----------------|----------|----------|-----------|----------|-----------|----------| + | | DMA | Fpclk/2 | Fpclk/2 | Fpclk/64 | Fpclk/2 | Fpclk/128 | Fpclk/2 | + |=========|================|==========|==========|===========|==========|===========|==========| + | | Polling | Fpclk/2 | Fpclk/2 | NA | NA | Fpclk/2 | Fpclk/32 | + | |----------------|----------|----------|-----------|----------|-----------|----------| + | T | Interrupt | Fpclk/2 | Fpclk/2 | NA | NA | Fpclk/2 | Fpclk/64 | + | X |----------------|----------|----------|-----------|----------|-----------|----------| + | | DMA | Fpclk/2 | Fpclk/2 | NA | NA | Fpclk/2 | Fpclk/128| + +----------------------------------------------------------------------------------------------+ + @note The max SPI frequency depend on SPI data size (8bits, 16bits), + SPI mode(2 Lines fullduplex, 2 lines RxOnly, 1 line TX/RX) and Process mode (Polling, IT, DMA). + @note + (#) TX/RX processes are HAL_SPI_TransmitReceive(), HAL_SPI_TransmitReceive_IT() and HAL_SPI_TransmitReceive_DMA() + (#) RX processes are HAL_SPI_Receive(), HAL_SPI_Receive_IT() and HAL_SPI_Receive_DMA() + (#) TX processes are HAL_SPI_Transmit(), HAL_SPI_Transmit_IT() and HAL_SPI_Transmit_DMA() + + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal.h" + +/** @addtogroup STM32F4xx_HAL_Driver + * @{ + */ + +/** @defgroup SPI SPI + * @brief SPI HAL module driver + * @{ + */ +#ifdef HAL_SPI_MODULE_ENABLED + +/* Private typedef -----------------------------------------------------------*/ +/* Private defines -----------------------------------------------------------*/ +/** @defgroup SPI_Private_Constants SPI Private Constants + * @{ + */ +#define SPI_DEFAULT_TIMEOUT 100U +#define SPI_BSY_FLAG_WORKAROUND_TIMEOUT 1000U /*!< Timeout 1000 碌s */ +/** + * @} + */ + +/* Private macros ------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/** @defgroup SPI_Private_Functions SPI Private Functions + * @{ + */ +static void SPI_DMATransmitCplt(DMA_HandleTypeDef *hdma); +static void SPI_DMAReceiveCplt(DMA_HandleTypeDef *hdma); +static void SPI_DMATransmitReceiveCplt(DMA_HandleTypeDef *hdma); +static void SPI_DMAHalfTransmitCplt(DMA_HandleTypeDef *hdma); +static void SPI_DMAHalfReceiveCplt(DMA_HandleTypeDef *hdma); +static void SPI_DMAHalfTransmitReceiveCplt(DMA_HandleTypeDef *hdma); +static void SPI_DMAError(DMA_HandleTypeDef *hdma); +static void SPI_DMAAbortOnError(DMA_HandleTypeDef *hdma); +static void SPI_DMATxAbortCallback(DMA_HandleTypeDef *hdma); +static void SPI_DMARxAbortCallback(DMA_HandleTypeDef *hdma); +static HAL_StatusTypeDef SPI_WaitFlagStateUntilTimeout(SPI_HandleTypeDef *hspi, uint32_t Flag, FlagStatus State, + uint32_t Timeout, uint32_t Tickstart); +static void SPI_TxISR_8BIT(struct __SPI_HandleTypeDef *hspi); +static void SPI_TxISR_16BIT(struct __SPI_HandleTypeDef *hspi); +static void SPI_RxISR_8BIT(struct __SPI_HandleTypeDef *hspi); +static void SPI_RxISR_16BIT(struct __SPI_HandleTypeDef *hspi); +static void SPI_2linesRxISR_8BIT(struct __SPI_HandleTypeDef *hspi); +static void SPI_2linesTxISR_8BIT(struct __SPI_HandleTypeDef *hspi); +static void SPI_2linesTxISR_16BIT(struct __SPI_HandleTypeDef *hspi); +static void SPI_2linesRxISR_16BIT(struct __SPI_HandleTypeDef *hspi); +#if (USE_SPI_CRC != 0U) +static void SPI_RxISR_8BITCRC(struct __SPI_HandleTypeDef *hspi); +static void SPI_RxISR_16BITCRC(struct __SPI_HandleTypeDef *hspi); +static void SPI_2linesRxISR_8BITCRC(struct __SPI_HandleTypeDef *hspi); +static void SPI_2linesRxISR_16BITCRC(struct __SPI_HandleTypeDef *hspi); +#endif /* USE_SPI_CRC */ +static void SPI_AbortRx_ISR(SPI_HandleTypeDef *hspi); +static void SPI_AbortTx_ISR(SPI_HandleTypeDef *hspi); +static void SPI_CloseRxTx_ISR(SPI_HandleTypeDef *hspi); +static void SPI_CloseRx_ISR(SPI_HandleTypeDef *hspi); +static void SPI_CloseTx_ISR(SPI_HandleTypeDef *hspi); +static HAL_StatusTypeDef SPI_EndRxTransaction(SPI_HandleTypeDef *hspi, uint32_t Timeout, uint32_t Tickstart); +static HAL_StatusTypeDef SPI_EndRxTxTransaction(SPI_HandleTypeDef *hspi, uint32_t Timeout, uint32_t Tickstart); +/** + * @} + */ + +/* Exported functions --------------------------------------------------------*/ +/** @defgroup SPI_Exported_Functions SPI Exported Functions + * @{ + */ + +/** @defgroup SPI_Exported_Functions_Group1 Initialization and de-initialization functions + * @brief Initialization and Configuration functions + * +@verbatim + =============================================================================== + ##### Initialization and de-initialization functions ##### + =============================================================================== + [..] This subsection provides a set of functions allowing to initialize and + de-initialize the SPIx peripheral: + + (+) User must implement HAL_SPI_MspInit() function in which he configures + all related peripherals resources (CLOCK, GPIO, DMA, IT and NVIC ). + + (+) Call the function HAL_SPI_Init() to configure the selected device with + the selected configuration: + (++) Mode + (++) Direction + (++) Data Size + (++) Clock Polarity and Phase + (++) NSS Management + (++) BaudRate Prescaler + (++) FirstBit + (++) TIMode + (++) CRC Calculation + (++) CRC Polynomial if CRC enabled + + (+) Call the function HAL_SPI_DeInit() to restore the default configuration + of the selected SPIx peripheral. + +@endverbatim + * @{ + */ + +/** + * @brief Initialize the SPI according to the specified parameters + * in the SPI_InitTypeDef and initialize the associated handle. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi) +{ + /* Check the SPI handle allocation */ + if (hspi == NULL) + { + return HAL_ERROR; + } + + /* Check the parameters */ + assert_param(IS_SPI_ALL_INSTANCE(hspi->Instance)); + assert_param(IS_SPI_MODE(hspi->Init.Mode)); + assert_param(IS_SPI_DIRECTION(hspi->Init.Direction)); + assert_param(IS_SPI_DATASIZE(hspi->Init.DataSize)); + assert_param(IS_SPI_NSS(hspi->Init.NSS)); + assert_param(IS_SPI_BAUDRATE_PRESCALER(hspi->Init.BaudRatePrescaler)); + assert_param(IS_SPI_FIRST_BIT(hspi->Init.FirstBit)); + assert_param(IS_SPI_TIMODE(hspi->Init.TIMode)); + if (hspi->Init.TIMode == SPI_TIMODE_DISABLE) + { + assert_param(IS_SPI_CPOL(hspi->Init.CLKPolarity)); + assert_param(IS_SPI_CPHA(hspi->Init.CLKPhase)); + + if (hspi->Init.Mode == SPI_MODE_MASTER) + { + assert_param(IS_SPI_BAUDRATE_PRESCALER(hspi->Init.BaudRatePrescaler)); + } + else + { + /* Baudrate prescaler not use in Motoraola Slave mode. force to default value */ + hspi->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; + } + } + else + { + assert_param(IS_SPI_BAUDRATE_PRESCALER(hspi->Init.BaudRatePrescaler)); + + /* Force polarity and phase to TI protocaol requirements */ + hspi->Init.CLKPolarity = SPI_POLARITY_LOW; + hspi->Init.CLKPhase = SPI_PHASE_1EDGE; + } +#if (USE_SPI_CRC != 0U) + assert_param(IS_SPI_CRC_CALCULATION(hspi->Init.CRCCalculation)); + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + { + assert_param(IS_SPI_CRC_POLYNOMIAL(hspi->Init.CRCPolynomial)); + } +#else + hspi->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; +#endif /* USE_SPI_CRC */ + + if (hspi->State == HAL_SPI_STATE_RESET) + { + /* Allocate lock resource and initialize it */ + hspi->Lock = HAL_UNLOCKED; + +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + /* Init the SPI Callback settings */ + hspi->TxCpltCallback = HAL_SPI_TxCpltCallback; /* Legacy weak TxCpltCallback */ + hspi->RxCpltCallback = HAL_SPI_RxCpltCallback; /* Legacy weak RxCpltCallback */ + hspi->TxRxCpltCallback = HAL_SPI_TxRxCpltCallback; /* Legacy weak TxRxCpltCallback */ + hspi->TxHalfCpltCallback = HAL_SPI_TxHalfCpltCallback; /* Legacy weak TxHalfCpltCallback */ + hspi->RxHalfCpltCallback = HAL_SPI_RxHalfCpltCallback; /* Legacy weak RxHalfCpltCallback */ + hspi->TxRxHalfCpltCallback = HAL_SPI_TxRxHalfCpltCallback; /* Legacy weak TxRxHalfCpltCallback */ + hspi->ErrorCallback = HAL_SPI_ErrorCallback; /* Legacy weak ErrorCallback */ + hspi->AbortCpltCallback = HAL_SPI_AbortCpltCallback; /* Legacy weak AbortCpltCallback */ + + if (hspi->MspInitCallback == NULL) + { + hspi->MspInitCallback = HAL_SPI_MspInit; /* Legacy weak MspInit */ + } + + /* Init the low level hardware : GPIO, CLOCK, NVIC... */ + hspi->MspInitCallback(hspi); +#else + /* Init the low level hardware : GPIO, CLOCK, NVIC... */ + HAL_SPI_MspInit(hspi); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ + } + + hspi->State = HAL_SPI_STATE_BUSY; + + /* Disable the selected SPI peripheral */ + __HAL_SPI_DISABLE(hspi); + + /*----------------------- SPIx CR1 & CR2 Configuration ---------------------*/ + /* Configure : SPI Mode, Communication Mode, Data size, Clock polarity and phase, NSS management, + Communication speed, First bit and CRC calculation state */ + WRITE_REG(hspi->Instance->CR1, ((hspi->Init.Mode & (SPI_CR1_MSTR | SPI_CR1_SSI)) | + (hspi->Init.Direction & (SPI_CR1_RXONLY | SPI_CR1_BIDIMODE)) | + (hspi->Init.DataSize & SPI_CR1_DFF) | + (hspi->Init.CLKPolarity & SPI_CR1_CPOL) | + (hspi->Init.CLKPhase & SPI_CR1_CPHA) | + (hspi->Init.NSS & SPI_CR1_SSM) | + (hspi->Init.BaudRatePrescaler & SPI_CR1_BR_Msk) | + (hspi->Init.FirstBit & SPI_CR1_LSBFIRST) | + (hspi->Init.CRCCalculation & SPI_CR1_CRCEN))); + + /* Configure : NSS management, TI Mode */ + WRITE_REG(hspi->Instance->CR2, (((hspi->Init.NSS >> 16U) & SPI_CR2_SSOE) | (hspi->Init.TIMode & SPI_CR2_FRF))); + +#if (USE_SPI_CRC != 0U) + /*---------------------------- SPIx CRCPOLY Configuration ------------------*/ + /* Configure : CRC Polynomial */ + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + { + WRITE_REG(hspi->Instance->CRCPR, (hspi->Init.CRCPolynomial & SPI_CRCPR_CRCPOLY_Msk)); + } +#endif /* USE_SPI_CRC */ + +#if defined(SPI_I2SCFGR_I2SMOD) + /* Activate the SPI mode (Make sure that I2SMOD bit in I2SCFGR register is reset) */ + CLEAR_BIT(hspi->Instance->I2SCFGR, SPI_I2SCFGR_I2SMOD); +#endif /* SPI_I2SCFGR_I2SMOD */ + + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + hspi->State = HAL_SPI_STATE_READY; + + return HAL_OK; +} + +/** + * @brief De-Initialize the SPI peripheral. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SPI_DeInit(SPI_HandleTypeDef *hspi) +{ + /* Check the SPI handle allocation */ + if (hspi == NULL) + { + return HAL_ERROR; + } + + /* Check SPI Instance parameter */ + assert_param(IS_SPI_ALL_INSTANCE(hspi->Instance)); + + hspi->State = HAL_SPI_STATE_BUSY; + + /* Disable the SPI Peripheral Clock */ + __HAL_SPI_DISABLE(hspi); + +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + if (hspi->MspDeInitCallback == NULL) + { + hspi->MspDeInitCallback = HAL_SPI_MspDeInit; /* Legacy weak MspDeInit */ + } + + /* DeInit the low level hardware: GPIO, CLOCK, NVIC... */ + hspi->MspDeInitCallback(hspi); +#else + /* DeInit the low level hardware: GPIO, CLOCK, NVIC... */ + HAL_SPI_MspDeInit(hspi); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ + + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + hspi->State = HAL_SPI_STATE_RESET; + + /* Release Lock */ + __HAL_UNLOCK(hspi); + + return HAL_OK; +} + +/** + * @brief Initialize the SPI MSP. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval None + */ +__weak void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hspi); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_SPI_MspInit should be implemented in the user file + */ +} + +/** + * @brief De-Initialize the SPI MSP. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval None + */ +__weak void HAL_SPI_MspDeInit(SPI_HandleTypeDef *hspi) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hspi); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_SPI_MspDeInit should be implemented in the user file + */ +} + +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) +/** + * @brief Register a User SPI Callback + * To be used instead of the weak predefined callback + * @param hspi Pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for the specified SPI. + * @param CallbackID ID of the callback to be registered + * @param pCallback pointer to the Callback function + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SPI_RegisterCallback(SPI_HandleTypeDef *hspi, HAL_SPI_CallbackIDTypeDef CallbackID, + pSPI_CallbackTypeDef pCallback) +{ + HAL_StatusTypeDef status = HAL_OK; + + if (pCallback == NULL) + { + /* Update the error code */ + hspi->ErrorCode |= HAL_SPI_ERROR_INVALID_CALLBACK; + + return HAL_ERROR; + } + /* Process locked */ + __HAL_LOCK(hspi); + + if (HAL_SPI_STATE_READY == hspi->State) + { + switch (CallbackID) + { + case HAL_SPI_TX_COMPLETE_CB_ID : + hspi->TxCpltCallback = pCallback; + break; + + case HAL_SPI_RX_COMPLETE_CB_ID : + hspi->RxCpltCallback = pCallback; + break; + + case HAL_SPI_TX_RX_COMPLETE_CB_ID : + hspi->TxRxCpltCallback = pCallback; + break; + + case HAL_SPI_TX_HALF_COMPLETE_CB_ID : + hspi->TxHalfCpltCallback = pCallback; + break; + + case HAL_SPI_RX_HALF_COMPLETE_CB_ID : + hspi->RxHalfCpltCallback = pCallback; + break; + + case HAL_SPI_TX_RX_HALF_COMPLETE_CB_ID : + hspi->TxRxHalfCpltCallback = pCallback; + break; + + case HAL_SPI_ERROR_CB_ID : + hspi->ErrorCallback = pCallback; + break; + + case HAL_SPI_ABORT_CB_ID : + hspi->AbortCpltCallback = pCallback; + break; + + case HAL_SPI_MSPINIT_CB_ID : + hspi->MspInitCallback = pCallback; + break; + + case HAL_SPI_MSPDEINIT_CB_ID : + hspi->MspDeInitCallback = pCallback; + break; + + default : + /* Update the error code */ + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_INVALID_CALLBACK); + + /* Return error status */ + status = HAL_ERROR; + break; + } + } + else if (HAL_SPI_STATE_RESET == hspi->State) + { + switch (CallbackID) + { + case HAL_SPI_MSPINIT_CB_ID : + hspi->MspInitCallback = pCallback; + break; + + case HAL_SPI_MSPDEINIT_CB_ID : + hspi->MspDeInitCallback = pCallback; + break; + + default : + /* Update the error code */ + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_INVALID_CALLBACK); + + /* Return error status */ + status = HAL_ERROR; + break; + } + } + else + { + /* Update the error code */ + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_INVALID_CALLBACK); + + /* Return error status */ + status = HAL_ERROR; + } + + /* Release Lock */ + __HAL_UNLOCK(hspi); + return status; +} + +/** + * @brief Unregister an SPI Callback + * SPI callback is redirected to the weak predefined callback + * @param hspi Pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for the specified SPI. + * @param CallbackID ID of the callback to be unregistered + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SPI_UnRegisterCallback(SPI_HandleTypeDef *hspi, HAL_SPI_CallbackIDTypeDef CallbackID) +{ + HAL_StatusTypeDef status = HAL_OK; + + /* Process locked */ + __HAL_LOCK(hspi); + + if (HAL_SPI_STATE_READY == hspi->State) + { + switch (CallbackID) + { + case HAL_SPI_TX_COMPLETE_CB_ID : + hspi->TxCpltCallback = HAL_SPI_TxCpltCallback; /* Legacy weak TxCpltCallback */ + break; + + case HAL_SPI_RX_COMPLETE_CB_ID : + hspi->RxCpltCallback = HAL_SPI_RxCpltCallback; /* Legacy weak RxCpltCallback */ + break; + + case HAL_SPI_TX_RX_COMPLETE_CB_ID : + hspi->TxRxCpltCallback = HAL_SPI_TxRxCpltCallback; /* Legacy weak TxRxCpltCallback */ + break; + + case HAL_SPI_TX_HALF_COMPLETE_CB_ID : + hspi->TxHalfCpltCallback = HAL_SPI_TxHalfCpltCallback; /* Legacy weak TxHalfCpltCallback */ + break; + + case HAL_SPI_RX_HALF_COMPLETE_CB_ID : + hspi->RxHalfCpltCallback = HAL_SPI_RxHalfCpltCallback; /* Legacy weak RxHalfCpltCallback */ + break; + + case HAL_SPI_TX_RX_HALF_COMPLETE_CB_ID : + hspi->TxRxHalfCpltCallback = HAL_SPI_TxRxHalfCpltCallback; /* Legacy weak TxRxHalfCpltCallback */ + break; + + case HAL_SPI_ERROR_CB_ID : + hspi->ErrorCallback = HAL_SPI_ErrorCallback; /* Legacy weak ErrorCallback */ + break; + + case HAL_SPI_ABORT_CB_ID : + hspi->AbortCpltCallback = HAL_SPI_AbortCpltCallback; /* Legacy weak AbortCpltCallback */ + break; + + case HAL_SPI_MSPINIT_CB_ID : + hspi->MspInitCallback = HAL_SPI_MspInit; /* Legacy weak MspInit */ + break; + + case HAL_SPI_MSPDEINIT_CB_ID : + hspi->MspDeInitCallback = HAL_SPI_MspDeInit; /* Legacy weak MspDeInit */ + break; + + default : + /* Update the error code */ + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_INVALID_CALLBACK); + + /* Return error status */ + status = HAL_ERROR; + break; + } + } + else if (HAL_SPI_STATE_RESET == hspi->State) + { + switch (CallbackID) + { + case HAL_SPI_MSPINIT_CB_ID : + hspi->MspInitCallback = HAL_SPI_MspInit; /* Legacy weak MspInit */ + break; + + case HAL_SPI_MSPDEINIT_CB_ID : + hspi->MspDeInitCallback = HAL_SPI_MspDeInit; /* Legacy weak MspDeInit */ + break; + + default : + /* Update the error code */ + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_INVALID_CALLBACK); + + /* Return error status */ + status = HAL_ERROR; + break; + } + } + else + { + /* Update the error code */ + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_INVALID_CALLBACK); + + /* Return error status */ + status = HAL_ERROR; + } + + /* Release Lock */ + __HAL_UNLOCK(hspi); + return status; +} +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ +/** + * @} + */ + +/** @defgroup SPI_Exported_Functions_Group2 IO operation functions + * @brief Data transfers functions + * +@verbatim + ============================================================================== + ##### IO operation functions ##### + =============================================================================== + [..] + This subsection provides a set of functions allowing to manage the SPI + data transfers. + + [..] The SPI supports master and slave mode : + + (#) There are two modes of transfer: + (++) Blocking mode: The communication is performed in polling mode. + The HAL status of all data processing is returned by the same function + after finishing transfer. + (++) No-Blocking mode: The communication is performed using Interrupts + or DMA, These APIs return the HAL status. + The end of the data processing will be indicated through the + dedicated SPI IRQ when using Interrupt mode or the DMA IRQ when + using DMA mode. + The HAL_SPI_TxCpltCallback(), HAL_SPI_RxCpltCallback() and HAL_SPI_TxRxCpltCallback() user callbacks + will be executed respectively at the end of the transmit or Receive process + The HAL_SPI_ErrorCallback()user callback will be executed when a communication error is detected + + (#) APIs provided for these 2 transfer modes (Blocking mode or Non blocking mode using either Interrupt or DMA) + exist for 1Line (simplex) and 2Lines (full duplex) modes. + +@endverbatim + * @{ + */ + +/** + * @brief Transmit an amount of data in blocking mode. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @param pData pointer to data buffer + * @param Size amount of data to be sent + * @param Timeout Timeout duration + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout) +{ + uint32_t tickstart; + HAL_StatusTypeDef errorcode = HAL_OK; + uint16_t initial_TxXferCount; + + /* Check Direction parameter */ + assert_param(IS_SPI_DIRECTION_2LINES_OR_1LINE(hspi->Init.Direction)); + + /* Process Locked */ + __HAL_LOCK(hspi); + + /* Init tickstart for timeout management*/ + tickstart = HAL_GetTick(); + initial_TxXferCount = Size; + + if (hspi->State != HAL_SPI_STATE_READY) + { + errorcode = HAL_BUSY; + goto error; + } + + if ((pData == NULL) || (Size == 0U)) + { + errorcode = HAL_ERROR; + goto error; + } + + /* Set the transaction information */ + hspi->State = HAL_SPI_STATE_BUSY_TX; + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + hspi->pTxBuffPtr = (uint8_t *)pData; + hspi->TxXferSize = Size; + hspi->TxXferCount = Size; + + /*Init field not used in handle to zero */ + hspi->pRxBuffPtr = (uint8_t *)NULL; + hspi->RxXferSize = 0U; + hspi->RxXferCount = 0U; + hspi->TxISR = NULL; + hspi->RxISR = NULL; + + /* Configure communication direction : 1Line */ + if (hspi->Init.Direction == SPI_DIRECTION_1LINE) + { + /* Disable SPI Peripheral before set 1Line direction (BIDIOE bit) */ + __HAL_SPI_DISABLE(hspi); + SPI_1LINE_TX(hspi); + } + +#if (USE_SPI_CRC != 0U) + /* Reset CRC Calculation */ + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + { + SPI_RESET_CRC(hspi); + } +#endif /* USE_SPI_CRC */ + + /* Check if the SPI is already enabled */ + if ((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE) + { + /* Enable SPI peripheral */ + __HAL_SPI_ENABLE(hspi); + } + + /* Transmit data in 16 Bit mode */ + if (hspi->Init.DataSize == SPI_DATASIZE_16BIT) + { + if ((hspi->Init.Mode == SPI_MODE_SLAVE) || (initial_TxXferCount == 0x01U)) + { + hspi->Instance->DR = *((uint16_t *)hspi->pTxBuffPtr); + hspi->pTxBuffPtr += sizeof(uint16_t); + hspi->TxXferCount--; + } + /* Transmit data in 16 Bit mode */ + while (hspi->TxXferCount > 0U) + { + /* Wait until TXE flag is set to send data */ + if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE)) + { + hspi->Instance->DR = *((uint16_t *)hspi->pTxBuffPtr); + hspi->pTxBuffPtr += sizeof(uint16_t); + hspi->TxXferCount--; + } + else + { + /* Timeout management */ + if ((((HAL_GetTick() - tickstart) >= Timeout) && (Timeout != HAL_MAX_DELAY)) || (Timeout == 0U)) + { + errorcode = HAL_TIMEOUT; + goto error; + } + } + } + } + /* Transmit data in 8 Bit mode */ + else + { + if ((hspi->Init.Mode == SPI_MODE_SLAVE) || (initial_TxXferCount == 0x01U)) + { + *((__IO uint8_t *)&hspi->Instance->DR) = (*hspi->pTxBuffPtr); + hspi->pTxBuffPtr += sizeof(uint8_t); + hspi->TxXferCount--; + } + while (hspi->TxXferCount > 0U) + { + /* Wait until TXE flag is set to send data */ + if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE)) + { + *((__IO uint8_t *)&hspi->Instance->DR) = (*hspi->pTxBuffPtr); + hspi->pTxBuffPtr += sizeof(uint8_t); + hspi->TxXferCount--; + } + else + { + /* Timeout management */ + if ((((HAL_GetTick() - tickstart) >= Timeout) && (Timeout != HAL_MAX_DELAY)) || (Timeout == 0U)) + { + errorcode = HAL_TIMEOUT; + goto error; + } + } + } + } +#if (USE_SPI_CRC != 0U) + /* Enable CRC Transmission */ + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + { + SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT); + } +#endif /* USE_SPI_CRC */ + + /* Check the end of the transaction */ + if (SPI_EndRxTxTransaction(hspi, Timeout, tickstart) != HAL_OK) + { + hspi->ErrorCode = HAL_SPI_ERROR_FLAG; + } + + /* Clear overrun flag in 2 Lines communication mode because received is not read */ + if (hspi->Init.Direction == SPI_DIRECTION_2LINES) + { + __HAL_SPI_CLEAR_OVRFLAG(hspi); + } + + if (hspi->ErrorCode != HAL_SPI_ERROR_NONE) + { + errorcode = HAL_ERROR; + } + +error: + hspi->State = HAL_SPI_STATE_READY; + /* Process Unlocked */ + __HAL_UNLOCK(hspi); + return errorcode; +} + +/** + * @brief Receive an amount of data in blocking mode. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @param pData pointer to data buffer + * @param Size amount of data to be received + * @param Timeout Timeout duration + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout) +{ +#if (USE_SPI_CRC != 0U) + __IO uint32_t tmpreg = 0U; +#endif /* USE_SPI_CRC */ + uint32_t tickstart; + HAL_StatusTypeDef errorcode = HAL_OK; + + if ((hspi->Init.Mode == SPI_MODE_MASTER) && (hspi->Init.Direction == SPI_DIRECTION_2LINES)) + { + hspi->State = HAL_SPI_STATE_BUSY_RX; + /* Call transmit-receive function to send Dummy data on Tx line and generate clock on CLK line */ + return HAL_SPI_TransmitReceive(hspi, pData, pData, Size, Timeout); + } + + /* Process Locked */ + __HAL_LOCK(hspi); + + /* Init tickstart for timeout management*/ + tickstart = HAL_GetTick(); + + if (hspi->State != HAL_SPI_STATE_READY) + { + errorcode = HAL_BUSY; + goto error; + } + + if ((pData == NULL) || (Size == 0U)) + { + errorcode = HAL_ERROR; + goto error; + } + + /* Set the transaction information */ + hspi->State = HAL_SPI_STATE_BUSY_RX; + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + hspi->pRxBuffPtr = (uint8_t *)pData; + hspi->RxXferSize = Size; + hspi->RxXferCount = Size; + + /*Init field not used in handle to zero */ + hspi->pTxBuffPtr = (uint8_t *)NULL; + hspi->TxXferSize = 0U; + hspi->TxXferCount = 0U; + hspi->RxISR = NULL; + hspi->TxISR = NULL; + +#if (USE_SPI_CRC != 0U) + /* Reset CRC Calculation */ + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + { + SPI_RESET_CRC(hspi); + /* this is done to handle the CRCNEXT before the latest data */ + hspi->RxXferCount--; + } +#endif /* USE_SPI_CRC */ + + /* Configure communication direction: 1Line */ + if (hspi->Init.Direction == SPI_DIRECTION_1LINE) + { + /* Disable SPI Peripheral before set 1Line direction (BIDIOE bit) */ + __HAL_SPI_DISABLE(hspi); + SPI_1LINE_RX(hspi); + } + + /* Check if the SPI is already enabled */ + if ((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE) + { + /* Enable SPI peripheral */ + __HAL_SPI_ENABLE(hspi); + } + + /* Receive data in 8 Bit mode */ + if (hspi->Init.DataSize == SPI_DATASIZE_8BIT) + { + /* Transfer loop */ + while (hspi->RxXferCount > 0U) + { + /* Check the RXNE flag */ + if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_RXNE)) + { + /* read the received data */ + (* (uint8_t *)hspi->pRxBuffPtr) = *(__IO uint8_t *)&hspi->Instance->DR; + hspi->pRxBuffPtr += sizeof(uint8_t); + hspi->RxXferCount--; + } + else + { + /* Timeout management */ + if ((((HAL_GetTick() - tickstart) >= Timeout) && (Timeout != HAL_MAX_DELAY)) || (Timeout == 0U)) + { + errorcode = HAL_TIMEOUT; + goto error; + } + } + } + } + else + { + /* Transfer loop */ + while (hspi->RxXferCount > 0U) + { + /* Check the RXNE flag */ + if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_RXNE)) + { + *((uint16_t *)hspi->pRxBuffPtr) = (uint16_t)hspi->Instance->DR; + hspi->pRxBuffPtr += sizeof(uint16_t); + hspi->RxXferCount--; + } + else + { + /* Timeout management */ + if ((((HAL_GetTick() - tickstart) >= Timeout) && (Timeout != HAL_MAX_DELAY)) || (Timeout == 0U)) + { + errorcode = HAL_TIMEOUT; + goto error; + } + } + } + } + +#if (USE_SPI_CRC != 0U) + /* Handle the CRC Transmission */ + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + { + /* freeze the CRC before the latest data */ + SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT); + + /* Read the latest data */ + if (SPI_WaitFlagStateUntilTimeout(hspi, SPI_FLAG_RXNE, SET, Timeout, tickstart) != HAL_OK) + { + /* the latest data has not been received */ + errorcode = HAL_TIMEOUT; + goto error; + } + + /* Receive last data in 16 Bit mode */ + if (hspi->Init.DataSize == SPI_DATASIZE_16BIT) + { + *((uint16_t *)hspi->pRxBuffPtr) = (uint16_t)hspi->Instance->DR; + } + /* Receive last data in 8 Bit mode */ + else + { + (*(uint8_t *)hspi->pRxBuffPtr) = *(__IO uint8_t *)&hspi->Instance->DR; + } + + /* Wait the CRC data */ + if (SPI_WaitFlagStateUntilTimeout(hspi, SPI_FLAG_RXNE, SET, Timeout, tickstart) != HAL_OK) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_CRC); + errorcode = HAL_TIMEOUT; + goto error; + } + + /* Read CRC to Flush DR and RXNE flag */ + tmpreg = READ_REG(hspi->Instance->DR); + /* To avoid GCC warning */ + UNUSED(tmpreg); + } +#endif /* USE_SPI_CRC */ + + /* Check the end of the transaction */ + if (SPI_EndRxTransaction(hspi, Timeout, tickstart) != HAL_OK) + { + hspi->ErrorCode = HAL_SPI_ERROR_FLAG; + } + +#if (USE_SPI_CRC != 0U) + /* Check if CRC error occurred */ + if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_CRCERR)) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_CRC); + __HAL_SPI_CLEAR_CRCERRFLAG(hspi); + } +#endif /* USE_SPI_CRC */ + + if (hspi->ErrorCode != HAL_SPI_ERROR_NONE) + { + errorcode = HAL_ERROR; + } + +error : + hspi->State = HAL_SPI_STATE_READY; + __HAL_UNLOCK(hspi); + return errorcode; +} + +/** + * @brief Transmit and Receive an amount of data in blocking mode. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @param pTxData pointer to transmission data buffer + * @param pRxData pointer to reception data buffer + * @param Size amount of data to be sent and received + * @param Timeout Timeout duration + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, + uint32_t Timeout) +{ + uint16_t initial_TxXferCount; + uint32_t tmp_mode; + HAL_SPI_StateTypeDef tmp_state; + uint32_t tickstart; +#if (USE_SPI_CRC != 0U) + __IO uint32_t tmpreg = 0U; +#endif /* USE_SPI_CRC */ + + /* Variable used to alternate Rx and Tx during transfer */ + uint32_t txallowed = 1U; + HAL_StatusTypeDef errorcode = HAL_OK; + + /* Check Direction parameter */ + assert_param(IS_SPI_DIRECTION_2LINES(hspi->Init.Direction)); + + /* Process Locked */ + __HAL_LOCK(hspi); + + /* Init tickstart for timeout management*/ + tickstart = HAL_GetTick(); + + /* Init temporary variables */ + tmp_state = hspi->State; + tmp_mode = hspi->Init.Mode; + initial_TxXferCount = Size; + + if (!((tmp_state == HAL_SPI_STATE_READY) || \ + ((tmp_mode == SPI_MODE_MASTER) && (hspi->Init.Direction == SPI_DIRECTION_2LINES) && (tmp_state == HAL_SPI_STATE_BUSY_RX)))) + { + errorcode = HAL_BUSY; + goto error; + } + + if ((pTxData == NULL) || (pRxData == NULL) || (Size == 0U)) + { + errorcode = HAL_ERROR; + goto error; + } + + /* Don't overwrite in case of HAL_SPI_STATE_BUSY_RX */ + if (hspi->State != HAL_SPI_STATE_BUSY_RX) + { + hspi->State = HAL_SPI_STATE_BUSY_TX_RX; + } + + /* Set the transaction information */ + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + hspi->pRxBuffPtr = (uint8_t *)pRxData; + hspi->RxXferCount = Size; + hspi->RxXferSize = Size; + hspi->pTxBuffPtr = (uint8_t *)pTxData; + hspi->TxXferCount = Size; + hspi->TxXferSize = Size; + + /*Init field not used in handle to zero */ + hspi->RxISR = NULL; + hspi->TxISR = NULL; + +#if (USE_SPI_CRC != 0U) + /* Reset CRC Calculation */ + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + { + SPI_RESET_CRC(hspi); + } +#endif /* USE_SPI_CRC */ + + /* Check if the SPI is already enabled */ + if ((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE) + { + /* Enable SPI peripheral */ + __HAL_SPI_ENABLE(hspi); + } + + /* Transmit and Receive data in 16 Bit mode */ + if (hspi->Init.DataSize == SPI_DATASIZE_16BIT) + { + if ((hspi->Init.Mode == SPI_MODE_SLAVE) || (initial_TxXferCount == 0x01U)) + { + hspi->Instance->DR = *((uint16_t *)hspi->pTxBuffPtr); + hspi->pTxBuffPtr += sizeof(uint16_t); + hspi->TxXferCount--; + } + while ((hspi->TxXferCount > 0U) || (hspi->RxXferCount > 0U)) + { + /* Check TXE flag */ + if ((__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE)) && (hspi->TxXferCount > 0U) && (txallowed == 1U)) + { + hspi->Instance->DR = *((uint16_t *)hspi->pTxBuffPtr); + hspi->pTxBuffPtr += sizeof(uint16_t); + hspi->TxXferCount--; + /* Next Data is a reception (Rx). Tx not allowed */ + txallowed = 0U; + +#if (USE_SPI_CRC != 0U) + /* Enable CRC Transmission */ + if ((hspi->TxXferCount == 0U) && (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)) + { + SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT); + } +#endif /* USE_SPI_CRC */ + } + + /* Check RXNE flag */ + if ((__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_RXNE)) && (hspi->RxXferCount > 0U)) + { + *((uint16_t *)hspi->pRxBuffPtr) = (uint16_t)hspi->Instance->DR; + hspi->pRxBuffPtr += sizeof(uint16_t); + hspi->RxXferCount--; + /* Next Data is a Transmission (Tx). Tx is allowed */ + txallowed = 1U; + } + if (((HAL_GetTick() - tickstart) >= Timeout) && (Timeout != HAL_MAX_DELAY)) + { + errorcode = HAL_TIMEOUT; + goto error; + } + } + } + /* Transmit and Receive data in 8 Bit mode */ + else + { + if ((hspi->Init.Mode == SPI_MODE_SLAVE) || (initial_TxXferCount == 0x01U)) + { + *((__IO uint8_t *)&hspi->Instance->DR) = (*hspi->pTxBuffPtr); + hspi->pTxBuffPtr += sizeof(uint8_t); + hspi->TxXferCount--; + } + while ((hspi->TxXferCount > 0U) || (hspi->RxXferCount > 0U)) + { + /* Check TXE flag */ + if ((__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE)) && (hspi->TxXferCount > 0U) && (txallowed == 1U)) + { + *(__IO uint8_t *)&hspi->Instance->DR = (*hspi->pTxBuffPtr); + hspi->pTxBuffPtr++; + hspi->TxXferCount--; + /* Next Data is a reception (Rx). Tx not allowed */ + txallowed = 0U; + +#if (USE_SPI_CRC != 0U) + /* Enable CRC Transmission */ + if ((hspi->TxXferCount == 0U) && (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)) + { + SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT); + } +#endif /* USE_SPI_CRC */ + } + + /* Wait until RXNE flag is reset */ + if ((__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_RXNE)) && (hspi->RxXferCount > 0U)) + { + (*(uint8_t *)hspi->pRxBuffPtr) = hspi->Instance->DR; + hspi->pRxBuffPtr++; + hspi->RxXferCount--; + /* Next Data is a Transmission (Tx). Tx is allowed */ + txallowed = 1U; + } + if ((((HAL_GetTick() - tickstart) >= Timeout) && ((Timeout != HAL_MAX_DELAY))) || (Timeout == 0U)) + { + errorcode = HAL_TIMEOUT; + goto error; + } + } + } + +#if (USE_SPI_CRC != 0U) + /* Read CRC from DR to close CRC calculation process */ + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + { + /* Wait until TXE flag */ + if (SPI_WaitFlagStateUntilTimeout(hspi, SPI_FLAG_RXNE, SET, Timeout, tickstart) != HAL_OK) + { + /* Error on the CRC reception */ + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_CRC); + errorcode = HAL_TIMEOUT; + goto error; + } + /* Read CRC */ + tmpreg = READ_REG(hspi->Instance->DR); + /* To avoid GCC warning */ + UNUSED(tmpreg); + } + + /* Check if CRC error occurred */ + if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_CRCERR)) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_CRC); + /* Clear CRC Flag */ + __HAL_SPI_CLEAR_CRCERRFLAG(hspi); + + errorcode = HAL_ERROR; + } +#endif /* USE_SPI_CRC */ + + /* Check the end of the transaction */ + if (SPI_EndRxTxTransaction(hspi, Timeout, tickstart) != HAL_OK) + { + errorcode = HAL_ERROR; + hspi->ErrorCode = HAL_SPI_ERROR_FLAG; + goto error; + } + + /* Clear overrun flag in 2 Lines communication mode because received is not read */ + if (hspi->Init.Direction == SPI_DIRECTION_2LINES) + { + __HAL_SPI_CLEAR_OVRFLAG(hspi); + } + +error : + hspi->State = HAL_SPI_STATE_READY; + __HAL_UNLOCK(hspi); + return errorcode; +} + +/** + * @brief Transmit an amount of data in non-blocking mode with Interrupt. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @param pData pointer to data buffer + * @param Size amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SPI_Transmit_IT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size) +{ + HAL_StatusTypeDef errorcode = HAL_OK; + + /* Check Direction parameter */ + assert_param(IS_SPI_DIRECTION_2LINES_OR_1LINE(hspi->Init.Direction)); + + /* Process Locked */ + __HAL_LOCK(hspi); + + if ((pData == NULL) || (Size == 0U)) + { + errorcode = HAL_ERROR; + goto error; + } + + if (hspi->State != HAL_SPI_STATE_READY) + { + errorcode = HAL_BUSY; + goto error; + } + + /* Set the transaction information */ + hspi->State = HAL_SPI_STATE_BUSY_TX; + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + hspi->pTxBuffPtr = (uint8_t *)pData; + hspi->TxXferSize = Size; + hspi->TxXferCount = Size; + + /* Init field not used in handle to zero */ + hspi->pRxBuffPtr = (uint8_t *)NULL; + hspi->RxXferSize = 0U; + hspi->RxXferCount = 0U; + hspi->RxISR = NULL; + + /* Set the function for IT treatment */ + if (hspi->Init.DataSize > SPI_DATASIZE_8BIT) + { + hspi->TxISR = SPI_TxISR_16BIT; + } + else + { + hspi->TxISR = SPI_TxISR_8BIT; + } + + /* Configure communication direction : 1Line */ + if (hspi->Init.Direction == SPI_DIRECTION_1LINE) + { + /* Disable SPI Peripheral before set 1Line direction (BIDIOE bit) */ + __HAL_SPI_DISABLE(hspi); + SPI_1LINE_TX(hspi); + } + +#if (USE_SPI_CRC != 0U) + /* Reset CRC Calculation */ + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + { + SPI_RESET_CRC(hspi); + } +#endif /* USE_SPI_CRC */ + + /* Enable TXE and ERR interrupt */ + __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_TXE | SPI_IT_ERR)); + + + /* Check if the SPI is already enabled */ + if ((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE) + { + /* Enable SPI peripheral */ + __HAL_SPI_ENABLE(hspi); + } + +error : + __HAL_UNLOCK(hspi); + return errorcode; +} + +/** + * @brief Receive an amount of data in non-blocking mode with Interrupt. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @param pData pointer to data buffer + * @param Size amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SPI_Receive_IT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size) +{ + HAL_StatusTypeDef errorcode = HAL_OK; + + if ((hspi->Init.Direction == SPI_DIRECTION_2LINES) && (hspi->Init.Mode == SPI_MODE_MASTER)) + { + hspi->State = HAL_SPI_STATE_BUSY_RX; + /* Call transmit-receive function to send Dummy data on Tx line and generate clock on CLK line */ + return HAL_SPI_TransmitReceive_IT(hspi, pData, pData, Size); + } + + /* Process Locked */ + __HAL_LOCK(hspi); + + if (hspi->State != HAL_SPI_STATE_READY) + { + errorcode = HAL_BUSY; + goto error; + } + + if ((pData == NULL) || (Size == 0U)) + { + errorcode = HAL_ERROR; + goto error; + } + + /* Set the transaction information */ + hspi->State = HAL_SPI_STATE_BUSY_RX; + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + hspi->pRxBuffPtr = (uint8_t *)pData; + hspi->RxXferSize = Size; + hspi->RxXferCount = Size; + + /* Init field not used in handle to zero */ + hspi->pTxBuffPtr = (uint8_t *)NULL; + hspi->TxXferSize = 0U; + hspi->TxXferCount = 0U; + hspi->TxISR = NULL; + + /* Set the function for IT treatment */ + if (hspi->Init.DataSize > SPI_DATASIZE_8BIT) + { + hspi->RxISR = SPI_RxISR_16BIT; + } + else + { + hspi->RxISR = SPI_RxISR_8BIT; + } + + /* Configure communication direction : 1Line */ + if (hspi->Init.Direction == SPI_DIRECTION_1LINE) + { + /* Disable SPI Peripheral before set 1Line direction (BIDIOE bit) */ + __HAL_SPI_DISABLE(hspi); + SPI_1LINE_RX(hspi); + } + +#if (USE_SPI_CRC != 0U) + /* Reset CRC Calculation */ + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + { + SPI_RESET_CRC(hspi); + } +#endif /* USE_SPI_CRC */ + + /* Enable TXE and ERR interrupt */ + __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_RXNE | SPI_IT_ERR)); + + /* Note : The SPI must be enabled after unlocking current process + to avoid the risk of SPI interrupt handle execution before current + process unlock */ + + /* Check if the SPI is already enabled */ + if ((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE) + { + /* Enable SPI peripheral */ + __HAL_SPI_ENABLE(hspi); + } + +error : + /* Process Unlocked */ + __HAL_UNLOCK(hspi); + return errorcode; +} + +/** + * @brief Transmit and Receive an amount of data in non-blocking mode with Interrupt. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @param pTxData pointer to transmission data buffer + * @param pRxData pointer to reception data buffer + * @param Size amount of data to be sent and received + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SPI_TransmitReceive_IT(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size) +{ + uint32_t tmp_mode; + HAL_SPI_StateTypeDef tmp_state; + HAL_StatusTypeDef errorcode = HAL_OK; + + /* Check Direction parameter */ + assert_param(IS_SPI_DIRECTION_2LINES(hspi->Init.Direction)); + + /* Process locked */ + __HAL_LOCK(hspi); + + /* Init temporary variables */ + tmp_state = hspi->State; + tmp_mode = hspi->Init.Mode; + + if (!((tmp_state == HAL_SPI_STATE_READY) || \ + ((tmp_mode == SPI_MODE_MASTER) && (hspi->Init.Direction == SPI_DIRECTION_2LINES) && (tmp_state == HAL_SPI_STATE_BUSY_RX)))) + { + errorcode = HAL_BUSY; + goto error; + } + + if ((pTxData == NULL) || (pRxData == NULL) || (Size == 0U)) + { + errorcode = HAL_ERROR; + goto error; + } + + /* Don't overwrite in case of HAL_SPI_STATE_BUSY_RX */ + if (hspi->State != HAL_SPI_STATE_BUSY_RX) + { + hspi->State = HAL_SPI_STATE_BUSY_TX_RX; + } + + /* Set the transaction information */ + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + hspi->pTxBuffPtr = (uint8_t *)pTxData; + hspi->TxXferSize = Size; + hspi->TxXferCount = Size; + hspi->pRxBuffPtr = (uint8_t *)pRxData; + hspi->RxXferSize = Size; + hspi->RxXferCount = Size; + + /* Set the function for IT treatment */ + if (hspi->Init.DataSize > SPI_DATASIZE_8BIT) + { + hspi->RxISR = SPI_2linesRxISR_16BIT; + hspi->TxISR = SPI_2linesTxISR_16BIT; + } + else + { + hspi->RxISR = SPI_2linesRxISR_8BIT; + hspi->TxISR = SPI_2linesTxISR_8BIT; + } + +#if (USE_SPI_CRC != 0U) + /* Reset CRC Calculation */ + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + { + SPI_RESET_CRC(hspi); + } +#endif /* USE_SPI_CRC */ + + /* Enable TXE, RXNE and ERR interrupt */ + __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_TXE | SPI_IT_RXNE | SPI_IT_ERR)); + + /* Check if the SPI is already enabled */ + if ((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE) + { + /* Enable SPI peripheral */ + __HAL_SPI_ENABLE(hspi); + } + +error : + /* Process Unlocked */ + __HAL_UNLOCK(hspi); + return errorcode; +} + +/** + * @brief Transmit an amount of data in non-blocking mode with DMA. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @param pData pointer to data buffer + * @param Size amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SPI_Transmit_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size) +{ + HAL_StatusTypeDef errorcode = HAL_OK; + + /* Check tx dma handle */ + assert_param(IS_SPI_DMA_HANDLE(hspi->hdmatx)); + + /* Check Direction parameter */ + assert_param(IS_SPI_DIRECTION_2LINES_OR_1LINE(hspi->Init.Direction)); + + /* Process Locked */ + __HAL_LOCK(hspi); + + if (hspi->State != HAL_SPI_STATE_READY) + { + errorcode = HAL_BUSY; + goto error; + } + + if ((pData == NULL) || (Size == 0U)) + { + errorcode = HAL_ERROR; + goto error; + } + + /* Set the transaction information */ + hspi->State = HAL_SPI_STATE_BUSY_TX; + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + hspi->pTxBuffPtr = (uint8_t *)pData; + hspi->TxXferSize = Size; + hspi->TxXferCount = Size; + + /* Init field not used in handle to zero */ + hspi->pRxBuffPtr = (uint8_t *)NULL; + hspi->TxISR = NULL; + hspi->RxISR = NULL; + hspi->RxXferSize = 0U; + hspi->RxXferCount = 0U; + + /* Configure communication direction : 1Line */ + if (hspi->Init.Direction == SPI_DIRECTION_1LINE) + { + /* Disable SPI Peripheral before set 1Line direction (BIDIOE bit) */ + __HAL_SPI_DISABLE(hspi); + SPI_1LINE_TX(hspi); + } + +#if (USE_SPI_CRC != 0U) + /* Reset CRC Calculation */ + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + { + SPI_RESET_CRC(hspi); + } +#endif /* USE_SPI_CRC */ + + /* Set the SPI TxDMA Half transfer complete callback */ + hspi->hdmatx->XferHalfCpltCallback = SPI_DMAHalfTransmitCplt; + + /* Set the SPI TxDMA transfer complete callback */ + hspi->hdmatx->XferCpltCallback = SPI_DMATransmitCplt; + + /* Set the DMA error callback */ + hspi->hdmatx->XferErrorCallback = SPI_DMAError; + + /* Set the DMA AbortCpltCallback */ + hspi->hdmatx->XferAbortCallback = NULL; + + /* Enable the Tx DMA Stream/Channel */ + if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmatx, (uint32_t)hspi->pTxBuffPtr, (uint32_t)&hspi->Instance->DR, + hspi->TxXferCount)) + { + /* Update SPI error code */ + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_DMA); + errorcode = HAL_ERROR; + + hspi->State = HAL_SPI_STATE_READY; + goto error; + } + + /* Check if the SPI is already enabled */ + if ((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE) + { + /* Enable SPI peripheral */ + __HAL_SPI_ENABLE(hspi); + } + + /* Enable the SPI Error Interrupt Bit */ + __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_ERR)); + + /* Enable Tx DMA Request */ + SET_BIT(hspi->Instance->CR2, SPI_CR2_TXDMAEN); + +error : + /* Process Unlocked */ + __HAL_UNLOCK(hspi); + return errorcode; +} + +/** + * @brief Receive an amount of data in non-blocking mode with DMA. + * @note In case of MASTER mode and SPI_DIRECTION_2LINES direction, hdmatx shall be defined. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @param pData pointer to data buffer + * @note When the CRC feature is enabled the pData Length must be Size + 1. + * @param Size amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SPI_Receive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size) +{ + HAL_StatusTypeDef errorcode = HAL_OK; + + /* Check rx dma handle */ + assert_param(IS_SPI_DMA_HANDLE(hspi->hdmarx)); + + if ((hspi->Init.Direction == SPI_DIRECTION_2LINES) && (hspi->Init.Mode == SPI_MODE_MASTER)) + { + hspi->State = HAL_SPI_STATE_BUSY_RX; + + /* Check tx dma handle */ + assert_param(IS_SPI_DMA_HANDLE(hspi->hdmatx)); + + /* Call transmit-receive function to send Dummy data on Tx line and generate clock on CLK line */ + return HAL_SPI_TransmitReceive_DMA(hspi, pData, pData, Size); + } + + /* Process Locked */ + __HAL_LOCK(hspi); + + if (hspi->State != HAL_SPI_STATE_READY) + { + errorcode = HAL_BUSY; + goto error; + } + + if ((pData == NULL) || (Size == 0U)) + { + errorcode = HAL_ERROR; + goto error; + } + + /* Set the transaction information */ + hspi->State = HAL_SPI_STATE_BUSY_RX; + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + hspi->pRxBuffPtr = (uint8_t *)pData; + hspi->RxXferSize = Size; + hspi->RxXferCount = Size; + + /*Init field not used in handle to zero */ + hspi->RxISR = NULL; + hspi->TxISR = NULL; + hspi->TxXferSize = 0U; + hspi->TxXferCount = 0U; + + /* Configure communication direction : 1Line */ + if (hspi->Init.Direction == SPI_DIRECTION_1LINE) + { + /* Disable SPI Peripheral before set 1Line direction (BIDIOE bit) */ + __HAL_SPI_DISABLE(hspi); + SPI_1LINE_RX(hspi); + } + +#if (USE_SPI_CRC != 0U) + /* Reset CRC Calculation */ + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + { + SPI_RESET_CRC(hspi); + } +#endif /* USE_SPI_CRC */ + + /* Set the SPI RxDMA Half transfer complete callback */ + hspi->hdmarx->XferHalfCpltCallback = SPI_DMAHalfReceiveCplt; + + /* Set the SPI Rx DMA transfer complete callback */ + hspi->hdmarx->XferCpltCallback = SPI_DMAReceiveCplt; + + /* Set the DMA error callback */ + hspi->hdmarx->XferErrorCallback = SPI_DMAError; + + /* Set the DMA AbortCpltCallback */ + hspi->hdmarx->XferAbortCallback = NULL; + + /* Enable the Rx DMA Stream/Channel */ + if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmarx, (uint32_t)&hspi->Instance->DR, (uint32_t)hspi->pRxBuffPtr, + hspi->RxXferCount)) + { + /* Update SPI error code */ + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_DMA); + errorcode = HAL_ERROR; + + hspi->State = HAL_SPI_STATE_READY; + goto error; + } + + /* Check if the SPI is already enabled */ + if ((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE) + { + /* Enable SPI peripheral */ + __HAL_SPI_ENABLE(hspi); + } + + /* Enable the SPI Error Interrupt Bit */ + __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_ERR)); + + /* Enable Rx DMA Request */ + SET_BIT(hspi->Instance->CR2, SPI_CR2_RXDMAEN); + +error: + /* Process Unlocked */ + __HAL_UNLOCK(hspi); + return errorcode; +} + +/** + * @brief Transmit and Receive an amount of data in non-blocking mode with DMA. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @param pTxData pointer to transmission data buffer + * @param pRxData pointer to reception data buffer + * @note When the CRC feature is enabled the pRxData Length must be Size + 1 + * @param Size amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SPI_TransmitReceive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, + uint16_t Size) +{ + uint32_t tmp_mode; + HAL_SPI_StateTypeDef tmp_state; + HAL_StatusTypeDef errorcode = HAL_OK; + + /* Check rx & tx dma handles */ + assert_param(IS_SPI_DMA_HANDLE(hspi->hdmarx)); + assert_param(IS_SPI_DMA_HANDLE(hspi->hdmatx)); + + /* Check Direction parameter */ + assert_param(IS_SPI_DIRECTION_2LINES(hspi->Init.Direction)); + + /* Process locked */ + __HAL_LOCK(hspi); + + /* Init temporary variables */ + tmp_state = hspi->State; + tmp_mode = hspi->Init.Mode; + + if (!((tmp_state == HAL_SPI_STATE_READY) || + ((tmp_mode == SPI_MODE_MASTER) && (hspi->Init.Direction == SPI_DIRECTION_2LINES) && (tmp_state == HAL_SPI_STATE_BUSY_RX)))) + { + errorcode = HAL_BUSY; + goto error; + } + + if ((pTxData == NULL) || (pRxData == NULL) || (Size == 0U)) + { + errorcode = HAL_ERROR; + goto error; + } + + /* Don't overwrite in case of HAL_SPI_STATE_BUSY_RX */ + if (hspi->State != HAL_SPI_STATE_BUSY_RX) + { + hspi->State = HAL_SPI_STATE_BUSY_TX_RX; + } + + /* Set the transaction information */ + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + hspi->pTxBuffPtr = (uint8_t *)pTxData; + hspi->TxXferSize = Size; + hspi->TxXferCount = Size; + hspi->pRxBuffPtr = (uint8_t *)pRxData; + hspi->RxXferSize = Size; + hspi->RxXferCount = Size; + + /* Init field not used in handle to zero */ + hspi->RxISR = NULL; + hspi->TxISR = NULL; + +#if (USE_SPI_CRC != 0U) + /* Reset CRC Calculation */ + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + { + SPI_RESET_CRC(hspi); + } +#endif /* USE_SPI_CRC */ + + /* Check if we are in Rx only or in Rx/Tx Mode and configure the DMA transfer complete callback */ + if (hspi->State == HAL_SPI_STATE_BUSY_RX) + { + /* Set the SPI Rx DMA Half transfer complete callback */ + hspi->hdmarx->XferHalfCpltCallback = SPI_DMAHalfReceiveCplt; + hspi->hdmarx->XferCpltCallback = SPI_DMAReceiveCplt; + } + else + { + /* Set the SPI Tx/Rx DMA Half transfer complete callback */ + hspi->hdmarx->XferHalfCpltCallback = SPI_DMAHalfTransmitReceiveCplt; + hspi->hdmarx->XferCpltCallback = SPI_DMATransmitReceiveCplt; + } + + /* Set the DMA error callback */ + hspi->hdmarx->XferErrorCallback = SPI_DMAError; + + /* Set the DMA AbortCpltCallback */ + hspi->hdmarx->XferAbortCallback = NULL; + + /* Enable the Rx DMA Stream/Channel */ + if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmarx, (uint32_t)&hspi->Instance->DR, (uint32_t)hspi->pRxBuffPtr, + hspi->RxXferCount)) + { + /* Update SPI error code */ + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_DMA); + errorcode = HAL_ERROR; + + hspi->State = HAL_SPI_STATE_READY; + goto error; + } + + /* Enable Rx DMA Request */ + SET_BIT(hspi->Instance->CR2, SPI_CR2_RXDMAEN); + + /* Set the SPI Tx DMA transfer complete callback as NULL because the communication closing + is performed in DMA reception complete callback */ + hspi->hdmatx->XferHalfCpltCallback = NULL; + hspi->hdmatx->XferCpltCallback = NULL; + hspi->hdmatx->XferErrorCallback = NULL; + hspi->hdmatx->XferAbortCallback = NULL; + + /* Enable the Tx DMA Stream/Channel */ + if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmatx, (uint32_t)hspi->pTxBuffPtr, (uint32_t)&hspi->Instance->DR, + hspi->TxXferCount)) + { + /* Update SPI error code */ + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_DMA); + errorcode = HAL_ERROR; + + hspi->State = HAL_SPI_STATE_READY; + goto error; + } + + /* Check if the SPI is already enabled */ + if ((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE) + { + /* Enable SPI peripheral */ + __HAL_SPI_ENABLE(hspi); + } + /* Enable the SPI Error Interrupt Bit */ + __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_ERR)); + + /* Enable Tx DMA Request */ + SET_BIT(hspi->Instance->CR2, SPI_CR2_TXDMAEN); + +error : + /* Process Unlocked */ + __HAL_UNLOCK(hspi); + return errorcode; +} + +/** + * @brief Abort ongoing transfer (blocking mode). + * @param hspi SPI handle. + * @note This procedure could be used for aborting any ongoing transfer (Tx and Rx), + * started in Interrupt or DMA mode. + * This procedure performs following operations : + * - Disable SPI Interrupts (depending of transfer direction) + * - Disable the DMA transfer in the peripheral register (if enabled) + * - Abort DMA transfer by calling HAL_DMA_Abort (in case of transfer in DMA mode) + * - Set handle State to READY + * @note This procedure is executed in blocking mode : when exiting function, Abort is considered as completed. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SPI_Abort(SPI_HandleTypeDef *hspi) +{ + HAL_StatusTypeDef errorcode; + __IO uint32_t count; + __IO uint32_t resetcount; + + /* Initialized local variable */ + errorcode = HAL_OK; + resetcount = SPI_DEFAULT_TIMEOUT * (SystemCoreClock / 24U / 1000U); + count = resetcount; + + /* Clear ERRIE interrupt to avoid error interrupts generation during Abort procedure */ + CLEAR_BIT(hspi->Instance->CR2, SPI_CR2_ERRIE); + + /* Disable TXEIE, RXNEIE and ERRIE(mode fault event, overrun error, TI frame error) interrupts */ + if (HAL_IS_BIT_SET(hspi->Instance->CR2, SPI_CR2_TXEIE)) + { + hspi->TxISR = SPI_AbortTx_ISR; + /* Wait HAL_SPI_STATE_ABORT state */ + do + { + if (count == 0U) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_ABORT); + break; + } + count--; + } while (hspi->State != HAL_SPI_STATE_ABORT); + /* Reset Timeout Counter */ + count = resetcount; + } + + if (HAL_IS_BIT_SET(hspi->Instance->CR2, SPI_CR2_RXNEIE)) + { + hspi->RxISR = SPI_AbortRx_ISR; + /* Wait HAL_SPI_STATE_ABORT state */ + do + { + if (count == 0U) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_ABORT); + break; + } + count--; + } while (hspi->State != HAL_SPI_STATE_ABORT); + /* Reset Timeout Counter */ + count = resetcount; + } + + /* Disable the SPI DMA Tx request if enabled */ + if (HAL_IS_BIT_SET(hspi->Instance->CR2, SPI_CR2_TXDMAEN)) + { + /* Abort the SPI DMA Tx Stream/Channel : use blocking DMA Abort API (no callback) */ + if (hspi->hdmatx != NULL) + { + /* Set the SPI DMA Abort callback : + will lead to call HAL_SPI_AbortCpltCallback() at end of DMA abort procedure */ + hspi->hdmatx->XferAbortCallback = NULL; + + /* Abort DMA Tx Handle linked to SPI Peripheral */ + if (HAL_DMA_Abort(hspi->hdmatx) != HAL_OK) + { + hspi->ErrorCode = HAL_SPI_ERROR_ABORT; + } + + /* Disable Tx DMA Request */ + CLEAR_BIT(hspi->Instance->CR2, (SPI_CR2_TXDMAEN)); + + /* Wait until TXE flag is set */ + do + { + if (count == 0U) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_ABORT); + break; + } + count--; + } while ((hspi->Instance->SR & SPI_FLAG_TXE) == RESET); + } + } + + /* Disable the SPI DMA Rx request if enabled */ + if (HAL_IS_BIT_SET(hspi->Instance->CR2, SPI_CR2_RXDMAEN)) + { + /* Abort the SPI DMA Rx Stream/Channel : use blocking DMA Abort API (no callback) */ + if (hspi->hdmarx != NULL) + { + /* Set the SPI DMA Abort callback : + will lead to call HAL_SPI_AbortCpltCallback() at end of DMA abort procedure */ + hspi->hdmarx->XferAbortCallback = NULL; + + /* Abort DMA Rx Handle linked to SPI Peripheral */ + if (HAL_DMA_Abort(hspi->hdmarx) != HAL_OK) + { + hspi->ErrorCode = HAL_SPI_ERROR_ABORT; + } + + /* Disable peripheral */ + __HAL_SPI_DISABLE(hspi); + + /* Disable Rx DMA Request */ + CLEAR_BIT(hspi->Instance->CR2, (SPI_CR2_RXDMAEN)); + } + } + /* Reset Tx and Rx transfer counters */ + hspi->RxXferCount = 0U; + hspi->TxXferCount = 0U; + + /* Check error during Abort procedure */ + if (hspi->ErrorCode == HAL_SPI_ERROR_ABORT) + { + /* return HAL_Error in case of error during Abort procedure */ + errorcode = HAL_ERROR; + } + else + { + /* Reset errorCode */ + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + } + + /* Clear the Error flags in the SR register */ + __HAL_SPI_CLEAR_OVRFLAG(hspi); + __HAL_SPI_CLEAR_FREFLAG(hspi); + + /* Restore hspi->state to ready */ + hspi->State = HAL_SPI_STATE_READY; + + return errorcode; +} + +/** + * @brief Abort ongoing transfer (Interrupt mode). + * @param hspi SPI handle. + * @note This procedure could be used for aborting any ongoing transfer (Tx and Rx), + * started in Interrupt or DMA mode. + * This procedure performs following operations : + * - Disable SPI Interrupts (depending of transfer direction) + * - Disable the DMA transfer in the peripheral register (if enabled) + * - Abort DMA transfer by calling HAL_DMA_Abort_IT (in case of transfer in DMA mode) + * - Set handle State to READY + * - At abort completion, call user abort complete callback + * @note This procedure is executed in Interrupt mode, meaning that abort procedure could be + * considered as completed only when user abort complete callback is executed (not when exiting function). + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SPI_Abort_IT(SPI_HandleTypeDef *hspi) +{ + HAL_StatusTypeDef errorcode; + uint32_t abortcplt ; + __IO uint32_t count; + __IO uint32_t resetcount; + + /* Initialized local variable */ + errorcode = HAL_OK; + abortcplt = 1U; + resetcount = SPI_DEFAULT_TIMEOUT * (SystemCoreClock / 24U / 1000U); + count = resetcount; + + /* Clear ERRIE interrupt to avoid error interrupts generation during Abort procedure */ + CLEAR_BIT(hspi->Instance->CR2, SPI_CR2_ERRIE); + + /* Change Rx and Tx Irq Handler to Disable TXEIE, RXNEIE and ERRIE interrupts */ + if (HAL_IS_BIT_SET(hspi->Instance->CR2, SPI_CR2_TXEIE)) + { + hspi->TxISR = SPI_AbortTx_ISR; + /* Wait HAL_SPI_STATE_ABORT state */ + do + { + if (count == 0U) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_ABORT); + break; + } + count--; + } while (hspi->State != HAL_SPI_STATE_ABORT); + /* Reset Timeout Counter */ + count = resetcount; + } + + if (HAL_IS_BIT_SET(hspi->Instance->CR2, SPI_CR2_RXNEIE)) + { + hspi->RxISR = SPI_AbortRx_ISR; + /* Wait HAL_SPI_STATE_ABORT state */ + do + { + if (count == 0U) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_ABORT); + break; + } + count--; + } while (hspi->State != HAL_SPI_STATE_ABORT); + /* Reset Timeout Counter */ + count = resetcount; + } + + /* If DMA Tx and/or DMA Rx Handles are associated to SPI Handle, DMA Abort complete callbacks should be initialised + before any call to DMA Abort functions */ + /* DMA Tx Handle is valid */ + if (hspi->hdmatx != NULL) + { + /* Set DMA Abort Complete callback if UART DMA Tx request if enabled. + Otherwise, set it to NULL */ + if (HAL_IS_BIT_SET(hspi->Instance->CR2, SPI_CR2_TXDMAEN)) + { + hspi->hdmatx->XferAbortCallback = SPI_DMATxAbortCallback; + } + else + { + hspi->hdmatx->XferAbortCallback = NULL; + } + } + /* DMA Rx Handle is valid */ + if (hspi->hdmarx != NULL) + { + /* Set DMA Abort Complete callback if UART DMA Rx request if enabled. + Otherwise, set it to NULL */ + if (HAL_IS_BIT_SET(hspi->Instance->CR2, SPI_CR2_RXDMAEN)) + { + hspi->hdmarx->XferAbortCallback = SPI_DMARxAbortCallback; + } + else + { + hspi->hdmarx->XferAbortCallback = NULL; + } + } + + /* Disable the SPI DMA Tx request if enabled */ + if (HAL_IS_BIT_SET(hspi->Instance->CR2, SPI_CR2_TXDMAEN)) + { + /* Abort the SPI DMA Tx Stream/Channel */ + if (hspi->hdmatx != NULL) + { + /* Abort DMA Tx Handle linked to SPI Peripheral */ + if (HAL_DMA_Abort_IT(hspi->hdmatx) != HAL_OK) + { + hspi->hdmatx->XferAbortCallback = NULL; + hspi->ErrorCode = HAL_SPI_ERROR_ABORT; + } + else + { + abortcplt = 0U; + } + } + } + /* Disable the SPI DMA Rx request if enabled */ + if (HAL_IS_BIT_SET(hspi->Instance->CR2, SPI_CR2_RXDMAEN)) + { + /* Abort the SPI DMA Rx Stream/Channel */ + if (hspi->hdmarx != NULL) + { + /* Abort DMA Rx Handle linked to SPI Peripheral */ + if (HAL_DMA_Abort_IT(hspi->hdmarx) != HAL_OK) + { + hspi->hdmarx->XferAbortCallback = NULL; + hspi->ErrorCode = HAL_SPI_ERROR_ABORT; + } + else + { + abortcplt = 0U; + } + } + } + + if (abortcplt == 1U) + { + /* Reset Tx and Rx transfer counters */ + hspi->RxXferCount = 0U; + hspi->TxXferCount = 0U; + + /* Check error during Abort procedure */ + if (hspi->ErrorCode == HAL_SPI_ERROR_ABORT) + { + /* return HAL_Error in case of error during Abort procedure */ + errorcode = HAL_ERROR; + } + else + { + /* Reset errorCode */ + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + } + + /* Clear the Error flags in the SR register */ + __HAL_SPI_CLEAR_OVRFLAG(hspi); + __HAL_SPI_CLEAR_FREFLAG(hspi); + + /* Restore hspi->State to Ready */ + hspi->State = HAL_SPI_STATE_READY; + + /* As no DMA to be aborted, call directly user Abort complete callback */ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + hspi->AbortCpltCallback(hspi); +#else + HAL_SPI_AbortCpltCallback(hspi); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ + } + + return errorcode; +} + +/** + * @brief Pause the DMA Transfer. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for the specified SPI module. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SPI_DMAPause(SPI_HandleTypeDef *hspi) +{ + /* Process Locked */ + __HAL_LOCK(hspi); + + /* Disable the SPI DMA Tx & Rx requests */ + CLEAR_BIT(hspi->Instance->CR2, SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN); + + /* Process Unlocked */ + __HAL_UNLOCK(hspi); + + return HAL_OK; +} + +/** + * @brief Resume the DMA Transfer. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for the specified SPI module. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SPI_DMAResume(SPI_HandleTypeDef *hspi) +{ + /* Process Locked */ + __HAL_LOCK(hspi); + + /* Enable the SPI DMA Tx & Rx requests */ + SET_BIT(hspi->Instance->CR2, SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN); + + /* Process Unlocked */ + __HAL_UNLOCK(hspi); + + return HAL_OK; +} + +/** + * @brief Stop the DMA Transfer. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for the specified SPI module. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SPI_DMAStop(SPI_HandleTypeDef *hspi) +{ + HAL_StatusTypeDef errorcode = HAL_OK; + /* The Lock is not implemented on this API to allow the user application + to call the HAL SPI API under callbacks HAL_SPI_TxCpltCallback() or HAL_SPI_RxCpltCallback() or HAL_SPI_TxRxCpltCallback(): + when calling HAL_DMA_Abort() API the DMA TX/RX Transfer complete interrupt is generated + and the correspond call back is executed HAL_SPI_TxCpltCallback() or HAL_SPI_RxCpltCallback() or HAL_SPI_TxRxCpltCallback() + */ + + /* Abort the SPI DMA tx Stream/Channel */ + if (hspi->hdmatx != NULL) + { + if (HAL_OK != HAL_DMA_Abort(hspi->hdmatx)) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_DMA); + errorcode = HAL_ERROR; + } + } + /* Abort the SPI DMA rx Stream/Channel */ + if (hspi->hdmarx != NULL) + { + if (HAL_OK != HAL_DMA_Abort(hspi->hdmarx)) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_DMA); + errorcode = HAL_ERROR; + } + } + + /* Disable the SPI DMA Tx & Rx requests */ + CLEAR_BIT(hspi->Instance->CR2, SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN); + hspi->State = HAL_SPI_STATE_READY; + return errorcode; +} + +/** + * @brief Handle SPI interrupt request. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for the specified SPI module. + * @retval None + */ +void HAL_SPI_IRQHandler(SPI_HandleTypeDef *hspi) +{ + uint32_t itsource = hspi->Instance->CR2; + uint32_t itflag = hspi->Instance->SR; + + /* SPI in mode Receiver ----------------------------------------------------*/ + if ((SPI_CHECK_FLAG(itflag, SPI_FLAG_OVR) == RESET) && + (SPI_CHECK_FLAG(itflag, SPI_FLAG_RXNE) != RESET) && (SPI_CHECK_IT_SOURCE(itsource, SPI_IT_RXNE) != RESET)) + { + hspi->RxISR(hspi); + return; + } + + /* SPI in mode Transmitter -------------------------------------------------*/ + if ((SPI_CHECK_FLAG(itflag, SPI_FLAG_TXE) != RESET) && (SPI_CHECK_IT_SOURCE(itsource, SPI_IT_TXE) != RESET)) + { + hspi->TxISR(hspi); + return; + } + + /* SPI in Error Treatment --------------------------------------------------*/ + if (((SPI_CHECK_FLAG(itflag, SPI_FLAG_MODF) != RESET) || (SPI_CHECK_FLAG(itflag, SPI_FLAG_OVR) != RESET) + || (SPI_CHECK_FLAG(itflag, SPI_FLAG_FRE) != RESET)) && (SPI_CHECK_IT_SOURCE(itsource, SPI_IT_ERR) != RESET)) + { + /* SPI Overrun error interrupt occurred ----------------------------------*/ + if (SPI_CHECK_FLAG(itflag, SPI_FLAG_OVR) != RESET) + { + if (hspi->State != HAL_SPI_STATE_BUSY_TX) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_OVR); + __HAL_SPI_CLEAR_OVRFLAG(hspi); + } + else + { + __HAL_SPI_CLEAR_OVRFLAG(hspi); + return; + } + } + + /* SPI Mode Fault error interrupt occurred -------------------------------*/ + if (SPI_CHECK_FLAG(itflag, SPI_FLAG_MODF) != RESET) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_MODF); + __HAL_SPI_CLEAR_MODFFLAG(hspi); + } + + /* SPI Frame error interrupt occurred ------------------------------------*/ + if (SPI_CHECK_FLAG(itflag, SPI_FLAG_FRE) != RESET) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_FRE); + __HAL_SPI_CLEAR_FREFLAG(hspi); + } + + if (hspi->ErrorCode != HAL_SPI_ERROR_NONE) + { + /* Disable all interrupts */ + __HAL_SPI_DISABLE_IT(hspi, SPI_IT_RXNE | SPI_IT_TXE | SPI_IT_ERR); + + hspi->State = HAL_SPI_STATE_READY; + /* Disable the SPI DMA requests if enabled */ + if ((HAL_IS_BIT_SET(itsource, SPI_CR2_TXDMAEN)) || (HAL_IS_BIT_SET(itsource, SPI_CR2_RXDMAEN))) + { + CLEAR_BIT(hspi->Instance->CR2, (SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN)); + + /* Abort the SPI DMA Rx channel */ + if (hspi->hdmarx != NULL) + { + /* Set the SPI DMA Abort callback : + will lead to call HAL_SPI_ErrorCallback() at end of DMA abort procedure */ + hspi->hdmarx->XferAbortCallback = SPI_DMAAbortOnError; + if (HAL_OK != HAL_DMA_Abort_IT(hspi->hdmarx)) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_ABORT); + } + } + /* Abort the SPI DMA Tx channel */ + if (hspi->hdmatx != NULL) + { + /* Set the SPI DMA Abort callback : + will lead to call HAL_SPI_ErrorCallback() at end of DMA abort procedure */ + hspi->hdmatx->XferAbortCallback = SPI_DMAAbortOnError; + if (HAL_OK != HAL_DMA_Abort_IT(hspi->hdmatx)) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_ABORT); + } + } + } + else + { + /* Call user error callback */ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + hspi->ErrorCallback(hspi); +#else + HAL_SPI_ErrorCallback(hspi); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ + } + } + return; + } +} + +/** + * @brief Tx Transfer completed callback. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval None + */ +__weak void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hspi); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_SPI_TxCpltCallback should be implemented in the user file + */ +} + +/** + * @brief Rx Transfer completed callback. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval None + */ +__weak void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hspi); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_SPI_RxCpltCallback should be implemented in the user file + */ +} + +/** + * @brief Tx and Rx Transfer completed callback. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval None + */ +__weak void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hspi); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_SPI_TxRxCpltCallback should be implemented in the user file + */ +} + +/** + * @brief Tx Half Transfer completed callback. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval None + */ +__weak void HAL_SPI_TxHalfCpltCallback(SPI_HandleTypeDef *hspi) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hspi); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_SPI_TxHalfCpltCallback should be implemented in the user file + */ +} + +/** + * @brief Rx Half Transfer completed callback. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval None + */ +__weak void HAL_SPI_RxHalfCpltCallback(SPI_HandleTypeDef *hspi) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hspi); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_SPI_RxHalfCpltCallback() should be implemented in the user file + */ +} + +/** + * @brief Tx and Rx Half Transfer callback. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval None + */ +__weak void HAL_SPI_TxRxHalfCpltCallback(SPI_HandleTypeDef *hspi) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hspi); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_SPI_TxRxHalfCpltCallback() should be implemented in the user file + */ +} + +/** + * @brief SPI error callback. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval None + */ +__weak void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hspi); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_SPI_ErrorCallback should be implemented in the user file + */ + /* NOTE : The ErrorCode parameter in the hspi handle is updated by the SPI processes + and user can use HAL_SPI_GetError() API to check the latest error occurred + */ +} + +/** + * @brief SPI Abort Complete callback. + * @param hspi SPI handle. + * @retval None + */ +__weak void HAL_SPI_AbortCpltCallback(SPI_HandleTypeDef *hspi) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hspi); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_SPI_AbortCpltCallback can be implemented in the user file. + */ +} + +/** + * @} + */ + +/** @defgroup SPI_Exported_Functions_Group3 Peripheral State and Errors functions + * @brief SPI control functions + * +@verbatim + =============================================================================== + ##### Peripheral State and Errors functions ##### + =============================================================================== + [..] + This subsection provides a set of functions allowing to control the SPI. + (+) HAL_SPI_GetState() API can be helpful to check in run-time the state of the SPI peripheral + (+) HAL_SPI_GetError() check in run-time Errors occurring during communication +@endverbatim + * @{ + */ + +/** + * @brief Return the SPI handle state. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval SPI state + */ +HAL_SPI_StateTypeDef HAL_SPI_GetState(SPI_HandleTypeDef *hspi) +{ + /* Return SPI handle state */ + return hspi->State; +} + +/** + * @brief Return the SPI error code. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval SPI error code in bitmap format + */ +uint32_t HAL_SPI_GetError(SPI_HandleTypeDef *hspi) +{ + /* Return SPI ErrorCode */ + return hspi->ErrorCode; +} + +/** + * @} + */ + +/** + * @} + */ + +/** @addtogroup SPI_Private_Functions + * @brief Private functions + * @{ + */ + +/** + * @brief DMA SPI transmit process complete callback. + * @param hdma pointer to a DMA_HandleTypeDef structure that contains + * the configuration information for the specified DMA module. + * @retval None + */ +static void SPI_DMATransmitCplt(DMA_HandleTypeDef *hdma) +{ + SPI_HandleTypeDef *hspi = (SPI_HandleTypeDef *)(((DMA_HandleTypeDef *)hdma)->Parent); /* Derogation MISRAC2012-Rule-11.5 */ + uint32_t tickstart; + + /* Init tickstart for timeout management*/ + tickstart = HAL_GetTick(); + + /* DMA Normal Mode */ + if ((hdma->Instance->CR & DMA_SxCR_CIRC) != DMA_SxCR_CIRC) + { + /* Disable ERR interrupt */ + __HAL_SPI_DISABLE_IT(hspi, SPI_IT_ERR); + + /* Disable Tx DMA Request */ + CLEAR_BIT(hspi->Instance->CR2, SPI_CR2_TXDMAEN); + + /* Check the end of the transaction */ + if (SPI_EndRxTxTransaction(hspi, SPI_DEFAULT_TIMEOUT, tickstart) != HAL_OK) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_FLAG); + } + + /* Clear overrun flag in 2 Lines communication mode because received data is not read */ + if (hspi->Init.Direction == SPI_DIRECTION_2LINES) + { + __HAL_SPI_CLEAR_OVRFLAG(hspi); + } + + hspi->TxXferCount = 0U; + hspi->State = HAL_SPI_STATE_READY; + + if (hspi->ErrorCode != HAL_SPI_ERROR_NONE) + { + /* Call user error callback */ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + hspi->ErrorCallback(hspi); +#else + HAL_SPI_ErrorCallback(hspi); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ + return; + } + } + /* Call user Tx complete callback */ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + hspi->TxCpltCallback(hspi); +#else + HAL_SPI_TxCpltCallback(hspi); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ +} + +/** + * @brief DMA SPI receive process complete callback. + * @param hdma pointer to a DMA_HandleTypeDef structure that contains + * the configuration information for the specified DMA module. + * @retval None + */ +static void SPI_DMAReceiveCplt(DMA_HandleTypeDef *hdma) +{ + SPI_HandleTypeDef *hspi = (SPI_HandleTypeDef *)(((DMA_HandleTypeDef *)hdma)->Parent); /* Derogation MISRAC2012-Rule-11.5 */ + uint32_t tickstart; +#if (USE_SPI_CRC != 0U) + __IO uint32_t tmpreg = 0U; +#endif /* USE_SPI_CRC */ + + /* Init tickstart for timeout management*/ + tickstart = HAL_GetTick(); + + /* DMA Normal Mode */ + if ((hdma->Instance->CR & DMA_SxCR_CIRC) != DMA_SxCR_CIRC) + { + /* Disable ERR interrupt */ + __HAL_SPI_DISABLE_IT(hspi, SPI_IT_ERR); + +#if (USE_SPI_CRC != 0U) + /* CRC handling */ + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + { + /* Wait until RXNE flag */ + if (SPI_WaitFlagStateUntilTimeout(hspi, SPI_FLAG_RXNE, SET, SPI_DEFAULT_TIMEOUT, tickstart) != HAL_OK) + { + /* Error on the CRC reception */ + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_CRC); + } + /* Read CRC */ + tmpreg = READ_REG(hspi->Instance->DR); + /* To avoid GCC warning */ + UNUSED(tmpreg); + } +#endif /* USE_SPI_CRC */ + + /* Check if we are in Master RX 2 line mode */ + if ((hspi->Init.Direction == SPI_DIRECTION_2LINES) && (hspi->Init.Mode == SPI_MODE_MASTER)) + { + /* Disable Rx/Tx DMA Request (done by default to handle the case master rx direction 2 lines) */ + CLEAR_BIT(hspi->Instance->CR2, SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN); + } + else + { + /* Normal case */ + CLEAR_BIT(hspi->Instance->CR2, SPI_CR2_RXDMAEN); + } + + /* Check the end of the transaction */ + if (SPI_EndRxTransaction(hspi, SPI_DEFAULT_TIMEOUT, tickstart) != HAL_OK) + { + hspi->ErrorCode = HAL_SPI_ERROR_FLAG; + } + + hspi->RxXferCount = 0U; + hspi->State = HAL_SPI_STATE_READY; + +#if (USE_SPI_CRC != 0U) + /* Check if CRC error occurred */ + if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_CRCERR)) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_CRC); + __HAL_SPI_CLEAR_CRCERRFLAG(hspi); + } +#endif /* USE_SPI_CRC */ + + if (hspi->ErrorCode != HAL_SPI_ERROR_NONE) + { + /* Call user error callback */ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + hspi->ErrorCallback(hspi); +#else + HAL_SPI_ErrorCallback(hspi); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ + return; + } + } + /* Call user Rx complete callback */ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + hspi->RxCpltCallback(hspi); +#else + HAL_SPI_RxCpltCallback(hspi); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ +} + +/** + * @brief DMA SPI transmit receive process complete callback. + * @param hdma pointer to a DMA_HandleTypeDef structure that contains + * the configuration information for the specified DMA module. + * @retval None + */ +static void SPI_DMATransmitReceiveCplt(DMA_HandleTypeDef *hdma) +{ + SPI_HandleTypeDef *hspi = (SPI_HandleTypeDef *)(((DMA_HandleTypeDef *)hdma)->Parent); /* Derogation MISRAC2012-Rule-11.5 */ + uint32_t tickstart; +#if (USE_SPI_CRC != 0U) + __IO uint32_t tmpreg = 0U; +#endif /* USE_SPI_CRC */ + + /* Init tickstart for timeout management*/ + tickstart = HAL_GetTick(); + + /* DMA Normal Mode */ + if ((hdma->Instance->CR & DMA_SxCR_CIRC) != DMA_SxCR_CIRC) + { + /* Disable ERR interrupt */ + __HAL_SPI_DISABLE_IT(hspi, SPI_IT_ERR); + +#if (USE_SPI_CRC != 0U) + /* CRC handling */ + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + { + /* Wait the CRC data */ + if (SPI_WaitFlagStateUntilTimeout(hspi, SPI_FLAG_RXNE, SET, SPI_DEFAULT_TIMEOUT, tickstart) != HAL_OK) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_CRC); + } + /* Read CRC to Flush DR and RXNE flag */ + tmpreg = READ_REG(hspi->Instance->DR); + /* To avoid GCC warning */ + UNUSED(tmpreg); + } +#endif /* USE_SPI_CRC */ + + /* Check the end of the transaction */ + if (SPI_EndRxTxTransaction(hspi, SPI_DEFAULT_TIMEOUT, tickstart) != HAL_OK) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_FLAG); + } + + /* Disable Rx/Tx DMA Request */ + CLEAR_BIT(hspi->Instance->CR2, SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN); + + hspi->TxXferCount = 0U; + hspi->RxXferCount = 0U; + hspi->State = HAL_SPI_STATE_READY; + +#if (USE_SPI_CRC != 0U) + /* Check if CRC error occurred */ + if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_CRCERR)) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_CRC); + __HAL_SPI_CLEAR_CRCERRFLAG(hspi); + } +#endif /* USE_SPI_CRC */ + + if (hspi->ErrorCode != HAL_SPI_ERROR_NONE) + { + /* Call user error callback */ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + hspi->ErrorCallback(hspi); +#else + HAL_SPI_ErrorCallback(hspi); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ + return; + } + } + /* Call user TxRx complete callback */ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + hspi->TxRxCpltCallback(hspi); +#else + HAL_SPI_TxRxCpltCallback(hspi); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ +} + +/** + * @brief DMA SPI half transmit process complete callback. + * @param hdma pointer to a DMA_HandleTypeDef structure that contains + * the configuration information for the specified DMA module. + * @retval None + */ +static void SPI_DMAHalfTransmitCplt(DMA_HandleTypeDef *hdma) +{ + SPI_HandleTypeDef *hspi = (SPI_HandleTypeDef *)(((DMA_HandleTypeDef *)hdma)->Parent); /* Derogation MISRAC2012-Rule-11.5 */ + + /* Call user Tx half complete callback */ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + hspi->TxHalfCpltCallback(hspi); +#else + HAL_SPI_TxHalfCpltCallback(hspi); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ +} + +/** + * @brief DMA SPI half receive process complete callback + * @param hdma pointer to a DMA_HandleTypeDef structure that contains + * the configuration information for the specified DMA module. + * @retval None + */ +static void SPI_DMAHalfReceiveCplt(DMA_HandleTypeDef *hdma) +{ + SPI_HandleTypeDef *hspi = (SPI_HandleTypeDef *)(((DMA_HandleTypeDef *)hdma)->Parent); /* Derogation MISRAC2012-Rule-11.5 */ + + /* Call user Rx half complete callback */ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + hspi->RxHalfCpltCallback(hspi); +#else + HAL_SPI_RxHalfCpltCallback(hspi); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ +} + +/** + * @brief DMA SPI half transmit receive process complete callback. + * @param hdma pointer to a DMA_HandleTypeDef structure that contains + * the configuration information for the specified DMA module. + * @retval None + */ +static void SPI_DMAHalfTransmitReceiveCplt(DMA_HandleTypeDef *hdma) +{ + SPI_HandleTypeDef *hspi = (SPI_HandleTypeDef *)(((DMA_HandleTypeDef *)hdma)->Parent); /* Derogation MISRAC2012-Rule-11.5 */ + + /* Call user TxRx half complete callback */ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + hspi->TxRxHalfCpltCallback(hspi); +#else + HAL_SPI_TxRxHalfCpltCallback(hspi); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ +} + +/** + * @brief DMA SPI communication error callback. + * @param hdma pointer to a DMA_HandleTypeDef structure that contains + * the configuration information for the specified DMA module. + * @retval None + */ +static void SPI_DMAError(DMA_HandleTypeDef *hdma) +{ + SPI_HandleTypeDef *hspi = (SPI_HandleTypeDef *)(((DMA_HandleTypeDef *)hdma)->Parent); /* Derogation MISRAC2012-Rule-11.5 */ + + /* Stop the disable DMA transfer on SPI side */ + CLEAR_BIT(hspi->Instance->CR2, SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN); + + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_DMA); + hspi->State = HAL_SPI_STATE_READY; + /* Call user error callback */ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + hspi->ErrorCallback(hspi); +#else + HAL_SPI_ErrorCallback(hspi); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ +} + +/** + * @brief DMA SPI communication abort callback, when initiated by HAL services on Error + * (To be called at end of DMA Abort procedure following error occurrence). + * @param hdma DMA handle. + * @retval None + */ +static void SPI_DMAAbortOnError(DMA_HandleTypeDef *hdma) +{ + SPI_HandleTypeDef *hspi = (SPI_HandleTypeDef *)(((DMA_HandleTypeDef *)hdma)->Parent); /* Derogation MISRAC2012-Rule-11.5 */ + hspi->RxXferCount = 0U; + hspi->TxXferCount = 0U; + + /* Call user error callback */ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + hspi->ErrorCallback(hspi); +#else + HAL_SPI_ErrorCallback(hspi); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ +} + +/** + * @brief DMA SPI Tx communication abort callback, when initiated by user + * (To be called at end of DMA Tx Abort procedure following user abort request). + * @note When this callback is executed, User Abort complete call back is called only if no + * Abort still ongoing for Rx DMA Handle. + * @param hdma DMA handle. + * @retval None + */ +static void SPI_DMATxAbortCallback(DMA_HandleTypeDef *hdma) +{ + SPI_HandleTypeDef *hspi = (SPI_HandleTypeDef *)(((DMA_HandleTypeDef *)hdma)->Parent); /* Derogation MISRAC2012-Rule-11.5 */ + __IO uint32_t count; + + hspi->hdmatx->XferAbortCallback = NULL; + count = SPI_DEFAULT_TIMEOUT * (SystemCoreClock / 24U / 1000U); + + /* Disable Tx DMA Request */ + CLEAR_BIT(hspi->Instance->CR2, SPI_CR2_TXDMAEN); + + /* Wait until TXE flag is set */ + do + { + if (count == 0U) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_ABORT); + break; + } + count--; + } while ((hspi->Instance->SR & SPI_FLAG_TXE) == RESET); + + /* Check if an Abort process is still ongoing */ + if (hspi->hdmarx != NULL) + { + if (hspi->hdmarx->XferAbortCallback != NULL) + { + return; + } + } + + /* No Abort process still ongoing : All DMA Stream/Channel are aborted, call user Abort Complete callback */ + hspi->RxXferCount = 0U; + hspi->TxXferCount = 0U; + + /* Check no error during Abort procedure */ + if (hspi->ErrorCode != HAL_SPI_ERROR_ABORT) + { + /* Reset errorCode */ + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + } + + /* Clear the Error flags in the SR register */ + __HAL_SPI_CLEAR_OVRFLAG(hspi); + __HAL_SPI_CLEAR_FREFLAG(hspi); + + /* Restore hspi->State to Ready */ + hspi->State = HAL_SPI_STATE_READY; + + /* Call user Abort complete callback */ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + hspi->AbortCpltCallback(hspi); +#else + HAL_SPI_AbortCpltCallback(hspi); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ +} + +/** + * @brief DMA SPI Rx communication abort callback, when initiated by user + * (To be called at end of DMA Rx Abort procedure following user abort request). + * @note When this callback is executed, User Abort complete call back is called only if no + * Abort still ongoing for Tx DMA Handle. + * @param hdma DMA handle. + * @retval None + */ +static void SPI_DMARxAbortCallback(DMA_HandleTypeDef *hdma) +{ + SPI_HandleTypeDef *hspi = (SPI_HandleTypeDef *)(((DMA_HandleTypeDef *)hdma)->Parent); /* Derogation MISRAC2012-Rule-11.5 */ + + /* Disable SPI Peripheral */ + __HAL_SPI_DISABLE(hspi); + + hspi->hdmarx->XferAbortCallback = NULL; + + /* Disable Rx DMA Request */ + CLEAR_BIT(hspi->Instance->CR2, SPI_CR2_RXDMAEN); + + /* Check Busy flag */ + if (SPI_EndRxTxTransaction(hspi, SPI_DEFAULT_TIMEOUT, HAL_GetTick()) != HAL_OK) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_ABORT); + } + + /* Check if an Abort process is still ongoing */ + if (hspi->hdmatx != NULL) + { + if (hspi->hdmatx->XferAbortCallback != NULL) + { + return; + } + } + + /* No Abort process still ongoing : All DMA Stream/Channel are aborted, call user Abort Complete callback */ + hspi->RxXferCount = 0U; + hspi->TxXferCount = 0U; + + /* Check no error during Abort procedure */ + if (hspi->ErrorCode != HAL_SPI_ERROR_ABORT) + { + /* Reset errorCode */ + hspi->ErrorCode = HAL_SPI_ERROR_NONE; + } + + /* Clear the Error flags in the SR register */ + __HAL_SPI_CLEAR_OVRFLAG(hspi); + __HAL_SPI_CLEAR_FREFLAG(hspi); + + /* Restore hspi->State to Ready */ + hspi->State = HAL_SPI_STATE_READY; + + /* Call user Abort complete callback */ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + hspi->AbortCpltCallback(hspi); +#else + HAL_SPI_AbortCpltCallback(hspi); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ +} + +/** + * @brief Rx 8-bit handler for Transmit and Receive in Interrupt mode. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval None + */ +static void SPI_2linesRxISR_8BIT(struct __SPI_HandleTypeDef *hspi) +{ + /* Receive data in 8bit mode */ + *hspi->pRxBuffPtr = *((__IO uint8_t *)&hspi->Instance->DR); + hspi->pRxBuffPtr++; + hspi->RxXferCount--; + + /* Check end of the reception */ + if (hspi->RxXferCount == 0U) + { +#if (USE_SPI_CRC != 0U) + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + { + hspi->RxISR = SPI_2linesRxISR_8BITCRC; + return; + } +#endif /* USE_SPI_CRC */ + + /* Disable RXNE and ERR interrupt */ + __HAL_SPI_DISABLE_IT(hspi, (SPI_IT_RXNE | SPI_IT_ERR)); + + if (hspi->TxXferCount == 0U) + { + SPI_CloseRxTx_ISR(hspi); + } + } +} + +#if (USE_SPI_CRC != 0U) +/** + * @brief Rx 8-bit handler for Transmit and Receive in Interrupt mode. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval None + */ +static void SPI_2linesRxISR_8BITCRC(struct __SPI_HandleTypeDef *hspi) +{ + __IO uint8_t *ptmpreg8; + __IO uint8_t tmpreg8 = 0; + + /* Initialize the 8bit temporary pointer */ + ptmpreg8 = (__IO uint8_t *)&hspi->Instance->DR; + /* Read 8bit CRC to flush Data Register */ + tmpreg8 = *ptmpreg8; + /* To avoid GCC warning */ + UNUSED(tmpreg8); + + /* Disable RXNE and ERR interrupt */ + __HAL_SPI_DISABLE_IT(hspi, (SPI_IT_RXNE | SPI_IT_ERR)); + + if (hspi->TxXferCount == 0U) + { + SPI_CloseRxTx_ISR(hspi); + } +} +#endif /* USE_SPI_CRC */ + +/** + * @brief Tx 8-bit handler for Transmit and Receive in Interrupt mode. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval None + */ +static void SPI_2linesTxISR_8BIT(struct __SPI_HandleTypeDef *hspi) +{ + *(__IO uint8_t *)&hspi->Instance->DR = (*hspi->pTxBuffPtr); + hspi->pTxBuffPtr++; + hspi->TxXferCount--; + + /* Check the end of the transmission */ + if (hspi->TxXferCount == 0U) + { +#if (USE_SPI_CRC != 0U) + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + { + /* Set CRC Next Bit to send CRC */ + SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT); + /* Disable TXE interrupt */ + __HAL_SPI_DISABLE_IT(hspi, SPI_IT_TXE); + return; + } +#endif /* USE_SPI_CRC */ + + /* Disable TXE interrupt */ + __HAL_SPI_DISABLE_IT(hspi, SPI_IT_TXE); + + if (hspi->RxXferCount == 0U) + { + SPI_CloseRxTx_ISR(hspi); + } + } +} + +/** + * @brief Rx 16-bit handler for Transmit and Receive in Interrupt mode. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval None + */ +static void SPI_2linesRxISR_16BIT(struct __SPI_HandleTypeDef *hspi) +{ + /* Receive data in 16 Bit mode */ + *((uint16_t *)hspi->pRxBuffPtr) = (uint16_t)(hspi->Instance->DR); + hspi->pRxBuffPtr += sizeof(uint16_t); + hspi->RxXferCount--; + + if (hspi->RxXferCount == 0U) + { +#if (USE_SPI_CRC != 0U) + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + { + hspi->RxISR = SPI_2linesRxISR_16BITCRC; + return; + } +#endif /* USE_SPI_CRC */ + + /* Disable RXNE interrupt */ + __HAL_SPI_DISABLE_IT(hspi, SPI_IT_RXNE); + + if (hspi->TxXferCount == 0U) + { + SPI_CloseRxTx_ISR(hspi); + } + } +} + +#if (USE_SPI_CRC != 0U) +/** + * @brief Manage the CRC 16-bit receive for Transmit and Receive in Interrupt mode. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval None + */ +static void SPI_2linesRxISR_16BITCRC(struct __SPI_HandleTypeDef *hspi) +{ + __IO uint32_t tmpreg = 0U; + + /* Read 16bit CRC to flush Data Register */ + tmpreg = READ_REG(hspi->Instance->DR); + /* To avoid GCC warning */ + UNUSED(tmpreg); + + /* Disable RXNE interrupt */ + __HAL_SPI_DISABLE_IT(hspi, SPI_IT_RXNE); + + SPI_CloseRxTx_ISR(hspi); +} +#endif /* USE_SPI_CRC */ + +/** + * @brief Tx 16-bit handler for Transmit and Receive in Interrupt mode. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval None + */ +static void SPI_2linesTxISR_16BIT(struct __SPI_HandleTypeDef *hspi) +{ + /* Transmit data in 16 Bit mode */ + hspi->Instance->DR = *((uint16_t *)hspi->pTxBuffPtr); + hspi->pTxBuffPtr += sizeof(uint16_t); + hspi->TxXferCount--; + + /* Enable CRC Transmission */ + if (hspi->TxXferCount == 0U) + { +#if (USE_SPI_CRC != 0U) + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + { + /* Set CRC Next Bit to send CRC */ + SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT); + /* Disable TXE interrupt */ + __HAL_SPI_DISABLE_IT(hspi, SPI_IT_TXE); + return; + } +#endif /* USE_SPI_CRC */ + + /* Disable TXE interrupt */ + __HAL_SPI_DISABLE_IT(hspi, SPI_IT_TXE); + + if (hspi->RxXferCount == 0U) + { + SPI_CloseRxTx_ISR(hspi); + } + } +} + +#if (USE_SPI_CRC != 0U) +/** + * @brief Manage the CRC 8-bit receive in Interrupt context. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval None + */ +static void SPI_RxISR_8BITCRC(struct __SPI_HandleTypeDef *hspi) +{ + __IO uint8_t *ptmpreg8; + __IO uint8_t tmpreg8 = 0; + + /* Initialize the 8bit temporary pointer */ + ptmpreg8 = (__IO uint8_t *)&hspi->Instance->DR; + /* Read 8bit CRC to flush Data Register */ + tmpreg8 = *ptmpreg8; + /* To avoid GCC warning */ + UNUSED(tmpreg8); + + SPI_CloseRx_ISR(hspi); +} +#endif /* USE_SPI_CRC */ + +/** + * @brief Manage the receive 8-bit in Interrupt context. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval None + */ +static void SPI_RxISR_8BIT(struct __SPI_HandleTypeDef *hspi) +{ + *hspi->pRxBuffPtr = (*(__IO uint8_t *)&hspi->Instance->DR); + hspi->pRxBuffPtr++; + hspi->RxXferCount--; + +#if (USE_SPI_CRC != 0U) + /* Enable CRC Transmission */ + if ((hspi->RxXferCount == 1U) && (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)) + { + SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT); + } +#endif /* USE_SPI_CRC */ + + if (hspi->RxXferCount == 0U) + { +#if (USE_SPI_CRC != 0U) + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + { + hspi->RxISR = SPI_RxISR_8BITCRC; + return; + } +#endif /* USE_SPI_CRC */ + SPI_CloseRx_ISR(hspi); + } +} + +#if (USE_SPI_CRC != 0U) +/** + * @brief Manage the CRC 16-bit receive in Interrupt context. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval None + */ +static void SPI_RxISR_16BITCRC(struct __SPI_HandleTypeDef *hspi) +{ + __IO uint32_t tmpreg = 0U; + + /* Read 16bit CRC to flush Data Register */ + tmpreg = READ_REG(hspi->Instance->DR); + /* To avoid GCC warning */ + UNUSED(tmpreg); + + /* Disable RXNE and ERR interrupt */ + __HAL_SPI_DISABLE_IT(hspi, (SPI_IT_RXNE | SPI_IT_ERR)); + + SPI_CloseRx_ISR(hspi); +} +#endif /* USE_SPI_CRC */ + +/** + * @brief Manage the 16-bit receive in Interrupt context. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval None + */ +static void SPI_RxISR_16BIT(struct __SPI_HandleTypeDef *hspi) +{ + *((uint16_t *)hspi->pRxBuffPtr) = (uint16_t)(hspi->Instance->DR); + hspi->pRxBuffPtr += sizeof(uint16_t); + hspi->RxXferCount--; + +#if (USE_SPI_CRC != 0U) + /* Enable CRC Transmission */ + if ((hspi->RxXferCount == 1U) && (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)) + { + SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT); + } +#endif /* USE_SPI_CRC */ + + if (hspi->RxXferCount == 0U) + { +#if (USE_SPI_CRC != 0U) + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + { + hspi->RxISR = SPI_RxISR_16BITCRC; + return; + } +#endif /* USE_SPI_CRC */ + SPI_CloseRx_ISR(hspi); + } +} + +/** + * @brief Handle the data 8-bit transmit in Interrupt mode. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval None + */ +static void SPI_TxISR_8BIT(struct __SPI_HandleTypeDef *hspi) +{ + *(__IO uint8_t *)&hspi->Instance->DR = (*hspi->pTxBuffPtr); + hspi->pTxBuffPtr++; + hspi->TxXferCount--; + + if (hspi->TxXferCount == 0U) + { +#if (USE_SPI_CRC != 0U) + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + { + /* Enable CRC Transmission */ + SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT); + } +#endif /* USE_SPI_CRC */ + SPI_CloseTx_ISR(hspi); + } +} + +/** + * @brief Handle the data 16-bit transmit in Interrupt mode. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval None + */ +static void SPI_TxISR_16BIT(struct __SPI_HandleTypeDef *hspi) +{ + /* Transmit data in 16 Bit mode */ + hspi->Instance->DR = *((uint16_t *)hspi->pTxBuffPtr); + hspi->pTxBuffPtr += sizeof(uint16_t); + hspi->TxXferCount--; + + if (hspi->TxXferCount == 0U) + { +#if (USE_SPI_CRC != 0U) + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + { + /* Enable CRC Transmission */ + SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT); + } +#endif /* USE_SPI_CRC */ + SPI_CloseTx_ISR(hspi); + } +} + +/** + * @brief Handle SPI Communication Timeout. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @param Flag SPI flag to check + * @param State flag state to check + * @param Timeout Timeout duration + * @param Tickstart tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef SPI_WaitFlagStateUntilTimeout(SPI_HandleTypeDef *hspi, uint32_t Flag, FlagStatus State, + uint32_t Timeout, uint32_t Tickstart) +{ + __IO uint32_t count; + uint32_t tmp_timeout; + uint32_t tmp_tickstart; + + /* Adjust Timeout value in case of end of transfer */ + tmp_timeout = Timeout - (HAL_GetTick() - Tickstart); + tmp_tickstart = HAL_GetTick(); + + /* Calculate Timeout based on a software loop to avoid blocking issue if Systick is disabled */ + count = tmp_timeout * ((SystemCoreClock * 32U) >> 20U); + + while ((__HAL_SPI_GET_FLAG(hspi, Flag) ? SET : RESET) != State) + { + if (Timeout != HAL_MAX_DELAY) + { + if (((HAL_GetTick() - tmp_tickstart) >= tmp_timeout) || (tmp_timeout == 0U)) + { + /* Disable the SPI and reset the CRC: the CRC value should be cleared + on both master and slave sides in order to resynchronize the master + and slave for their respective CRC calculation */ + + /* Disable TXE, RXNE and ERR interrupts for the interrupt process */ + __HAL_SPI_DISABLE_IT(hspi, (SPI_IT_TXE | SPI_IT_RXNE | SPI_IT_ERR)); + + if ((hspi->Init.Mode == SPI_MODE_MASTER) && ((hspi->Init.Direction == SPI_DIRECTION_1LINE) + || (hspi->Init.Direction == SPI_DIRECTION_2LINES_RXONLY))) + { + /* Disable SPI peripheral */ + __HAL_SPI_DISABLE(hspi); + } + + /* Reset CRC Calculation */ + if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) + { + SPI_RESET_CRC(hspi); + } + + hspi->State = HAL_SPI_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hspi); + + return HAL_TIMEOUT; + } + /* If Systick is disabled or not incremented, deactivate timeout to go in disable loop procedure */ + if (count == 0U) + { + tmp_timeout = 0U; + } + count--; + } + } + + return HAL_OK; +} + +/** + * @brief Handle the check of the RX transaction complete. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @param Timeout Timeout duration + * @param Tickstart tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef SPI_EndRxTransaction(SPI_HandleTypeDef *hspi, uint32_t Timeout, uint32_t Tickstart) +{ + if ((hspi->Init.Mode == SPI_MODE_MASTER) && ((hspi->Init.Direction == SPI_DIRECTION_1LINE) + || (hspi->Init.Direction == SPI_DIRECTION_2LINES_RXONLY))) + { + /* Disable SPI peripheral */ + __HAL_SPI_DISABLE(hspi); + } + + /* Erratasheet: BSY bit may stay high at the end of a data transfer in Slave mode */ + if (hspi->Init.Mode == SPI_MODE_MASTER) + { + if (hspi->Init.Direction != SPI_DIRECTION_2LINES_RXONLY) + { + /* Control the BSY flag */ + if (SPI_WaitFlagStateUntilTimeout(hspi, SPI_FLAG_BSY, RESET, Timeout, Tickstart) != HAL_OK) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_FLAG); + return HAL_TIMEOUT; + } + } + else + { + /* Wait the RXNE reset */ + if (SPI_WaitFlagStateUntilTimeout(hspi, SPI_FLAG_RXNE, RESET, Timeout, Tickstart) != HAL_OK) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_FLAG); + return HAL_TIMEOUT; + } + } + } + else + { + /* Wait the RXNE reset */ + if (SPI_WaitFlagStateUntilTimeout(hspi, SPI_FLAG_RXNE, RESET, Timeout, Tickstart) != HAL_OK) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_FLAG); + return HAL_TIMEOUT; + } + } + return HAL_OK; +} + +/** + * @brief Handle the check of the RXTX or TX transaction complete. + * @param hspi SPI handle + * @param Timeout Timeout duration + * @param Tickstart tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef SPI_EndRxTxTransaction(SPI_HandleTypeDef *hspi, uint32_t Timeout, uint32_t Tickstart) +{ + /* Timeout in 碌s */ + __IO uint32_t count = SPI_BSY_FLAG_WORKAROUND_TIMEOUT * (SystemCoreClock / 24U / 1000000U); + /* Erratasheet: BSY bit may stay high at the end of a data transfer in Slave mode */ + if (hspi->Init.Mode == SPI_MODE_MASTER) + { + /* Control the BSY flag */ + if (SPI_WaitFlagStateUntilTimeout(hspi, SPI_FLAG_BSY, RESET, Timeout, Tickstart) != HAL_OK) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_FLAG); + return HAL_TIMEOUT; + } + } + else + { + /* Wait BSY flag during 1 Byte time transfer in case of Full-Duplex and Tx transfer + * If Timeout is reached, the transfer is considered as finish. + * User have to calculate the timeout value to fit with the time of 1 byte transfer. + * This time is directly link with the SPI clock from Master device. + */ + do + { + if (count == 0U) + { + break; + } + count--; + } while (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_BSY) != RESET); + } + + return HAL_OK; +} + +/** + * @brief Handle the end of the RXTX transaction. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval None + */ +static void SPI_CloseRxTx_ISR(SPI_HandleTypeDef *hspi) +{ + uint32_t tickstart; + __IO uint32_t count = SPI_DEFAULT_TIMEOUT * (SystemCoreClock / 24U / 1000U); + + /* Init tickstart for timeout management */ + tickstart = HAL_GetTick(); + + /* Disable ERR interrupt */ + __HAL_SPI_DISABLE_IT(hspi, SPI_IT_ERR); + + /* Wait until TXE flag is set */ + do + { + if (count == 0U) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_FLAG); + break; + } + count--; + } while ((hspi->Instance->SR & SPI_FLAG_TXE) == RESET); + + /* Check the end of the transaction */ + if (SPI_EndRxTxTransaction(hspi, SPI_DEFAULT_TIMEOUT, tickstart) != HAL_OK) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_FLAG); + } + + /* Clear overrun flag in 2 Lines communication mode because received is not read */ + if (hspi->Init.Direction == SPI_DIRECTION_2LINES) + { + __HAL_SPI_CLEAR_OVRFLAG(hspi); + } + +#if (USE_SPI_CRC != 0U) + /* Check if CRC error occurred */ + if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_CRCERR) != RESET) + { + hspi->State = HAL_SPI_STATE_READY; + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_CRC); + __HAL_SPI_CLEAR_CRCERRFLAG(hspi); + /* Call user error callback */ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + hspi->ErrorCallback(hspi); +#else + HAL_SPI_ErrorCallback(hspi); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ + } + else + { +#endif /* USE_SPI_CRC */ + if (hspi->ErrorCode == HAL_SPI_ERROR_NONE) + { + if (hspi->State == HAL_SPI_STATE_BUSY_RX) + { + hspi->State = HAL_SPI_STATE_READY; + /* Call user Rx complete callback */ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + hspi->RxCpltCallback(hspi); +#else + HAL_SPI_RxCpltCallback(hspi); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ + } + else + { + hspi->State = HAL_SPI_STATE_READY; + /* Call user TxRx complete callback */ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + hspi->TxRxCpltCallback(hspi); +#else + HAL_SPI_TxRxCpltCallback(hspi); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ + } + } + else + { + hspi->State = HAL_SPI_STATE_READY; + /* Call user error callback */ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + hspi->ErrorCallback(hspi); +#else + HAL_SPI_ErrorCallback(hspi); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ + } +#if (USE_SPI_CRC != 0U) + } +#endif /* USE_SPI_CRC */ +} + +/** + * @brief Handle the end of the RX transaction. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval None + */ +static void SPI_CloseRx_ISR(SPI_HandleTypeDef *hspi) +{ + /* Disable RXNE and ERR interrupt */ + __HAL_SPI_DISABLE_IT(hspi, (SPI_IT_RXNE | SPI_IT_ERR)); + + /* Check the end of the transaction */ + if (SPI_EndRxTransaction(hspi, SPI_DEFAULT_TIMEOUT, HAL_GetTick()) != HAL_OK) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_FLAG); + } + + /* Clear overrun flag in 2 Lines communication mode because received is not read */ + if (hspi->Init.Direction == SPI_DIRECTION_2LINES) + { + __HAL_SPI_CLEAR_OVRFLAG(hspi); + } + hspi->State = HAL_SPI_STATE_READY; + +#if (USE_SPI_CRC != 0U) + /* Check if CRC error occurred */ + if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_CRCERR) != RESET) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_CRC); + __HAL_SPI_CLEAR_CRCERRFLAG(hspi); + /* Call user error callback */ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + hspi->ErrorCallback(hspi); +#else + HAL_SPI_ErrorCallback(hspi); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ + } + else + { +#endif /* USE_SPI_CRC */ + if (hspi->ErrorCode == HAL_SPI_ERROR_NONE) + { + /* Call user Rx complete callback */ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + hspi->RxCpltCallback(hspi); +#else + HAL_SPI_RxCpltCallback(hspi); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ + } + else + { + /* Call user error callback */ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + hspi->ErrorCallback(hspi); +#else + HAL_SPI_ErrorCallback(hspi); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ + } +#if (USE_SPI_CRC != 0U) + } +#endif /* USE_SPI_CRC */ +} + +/** + * @brief Handle the end of the TX transaction. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval None + */ +static void SPI_CloseTx_ISR(SPI_HandleTypeDef *hspi) +{ + uint32_t tickstart; + __IO uint32_t count = SPI_DEFAULT_TIMEOUT * (SystemCoreClock / 24U / 1000U); + + /* Init tickstart for timeout management*/ + tickstart = HAL_GetTick(); + + /* Wait until TXE flag is set */ + do + { + if (count == 0U) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_FLAG); + break; + } + count--; + } while ((hspi->Instance->SR & SPI_FLAG_TXE) == RESET); + + /* Disable TXE and ERR interrupt */ + __HAL_SPI_DISABLE_IT(hspi, (SPI_IT_TXE | SPI_IT_ERR)); + + /* Check the end of the transaction */ + if (SPI_EndRxTxTransaction(hspi, SPI_DEFAULT_TIMEOUT, tickstart) != HAL_OK) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_FLAG); + } + + /* Clear overrun flag in 2 Lines communication mode because received is not read */ + if (hspi->Init.Direction == SPI_DIRECTION_2LINES) + { + __HAL_SPI_CLEAR_OVRFLAG(hspi); + } + + hspi->State = HAL_SPI_STATE_READY; + if (hspi->ErrorCode != HAL_SPI_ERROR_NONE) + { + /* Call user error callback */ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + hspi->ErrorCallback(hspi); +#else + HAL_SPI_ErrorCallback(hspi); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ + } + else + { + /* Call user Rx complete callback */ +#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U) + hspi->TxCpltCallback(hspi); +#else + HAL_SPI_TxCpltCallback(hspi); +#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */ + } +} + +/** + * @brief Handle abort a Rx transaction. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval None + */ +static void SPI_AbortRx_ISR(SPI_HandleTypeDef *hspi) +{ + __IO uint32_t tmpreg = 0U; + __IO uint32_t count = SPI_DEFAULT_TIMEOUT * (SystemCoreClock / 24U / 1000U); + + /* Wait until TXE flag is set */ + do + { + if (count == 0U) + { + SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_ABORT); + break; + } + count--; + } while ((hspi->Instance->SR & SPI_FLAG_TXE) == RESET); + + /* Disable SPI Peripheral */ + __HAL_SPI_DISABLE(hspi); + + /* Disable TXEIE, RXNEIE and ERRIE(mode fault event, overrun error, TI frame error) interrupts */ + CLEAR_BIT(hspi->Instance->CR2, (SPI_CR2_TXEIE | SPI_CR2_RXNEIE | SPI_CR2_ERRIE)); + + /* Flush Data Register by a blank read */ + tmpreg = READ_REG(hspi->Instance->DR); + /* To avoid GCC warning */ + UNUSED(tmpreg); + + hspi->State = HAL_SPI_STATE_ABORT; +} + +/** + * @brief Handle abort a Tx or Rx/Tx transaction. + * @param hspi pointer to a SPI_HandleTypeDef structure that contains + * the configuration information for SPI module. + * @retval None + */ +static void SPI_AbortTx_ISR(SPI_HandleTypeDef *hspi) +{ + /* Disable TXEIE interrupt */ + CLEAR_BIT(hspi->Instance->CR2, (SPI_CR2_TXEIE)); + + /* Disable SPI Peripheral */ + __HAL_SPI_DISABLE(hspi); + + hspi->State = HAL_SPI_STATE_ABORT; +} + +/** + * @} + */ + +#endif /* HAL_SPI_MODULE_ENABLED */ + +/** + * @} + */ + +/** + * @} + */ + diff --git a/calib_board/usr/app/usr_config.h b/calib_board/usr/app/usr_config.h new file mode 100644 index 0000000..6e203c5 --- /dev/null +++ b/calib_board/usr/app/usr_config.h @@ -0,0 +1,9 @@ +#ifndef _USR_CONFIG_H_ +#define _USR_CONFIG_H_ + +#define USR_TRUE (1U) +#define USR_FALSE (0U) + +#define USR_ENABLE (1U) +#define USR_DISENABLE (0U) +#endif diff --git a/calib_board/usr/bsp/bsp_DS1302.c b/calib_board/usr/bsp/bsp_DS1302.c new file mode 100644 index 0000000..5f1c9dd --- /dev/null +++ b/calib_board/usr/bsp/bsp_DS1302.c @@ -0,0 +1,247 @@ +#include "bsp_DS1302.h" + +#define bsp_DS1302_DELAY() do{ \ + __NOP();__NOP();__NOP();__NOP();\ + __NOP();__NOP();__NOP();__NOP();\ + __NOP();__NOP();__NOP();__NOP();\ + __NOP();__NOP();__NOP();__NOP();\ + __NOP();__NOP();__NOP();__NOP();\ + __NOP();__NOP();__NOP();__NOP();\ + __NOP();__NOP();__NOP();__NOP();\ + }while(0) + +#define RST_CLR HAL_GPIO_WritePin(DS1302_RST_GPIO_Port, DS1302_RST_Pin, GPIO_PIN_RESET ) +#define RST_SET HAL_GPIO_WritePin(DS1302_RST_GPIO_Port, DS1302_RST_Pin, GPIO_PIN_SET ) + +#define IO_CLR HAL_GPIO_WritePin(DS1302_DIO_GPIO_Port, DS1302_DIO_Pin, GPIO_PIN_RESET ) +#define IO_SET HAL_GPIO_WritePin(DS1302_DIO_GPIO_Port, DS1302_DIO_Pin, GPIO_PIN_SET ) +#define IO_READ HAL_GPIO_ReadPin (DS1302_DIO_GPIO_Port, DS1302_DIO_Pin ) + +#define SCK_CLR HAL_GPIO_WritePin(DS1302_CLK_GPIO_Port, DS1302_CLK_Pin, GPIO_PIN_RESET ) +#define SCK_SET HAL_GPIO_WritePin(DS1302_CLK_GPIO_Port, DS1302_CLK_Pin, GPIO_PIN_SET ) + +static void bsp_DS1302Init(void); +static void bsp_DS1302_Task(void); +static u8 bsp_DS1302_Set(bsp_DS1302_Time_t *pTime); + +bsp_DS1302_t DS1302 = +{ + .Init = bsp_DS1302Init, + .Task = bsp_DS1302_Task, + .Set = bsp_DS1302_Set, +}; + +bsp_DS1302_t *pDS1302 = &DS1302; + +static void bsp_DS1302DataInput(void) +{ + GPIO_InitTypeDef GPIO_InitStruct; //定义GPIO结构体 + + GPIO_InitStruct.Pin = DS1302_DIO_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + HAL_GPIO_Init(DS1302_DIO_GPIO_Port, &GPIO_InitStruct); +} + +static void bsp_DS1302DataOutput(void) +{ + GPIO_InitTypeDef GPIO_InitStruct; //定义GPIO结构体 + + GPIO_InitStruct.Pin = DS1302_DIO_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + HAL_GPIO_Init(DS1302_DIO_GPIO_Port, &GPIO_InitStruct); +} + +/*向bsp_DS1302写入一字节数据*/ +static void bsp_DS1302_write_byte(u8 Addr, u8 Data) +{ + u8 i; + RST_SET; /*启动bsp_DS1302总线*/ + + bsp_DS1302_DELAY(); + /*写入目标地址:addr*/ + Addr = Addr & 0xFE;/*最低位置零*/ + + for (i = 0; i < 8; i++) + { + if (Addr & 0x01) + { + IO_SET; + } + + else + { + IO_CLR; + } + + bsp_DS1302_DELAY(); + SCK_SET; + bsp_DS1302_DELAY(); + SCK_CLR; + bsp_DS1302_DELAY(); + Addr = Addr >> 1; + } + + /*写入数据:d*/ + for (i = 0; i < 8; i++) + { + if (Data & 0x01) + { + IO_SET; + } + + else + { + IO_CLR; + } + + bsp_DS1302_DELAY(); + SCK_SET; + bsp_DS1302_DELAY(); + SCK_CLR; + bsp_DS1302_DELAY(); + Data = Data >> 1; + } + + RST_CLR; /*停止bsp_DS1302总线*/ + bsp_DS1302_DELAY(); +} + +/*从bsp_DS1302读出一字节数据*/ +static u8 bsp_DS1302_read_byte(u8 Addr) +{ + u8 i; + u8 temp; + RST_SET; /*启动bsp_DS1302总线*/ + bsp_DS1302_DELAY(); + + /*写入目标地址:addr*/ + Addr = Addr | 0x01;/*最低位置高*/ + + for (i = 0; i < 8; i++) + { + if (Addr & 0x01) + { + IO_SET; + } + + else + { + IO_CLR; + } + + bsp_DS1302_DELAY(); + SCK_SET; + bsp_DS1302_DELAY(); + SCK_CLR; + bsp_DS1302_DELAY(); + Addr = Addr >> 1; + } + + bsp_DS1302DataInput(); + + /*输出数据:temp*/ + for (i = 0; i < 8; i++) + { + temp = temp >> 1; + + if (IO_READ) + { + temp |= 0x80; + } + + else + { + temp &= 0x7F; + } + + bsp_DS1302_DELAY(); + SCK_SET; + bsp_DS1302_DELAY(); + SCK_CLR; + bsp_DS1302_DELAY(); + } + + RST_CLR; /*停止bsp_DS1302总线*/ + bsp_DS1302_DELAY(); + bsp_DS1302DataOutput(); + return temp; +} + +static u8 HexToBCD(u8 code) +{ + u8 temp; + temp = ((code / 10) << 4) + (code % 10); + return temp; +} + +static u8 bsp_DS1302_Set(bsp_DS1302_Time_t *pTime) +{ + if ((pDS1302->Time.Year > 99) || (pDS1302->Time.Month > 12) || (pDS1302->Time.Day > 31) || + (pDS1302->Time.Hour > 23) || (pDS1302->Time.Minute > 59) || (pDS1302->Time.Second > 59)) + { + return USR_FALSE; + + } + else + { + bsp_DS1302_write_byte(BSP_DS1302_CONTROL_ADDR, 0x00); //关闭写保护 + bsp_DS1302_write_byte(BSP_DS1302_SEC_ADDR, 0x80); //暂停 + + bsp_DS1302_write_byte(BSP_DS1302_YEAR_ADDR, HexToBCD(pTime->Year)); + bsp_DS1302_write_byte(BSP_DS1302_MONTH_ADDR, HexToBCD(pTime->Month)); + bsp_DS1302_write_byte(BSP_DS1302_DATA_ADDR, HexToBCD(pTime->Day)); + bsp_DS1302_write_byte(BSP_DS1302_HOUR_ADDR, HexToBCD(pTime->Hour)); + bsp_DS1302_write_byte(BSP_DS1302_MIN_ADDR, HexToBCD(pTime->Minute)); + bsp_DS1302_write_byte(BSP_DS1302_SEC_ADDR, HexToBCD(pTime->Second)); + + bsp_DS1302_write_byte(BSP_DS1302_CONTROL_ADDR, 0x80); //打开写保护 + return USR_TRUE; + } +} + +static void bsp_DS1302_Task(void) +{ + u8 RegData; + + RegData = bsp_DS1302_read_byte(BSP_DS1302_YEAR_ADDR); + pDS1302->Time.Year = (RegData / 16) * 10 + RegData % 16; + + RegData = bsp_DS1302_read_byte(BSP_DS1302_MONTH_ADDR); + pDS1302->Time.Month = (RegData / 16) * 10 + RegData % 16; + + RegData = bsp_DS1302_read_byte(BSP_DS1302_DATA_ADDR); + pDS1302->Time.Day = (RegData / 16) * 10 + RegData % 16; + + RegData = bsp_DS1302_read_byte(BSP_DS1302_HOUR_ADDR); + pDS1302->Time.Hour = (RegData / 16) * 10 + RegData % 16; + + RegData = bsp_DS1302_read_byte(BSP_DS1302_MIN_ADDR); + pDS1302->Time.Minute = (RegData / 16) * 10 + RegData % 16; + + RegData = bsp_DS1302_read_byte(BSP_DS1302_SEC_ADDR); + pDS1302->Time.Second = (RegData / 16) * 10 + RegData % 16; + +} + +static void bsp_DS1302Init(void) +{ + RST_SET; + SCK_CLR; + bsp_DS1302_Task(); + + if ((pDS1302->Time.Year > 99) || (pDS1302->Time.Month > 12) || (pDS1302->Time.Day > 31) || + (pDS1302->Time.Hour > 23) || (pDS1302->Time.Minute > 59) || (pDS1302->Time.Second > 59)) + { + pDS1302->Time.Year = 25; + pDS1302->Time.Month = 1; + pDS1302->Time.Day = 1; + pDS1302->Time.Hour = 0; + pDS1302->Time.Minute = 0; + pDS1302->Time.Second = 0; + bsp_DS1302_Set(&pDS1302->Time); + } +} diff --git a/calib_board/usr/bsp/bsp_DS1302.c.orig b/calib_board/usr/bsp/bsp_DS1302.c.orig new file mode 100644 index 0000000..b599c52 --- /dev/null +++ b/calib_board/usr/bsp/bsp_DS1302.c.orig @@ -0,0 +1,206 @@ +#include "bsp_DS1302.h" + +#define bsp_DS1302_DELAY() do{ \ + __NOP();__NOP();__NOP();__NOP();\ + __NOP();__NOP();__NOP();__NOP();\ + __NOP();__NOP();__NOP();__NOP();\ + __NOP();__NOP();__NOP();__NOP();\ + __NOP();__NOP();__NOP();__NOP();\ + }while(0) + + +#define RST_CLR HAL_GPIO_WritePin(DS1302_RST_GPIO_Port, DS1302_RST_Pin, GPIO_PIN_RESET ) +#define RST_SET HAL_GPIO_WritePin(DS1302_RST_GPIO_Port, DS1302_RST_Pin, GPIO_PIN_SET ) + +#define IO_CLR HAL_GPIO_WritePin(DS1302_DIO_GPIO_Port, DS1302_DIO_Pin, GPIO_PIN_RESET ) +#define IO_SET HAL_GPIO_WritePin(DS1302_DIO_GPIO_Port, DS1302_DIO_Pin, GPIO_PIN_SET ) +#define IO_READ HAL_GPIO_ReadPin (DS1302_DIO_GPIO_Port, DS1302_DIO_Pin ) + +#define SCK_CLR HAL_GPIO_WritePin(DS1302_CLK_GPIO_Port, DS1302_CLK_Pin, GPIO_PIN_RESET ) +#define SCK_SET HAL_GPIO_WritePin(DS1302_CLK_GPIO_Port, DS1302_CLK_Pin, GPIO_PIN_SET ) + +static void bsp_DS1302Init(void); +static void bsp_DS1302_Task(void); +static void bsp_DS1302_Set(bsp_DS1302_Time_t *pTime); + + +bsp_DS1302_t DS1302 = +{ + .Init = bsp_DS1302Init, + .Task = bsp_DS1302_Task, + .Set = bsp_DS1302_Set, +}; + + +bsp_DS1302_t *pDS1302 = &DS1302; + +static void bsp_DS1302DataInput(void) +{ + GPIO_InitTypeDef GPIO_InitStruct; //定义GPIO结构体 + + GPIO_InitStruct.Pin = DS1302_DIO_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + HAL_GPIO_Init(DS1302_DIO_GPIO_Port, &GPIO_InitStruct); +} + +static void bsp_DS1302DataOutput(void) +{ + GPIO_InitTypeDef GPIO_InitStruct; //定义GPIO结构体 + + GPIO_InitStruct.Pin = DS1302_DIO_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + HAL_GPIO_Init(DS1302_DIO_GPIO_Port, &GPIO_InitStruct); +} + +/*向bsp_DS1302写入一字节数据*/ +static void bsp_DS1302_write_byte(u8 Addr, u8 Data) +{ + u8 i; + RST_SET; /*启动bsp_DS1302总线*/ + + bsp_DS1302_DELAY(); + /*写入目标地址:addr*/ + Addr = Addr & 0xFE;/*最低位置零*/ + for(i=0; i<8; i++){ + if(Addr&0x01) IO_SET; + else IO_CLR; + bsp_DS1302_DELAY(); + SCK_SET; + bsp_DS1302_DELAY(); + SCK_CLR; + bsp_DS1302_DELAY(); + Addr = Addr >> 1; + } + + /*写入数据:d*/ + for(i=0; i<8; i++){ + if(Data&0x01) IO_SET; + else IO_CLR; + bsp_DS1302_DELAY(); + SCK_SET; + bsp_DS1302_DELAY(); + SCK_CLR; + bsp_DS1302_DELAY(); + Data = Data >> 1; + } + RST_CLR; /*停止bsp_DS1302总线*/ + bsp_DS1302_DELAY(); +} + +/*从bsp_DS1302读出一字节数据*/ +static u8 bsp_DS1302_read_byte(u8 Addr) +{ + u8 i; + u8 temp; + RST_SET; /*启动bsp_DS1302总线*/ + bsp_DS1302_DELAY(); + + /*写入目标地址:addr*/ + Addr = Addr | 0x01;/*最低位置高*/ + for(i=0; i<8; i++) + { + if(Addr&0x01) + { + IO_SET; + } + else + { + IO_CLR; + } + bsp_DS1302_DELAY(); + SCK_SET; + bsp_DS1302_DELAY(); + SCK_CLR; + bsp_DS1302_DELAY(); + Addr = Addr >> 1; + } + + bsp_DS1302DataInput(); + /*输出数据:temp*/ + for(i=0; i<8; i++) + { + temp = temp>>1; + if(IO_READ) temp |= 0x80; + else temp&=0x7F; + bsp_DS1302_DELAY(); + SCK_SET; + bsp_DS1302_DELAY(); + SCK_CLR; + bsp_DS1302_DELAY(); + } + RST_CLR; /*停止bsp_DS1302总线*/ + bsp_DS1302_DELAY(); + bsp_DS1302DataOutput(); + return temp; +} + +static u8 HexToBCD(u8 code) +{ + u8 temp; + temp = ((code / 10)<<4)+(code % 10); + return temp; +} + +static void bsp_DS1302_Set(bsp_DS1302_Time_t *pTime) +{ + bsp_DS1302_write_byte(BSP_DS1302_CONTROL_ADDR,0x00); //关闭写保护 + bsp_DS1302_write_byte(BSP_DS1302_SEC_ADDR,0x80); //暂停 + + bsp_DS1302_write_byte(BSP_DS1302_YEAR_ADDR, HexToBCD(pTime->Year)); + bsp_DS1302_write_byte(BSP_DS1302_MONTH_ADDR, HexToBCD(pTime->Month)); + bsp_DS1302_write_byte(BSP_DS1302_DATA_ADDR, HexToBCD(pTime->Day)); + bsp_DS1302_write_byte(BSP_DS1302_HOUR_ADDR, HexToBCD(pTime->Hour)); + bsp_DS1302_write_byte(BSP_DS1302_MIN_ADDR, HexToBCD(pTime->Minute)); + bsp_DS1302_write_byte(BSP_DS1302_SEC_ADDR, HexToBCD(pTime->Second)); + + bsp_DS1302_write_byte(BSP_DS1302_CONTROL_ADDR,0x80); //打开写保护 +} + +static void bsp_DS1302_Task(void) +{ + u8 RegData; + + RegData = bsp_DS1302_read_byte(BSP_DS1302_YEAR_ADDR); + pDS1302->Time.Year = (RegData/16)*10 + RegData%16; + + RegData = bsp_DS1302_read_byte(BSP_DS1302_MONTH_ADDR); + pDS1302->Time.Month = (RegData/16)*10 + RegData%16; + + RegData = bsp_DS1302_read_byte(BSP_DS1302_DATA_ADDR); + pDS1302->Time.Day = (RegData/16)*10 + RegData%16; + + RegData = bsp_DS1302_read_byte(BSP_DS1302_HOUR_ADDR); + pDS1302->Time.Hour = (RegData/16)*10 + RegData%16; + + RegData = bsp_DS1302_read_byte(BSP_DS1302_MIN_ADDR); + pDS1302->Time.Minute = (RegData/16)*10 + RegData%16; + + RegData = bsp_DS1302_read_byte(BSP_DS1302_SEC_ADDR); + pDS1302->Time.Second = (RegData/16)*10 + RegData%16; + +} + +static void bsp_DS1302Init(void) +{ + RST_SET; + SCK_CLR; + bsp_DS1302_Task(); + if((pDS1302->Time.Year>99)||(pDS1302->Time.Month>12)||(pDS1302->Time.Day>31)|| + (pDS1302->Time.Hour>23)||(pDS1302->Time.Minute>59)||(pDS1302->Time.Second>59)) + { + pDS1302->Time.Year = 25; + pDS1302->Time.Month = 1; + pDS1302->Time.Day = 1; + pDS1302->Time.Hour = 0; + pDS1302->Time.Minute = 0; + pDS1302->Time.Second = 0; + bsp_DS1302_Set(&pDS1302->Time); + } +} + + + diff --git a/calib_board/usr/bsp/bsp_DS1302.h b/calib_board/usr/bsp/bsp_DS1302.h new file mode 100644 index 0000000..5863632 --- /dev/null +++ b/calib_board/usr/bsp/bsp_DS1302.h @@ -0,0 +1,38 @@ +#ifndef __BSP_DS1302_H__ +#define __BSP_DS1302_H__ + +#include "main.h" +#include "usr_config.h" + +#define BSP_DS1302_SEC_ADDR 0x80 //秒数据地址 +#define BSP_DS1302_MIN_ADDR 0x82 //分数据地址 +#define BSP_DS1302_HOUR_ADDR 0x84 //时数据地址 +#define BSP_DS1302_DATA_ADDR 0x86 //日数据地址 +#define BSP_DS1302_MONTH_ADDR 0x88 //月数据地址 +#define BSP_DS1302_DAY_ADDR 0x8a //星期数据地址 +#define BSP_DS1302_YEAR_ADDR 0x8c //年数据地址 +#define BSP_DS1302_CONTROL_ADDR 0x8e //控制数据地址 +#define BSP_DS1302_CHARGER_ADDR 0x90 +#define BSP_DS1302_CLKBURST_ADDR 0xbe + +typedef struct +{ + u16 Year; + u8 Month; + u8 Day; + u8 Hour; + u8 Minute; + u8 Second; +}bsp_DS1302_Time_t; + +typedef struct +{ + bsp_DS1302_Time_t Time; + void (*Init)(void); + u8 (*Set)(bsp_DS1302_Time_t *); + void (*Task)(void); +}bsp_DS1302_t; + +extern bsp_DS1302_t DS1302;//系统时间 + +#endif diff --git a/calib_board/usr/bsp/bsp_W5500.c b/calib_board/usr/bsp/bsp_W5500.c new file mode 100644 index 0000000..f6e18cc --- /dev/null +++ b/calib_board/usr/bsp/bsp_W5500.c @@ -0,0 +1,808 @@ +/********************************************************************************** + * 文件名 :W5500.c + * 描述 :W5500 驱动函数库 + * 库版本 :ST_v3.5 + * 作者 :泥人通信模块开发团队 + * 博客 :http://nirenelec.blog.163.com + * 淘宝 :http://nirenelec.taobao.com + **********************************************************************************/ + +//#include "stm32f1xx.h" +//#include "stm32f1xx_hal_spi.h" +#include "main.h" + +#include "bsp_W5500.h" +#include "usart.h" +#include "stdio.h" +#include "spi.h" +//#include "bsp_print.h" + + +#define BSP_W5500_SPI_CS_LOW + + +/*Run_Mode 端口的运行模式*/ +#define BSP_W5500_PORT_RUN_MODE_TCP_SERVER 0x00 /*TCP服务器模式*/ +#define BSP_W5500_PORT_RUN_MODE_TCP_CLIENT 0x01 /*TCP客户端模式*/ +#define BSP_W5500_PORT_RUN_MODE_UDP 0x02 /*UDP(广播)模式*/ + +/*Run_State 端口的运行状态 BIT位*/ +#define BSP_W5500_PORT_RUN_STATE_INIT 0x01 /*端口完成初始化*/ +#define BSP_W5500_PORT_RUN_STATE_CONN 0x02 /*端口完成连接,可以正常传输数据*/ + +/*TR_Data_State 端口的收发数据状态*/ +#define BSP_W5500_PORT_DATA_RECEIVE 0x01 /*端口接收到一个数据包*/ +#define BSP_W5500_PORT_DATA_TRANSMITOK 0x02 /*端口发送一个数据包完成*/ + +static void bsp_W5500_Interrupt_Process(void); +static void bsp_W5500_Init(void); +static void bsp_W5500_Task(void); +static void Write_SOCK_Data_Buffer(bsp_W5500_Class_t *pW5500_Class, u8 *dat_ptr, u16 size); + +bsp_W5500_t W5500 = +{ + .Gateway_IP = {192,168,1,1}, + .Sub_Mask = {255,255,255,0}, + .Phy_Addr = {0x0c,0x29,0xab,0x7c,0x00,0x01}, + + //.IP_Addr = {169,254,107,101}, + .IP_Addr = {192,168,1,101}, + + .Interrupt_Process = bsp_W5500_Interrupt_Process, + + .Init = bsp_W5500_Init, + .Task = bsp_W5500_Task, + .Socket_Send = Write_SOCK_Data_Buffer, + + .W5500_Class[0] = + { + .SocketPort = 0, /*使用端口0*/ + .ConfigData.Gateway_IP = {192,168,1,1}, + .ConfigData.Sub_Mask = {255,255,255,0}, + .ConfigData.Phy_Addr = {0x0c,0x29,0xab,0x7c,0x00,0x01}, + + .ConfigData.IP_Addr = {192,168,1,101}, + .ConfigData.Port = {0x13,0x88}, + +// .ConfigData.DIP = {192,168,1,32}, +// .ConfigData.DPort = {0x03,0x09}, + + .Run_Mode = BSP_W5500_PORT_RUN_MODE_TCP_SERVER, +// .Rx_DataAnalysis = proto_HSMS_Rx_DataAnalysis, + }, +}; + +bsp_W5500_t *pW5500 = &W5500; + +/******************************************************************************* + * 函数名 : SPI1_Send_Byte + * 描述 : SPI1发送1个字节数据 + * 输入 : dat:待发送的数据 + * 输出 : 无 + * 返回值 : 无 + * 说明 : 无 + *******************************************************************************/ +void SPI1_Send_Byte(u8 dat) +{ + // hspi1.Instance->DR=dat; + HAL_SPI_Transmit(&hspi1, &dat, 1, 0xff); + // while(__HAL_SPI_GET_FLAG(&hspi1,SPI_FLAG_TXE)==RESET); + // SPI_I2S_SendData(SPI1,dat);//写1个字节数据 + // while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);//等待数据寄存器空 +} + +/******************************************************************************* + * 函数名 : SPI1_Send_Short + * 描述 : SPI1发送2个字节数据(16位) + * 输入 : dat:待发送的16位数据 + * 输出 : 无 + * 返回值 : 无 + * 说明 : 无 + *******************************************************************************/ +void SPI1_Send_Short(u16 dat) +{ + SPI1_Send_Byte(dat >> 8); // 写数据高位 + SPI1_Send_Byte(dat); // 写数据低位 +} + +/******************************************************************************* + * 函数名 : Write_W5500_1Byte + * 描述 : 通过SPI1向指定地址寄存器写1个字节数据 + * 输入 : reg:16位寄存器地址,dat:待写入的数据 + * 输出 : 无 + * 返回值 : 无 + * 说明 : 无 + *******************************************************************************/ +void Write_W5500_1Byte(u16 reg, u8 dat) +{ + HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平 + + SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址 + SPI1_Send_Byte(FDM1 | RWB_WRITE | COMMON_R); // 通过SPI1写控制字节,1个字节数据长度,写数据,选择通用寄存器 + SPI1_Send_Byte(dat); // 写1个字节数据 + + HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平 +} + +/******************************************************************************* + * 函数名 : Write_W5500_2Byte + * 描述 : 通过SPI1向指定地址寄存器写2个字节数据 + * 输入 : reg:16位寄存器地址,dat:16位待写入的数据(2个字节) + * 输出 : 无 + * 返回值 : 无 + * 说明 : 无 + *******************************************************************************/ +void Write_W5500_2Byte(u16 reg, u16 dat) +{ + HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平 + + SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址 + SPI1_Send_Byte(FDM2 | RWB_WRITE | COMMON_R); // 通过SPI1写控制字节,2个字节数据长度,写数据,选择通用寄存器 + SPI1_Send_Short(dat); // 写16位数据 + + HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平 +} + +/******************************************************************************* + * 函数名 : Write_W5500_nByte + * 描述 : 通过SPI1向指定地址寄存器写n个字节数据 + * 输入 : reg:16位寄存器地址,*dat_ptr:待写入数据缓冲区指针,size:待写入的数据长度 + * 输出 : 无 + * 返回值 : 无 + * 说明 : 无 + *******************************************************************************/ +void Write_W5500_nByte(u16 reg, u8 *dat_ptr, u16 size) +{ + u16 i; + + HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平 + + SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址 + SPI1_Send_Byte(VDM | RWB_WRITE | COMMON_R); // 通过SPI1写控制字节,N个字节数据长度,写数据,选择通用寄存器 + + for (i = 0; i < size; i++) // 循环将缓冲区的size个字节数据写入W5500 + { + SPI1_Send_Byte(*dat_ptr++); // 写一个字节数据 + } + + HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平 +} + +/******************************************************************************* + * 函数名 : Write_W5500_SOCK_1Byte + * 描述 : 通过SPI1向指定端口寄存器写1个字节数据 + * 输入 : s:端口号,reg:16位寄存器地址,dat:待写入的数据 + * 输出 : 无 + * 返回值 : 无 + * 说明 : 无 + *******************************************************************************/ +void Write_W5500_SOCK_1Byte(SOCKET s, u16 reg, u8 dat) +{ + HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平 + + SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址 + SPI1_Send_Byte(FDM1 | RWB_WRITE | (s * 0x20 + 0x08)); // 通过SPI1写控制字节,1个字节数据长度,写数据,选择端口s的寄存器 + SPI1_Send_Byte(dat); // 写1个字节数据 + + HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平 +} + +/******************************************************************************* + * 函数名 : Write_W5500_SOCK_2Byte + * 描述 : 通过SPI1向指定端口寄存器写2个字节数据 + * 输入 : s:端口号,reg:16位寄存器地址,dat:16位待写入的数据(2个字节) + * 输出 : 无 + * 返回值 : 无 + * 说明 : 无 + *******************************************************************************/ +void Write_W5500_SOCK_2Byte(SOCKET s, u16 reg, u16 dat) +{ + HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平 + + SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址 + SPI1_Send_Byte(FDM2 | RWB_WRITE | (s * 0x20 + 0x08)); // 通过SPI1写控制字节,2个字节数据长度,写数据,选择端口s的寄存器 + SPI1_Send_Short(dat); // 写16位数据 + + HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平 +} + +/******************************************************************************* + * 函数名 : Write_W5500_SOCK_4Byte + * 描述 : 通过SPI1向指定端口寄存器写4个字节数据 + * 输入 : s:端口号,reg:16位寄存器地址,*dat_ptr:待写入的4个字节缓冲区指针 + * 输出 : 无 + * 返回值 : 无 + * 说明 : 无 + *******************************************************************************/ +void Write_W5500_SOCK_4Byte(SOCKET s, u16 reg, u8 *dat_ptr) +{ + HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平 + + SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址 + SPI1_Send_Byte(FDM4 | RWB_WRITE | (s * 0x20 + 0x08)); // 通过SPI1写控制字节,4个字节数据长度,写数据,选择端口s的寄存器 + + SPI1_Send_Byte(*dat_ptr++); // 写第1个字节数据 + SPI1_Send_Byte(*dat_ptr++); // 写第2个字节数据 + SPI1_Send_Byte(*dat_ptr++); // 写第3个字节数据 + SPI1_Send_Byte(*dat_ptr++); // 写第4个字节数据 + + HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平 +} + +/******************************************************************************* + * 函数名 : Read_W5500_1Byte + * 描述 : 读W5500指定地址寄存器的1个字节数据 + * 输入 : reg:16位寄存器地址 + * 输出 : 无 + * 返回值 : 读取到寄存器的1个字节数据 + * 说明 : 无 + *******************************************************************************/ +u8 Read_W5500_1Byte(u16 reg) +{ + u8 i; + + HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平 + + SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址 + SPI1_Send_Byte(FDM1 | RWB_READ | COMMON_R); // 通过SPI1写控制字节,1个字节数据长度,读数据,选择通用寄存器 + i = hspi1.Instance->DR; + // HAL_SPI_Receive(&hspi1,&i,1,0xf); + // i=SPI_I2S_ReceiveData(SPI1); + SPI1_Send_Byte(0x00); // 发送一个哑数据 + + i = hspi1.Instance->DR; + // HAL_SPI_Receive(&hspi1,&i,1,0xf); + + // i=SPI_I2S_ReceiveData(SPI1);//读取1个字节数据 + + HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平 + return i; // 返回读取到的寄存器数据 +} + +/******************************************************************************* + * 函数名 : Read_W5500_SOCK_1Byte + * 描述 : 读W5500指定端口寄存器的1个字节数据 + * 输入 : s:端口号,reg:16位寄存器地址 + * 输出 : 无 + * 返回值 : 读取到寄存器的1个字节数据 + * 说明 : 无 + *******************************************************************************/ +u8 Read_W5500_SOCK_1Byte(SOCKET s, u16 reg) +{ + u8 i; + + HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平 + + SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址 + SPI1_Send_Byte(FDM1 | RWB_READ | (s * 0x20 + 0x08)); // 通过SPI1写控制字节,1个字节数据长度,读数据,选择端口s的寄存器 + + i = hspi1.Instance->DR; + // i=SPI_I2S_ReceiveData(SPI1); + SPI1_Send_Byte(0x00); // 发送一个哑数据 + i = hspi1.Instance->DR; + // i=SPI_I2S_ReceiveData(SPI1);//读取1个字节数据 + + HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平 + return i; // 返回读取到的寄存器数据 +} + +/******************************************************************************* + * 函数名 : Read_W5500_SOCK_2Byte + * 描述 : 读W5500指定端口寄存器的2个字节数据 + * 输入 : s:端口号,reg:16位寄存器地址 + * 输出 : 无 + * 返回值 : 读取到寄存器的2个字节数据(16位) + * 说明 : 无 + *******************************************************************************/ +u16 Read_W5500_SOCK_2Byte(SOCKET s, u16 reg) +{ + u16 i; + + HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平 + + SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址 + SPI1_Send_Byte(FDM2 | RWB_READ | (s * 0x20 + 0x08)); // 通过SPI1写控制字节,2个字节数据长度,读数据,选择端口s的寄存器 + + i = hspi1.Instance->DR; + // i=SPI_I2S_ReceiveData(SPI1); + SPI1_Send_Byte(0x00); // 发送一个哑数据 + i = hspi1.Instance->DR; + // i=SPI_I2S_ReceiveData(SPI1);//读取高位数据 + SPI1_Send_Byte(0x00); // 发送一个哑数据 + i *= 256; + i += hspi1.Instance->DR; + // i+=SPI_I2S_ReceiveData(SPI1);//读取低位数据 + + HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平 + return i; // 返回读取到的寄存器数据 +} + +/******************************************************************************* + * 函数名 : Read_SOCK_Data_Buffer + * 描述 : 从W5500接收数据缓冲区中读取数据 + * 输入 : s:端口号,*dat_ptr:数据保存缓冲区指针 + * 输出 : 无 + * 返回值 : 读取到的数据长度,rx_size个字节 + * 说明 : 无 + *******************************************************************************/ +u16 Read_SOCK_Data_Buffer(SOCKET s, u8 *dat_ptr) +{ + u16 rx_size; + u16 offset, offset1; + u16 i; + u8 j; + + rx_size = Read_W5500_SOCK_2Byte(s, Sn_RX_RSR); + if (rx_size == 0) + return 0; // 没接收到数据则返回 + if (rx_size > 1460) + rx_size = 1460; + + offset = Read_W5500_SOCK_2Byte(s, Sn_RX_RD); + offset1 = offset; + offset &= (S_RX_SIZE - 1); // 计算实际的物理地址 + + HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平 + + SPI1_Send_Short(offset); // 写16位地址 + SPI1_Send_Byte(VDM | RWB_READ | (s * 0x20 + 0x18)); // 写控制字节,N个字节数据长度,读数据,选择端口s的寄存器 + j = hspi1.Instance->DR; + // j=SPI_I2S_ReceiveData(SPI1); + + if ((offset + rx_size) < S_RX_SIZE) // 如果最大地址未超过W5500接收缓冲区寄存器的最大地址 + { + for (i = 0; i < rx_size; i++) // 循环读取rx_size个字节数据 + { + SPI1_Send_Byte(0x00); // 发送一个哑数据 + j = hspi1.Instance->DR; + // j=SPI_I2S_ReceiveData(SPI1);//读取1个字节数据 + *dat_ptr = j; // 将读取到的数据保存到数据保存缓冲区 + dat_ptr++; // 数据保存缓冲区指针地址自增1 + } + } + else // 如果最大地址超过W5500接收缓冲区寄存器的最大地址 + { + offset = S_RX_SIZE - offset; + for (i = 0; i < offset; i++) // 循环读取出前offset个字节数据 + { + SPI1_Send_Byte(0x00); // 发送一个哑数据 + j = hspi1.Instance->DR; + // j=SPI_I2S_ReceiveData(SPI1);//读取1个字节数据 + *dat_ptr = j; // 将读取到的数据保存到数据保存缓冲区 + dat_ptr++; // 数据保存缓冲区指针地址自增1 + } + HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平 + + HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平 + + SPI1_Send_Short(0x00); // 写16位地址 + SPI1_Send_Byte(VDM | RWB_READ | (s * 0x20 + 0x18)); // 写控制字节,N个字节数据长度,读数据,选择端口s的寄存器 + j = hspi1.Instance->DR; + // j=SPI_I2S_ReceiveData(SPI1); + + for (; i < rx_size; i++) // 循环读取后rx_size-offset个字节数据 + { + SPI1_Send_Byte(0x00); // 发送一个哑数据 + j = hspi1.Instance->DR; + // j=SPI_I2S_ReceiveData(SPI1);//读取1个字节数据 + *dat_ptr = j; // 将读取到的数据保存到数据保存缓冲区 + dat_ptr++; // 数据保存缓冲区指针地址自增1 + } + } + HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平 + offset1 += rx_size; // 更新实际物理地址,即下次读取接收到的数据的起始地址 + Write_W5500_SOCK_2Byte(s, Sn_RX_RD, offset1); + Write_W5500_SOCK_1Byte(s, Sn_CR, RECV); // 发送启动接收命令 + return rx_size; // 返回接收到数据的长度 +} +/******************************************************************************* + * 函数名 : Write_SOCK_Data_Buffer + * 描述 : 将数据写入W5500的数据发送缓冲区 + * 输入 : s:端口号,*dat_ptr:数据保存缓冲区指针,size:待写入数据的长度 + * 输出 : 无 + * 返回值 : 无 + * 说明 : 无 + *******************************************************************************/ +static void Write_SOCK_Data_Buffer(bsp_W5500_Class_t *pW5500_Class, u8 *dat_ptr, u16 size) +{ + u16 offset, offset1; + u16 i; + // 如果是UDP模式,可以在此设置目的主机的IP和端口号 + if ((Read_W5500_SOCK_1Byte(pW5500_Class->SocketPort, Sn_MR) & 0x0f) != SOCK_UDP) // 如果Socket打开失败 + { + Write_W5500_SOCK_4Byte(pW5500_Class->SocketPort, Sn_DIPR, pW5500_Class->ConfigData.UDP_DIPR); // 设置目的主机IP + Write_W5500_SOCK_2Byte(pW5500_Class->SocketPort, Sn_DPORTR, pW5500_Class->ConfigData.UDP_DPORT[0]<<8 | pW5500_Class->ConfigData.UDP_DPORT[1]); // 设置目的主机端口号 + } + + offset = Read_W5500_SOCK_2Byte(pW5500_Class->SocketPort, Sn_TX_WR); + offset1 = offset; + offset &= (S_TX_SIZE - 1); // 计算实际的物理地址 + + HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平 + + SPI1_Send_Short(offset); // 写16位地址 + SPI1_Send_Byte(VDM | RWB_WRITE | (pW5500_Class->SocketPort * 0x20 + 0x10)); // 写控制字节,N个字节数据长度,写数据,选择端口s的寄存器 + + if ((offset + size) < S_TX_SIZE) // 如果最大地址未超过W5500发送缓冲区寄存器的最大地址 + { + for (i = 0; i < size; i++) // 循环写入size个字节数据 + { + SPI1_Send_Byte(*dat_ptr++); // 写入一个字节的数据 + } + } + else // 如果最大地址超过W5500发送缓冲区寄存器的最大地址 + { + offset = S_TX_SIZE - offset; + for (i = 0; i < offset; i++) // 循环写入前offset个字节数据 + { + SPI1_Send_Byte(*dat_ptr++); // 写入一个字节的数据 + } + HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平 + + HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平 + + SPI1_Send_Short(0x00); // 写16位地址 + SPI1_Send_Byte(VDM | RWB_WRITE | (pW5500_Class->SocketPort * 0x20 + 0x10)); // 写控制字节,N个字节数据长度,写数据,选择端口s的寄存器 + + for (; i < size; i++) // 循环写入size-offset个字节数据 + { + SPI1_Send_Byte(*dat_ptr++); // 写入一个字节的数据 + } + } + HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平 + + offset1 += size; // 更新实际物理地址,即下次写待发送数据到发送数据缓冲区的起始地址 + Write_W5500_SOCK_2Byte(pW5500_Class->SocketPort, Sn_TX_WR, offset1); + Write_W5500_SOCK_1Byte(pW5500_Class->SocketPort, Sn_CR, SEND); // 发送启动发送命令 +} + +/******************************************************************************* + * 函数名 : W5500_Hardware_Reset + * 描述 : 硬件复位W5500 + * 输入 : 无 + * 输出 : 无 + * 返回值 : 无 + * 说明 : W5500的复位引脚保持低电平至少500us以上,才能重围W5500 + *******************************************************************************/ +void W5500_Hardware_Reset(void) +{ + HAL_GPIO_WritePin(W5500_RST_PORT, W5500_RST, GPIO_PIN_RESET); // 复位引脚拉低 + HAL_Delay(50); + HAL_GPIO_WritePin(W5500_RST_PORT, W5500_RST, GPIO_PIN_SET); // 复位引脚拉高 + HAL_Delay(100); + + // while((Read_W5500_1Byte(PHYCFGR)&LINK)==0);//等待以太网连接完成 +} + +/******************************************************************************* + * 函数名 : W5500_Init + * 描述 : 初始化W5500寄存器函数 + * 输入 : 无 + * 输出 : 无 + * 返回值 : 无 + * 说明 : 在使用W5500之前,先对W5500初始化 + *******************************************************************************/ +void W5500_Init(void) +{ + u16 i = 0; + + Write_W5500_1Byte(MR, RST); // 软件复位W5500,置1有效,复位后自动清0 + + HAL_Delay(10); // 延时10ms,自己定义该函数 + + // 设置网关(Gateway)的IP地址,Gateway_IP为4字节u8数组,自己定义 + // 使用网关可以使通信突破子网的局限,通过网关可以访问到其它子网或进入Internet + Write_W5500_nByte(GAR, pW5500->Gateway_IP, 4); + + // 设置子网掩码(MASK)值,SUB_MASK为4字节u8数组,自己定义 + // 子网掩码用于子网运算 + Write_W5500_nByte(SUBR, pW5500->Sub_Mask, 4); + + // 设置物理地址,PHY_ADDR为6字节u8数组,自己定义,用于唯一标识网络设备的物理地址值 + // 该地址值需要到IEEE申请,按照OUI的规定,前3个字节为厂商代码,后三个字节为产品序号 + // 如果自己定义物理地址,注意第一个字节必须为偶数 + Write_W5500_nByte(SHAR, pW5500->Phy_Addr, 6); + + // 设置本机的IP地址,IP_ADDR为4字节u8数组,自己定义 + // 注意,网关IP必须与本机IP属于同一个子网,否则本机将无法找到网关 + Write_W5500_nByte(SIPR, pW5500->IP_Addr, 4); + + // 设置发送缓冲区和接收缓冲区的大小,参考W5500数据手册 + for (i = 0; i < 8; i++) + { + Write_W5500_SOCK_1Byte(i, Sn_RXBUF_SIZE, 0x02); // Socket Rx memory size=2k + Write_W5500_SOCK_1Byte(i, Sn_TXBUF_SIZE, 0x02); // Socket Tx mempry size=2k + } + + // 设置重试时间,默认为2000(200ms) + // 每一单位数值为100微秒,初始化时值设为2000(0x07D0),等于200毫秒 + Write_W5500_2Byte(RTR, 0x07d0); + + // 设置重试次数,默认为8次 + // 如果重发的次数超过设定值,则产生超时中断(相关的端口中断寄存器中的Sn_IR 超时位(TIMEOUT)置“1”) + Write_W5500_1Byte(RCR, 8); +} + +/******************************************************************************* + * 函数名 : Detect_Gateway + * 描述 : 检查网关服务器 + * 输入 : 无 + * 输出 : 无 + * 返回值 : 成功返回TRUE(0xFF),失败返回FALSE(0x00) + * 说明 : 无 + *******************************************************************************/ +u8 Detect_Gateway(void) +{ + u8 ip_adde[4]; + ip_adde[0] = pW5500->IP_Addr[0] + 1; + ip_adde[1] = pW5500->IP_Addr[1] + 1; + ip_adde[2] = pW5500->IP_Addr[2] + 1; + ip_adde[3] = pW5500->IP_Addr[3] + 1; + + // 检查网关及获取网关的物理地址 + Write_W5500_SOCK_4Byte(0, Sn_DIPR, ip_adde); // 向目的地址寄存器写入与本机IP不同的IP值 + Write_W5500_SOCK_1Byte(0, Sn_MR, MR_TCP); // 设置socket为TCP模式 + Write_W5500_SOCK_1Byte(0, Sn_CR, OPEN); // 打开Socket + HAL_Delay(5); // 延时5ms + + if (Read_W5500_SOCK_1Byte(0, Sn_SR) != SOCK_INIT) // 如果socket打开失败 + { + Write_W5500_SOCK_1Byte(0, Sn_CR, CLOSE); // 打开不成功,关闭Socket + return FALSE; // 返回FALSE(0x00) + } + + Write_W5500_SOCK_1Byte(0, Sn_CR, CONNECT); // 设置Socket为Connect模式 + + do + { + u16 j = 0; + j = Read_W5500_SOCK_1Byte(0, Sn_IR); // 读取Socket0中断标志寄存器 + if (j != 0) + Write_W5500_SOCK_1Byte(0, Sn_IR, j); + HAL_Delay(5); // 延时5ms + if ((j & IR_TIMEOUT) == IR_TIMEOUT) + { + return FALSE; + } + else if (Read_W5500_SOCK_1Byte(0, Sn_DHAR) != 0xff) + { + Write_W5500_SOCK_1Byte(0, Sn_CR, CLOSE); // 关闭Socket + return TRUE; + } + } while (1); +} + +/******************************************************************************* + * 函数名 : Socket_Init + * 描述 : 指定Socket(0~7)初始化 + * 输入 : s:待初始化的端口 + * 输出 : 无 + * 返回值 : 无 + * 说明 : 无 + *******************************************************************************/ +static void bsp_W5500_Socket_Init(bsp_W5500_Class_t *pW5500_Class) +{ + Write_W5500_SOCK_2Byte(pW5500_Class->SocketPort, Sn_MSSR, 1460); // 最大分片字节数=1460(0x5b4) + Write_W5500_SOCK_2Byte(pW5500_Class->SocketPort, Sn_PORT, pW5500_Class->ConfigData.Port[0]<<8 | pW5500_Class->ConfigData.Port[1]); + // 设置端口0目的(远程)端口号 + Write_W5500_SOCK_2Byte(pW5500_Class->SocketPort, Sn_DPORTR, pW5500_Class->ConfigData.DPort[0]<<8 | pW5500_Class->ConfigData.DPort[1]); + // 设置端口0目的(远程)IP地址 + Write_W5500_SOCK_4Byte(pW5500_Class->SocketPort, Sn_DIPR, pW5500_Class->ConfigData.DIP); +} + +/******************************************************************************* + * 函数名 : Socket_Connect + * 描述 : 设置指定Socket(0~7)为客户端与远程服务器连接 + * 输入 : s:待设定的端口 + * 输出 : 无 + * 返回值 : 成功返回TRUE(0xFF),失败返回FALSE(0x00) + * 说明 : 当本机Socket工作在客户端模式时,引用该程序,与远程服务器建立连接 + * 如果启动连接后出现超时中断,则与服务器连接失败,需要重新调用该程序连接 + * 该程序每调用一次,就与服务器产生一次连接 + *******************************************************************************/ +u8 Socket_Connect(SOCKET s) +{ + Write_W5500_SOCK_1Byte(s, Sn_MR, MR_TCP); // 设置socket为TCP模式 + Write_W5500_SOCK_1Byte(s, Sn_CR, OPEN); // 打开Socket + HAL_Delay(5); // 延时5ms + if (Read_W5500_SOCK_1Byte(s, Sn_SR) != SOCK_INIT) // 如果socket打开失败 + { + Write_W5500_SOCK_1Byte(s, Sn_CR, CLOSE); // 打开不成功,关闭Socket + return FALSE; // 返回FALSE(0x00) + } + Write_W5500_SOCK_1Byte(s, Sn_CR, CONNECT); // 设置Socket为Connect模式 + return TRUE; // 返回TRUE,设置成功 +} + +/******************************************************************************* + * 函数名 : Socket_Listen + * 描述 : 设置指定Socket(0~7)作为服务器等待远程主机的连接 + * 输入 : s:待设定的端口 + * 输出 : 无 + * 返回值 : 成功返回TRUE(0xFF),失败返回FALSE(0x00) + * 说明 : 当本机Socket工作在服务器模式时,引用该程序,等等远程主机的连接 + * 该程序只调用一次,就使W5500设置为服务器模式 + *******************************************************************************/ +u8 Socket_Listen(SOCKET s) +{ + Write_W5500_SOCK_1Byte(s, Sn_MR, MR_TCP); // 设置socket为TCP模式 + Write_W5500_SOCK_1Byte(s, Sn_CR, OPEN); // 打开Socket + HAL_Delay(5); // 延时5ms + if (Read_W5500_SOCK_1Byte(s, Sn_SR) != SOCK_INIT) // 如果socket打开失败 + { + Write_W5500_SOCK_1Byte(s, Sn_CR, CLOSE); // 打开不成功,关闭Socket + return FALSE; // 返回FALSE(0x00) + } + Write_W5500_SOCK_1Byte(s, Sn_CR, LISTEN); // 设置Socket为侦听模式 + HAL_Delay(5); // 延时5ms + if (Read_W5500_SOCK_1Byte(s, Sn_SR) != SOCK_LISTEN) // 如果socket设置失败 + { + Write_W5500_SOCK_1Byte(s, Sn_CR, CLOSE); // 设置不成功,关闭Socket + return FALSE; // 返回FALSE(0x00) + } + + return TRUE; + + // 至此完成了Socket的打开和设置侦听工作,至于远程客户端是否与它建立连接,则需要等待Socket中断, + // 以判断Socket的连接是否成功。参考W5500数据手册的Socket中断状态 + // 在服务器侦听模式不需要设置目的IP和目的端口号 +} + +/******************************************************************************* + * 函数名 : Socket_UDP + * 描述 : 设置指定Socket(0~7)为UDP模式 + * 输入 : s:待设定的端口 + * 输出 : 无 + * 返回值 : 成功返回TRUE(0xFF),失败返回FALSE(0x00) + * 说明 : 如果Socket工作在UDP模式,引用该程序,在UDP模式下,Socket通信不需要建立连接 + * 该程序只调用一次,就使W5500设置为UDP模式 + *******************************************************************************/ +u8 Socket_UDP(SOCKET s) +{ + Write_W5500_SOCK_1Byte(s, Sn_MR, MR_UDP); // 设置Socket为UDP模式*/ + Write_W5500_SOCK_1Byte(s, Sn_CR, OPEN); // 打开Socket*/ + HAL_Delay(5); // 延时5ms + if (Read_W5500_SOCK_1Byte(s, Sn_SR) != SOCK_UDP) // 如果Socket打开失败 + { + Write_W5500_SOCK_1Byte(s, Sn_CR, CLOSE); // 打开不成功,关闭Socket + return FALSE; // 返回FALSE(0x00) + } + else + return TRUE; + + // 至此完成了Socket的打开和UDP模式设置,在这种模式下它不需要与远程主机建立连接 + // 因为Socket不需要建立连接,所以在发送数据前都可以设置目的主机IP和目的Socket的端口号 + // 如果目的主机IP和目的Socket的端口号是固定的,在运行过程中没有改变,那么也可以在这里设置 +} + +/******************************************************************************* + * 函数名 : W5500_Interrupt_Process + * 描述 : W5500中断处理程序框架 + * 输入 : 无 + * 输出 : 无 + * 返回值 : 无 + * 说明 : 无 + *******************************************************************************/ +static void bsp_W5500_Interrupt_Process(void) +{ + u8 i, j; + u8 Int_Flag,Socket_Flag; + +IntDispose: + + Int_Flag = Read_W5500_1Byte(SIR); // 读取端口中断标志寄存器 + HAL_Delay(10); + for(i=0;iW5500_Class[i].SocketPort, Sn_IR); // 读取Socket0中断标志寄存器 + Write_W5500_SOCK_1Byte(pW5500->W5500_Class[i].SocketPort, Sn_IR, Socket_Flag); + if (Socket_Flag & IR_CON) // 在TCP模式下,Socket0成功连接 + { + pW5500->W5500_Class[i].Run_State |= BSP_W5500_PORT_RUN_STATE_CONN; // 网络连接状态0x02,端口完成连接,可以正常传输数据 + } + if (Socket_Flag & IR_DISCON) // 在TCP模式下Socket断开连接处理 + { + Write_W5500_SOCK_1Byte(pW5500->W5500_Class[i].SocketPort, Sn_CR, CLOSE); // 关闭端口,等待重新打开连接 + bsp_W5500_Socket_Init(&pW5500->W5500_Class[i]); // 指定Socket(0~7)初始化,初始化端口0 + pW5500->W5500_Class[i].Run_State = 0; // 网络连接状态0x00,端口连接失败 + } + if (Socket_Flag & IR_SEND_OK) // Socket0数据发送完成,可以再次启动S_tx_process()函数发送数据 + { + pW5500->W5500_Class[i].TR_Data_State |= BSP_W5500_PORT_DATA_TRANSMITOK; // 端口发送一个数据包完成 + } + if (Socket_Flag & IR_RECV) // Socket接收到数据,可以启动S_rx_process()函数 + { + pW5500->W5500_Class[i].TR_Data_State |= BSP_W5500_PORT_DATA_RECEIVE; // 端口接收到一个数据包 + } + if (Socket_Flag & IR_TIMEOUT) // Socket连接或数据传输超时处理 + { + Write_W5500_SOCK_1Byte(pW5500->W5500_Class[i].SocketPort, Sn_CR, CLOSE); // 关闭端口,等待重新打开连接 + pW5500->W5500_Class[i].TR_Data_State = 0; // 网络连接状态0x00,端口连接失败 + } + } + } + + + if (Read_W5500_1Byte(SIR) != 0) + goto IntDispose; +} + + +void bsp_W5500_Socket_Set(bsp_W5500_Class_t *pW5500_Class) +{ + if (0 == pW5500_Class->Run_State) + { + switch(pW5500_Class->Run_Mode) + { + /*TCP服务器模式*/ + case BSP_W5500_PORT_RUN_MODE_TCP_SERVER: + { + if (Socket_Listen(pW5500_Class->SocketPort) == TRUE) + pW5500_Class->Run_State = BSP_W5500_PORT_RUN_STATE_INIT; + else + pW5500_Class->Run_State = 0; + }break; + /*TCP客户端模式*/ + case BSP_W5500_PORT_RUN_MODE_TCP_CLIENT: + { + if(Socket_Connect(pW5500_Class->SocketPort)==TRUE) + pW5500_Class->Run_State = BSP_W5500_PORT_RUN_STATE_INIT; + else + pW5500_Class->Run_State = 0; + }break; + /*UDP模式*/ + case BSP_W5500_PORT_RUN_MODE_UDP: + { + if(Socket_UDP(pW5500_Class->SocketPort)==TRUE) + pW5500_Class->Run_State = BSP_W5500_PORT_RUN_STATE_INIT | BSP_W5500_PORT_RUN_STATE_CONN; + else + pW5500_Class->Run_State = 0; + }break; + default:break; + } + } +} + +static void bsp_W5500_Init() +{ + u8 i; + W5500_Hardware_Reset(); /*硬件复位W5500*/ + W5500_Init(); /*初始化W5500寄存器函数*/ + Detect_Gateway(); /*检查网关服务器*/ + + for(i=0;iW5500_Class[i]); + pW5500->W5500_Class[i].Run_State = 0; /*复位状态*/ + //bsp_W5500_Socket_Set(&pW5500->W5500_Class[i]); /*W5500端口初始化配置*/ + } +} + +static void bsp_W5500_Task(void) +{ + u8 i; + for(i=0;iW5500_Class[i]); /*W5500端口初始化配置*/ + } + bsp_W5500_Interrupt_Process(); // W5500中断处理程序框架 + + for(i=0;iW5500_Class[i].TR_Data_State & BSP_W5500_PORT_DATA_RECEIVE) == BSP_W5500_PORT_DATA_RECEIVE) // 如果Socket0接收到数据 + { + pW5500->W5500_Class[i].TR_Data_State &= ~BSP_W5500_PORT_DATA_RECEIVE; + u16 Len = Read_SOCK_Data_Buffer(0, pW5500->W5500_Class[i].Rx_Buffer); +// Write_SOCK_Data_Buffer(&pW5500->W5500_Class[i], pW5500->W5500_Class[i].Rx_Buffer, Len); +// printf("RX"); +// Debug_UartSend(pW5500->W5500_Class[i].Rx_Buffer, Len); + if(pW5500->W5500_Class[i].Rx_DataAnalysis != NULL) + { + pW5500->W5500_Class[i].Rx_DataAnalysis(&pW5500->W5500_Class[i],pW5500->W5500_Class[i].Rx_Buffer,Len);/*数据解析*/ + } + } + } +} + diff --git a/calib_board/usr/bsp/bsp_W5500.h b/calib_board/usr/bsp/bsp_W5500.h new file mode 100644 index 0000000..6ef5aee --- /dev/null +++ b/calib_board/usr/bsp/bsp_W5500.h @@ -0,0 +1,322 @@ +#ifndef _W5500_H_ +#define _W5500_H_ + +#include "main.h" + +/***************** Common Register *****************/ +#define MR 0x0000 +#define RST 0x80 +#define WOL 0x20 +#define PB 0x10 +#define PPP 0x08 +#define FARP 0x02 + +#define GAR 0x0001 +#define SUBR 0x0005 +#define SHAR 0x0009 +#define SIPR 0x000f + +#define INTLEVEL 0x0013 +#define IR 0x0015 +#define CONFLICT 0x80 +#define UNREACH 0x40 +#define PPPOE 0x20 +#define MP 0x10 + +#define IMR 0x0016 +#define IM_IR7 0x80 +#define IM_IR6 0x40 +#define IM_IR5 0x20 +#define IM_IR4 0x10 + +#define SIR 0x0017 +#define S7_INT 0x80 +#define S6_INT 0x40 +#define S5_INT 0x20 +#define S4_INT 0x10 +#define S3_INT 0x08 +#define S2_INT 0x04 +#define S1_INT 0x02 +#define S0_INT 0x01 + +#define SIMR 0x0018 +#define S7_IMR 0x80 +#define S6_IMR 0x40 +#define S5_IMR 0x20 +#define S4_IMR 0x10 +#define S3_IMR 0x08 +#define S2_IMR 0x04 +#define S1_IMR 0x02 +#define S0_IMR 0x01 + +#define RTR 0x0019 +#define RCR 0x001b + +#define PTIMER 0x001c +#define PMAGIC 0x001d +#define PHA 0x001e +#define PSID 0x0024 +#define PMRU 0x0026 + +#define UIPR 0x0028 +#define UPORT 0x002c + +#define PHYCFGR 0x002e +#define RST_PHY 0x80 +#define OPMODE 0x40 +#define DPX 0x04 +#define SPD 0x02 +#define LINK 0x01 + +#define VERR 0x0039 + +/********************* Socket Register *******************/ +#define Sn_MR 0x0000 +#define MULTI_MFEN 0x80 +#define BCASTB 0x40 +#define ND_MC_MMB 0x20 +#define UCASTB_MIP6B 0x10 +#define MR_CLOSE 0x00 +#define MR_TCP 0x01 +#define MR_UDP 0x02 +#define MR_MACRAW 0x04 + +#define Sn_CR 0x0001 +#define OPEN 0x01 +#define LISTEN 0x02 +#define CONNECT 0x04 +#define DISCON 0x08 +#define CLOSE 0x10 +#define SEND 0x20 +#define SEND_MAC 0x21 +#define SEND_KEEP 0x22 +#define RECV 0x40 + +#define Sn_IR 0x0002 +#define IR_SEND_OK 0x10 +#define IR_TIMEOUT 0x08 +#define IR_RECV 0x04 +#define IR_DISCON 0x02 +#define IR_CON 0x01 + +#define Sn_SR 0x0003 +#define SOCK_CLOSED 0x00 +#define SOCK_INIT 0x13 +#define SOCK_LISTEN 0x14 +#define SOCK_ESTABLISHED 0x17 +#define SOCK_CLOSE_WAIT 0x1c +#define SOCK_UDP 0x22 +#define SOCK_MACRAW 0x02 + +#define SOCK_SYNSEND 0x15 +#define SOCK_SYNRECV 0x16 +#define SOCK_FIN_WAI 0x18 +#define SOCK_CLOSING 0x1a +#define SOCK_TIME_WAIT 0x1b +#define SOCK_LAST_ACK 0x1d + +#define Sn_PORT 0x0004 +#define Sn_DHAR 0x0006 +#define Sn_DIPR 0x000c +#define Sn_DPORTR 0x0010 + +#define Sn_MSSR 0x0012 +#define Sn_TOS 0x0015 +#define Sn_TTL 0x0016 + +#define Sn_RXBUF_SIZE 0x001e +#define Sn_TXBUF_SIZE 0x001f +#define Sn_TX_FSR 0x0020 +#define Sn_TX_RD 0x0022 +#define Sn_TX_WR 0x0024 +#define Sn_RX_RSR 0x0026 +#define Sn_RX_RD 0x0028 +#define Sn_RX_WR 0x002a + +#define Sn_IMR 0x002c +#define IMR_SENDOK 0x10 +#define IMR_TIMEOUT 0x08 +#define IMR_RECV 0x04 +#define IMR_DISCON 0x02 +#define IMR_CON 0x01 + +#define Sn_FRAG 0x002d +#define Sn_KPALVTR 0x002f + +/*******************************************************************/ +/************************ SPI Control Byte *************************/ +/*******************************************************************/ +/* Operation mode bits */ +#define VDM 0x00 +#define FDM1 0x01 +#define FDM2 0x02 +#define FDM4 0x03 + +/* Read_Write control bit */ +#define RWB_READ 0x00 +#define RWB_WRITE 0x04 + +/* Block select bits */ +#define COMMON_R 0x00 + +/* Socket 0 */ +#define S0_REG 0x08 +#define S0_TX_BUF 0x10 +#define S0_RX_BUF 0x18 + +/* Socket 1 */ +#define S1_REG 0x28 +#define S1_TX_BUF 0x30 +#define S1_RX_BUF 0x38 + +/* Socket 2 */ +#define S2_REG 0x48 +#define S2_TX_BUF 0x50 +#define S2_RX_BUF 0x58 + +/* Socket 3 */ +#define S3_REG 0x68 +#define S3_TX_BUF 0x70 +#define S3_RX_BUF 0x78 + +/* Socket 4 */ +#define S4_REG 0x88 +#define S4_TX_BUF 0x90 + +/* Socket 5 */ +#define S5_REG 0xa8 +#define S5_TX_BUF 0xb0 +#define S5_RX_BUF 0xb8 + +/* Socket 6 */ +#define S6_REG 0xc8 +#define S6_TX_BUF 0xd0 +#define S6_RX_BUF 0xd8 + +/* Socket 7 */ +#define S7_REG 0xe8 +#define S7_TX_BUF 0xf0 +#define S7_RX_BUF 0xf8 + +#define TRUE 0xff +#define FALSE 0x00 + +#define S_RX_SIZE 2048 /*定义Socket接收缓冲区的大小,可以根据W5500_RMSR的设置修改 */ +#define S_TX_SIZE 2048 /*定义Socket发送缓冲区的大小,可以根据W5500_TMSR的设置修改 */ + +/***************----- W5500 GPIO定义 -----***************/ +#define W5500_SCS GPIO_PIN_0 // 定义W5500的CS引脚 +#define W5500_SCS_PORT GPIOB + +#define W5500_RST GPIO_PIN_4 // 定义W5500的RST引脚 +#define W5500_RST_PORT GPIOA + +#define W5500_INT GPIO_PIN_1 // 定义W5500的INT引脚 +#define W5500_INT_PORT GPIOA + +///***************----- 网络参数变量定义 -----***************/ +//extern u8 Gateway_IP[4]; // 网关IP地址 +//extern u8 Sub_Mask[4]; // 子网掩码 +//extern u8 Phy_Addr[6]; // 物理地址(MAC) +//extern u8 IP_Addr[4]; // 本机IP地址 + +//extern u8 S0_Port[2]; // 端口0的端口号(5000) +//extern u8 S0_DIP[4]; // 端口0目的IP地址 +//extern u8 S0_DPort[2]; // 端口0目的端口号(6000) + +//extern u8 UDP_DIPR[4]; // UDP(广播)模式,目的主机IP地址 +//extern u8 UDP_DPORT[2]; // UDP(广播)模式,目的主机端口号 + +///***************----- 端口的运行模式 -----***************/ +//extern u8 S0_Mode; // 端口0的运行模式,0:TCP服务器模式,1:TCP客户端模式,2:UDP(广播)模式 +//#define TCP_SERVER 0x00 // TCP服务器模式 +//#define TCP_CLIENT 0x01 // TCP客户端模式 +//#define UDP_MODE 0x02 // UDP(广播)模式 + +///***************----- 端口的运行状态 -----***************/ +//extern u8 S0_State; // 端口0状态记录,1:端口完成初始化,2端口完成连接(可以正常传输数据) +//#define S_INIT 0x01 // 端口完成初始化 +//#define S_CONN 0x02 // 端口完成连接,可以正常传输数据 + +///***************----- 端口收发数据的状态 -----***************/ +//extern u8 S0_Data; // 端口0接收和发送数据的状态,1:端口接收到数据,2:端口发送数据完成 +//#define S_RECEIVE 0x01 // 端口接收到一个数据包 +//#define S_TRANSMITOK 0x02 // 端口发送一个数据包完成 + +///***************----- 端口数据缓冲区 -----***************/ +//extern u8 Rx_Buffer[2048]; // 端口接收数据缓冲区 +//extern u8 Tx_Buffer[2048]; // 端口发送数据缓冲区 + +//extern u8 W5500_Interrupt; // W5500中断标志(0:无中断,1:有中断) +typedef u8 SOCKET; // 自定义端口号数据类型 + +// extern void Delay(unsigned int d);//延时函数(ms) +//extern void W5500_GPIO_Configuration(void); // W5500 GPIO初始化配置 +//extern void W5500_NVIC_Configuration(void); // W5500 接收引脚中断优先级设置 +//extern void SPI_Configuration(void); // W5500 SPI初始化配置(STM32 SPI1) +//extern void W5500_Hardware_Reset(void); // 硬件复位W5500 +//extern void W5500_Init(void); // 初始化W5500寄存器函数 +//extern u8 Detect_Gateway(void); // 检查网关服务器 +//extern void Socket_Init(SOCKET s); // 指定Socket(0~7)初始化 +//extern u8 Socket_Connect(SOCKET s); // 设置指定Socket(0~7)为客户端与远程服务器连接 +//extern u8 Socket_Listen(SOCKET s); // 设置指定Socket(0~7)作为服务器等待远程主机的连接 +//extern u8 Socket_UDP(SOCKET s); // 设置指定Socket(0~7)为UDP模式 +//extern u16 Read_SOCK_Data_Buffer(SOCKET s, u8 *dat_ptr); // 指定Socket(0~7)接收数据处理 +//extern void Write_SOCK_Data_Buffer(SOCKET s, u8 *dat_ptr, u16 size); // 指定Socket(0~7)发送数据处理 +//extern void W5500_Interrupt_Process(void); // W5500中断处理程序框架 +#define BSP_W5500_PORT_NUM 1 +#define BSP_W5500_DATA_LEN 2048 + + + +typedef struct bsp_W5500_Class_t bsp_W5500_Class_t; + +struct bsp_W5500_Class_t +{ + SOCKET SocketPort; + struct + { + /***************----- 网络参数变量定义 -----***************/ + u8 Gateway_IP[4]; /*网关IP地址*/ + u8 Sub_Mask[4]; /*子网掩码*/ + u8 Phy_Addr[6]; /*物理地址(MAC)*/ + u8 IP_Addr[4]; /*本机IP地址*/ + u8 Port[2]; /*端口0的端口号(5000) */ + u8 DIP[4]; /*端口0目的IP地址*/ + u8 DPort[2]; /*端口0目的端口号(6000)*/ + + u8 UDP_DIPR[4]; /*UDP(广播)模式,目的主机IP地址*/ + u8 UDP_DPORT[2]; /*UDP(广播)模式,目的主机端口号*/ + }ConfigData; + /***************----- 端口的运行模式 -----***************/ + u8 Run_Mode; + /***************----- 端口的运行状态 -----***************/ + u8 Run_State; + /***************----- 端口收发数据的状态 -----***********/ + u8 TR_Data_State; + /***************----- 端口数据缓冲区 -----***************/ + u8 Rx_Buffer[BSP_W5500_DATA_LEN]; // 端口接收数据缓冲区 + u8 Tx_Buffer[BSP_W5500_DATA_LEN]; // 端口发送数据缓冲区 + + u8 Interrupt; // W5500中断标志(0:无中断,1:有中断) + + void (*Rx_DataAnalysis)(bsp_W5500_Class_t *,u8 *,u16 ); +}; + + +typedef struct +{ + u8 Gateway_IP[4]; /*网关IP地址*/ + u8 Sub_Mask[4]; /*子网掩码*/ + u8 Phy_Addr[6]; /*物理地址(MAC)*/ + u8 IP_Addr[4]; /*本机IP地址*/ + bsp_W5500_Class_t W5500_Class[BSP_W5500_PORT_NUM]; /*端口成员*/ + void (*Interrupt_Process)(void); /*处理进程*/ + void (*Init)(void); /*初始化*/ + void (*Task)(void); /*任务*/ + void (*Socket_Send)(bsp_W5500_Class_t *, u8 *, u16 ); /*端口发送数据*/ +}bsp_W5500_t; + + +extern bsp_W5500_t W5500; +#endif diff --git a/calib_board/usr/bsp/bsp_w25q.c b/calib_board/usr/bsp/bsp_w25q.c new file mode 100644 index 0000000..f584937 --- /dev/null +++ b/calib_board/usr/bsp/bsp_w25q.c @@ -0,0 +1,241 @@ +#include "bsp_w25q.h" +#include "spi.h" +#include "main.h" + +/* spi flash 片选引脚 - pb12 */ +#define W25Q32_CS_LOW() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET) +#define W25Q32_CS_HIGH() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET) + +/* spi 传输函数 */ +static void w25q32_spi_transmit(uint8_t *data, uint16_t size) { + HAL_SPI_Transmit(&hspi2, data, size, HAL_MAX_DELAY); +} + +static void w25q32_spi_receive(uint8_t *data, uint16_t size) { + HAL_SPI_Receive(&hspi2, data, size, HAL_MAX_DELAY); +} + +static uint8_t w25q32_spi_transmit_receive(uint8_t data) { + uint8_t rx_data; + HAL_SPI_TransmitReceive(&hspi2, &data, &rx_data, 1, HAL_MAX_DELAY); + return rx_data; +} + +/* 内部函数声明 */ +static void w25q32_init(void); +static void w25q32_read(uint32_t addr, uint8_t *data, uint32_t len); +static void w25q32_write(uint32_t addr, uint8_t *data, uint32_t len); +static void w25q32_chip_erase(void); +static void w25q32_write_enable(void); +static void w25q32_write_disable(void); +static uint8_t w25q32_read_status_reg(void); +static void w25q32_wait_for_write_end(void); +static void w25q32_sector_erase(uint32_t sector_addr); +static void w25q32_block_erase(uint32_t block_addr); +static void w25q32_page_write(uint32_t addr, uint8_t *data, uint16_t len); +static uint8_t w25q32_read_id(void); +static void w25q32_power_down(void); +static void w25q32_wake_up(void); + +/* w25q32 对象实例 */ +w25q32_t w25q32 = { + .init = w25q32_init, + .read = w25q32_read, + .write = w25q32_write, + .chip_erase = w25q32_chip_erase, +}; + + +/* 初始化函数 */ +static void w25q32_init(void) { + W25Q32_CS_HIGH(); /* 初始时片选拉高 */ + w25q32_wake_up(); /* 唤醒芯片 */ +} + +/* 读取芯片id */ +static uint8_t w25q32_read_id(void) { + uint8_t id = 0; + uint8_t cmd = W25Q32_JEDEC_ID; + + W25Q32_CS_LOW(); + w25q32_spi_transmit(&cmd, 1); + w25q32_spi_receive(&id, 1); /* 忽略前两个字节 */ + w25q32_spi_receive(&id, 1); + w25q32_spi_receive(&id, 1); /* 设备id在第三个字节 */ + W25Q32_CS_HIGH(); + + return id; +} + +/* 写使能 */ +static void w25q32_write_enable(void) { + uint8_t cmd = W25Q32_WRITE_ENABLE; + + W25Q32_CS_LOW(); + w25q32_spi_transmit(&cmd, 1); + W25Q32_CS_HIGH(); +} + +/* 写禁止 */ +static void w25q32_write_disable(void) { + uint8_t cmd = W25Q32_WRITE_DISABLE; + + W25Q32_CS_LOW(); + w25q32_spi_transmit(&cmd, 1); + W25Q32_CS_HIGH(); +} + +/* 读取状态寄存器 */ +static uint8_t w25q32_read_status_reg(void) { + uint8_t status; + uint8_t cmd = W25Q32_READ_STATUS_REG1; + + W25Q32_CS_LOW(); + w25q32_spi_transmit(&cmd, 1); + status = w25q32_spi_transmit_receive(0x00); + W25Q32_CS_HIGH(); + + return status; +} + +/* 等待写入完成 */ +static void w25q32_wait_for_write_end(void) { + while (w25q32_read_status_reg() & W25Q32_STATUS_BUSY) { + /* 可添加延时或看门狗喂狗 */ + } +} + +/* 扇区擦除 (4kb) */ +static void w25q32_sector_erase(uint32_t sector_addr) { + uint8_t cmd[4]; + + /* 确保地址是4k对齐 */ + sector_addr &= ~(W25Q32_SECTOR_SIZE - 1); + + w25q32_write_enable(); + + cmd[0] = W25Q32_SECTOR_ERASE; + cmd[1] = (sector_addr >> 16) & 0xFF; + cmd[2] = (sector_addr >> 8) & 0xFF; + cmd[3] = sector_addr & 0xFF; + + W25Q32_CS_LOW(); + w25q32_spi_transmit(cmd, 4); + W25Q32_CS_HIGH(); + + w25q32_wait_for_write_end(); +} + +/* 块擦除 (64kb) */ +static void w25q32_block_erase(uint32_t block_addr) { + uint8_t cmd[4]; + + /* 确保地址是64k对齐 */ + block_addr &= ~(W25Q32_BLOCK_SIZE - 1); + + w25q32_write_enable(); + + cmd[0] = W25Q32_BLOCK_ERASE_64K; + cmd[1] = (block_addr >> 16) & 0xFF; + cmd[2] = (block_addr >> 8) & 0xFF; + cmd[3] = block_addr & 0xFF; + + W25Q32_CS_LOW(); + w25q32_spi_transmit(cmd, 4); + W25Q32_CS_HIGH(); + + w25q32_wait_for_write_end(); +} + +/* 整片擦除 */ +static void w25q32_chip_erase(void) { + uint8_t cmd = W25Q32_CHIP_ERASE; + + w25q32_write_enable(); + + W25Q32_CS_LOW(); + w25q32_spi_transmit(&cmd, 1); + W25Q32_CS_HIGH(); + + w25q32_wait_for_write_end(); +} + +/* 页写入 (最大256字节) */ +static void w25q32_page_write(uint32_t addr, uint8_t *data, uint16_t len) { + uint8_t cmd[4]; + + if (len > W25Q32_PAGE_SIZE) { + len = W25Q32_PAGE_SIZE; + } + + w25q32_write_enable(); + + cmd[0] = W25Q32_PAGE_PROGRAM; + cmd[1] = (addr >> 16) & 0xFF; + cmd[2] = (addr >> 8) & 0xFF; + cmd[3] = addr & 0xFF; + + W25Q32_CS_LOW(); + w25q32_spi_transmit(cmd, 4); + w25q32_spi_transmit(data, len); + W25Q32_CS_HIGH(); + + w25q32_wait_for_write_end(); +} + +/* 任意长度写入 */ +static void w25q32_write(uint32_t addr, uint8_t *data, uint32_t len) { + uint32_t page_remaining; + uint32_t offset = 0; + + while (len > 0) { + /* 计算当前页剩余字节数 */ + page_remaining = W25Q32_PAGE_SIZE - (addr % W25Q32_PAGE_SIZE); + + /* 本次写入的长度 */ + uint32_t write_len = (len < page_remaining) ? len : page_remaining; + + /* 写入一页数据 */ + w25q32_page_write(addr, &data[offset], write_len); + + /* 更新地址和偏移 */ + addr += write_len; + offset += write_len; + len -= write_len; + } +} + +/* 读取数据 */ +static void w25q32_read(uint32_t addr, uint8_t *data, uint32_t len) { + uint8_t cmd[4]; + + cmd[0] = W25Q32_READ_DATA; + cmd[1] = (addr >> 16) & 0xFF; + cmd[2] = (addr >> 8) & 0xFF; + cmd[3] = addr & 0xFF; + + W25Q32_CS_LOW(); + w25q32_spi_transmit(cmd, 4); + w25q32_spi_receive(data, len); + W25Q32_CS_HIGH(); +} + +/* 进入掉电模式 */ +static void w25q32_power_down(void) { + uint8_t cmd = W25Q32_POWER_DOWN; + + W25Q32_CS_LOW(); + w25q32_spi_transmit(&cmd, 1); + W25Q32_CS_HIGH(); +} + +/* 唤醒芯片 */ +static void w25q32_wake_up(void) { + uint8_t cmd = W25Q32_RELEASE_POWER_DOWN; + + W25Q32_CS_LOW(); + w25q32_spi_transmit(&cmd, 1); + W25Q32_CS_HIGH(); + HAL_Delay(5); /* 等待芯片唤醒 */ +} + diff --git a/calib_board/usr/bsp/bsp_w25q.h b/calib_board/usr/bsp/bsp_w25q.h new file mode 100644 index 0000000..a271248 --- /dev/null +++ b/calib_board/usr/bsp/bsp_w25q.h @@ -0,0 +1,57 @@ +#ifndef __BSP_W25Q_H__ +#define __BSP_W25Q_H__ + +#include "main.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* w25q32jvssiq 容量参数 */ +#define W25Q32_FLASH_SIZE (0x400000UL) /* 4mb = 32mb */ +#define W25Q32_PAGE_SIZE (256) /* 页大小 */ +#define W25Q32_SECTOR_SIZE (4096) /* 扇区大小 */ +#define W25Q32_BLOCK_SIZE (65536) /* 块大小 */ + +/* w25q32jvssiq 命令字 */ +#define W25Q32_WRITE_ENABLE 0x06 +#define W25Q32_WRITE_DISABLE 0x04 +#define W25Q32_READ_STATUS_REG1 0x05 +#define W25Q32_WRITE_STATUS_REG 0x01 +#define W25Q32_READ_DATA 0x03 +#define W25Q32_FAST_READ 0x0B +#define W25Q32_PAGE_PROGRAM 0x02 +#define W25Q32_SECTOR_ERASE 0x20 +#define W25Q32_BLOCK_ERASE_32K 0x52 +#define W25Q32_BLOCK_ERASE_64K 0xD8 +#define W25Q32_CHIP_ERASE 0xC7 +#define W25Q32_POWER_DOWN 0xB9 +#define W25Q32_RELEASE_POWER_DOWN 0xAB +#define W25Q32_DEVICE_ID 0xAB +#define W25Q32_MANUFACTURER_ID 0x90 +#define W25Q32_JEDEC_ID 0x9F + +/* 状态寄存器位 */ +#define W25Q32_STATUS_BUSY (1 << 0) +#define W25Q32_STATUS_WRITE_EN (1 << 1) + +/* flash 存储区域 */ +#define W25Q32_USER_DATA_ADDR 0x000000 /* 用户数据存储起始地址 */ +#define W25Q32_USER_DATA_SIZE 0x100000 /* 大约1mb空间用于用户数据 */ + +/* w25q32 对象结构体 */ +typedef struct { + void (*init)(void); + void (*read)(uint32_t addr, uint8_t *data, uint32_t len); + void (*write)(uint32_t addr, uint8_t *data, uint32_t len); + void (*chip_erase)(void); +} w25q32_t; + +/* 全局对象 */ +extern w25q32_t w25q32; + +#ifdef __cplusplus +} +#endif + +#endif /* __BSP_W25Q_H__ */