Skip to main content
RIman.1
Associate
Aug 8, 2022 5:25 PM UTC
Question

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

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.

7 replies

Tesla DeLorean
Guru
Aug 8, 2022 5:32 PM UTC

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 Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
S.Ma
Principal
Aug 8, 2022 5:46 PM UTC

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

waclawek.jan
Super User
Aug 8, 2022 7:14 PM UTC

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
Aug 10, 2022 5:16 PM UTC

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
Super User
Aug 9, 2022 7:42 AM UTC

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
Aug 9, 2022 9:04 AM UTC

> 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
Aug 10, 2022 5:18 PM UTC

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