254 lines
8.3 KiB
C
254 lines
8.3 KiB
C
/* USER CODE BEGIN Header */
|
|
/**
|
|
******************************************************************************
|
|
* @file : hal_stm32f4_spi.c
|
|
* @brief : STM32F4 specific SPI HAL implementation
|
|
******************************************************************************
|
|
*/
|
|
/* USER CODE END Header */
|
|
|
|
#include "hal.h"
|
|
#include "hal_spi.h"
|
|
#include "hal_stm32f4_spi.h"
|
|
#include "stm32f4xx_hal.h"
|
|
#include "stm32f4xx_hal_spi.h"
|
|
#include <stdbool.h>
|
|
|
|
/* SPI handles */
|
|
static SPI_HandleTypeDef hspi1;
|
|
static SPI_HandleTypeDef hspi2;
|
|
static SPI_HandleTypeDef hspi3;
|
|
static SPI_HandleTypeDef hspi4;
|
|
static SPI_HandleTypeDef hspi5;
|
|
static SPI_HandleTypeDef hspi6;
|
|
|
|
/**
|
|
* @brief Get SPI handle based on instance
|
|
* @param instance SPI instance identifier
|
|
* @return Pointer to SPI handle
|
|
*/
|
|
static SPI_HandleTypeDef* get_spi_handle(hal_spi_instance_t instance) {
|
|
switch (instance) {
|
|
case HAL_SPI_INSTANCE_1:
|
|
return &hspi1;
|
|
case HAL_SPI_INSTANCE_2:
|
|
return &hspi2;
|
|
case HAL_SPI_INSTANCE_3:
|
|
return &hspi3;
|
|
case HAL_SPI_INSTANCE_4:
|
|
return &hspi4;
|
|
case HAL_SPI_INSTANCE_5:
|
|
return &hspi5;
|
|
case HAL_SPI_INSTANCE_6:
|
|
return &hspi6;
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief STM32F4 specific SPI initialization
|
|
* @param instance SPI instance identifier
|
|
* @param config SPI configuration structure
|
|
* @return true if initialization is successful, false otherwise
|
|
*/
|
|
bool hal_stm32f4_spi_init(hal_spi_instance_t instance, const hal_spi_config_t *config) {
|
|
if (config == NULL) {
|
|
return false;
|
|
}
|
|
|
|
SPI_HandleTypeDef* hspi = get_spi_handle(instance);
|
|
if (hspi == NULL) {
|
|
return false;
|
|
}
|
|
|
|
/* Configure SPI parameters */
|
|
hspi->Instance = NULL;
|
|
hspi->Init.Mode = (config->mode == HAL_SPI_MODE_MASTER) ? SPI_MODE_MASTER : SPI_MODE_SLAVE;
|
|
hspi->Init.DataSize = (config->databits == HAL_SPI_DATABITS_8) ? SPI_DATASIZE_8BIT : SPI_DATASIZE_16BIT;
|
|
hspi->Init.CLKPolarity = (config->polarity == HAL_SPI_POLARITY_LOW) ? SPI_POLARITY_LOW : SPI_POLARITY_HIGH;
|
|
hspi->Init.CLKPhase = (config->phase == HAL_SPI_PHASE_1EDGE) ? SPI_PHASE_1EDGE : SPI_PHASE_2EDGE;
|
|
hspi->Init.NSS = SPI_NSS_SOFT; /* Use software NSS */
|
|
|
|
/* Calculate baud rate prescaler based on desired baud rate */
|
|
uint32_t apb_clock = HAL_RCC_GetPCLK2Freq(); /* Assume SPI1 is on APB2 */
|
|
uint32_t prescaler = 0;
|
|
uint32_t temp_prescaler = 2;
|
|
|
|
while (apb_clock / temp_prescaler > config->baudrate) {
|
|
temp_prescaler <<= 1;
|
|
prescaler++;
|
|
}
|
|
|
|
hspi->Init.BaudRatePrescaler = (uint32_t)temp_prescaler;
|
|
hspi->Init.FirstBit = SPI_FIRSTBIT_MSB; /* Default to MSB first */
|
|
hspi->Init.TIMode = SPI_TIMODE_DISABLE;
|
|
hspi->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
|
|
hspi->Init.CRCPolynomial = 10;
|
|
|
|
/* Configure GPIO and enable clocks based on instance */
|
|
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
|
|
|
switch (instance) {
|
|
case HAL_SPI_INSTANCE_1:
|
|
/* Enable SPI1 clock */
|
|
__HAL_RCC_SPI1_CLK_ENABLE();
|
|
|
|
/* Enable GPIOB clock */
|
|
__HAL_RCC_GPIOB_CLK_ENABLE();
|
|
|
|
/* Configure SPI1 GPIO pins: SCK(PB3), MISO(PB4), MOSI(PB5) */
|
|
GPIO_InitStruct.Pin = GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5;
|
|
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
|
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
|
|
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
|
|
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
|
|
|
hspi->Instance = SPI1;
|
|
break;
|
|
|
|
case HAL_SPI_INSTANCE_2:
|
|
/* Enable SPI2 clock */
|
|
__HAL_RCC_SPI2_CLK_ENABLE();
|
|
|
|
/* Enable GPIOB clock */
|
|
__HAL_RCC_GPIOB_CLK_ENABLE();
|
|
|
|
/* Configure SPI2 GPIO pins: SCK(PB13), MISO(PB14), MOSI(PB15) */
|
|
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_HIGH;
|
|
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
|
|
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
|
|
|
hspi->Instance = SPI2;
|
|
break;
|
|
|
|
case HAL_SPI_INSTANCE_3:
|
|
/* Enable SPI3 clock */
|
|
__HAL_RCC_SPI3_CLK_ENABLE();
|
|
|
|
/* Enable GPIOC clock */
|
|
__HAL_RCC_GPIOC_CLK_ENABLE();
|
|
|
|
/* Configure SPI3 GPIO pins: SCK(PC10), MISO(PC11), MOSI(PC12) */
|
|
GPIO_InitStruct.Pin = GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12;
|
|
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
|
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
|
|
GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
|
|
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
|
|
|
hspi->Instance = SPI3;
|
|
break;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
/* Initialize SPI */
|
|
if (HAL_SPI_Init(hspi) != HAL_OK) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @brief STM32F4 specific SPI deinitialization
|
|
* @param instance SPI instance identifier
|
|
* @return true if deinitialization is successful, false otherwise
|
|
*/
|
|
bool hal_stm32f4_spi_deinit(hal_spi_instance_t instance) {
|
|
SPI_HandleTypeDef* hspi = get_spi_handle(instance);
|
|
if (hspi == NULL || hspi->Instance == NULL) {
|
|
return false;
|
|
}
|
|
|
|
if (HAL_SPI_DeInit(hspi) != HAL_OK) {
|
|
return false;
|
|
}
|
|
|
|
/* Disable SPI clock */
|
|
switch (instance) {
|
|
case HAL_SPI_INSTANCE_1:
|
|
__HAL_RCC_SPI1_CLK_DISABLE();
|
|
break;
|
|
case HAL_SPI_INSTANCE_2:
|
|
__HAL_RCC_SPI2_CLK_DISABLE();
|
|
break;
|
|
case HAL_SPI_INSTANCE_3:
|
|
__HAL_RCC_SPI3_CLK_DISABLE();
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @brief STM32F4 specific SPI transmit implementation
|
|
* @param instance SPI instance identifier
|
|
* @param p_data Pointer to data buffer to transmit
|
|
* @param size Size of data to transmit
|
|
* @return true if transmission is successful, false otherwise
|
|
*/
|
|
bool hal_stm32f4_spi_transmit(hal_spi_instance_t instance, const uint8_t *p_data, uint16_t size) {
|
|
if (p_data == NULL || size == 0) {
|
|
return false;
|
|
}
|
|
|
|
SPI_HandleTypeDef* hspi = get_spi_handle(instance);
|
|
if (hspi == NULL || hspi->Instance == NULL) {
|
|
return false;
|
|
}
|
|
|
|
HAL_StatusTypeDef status = HAL_SPI_Transmit(hspi, (uint8_t*)p_data, size, HAL_MAX_DELAY);
|
|
return (status == HAL_OK);
|
|
}
|
|
|
|
/**
|
|
* @brief STM32F4 specific SPI receive implementation
|
|
* @param instance SPI instance identifier
|
|
* @param p_data Pointer to data buffer to receive
|
|
* @param size Size of data to receive
|
|
* @return true if reception is successful, false otherwise
|
|
*/
|
|
bool hal_stm32f4_spi_receive(hal_spi_instance_t instance, uint8_t *p_data, uint16_t size) {
|
|
if (p_data == NULL || size == 0) {
|
|
return false;
|
|
}
|
|
|
|
SPI_HandleTypeDef* hspi = get_spi_handle(instance);
|
|
if (hspi == NULL || hspi->Instance == NULL) {
|
|
return false;
|
|
}
|
|
|
|
HAL_StatusTypeDef status = HAL_SPI_Receive(hspi, p_data, size, HAL_MAX_DELAY);
|
|
return (status == HAL_OK);
|
|
}
|
|
|
|
/**
|
|
* @brief STM32F4 specific SPI transmit and receive implementation
|
|
* @param instance SPI instance identifier
|
|
* @param p_tx_data Pointer to data buffer to transmit
|
|
* @param p_rx_data Pointer to data buffer to receive
|
|
* @param size Size of data to transmit/receive
|
|
* @return true if transmission and reception are successful, false otherwise
|
|
*/
|
|
bool hal_stm32f4_spi_transmit_receive(hal_spi_instance_t instance, const uint8_t *p_tx_data, uint8_t *p_rx_data, uint16_t size) {
|
|
if (p_tx_data == NULL || p_rx_data == NULL || size == 0) {
|
|
return false;
|
|
}
|
|
|
|
SPI_HandleTypeDef* hspi = get_spi_handle(instance);
|
|
if (hspi == NULL || hspi->Instance == NULL) {
|
|
return false;
|
|
}
|
|
|
|
HAL_StatusTypeDef status = HAL_SPI_TransmitReceive(hspi, (uint8_t*)p_tx_data, p_rx_data, size, HAL_MAX_DELAY);
|
|
return (status == HAL_OK);
|
|
} |