Skip to main content
RIman.1
Associate
August 8, 2022
Question

Unable to get SPI1 working on NUCLEO-F413ZH without using HAL

  • August 8, 2022
  • 5 replies
  • 1602 views

Hello,

Communication details (for now, the data transfer is only from master to slave):

(i) NUCLEO-F413ZH is the master

(ii) Arduino Uno R3 is the slave.

(iii) DFF is 8 bit

(iv) I want 2-line unidirectional

Using HAL: The SPI communication worked and I was able to print the transferred data on the serial monitor of Arduino IDE.

Without HAL: I don't know what the error is when I configure SPI1 on STM32 NUCLEO-F413ZH using registers. Nothing shows up on the serial monitor.

Please help me identify the error.

The code is as follows:

main.c - Ignore the gpio configuration of USB

#include "main.h"
SPI_HandleTypeDef hspi1;
 
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI1_Init(void);
 
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 */
 uint8_t tx_data = 8;
 uint8_t tx_data2 = 4;
 setupSPI();
 /* USER CODE END 2 */
 
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
 /* USER CODE END WHILE */
//	 HAL_SPI_Transmit(&hspi1, &tx_data2, 1, 100);
	 sendData(tx_data);
	 HAL_GPIO_TogglePin (GPIOB, GPIO_PIN_7);
	 HAL_Delay(2000);
 /* 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};
 
 /** Configure the main internal regulator output voltage
 */
 __HAL_RCC_PWR_CLK_ENABLE();
 __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
 /** 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_DIV2;
 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_16BIT;
 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 */
 
}
 
/**
 * @brief GPIO Initialization Function
 * @param None
 * @retval None
 */
static void MX_GPIO_Init(void)
{
 GPIO_InitTypeDef GPIO_InitStruct = {0};
 
 /* GPIO Ports Clock Enable */
 __HAL_RCC_GPIOC_CLK_ENABLE();
 __HAL_RCC_GPIOH_CLK_ENABLE();
 __HAL_RCC_GPIOA_CLK_ENABLE();
 __HAL_RCC_GPIOB_CLK_ENABLE();
 __HAL_RCC_GPIOD_CLK_ENABLE();
 __HAL_RCC_GPIOG_CLK_ENABLE();
 
 /*Configure GPIO pin Output Level */
 HAL_GPIO_WritePin(GPIOB, LD1_Pin|LD3_Pin|LD2_Pin, GPIO_PIN_RESET);
 
 /*Configure GPIO pin Output Level */
 HAL_GPIO_WritePin(USB_PowerSwitchOn_GPIO_Port, USB_PowerSwitchOn_Pin, GPIO_PIN_RESET);
 
 /*Configure GPIO pin : USER_Btn_Pin */
 GPIO_InitStruct.Pin = USER_Btn_Pin;
 GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 HAL_GPIO_Init(USER_Btn_GPIO_Port, &GPIO_InitStruct);
 
 /*Configure GPIO pins : LD1_Pin LD3_Pin LD2_Pin */
 GPIO_InitStruct.Pin = LD1_Pin|LD3_Pin|LD2_Pin;
 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
 HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
 /*Configure GPIO pins : STLK_RX_Pin STLK_TX_Pin */
 GPIO_InitStruct.Pin = STLK_RX_Pin|STLK_TX_Pin;
 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
 GPIO_InitStruct.Alternate = GPIO_AF7_USART3;
 HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
 
 /*Configure GPIO pin : USB_PowerSwitchOn_Pin */
 GPIO_InitStruct.Pin = USB_PowerSwitchOn_Pin;
 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
 HAL_GPIO_Init(USB_PowerSwitchOn_GPIO_Port, &GPIO_InitStruct);
 
 /*Configure GPIO pin : USB_OverCurrent_Pin */
 GPIO_InitStruct.Pin = USB_OverCurrent_Pin;
 GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 HAL_GPIO_Init(USB_OverCurrent_GPIO_Port, &GPIO_InitStruct);
 
 /*Configure GPIO pins : USB_SOF_Pin USB_ID_Pin USB_DM_Pin USB_DP_Pin */
 GPIO_InitStruct.Pin = USB_SOF_Pin|USB_ID_Pin|USB_DM_Pin|USB_DP_Pin;
 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
 GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
}
 
/* 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 */
 

spi_test.h

// Define to prevent recursive inclusion
#ifndef __SPI_TEST_H
#define __SPI_TEST_H
 
/* This code tests SPI1. */
 
// Configuration functions
void setupSPI(void);
void sendData(uint8_t data);	// Using 8-bit data format
 
 
#endif // __SPI_TEST_H

spi_test.c

#include "stm32f413xx.h"
#include "stm32f4xx_hal.h"
#include "spi_test.h"
 
void setupSPI(){
 
	//	Resets SPI1 in peripheral reset register 2
//	RCC->APB2RSTR |= RCC_APB2RSTR_SPI1RST;
 
	/* Configuring port A GPIO */
	RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;	// Enables GPIOA clock for SPI1
	RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;		//	Enables SPI1 clock
 
	// Enabling GPIO pins -- Pins PA5 (SPI1_SCK), PA6 (SPI1_MISO), PA7 (SPI1_MOSI) and PD14 (SPI1_CS)
	GPIOA->MODER &= ~(GPIO_MODER_MODER5 | GPIO_MODER_MODER6 | GPIO_MODER_MODER7);	// Clears the MODER5, MODER6 and MODER7 bits in GPIOA_MODER register
	GPIOA->MODER |= GPIO_MODER_MODER5_1 | GPIO_MODER_MODER6_1 | GPIO_MODER_MODER7_1;// Sets the MODER bits to alternate functions
	GPIOA->AFR[0] |= GPIO_AFRL_AFRL5_0 | GPIO_AFRL_AFRL5_2;	// Sets alternate function 5 or 0101 i.e. bits 0 and 2 are high in AFRL register
 
	/* Configure SPI -- SPI_CR1 and SPI_CR2 registers */
	// Data frame format (DFF) bit in SPI1_CR1 register is 0 as 8-bit data format is used
	SPI1->CR1 |= SPI_CR1_SSM | (0x02UL << SPI_CR1_BR_Pos) | SPI_CR1_MSTR;
	SPI1->CR2 |= SPI_CR2_SSOE;
	SPI1->CR1 |= SPI_CR1_SPE;	// Enables the SPI bit in SPI1_CR1 register
 
 
}
 
void sendData(uint8_t data){
 
//	SPI1->DR |= data
//	HAL_GPIO_TogglePin (GPIOB, GPIO_PIN_7);
//	while ((SPI1->SR & SPI_SR_TXE) != SPI_SR_TXE);
//	HAL_GPIO_TogglePin (GPIOB, GPIO_PIN_14);
	while ((SPI1->SR & SPI_SR_TXE) == SPI_SR_TXE)
	{
		// Checks whether tx buffer is empty. Sending data stops when tx buffer is empty
		// (read reference manual pg-953 if confused)
		SPI1->DR |= data;
		HAL_GPIO_TogglePin (GPIOB, GPIO_PIN_7);
	}
	if ((SPI1->SR & SPI_SR_BSY) == SPI_SR_BSY)
	{
		HAL_GPIO_TogglePin (GPIOB, GPIO_PIN_14);
	}
}

This topic has been closed for replies.

5 replies

Tesla DeLorean
Guru
August 8, 2022

The joys of register level, you've really got to own the debug.

You'll want to dissect the HAL implementation, and the registers along the way.

SPI1->DR |= data; // Pretty sure this is not kosher, different registers, and not memory

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
S.Ma
Principal
August 8, 2022

I would start with 4 wire full duplex mode, even if not all spi signals are going to a gpio.

waclawek.jan
Super User
August 8, 2022

Every time you are in doubt, start with reading out the registers and checking what's in them.

> GPIOA->AFR[0] |= GPIO_AFRL_AFRL5_0 | GPIO_AFRL_AFRL5_2; // Sets alternate function 5 or 0101 i.e. bits 0 and 2 are high in AFRL register

That's for PA5. PA6 and PA7 remained set to AF0.

> SPI1->DR |= data; // Pretty sure this is not kosher, different registers, and not memory

+1

Also, get an oscilloscope, or at least a cheap logic analyzer.

JW

RIman.1
RIman.1Author
Associate
August 10, 2022

Hello,

Thanks a lot for replying.

I made the changes but the Arduino still outputs garbage values on the serial monitor.

main.c

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 */
 uint8_t tx_data = 8;
 uint8_t tx_data2 = 4;
 setupSPI();
 /* USER CODE END 2 */
 
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
 /* USER CODE END WHILE */
//	 HAL_SPI_Transmit(&hspi1, &tx_data2, 1, 100);
	 sendData(tx_data2);
	 HAL_GPIO_TogglePin (GPIOB, GPIO_PIN_7);
	 HAL_Delay(2000);
 /* 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};
 
 /** Configure the main internal regulator output voltage
 */
 __HAL_RCC_PWR_CLK_ENABLE();
 __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
 /** 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_DIV2;
 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_16BIT;
 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 */
 
}
 
/**
 * @brief GPIO Initialization Function
 * @param None
 * @retval None
 */
static void MX_GPIO_Init(void)
{
 GPIO_InitTypeDef GPIO_InitStruct = {0};
 
 /* GPIO Ports Clock Enable */
 __HAL_RCC_GPIOC_CLK_ENABLE();
 __HAL_RCC_GPIOH_CLK_ENABLE();
 __HAL_RCC_GPIOA_CLK_ENABLE();
 __HAL_RCC_GPIOB_CLK_ENABLE();
 __HAL_RCC_GPIOD_CLK_ENABLE();
 __HAL_RCC_GPIOG_CLK_ENABLE();
 
 /*Configure GPIO pin Output Level */
 HAL_GPIO_WritePin(GPIOB, LD1_Pin|LD3_Pin|LD2_Pin, GPIO_PIN_RESET);
 
 /*Configure GPIO pin Output Level */
 HAL_GPIO_WritePin(USB_PowerSwitchOn_GPIO_Port, USB_PowerSwitchOn_Pin, GPIO_PIN_RESET);
 
 /*Configure GPIO pin : USER_Btn_Pin */
 GPIO_InitStruct.Pin = USER_Btn_Pin;
 GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 HAL_GPIO_Init(USER_Btn_GPIO_Port, &GPIO_InitStruct);
 
 /*Configure GPIO pins : LD1_Pin LD3_Pin LD2_Pin */
 GPIO_InitStruct.Pin = LD1_Pin|LD3_Pin|LD2_Pin;
 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
 HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
 /*Configure GPIO pins : STLK_RX_Pin STLK_TX_Pin */
 GPIO_InitStruct.Pin = STLK_RX_Pin|STLK_TX_Pin;
 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
 GPIO_InitStruct.Alternate = GPIO_AF7_USART3;
 HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
 
 /*Configure GPIO pin : USB_PowerSwitchOn_Pin */
 GPIO_InitStruct.Pin = USB_PowerSwitchOn_Pin;
 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
 HAL_GPIO_Init(USB_PowerSwitchOn_GPIO_Port, &GPIO_InitStruct);
 
 /*Configure GPIO pin : USB_OverCurrent_Pin */
 GPIO_InitStruct.Pin = USB_OverCurrent_Pin;
 GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 HAL_GPIO_Init(USB_OverCurrent_GPIO_Port, &GPIO_InitStruct);
 
 /*Configure GPIO pins : USB_SOF_Pin USB_ID_Pin USB_DM_Pin USB_DP_Pin */
 GPIO_InitStruct.Pin = USB_SOF_Pin|USB_ID_Pin|USB_DM_Pin|USB_DP_Pin;
 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
 GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
}
 
/* 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 */
 

spi_test.c

#include "stm32f413xx.h"
#include "stm32f4xx_hal.h"
#include "spi_test.h"
 
void setupSPI(){
 
	//	Resets SPI1 in peripheral reset register 2
//	RCC->APB2RSTR |= RCC_APB2RSTR_SPI1RST;
 
	/* Configuring port A GPIO */
	RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;	// Enables GPIOA clock for SPI1
	RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;		//	Enables SPI1 clock
 
	// Enabling GPIO pins -- Pins PA5 (SPI1_SCK), PA6 (SPI1_MISO), PA7 (SPI1_MOSI) and PD14 (SPI1_CS)
	GPIOA->MODER &= ~(GPIO_MODER_MODER5 | GPIO_MODER_MODER6 | GPIO_MODER_MODER7);	// Clears the MODER5, MODER6 and MODER7 bits in GPIOA_MODER register
	GPIOA->MODER |= GPIO_MODER_MODER5_1 | GPIO_MODER_MODER6_1 | GPIO_MODER_MODER7_1;// Sets the MODER bits to alternate functions
	GPIOA->AFR[0] |= GPIO_AFRL_AFRL5_0 | GPIO_AFRL_AFRL5_2 |
			GPIO_AFRL_AFRL6_0 | GPIO_AFRL_AFRL6_2 | GPIO_AFRL_AFRL7_0 | GPIO_AFRL_AFRL7_2;	// Sets alternate function 5 or 0101 i.e. bits 0 and 2 are high in AFRL register
	GPIOA->OTYPER &= (GPIO_OTYPER_OT_5 | GPIO_OTYPER_OT_6 | GPIO_OTYPER_OT_7);	// Sets pins 5, 6 and 7 in output type register to push-pull state
	GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR5 | GPIO_OSPEEDER_OSPEEDR6
			| GPIO_OSPEEDER_OSPEEDR7; // Output speed register is set to high speed
	GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPD5 | GPIO_PUPDR_PUPD6 | GPIO_PUPDR_PUPD7); // No pull-up/pull-down
 
 
	/* Configure SPI -- SPI_CR1 and SPI_CR2 registers */
	// Data frame format (DFF) bit in SPI1_CR1 register is 0 as 8-bit data format is used
	// Clock polarity is set to 0: '0' when idle
	// Clock phase is set to 0 where the first clock transition is the first data capture edge
	SPI1->CR1 |= SPI_CR1_SSM | (0x05UL << SPI_CR1_BR_Pos) | SPI_CR1_MSTR | (~SPI_CR1_CPOL) | (~SPI_CR1_CPHA);
	SPI1->CR2 |= SPI_CR2_SSOE;
	SPI1->CR1 |= SPI_CR1_SPE;	// Enables the SPI bit in SPI1_CR1 register
 
}
 
void sendData(uint8_t data){
 
	while (!(SPI1->SR & SPI_SR_TXE));
	SPI1->DR = data;
	HAL_GPIO_TogglePin (GPIOB, GPIO_PIN_14);
}

Right now, I don't have access to oscilloscope and logic analyzer. Will purchase one as soon as possible.:grinning_face_with_sweat:

gbm
Lead III
August 9, 2022

This will cause errors:

while ((SPI1->SR & SPI_SR_TXE) == SPI_SR_TXE)

Should be:

while (!(SPI1->SR & SPI_SR_TXE)) ;

SPI1->DR = data;

while (!(SPI1->SR & SPI_SR_RXNE)) ;

data = SPI1->DR;

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
waclawek.jan
Super User
August 9, 2022

> This will cause errors

Indeed. Sometimes it's hard to gather that "is empty" is in fact the flag being nonzero.

> if ((SPI1->SR & SPI_SR_BSY) == SPI_SR_BSY)

is suspicious, too, what was the intention? Btw. I generally recommend against using BSY, unless proven innocent in given STM32.

JW

RIman.1
RIman.1Author
Associate
August 10, 2022

I was trying to experiment with the SPI_SR_BSY flag as it failed with the SPI_SR_TXE flag. Failed in both cases.