Getting Started and Peripheral Coding STM32 MCU's STM32F1 Tech

Overview

So, in this blog we will be covering another alternate functionality of GPIO pins i.e SPI (Serial Peripheral Interface). Previously we hve covered following peripherals implementation in STM32F103 MCU’s.

  1. ADC(Analog To Digital Converter) in STM32F103
  2. UART Peripheral in STM32F103
  3. GPIO Peripheral in S32K144 MCU
  4. Clock Peripheral in STM32F103
  5. PWM on STM32F103

SPI is a synchronous and full duplex communication between a master and several slave devices. It is used in devices or sensors in which speed is a priority . It operates at data transmission rate 8 Mbits or more. The protocol uses 3 or usually 4 wires for data transmission and receiver .It is used by various sensors and modules such as OLED Display, BMP280 , RC522 , DAC , Shift Registers etc.

SPI Theory

The SPI uses 2 pins for data transfer SDIN and SDO , SCLK clock for synchronization of data transfer between 2 chips, CE chip select that is used to initiate and terminate the data transfer.

SDI  =  MOSI

SDO  =  MISO

SCLK  =  SCK

CE  =  SS

Besides SPI communication the SPI interface can switch between I2S communication protocol that is a synchronous serial communication interface. It supports 4 audio standards including the I2S Philips standard, the MSB- and LSB-justified standards, and the PCM standard. The operating modes can be full duplex(4 wires) and half duplex (6 wires)

Multi Mode Configuration

Multiple subnodes can be used with a single SPI main. The subnodes can be connected in regular mode or daisy-chain mode.

 

How Data is Transmitted in SPI

 

SPI Peripheral Bus Modes

Before discussing about the various bus modes we will be discussing the clock phase and polarity i.e CPOL:Clock Polarity and CPHA:Clock Phase and it is the combination of CPOL and CPHA that is referred to as Bus Modes.

CPOL = 0 

  • Active state of clock = 1
  • Idle state of clock= 0
  • Means the sampling on the first edge
  •      CPHA = 0 – Data is captured on the rising edge and output on falling edge
  •      CPHA = 1 – Data is captured on the falling edge and output on the rising edge

      

CPOL = 1

  • Active state of clock = 0
  • Idle state of clock = 1
  • Means sampling is on the second edge

 

  •        CPHA = 0 – Data is captured on the falling edge and output on rising edge
  •        CPHA = 1 – Data is captured on the rising edge and output on the falling edge

SPI Features in STM32F103

SPI Instances in STM32F103

SPI instances vary from microcontroller to microcontroller from 1 in stmf103c6t6a to 6 in stm32f7 each having different pins NSS pulse mode , TI mode and hardware crc calculations

SPI1 features PA5 as SCK , PA6 as MOSI  and PA7 as MISO

SPI2 features PB3 as SCK, PB4 as MISO and PB5 as MOSI. 

NSS Management in SPI protocol for STM32F103

NSS line can to be driven via 2 modes

  • Software Mode- SS is driven internally by firmware
  • Hardware Mode – A dedicated GPIO pin is used to drive the SS line

Also NSS features NSS output and output disabled mode. Output mode is used only when device operates in master mode and it is disabled allowing mutli master capability

NSS hardware mode must be used in TI mode . CPHA and CPOL are forced to conform to Texas Instrument (TI) protocol requirements. In this NSS signal pulses at the end of every transmitted byte

APPLICATIONS OF SPI PROTOCOL

RFID Module interfacing with STM32F103
W25Q SPI Flash Memory
ST77389 LCD Display with STM32F103
NRF24L01 RF Module with STM32F103

How to Configure SPI Peripheral for STM32F103

We would be using STM32 HAL and STM32CubeIDE for using the SPI peripheral in STM32F103 in this blog tutorial series.

CONFIGURATION IN STM32CUBEIDE

FIG 1- Selecting MOSI, MISO , SS and SCK pins

FIG2 – Selecting the operating mode

FIG3 – Configuring the parameters 

 

SPI Data Handling API Types

SDK Files

The hal.c contains all the macros and function declaration of the GPIO pins the clock configuration and the alternate function mapping of the GPIO pins.The SPI.C function has the declaration and initialization of the SPI function including various parameters , static function and SPI INIT Function . The SPI function contains various macros that establish the various values the functions in SPI.c files functions can attain it includes structure parameters and enumerations.

 

HAL APIs Involved

FUNCTION NAME

HAL_StatusTypeDef HAL_SPI_Init (SPI_HandleTypeDef * hspi) 

FUNCTION DESCRIPTION

This function initializes the SPI peripheral according to the parameters and intialize the handle typedef

PARAMETERS

hspi: pointer to a SPI_HandleTypeDef structure that contains the configuration information for SPI module.

RETURN VALUES

HAL-STATUS

FOR EXAMPLE

				
					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));
  /* TI mode is not supported on this device.
     TIMode parameter is mandatory equal to SPI_TIMODE_DISABLE */
  assert_param(IS_SPI_TIMODE(hspi->Init.TIMode));
				
			

FUNCTION NAME

void HAL_SPI_MspInit (SPI_HandleTypeDef * hspi)

FUNCTION DESCRIPTION

This function initializes the Msp of SPI 

PARAMETERS

hspi: pointer to a SPI_HandleTypeDef structure that contains the configuration information for SPI module.

RETURN VALUES

NONE

FUNCTION NAME

HAL_StatusTypeDef HAL_SPI_Transmit (SPI_HandleTypeDef * hspi, uint8_t * pData, uint16_t Size, uint32_t Timeout)

FUNCTION DESCRIPTION

This function transmits certain amount of data in blocking mode

PARAMETERS

  • hspi: pointer to a SPI_HandleTypeDef structure that contains the configuration information for SPI module.
  •  pData: pointer to data buffer 
  • Size: amount of data to be sent 
  •  Timeout: Timeout duration 

RETURN VALUES

HAL-STATUS

				
					MX_GPIO_Init();
  MX_SPI1_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */
HAL_SPI_Transmit(&hspi1,tx_buffer,10,100);
				
			

FUNCTION NAME

HAL_StatusTypeDef HAL_SPI_TransmitReceive (SPI_HandleTypeDef * hspi, uint8_t * pData, uint16_t Size, uint32_t Timeout)

FUNCTION DESCRIPTION

This function is used to both transmit as well receive certain amount of data in blocking mode

PARAMETERS

  •  hspi: pointer to a SPI_HandleTypeDef structure that contains the configuration information for SPI module.
  •  pTxData: pointer to transmission data buffer
  •   pRxData: pointer to reception data buffer 
  •  Size: amount of data to be sent and received 
  •  Timeout: Timeout duration

RETURN VALUES

HAL-STATUS

				
					HAL_SPI_TransmitReceive(&hspi1,tx_buffer,rx_buffer,10,100);

				
			

FUNCTION NAME

static void MX_SPI1_Init(void)

FUNCTION DESCRIPTION

This function is used to intialize the SPI1 along with the parameters

PARAMETERS

NONE

RETURN VALUES

NONE

				
					static 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 */
  /* SPI1 parameter configuration*/
  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_8;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 10;

				
			

CODE

EXERCISE- Transmit data in TX buffer and receive it in the RX buffer

				
					#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
SPI_HandleTypeDef hspi1;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI1_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */
uint8_t tx_buffer[10]= {10,20,30,40,50,60,70,80,90,100};
uint8_t rx_buffer[10];
/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_SPI1_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */
  HAL_SPI_TransmitReceive(&hspi1,tx_buffer,rx_buffer,10,100);
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief SPI1 Initialization Function
  * @param None
  * @retval None
  */
static 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 */
  /* SPI1 parameter configuration*/
  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_8;
  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 */

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_SET);

  /*Configure GPIO pin : SPI_CS_Pin */
  GPIO_InitStruct.Pin = SPI_CS_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(SPI_CS_GPIO_Port, &GPIO_InitStruct);

/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

				
			
Kunal Gupta
Author: Kunal Gupta

Author

Kunal Gupta

Leave a comment

Stay Updated With Us

Error: Contact form not found.

      Blog