I am testing out SPI communication between two STM32F429ZI DISC 1 boards. I downloaded the example codes for my board from STs website and it works. User has to press a button in Master board to initiate communication. But if I change the polarity to LOW communication fails (polarity is HIGH in downloaded code)
SpiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;
Code is written using CubeMX HAL and uses software slave select.
Original program sends long string and SPI speed was high. So in order to debug, I'm only sending "abc" and speed reduced to 1 MHz. Boards are connected using small jumper cables.
/**
******************************************************************************
* @file SPI/SPI_FullDuplex_ComPolling/Src/main.c
* @author MCD Application Team
* @brief This sample code shows how to use STM32F4xx SPI HAL API to transmit
* and receive a data buffer with a communication process based on
* Polling transfer.
* The communication is done using 2 Boards.
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/** @addtogroup STM32F4xx_HAL_Examples
* @{
*/
/** @addtogroup SPI_FullDuplex_ComPolling
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Uncomment this line to use the board as master, if not it is used as slave */
//#define MASTER_BOARD
/* Private variables ---------------------------------------------------------*/
/* SPI handler declaration */
SPI_HandleTypeDef SpiHandle;
/* Buffer used for transmission */
uint8_t aTxBuffer[] = "abc";
/* Buffer used for reception */
uint8_t aRxBuffer[BUFFERSIZE];
/* Private function prototypes -----------------------------------------------*/
static void SystemClock_Config(void);
static void Error_Handler(void);
static void Timeout_Error_Handler(void);
static uint16_t Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength);
/* Private functions ---------------------------------------------------------*/
/**
* @brief Main program
* @param None
* @retval None
*/
int main(void)
{
/* STM32F4xx HAL library initialization:
- Configure the Flash prefetch, instruction and Data caches
- Configure the Systick to generate an interrupt each 1 msec
- Set NVIC Group Priority to 4
- Global MSP (MCU Support Package) initialization
*/
HAL_Init();
/* Configure LED3 and LED4 */
BSP_LED_Init(LED3);
BSP_LED_Init(LED4);
/* Configure the system clock to 180 MHz */
//SystemClock_Config();
/*##-1- Configure the SPI peripheral #######################################*/
/* Set the SPI parameters */
SpiHandle.Instance = SPIx;
SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
SpiHandle.Init.Direction = SPI_DIRECTION_2LINES;
SpiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;
SpiHandle.Init.CLKPolarity = SPI_POLARITY_HIGH;
SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
SpiHandle.Init.CRCPolynomial = 7;
SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;
SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;
SpiHandle.Init.NSS = SPI_NSS_SOFT;
SpiHandle.Init.TIMode = SPI_TIMODE_DISABLE;
#ifdef MASTER_BOARD
SpiHandle.Init.Mode = SPI_MODE_MASTER;
#else
SpiHandle.Init.Mode = SPI_MODE_SLAVE;
#endif /* MASTER_BOARD */
if(HAL_SPI_Init(&SpiHandle) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
#ifdef MASTER_BOARD
/* Configure USER Button */
BSP_PB_Init(BUTTON_KEY, BUTTON_MODE_GPIO);
/* Wait for USER Button press before starting the Communication */
while (BSP_PB_GetState(BUTTON_KEY) != 1)
{
BSP_LED_Toggle(LED3);
HAL_Delay(40);
}
BSP_LED_Off(LED3);
#endif /* MASTER_BOARD */
/*##-2- Start the Full Duplex Communication process ########################*/
/* While the SPI in TransmitReceive process, user can transmit data through
"aTxBuffer" buffer & receive data through "aRxBuffer" */
/* Timeout is set to 5s */
switch(HAL_SPI_TransmitReceive(&SpiHandle, (uint8_t*)aTxBuffer, (uint8_t *)aRxBuffer, BUFFERSIZE, 5000))
{
case HAL_OK:
/* Communication is completed_____________________________________________*/
/* Compare the sent and received buffers */
if(Buffercmp((uint8_t*)aTxBuffer, (uint8_t*)aRxBuffer, BUFFERSIZE))
{
/* Transfer error in transmission process */
Error_Handler();
}
/* Turn LED3 on: Transfer process is correct */
BSP_LED_On(LED3);
break;
case HAL_TIMEOUT:
/* A Timeout occurred_____________________________________________________*/
/* Call Timeout Handler */
Timeout_Error_Handler();
break;
/* An Error occurred______________________________________________________*/
case HAL_ERROR:
/* Call Timeout Handler */
Error_Handler();
break;
default:
break;
}
/* Infinite loop */
while (1)
{
}
}
/**
* @brief This function is executed in case of error occurrence.
* @param None
* @retval None
*/
static void Error_Handler(void)
{
/* Turn LED4 on */
BSP_LED_On(LED4);
while(1)
{
}
}
/**
* @brief System Clock Configuration
* The system Clock is configured as follow :
* System Clock source = PLL (HSE)
* SYSCLK(Hz) = 180000000
* HCLK(Hz) = 180000000
* AHB Prescaler = 1
* APB1 Prescaler = 4
* APB2 Prescaler = 2
* HSE Frequency(Hz) = 8000000
* PLL_M = 8
* PLL_N = 360
* PLL_P = 2
* PLL_Q = 7
* VDD(V) = 3.3
* Main regulator output voltage = Scale1 mode
* Flash Latency(WS) = 5
* @param None
* @retval None
*/
static void SystemClock_Config(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
/* Enable Power Control clock */
__HAL_RCC_PWR_CLK_ENABLE();
/* The voltage scaling allows optimizing the power consumption when the device is
clocked below the maximum system frequency, to update the voltage scaling value
regarding system frequency refer to product datasheet. */
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/* Enable HSE Oscillator and activate PLL with HSE as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 360;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
/* Activate the Over-Drive mode */
HAL_PWREx_EnableOverDrive();
/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
clocks dividers */
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);
}
/**
* @brief SPI error callbacks
* @param hspi: SPI handle
* @note This example shows a simple way to report transfer error, and you can
* add your own implementation.
* @retval None
*/
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
/* Turn LED4 on: Transfer error in reception/transmission process */
BSP_LED_On(LED4);
}
/**
* @brief This function is executed in case of error occurrence.
* @param None
* @retval None
*/
static void Timeout_Error_Handler(void)
{
/* Toggle LED4 on */
while(1)
{
BSP_LED_On(LED4);
HAL_Delay(500);
BSP_LED_Off(LED4);
HAL_Delay(500);
}
}
/**
* @brief Compares two buffers.
* @param pBuffer1, pBuffer2: buffers to be compared.
* @param BufferLength: buffer's length
* @retval 0 : pBuffer1 identical to pBuffer2
* >0 : pBuffer1 differs from pBuffer2
*/
static uint16_t Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength)
{
while (BufferLength--)
{
if((*pBuffer1) != *pBuffer2)
{
return BufferLength;
}
pBuffer1++;
pBuffer2++;
}
return 0;
}
#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 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) */
/* Infinite loop */
while (1)
{
}
}
#endif
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
Connected a logic analyzer and here what it shows when Polarity is LOW
For Polarity = HIGH
What could be the reason for this? As long as both Master & Slave agrees on Polarity and Phase communication should work right? Someone told me to reduce GPIO speed to LOW and twist GND and CLK cables. I did that.
Here's the GPIO configurations
/* SPI SCK GPIO pin configuration */
GPIO_InitStruct.Pin = SPIx_SCK_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
GPIO_InitStruct.Alternate = SPIx_SCK_AF;
HAL_GPIO_Init(SPIx_SCK_GPIO_PORT, &GPIO_InitStruct);
/* SPI MISO GPIO pin configuration */
GPIO_InitStruct.Pin = SPIx_MISO_PIN;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Alternate = SPIx_MISO_AF;
HAL_GPIO_Init(SPIx_MISO_GPIO_PORT, &GPIO_InitStruct);
/* SPI MOSI GPIO pin configuration */
GPIO_InitStruct.Pin = SPIx_MOSI_PIN;
GPIO_InitStruct.Pull = GPIO_PULLUP;
I send one more string. May be someone can understand a pattern and could help me
UPDATE : WITH CHIP SELECT
master - main.c
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* SPI handler declaration */
SPI_HandleTypeDef SpiHandle;
/* Buffer used for transmission */
uint8_t aTxBuffer[] = "****SPI - Two Boards communication based on Polling **** SPI Message ******** SPI Message ******** SPI Message ****";
/* Buffer used for reception */
uint8_t aRxBuffer[BUFFERSIZE];
/* Private function prototypes -----------------------------------------------*/
static void Error_Handler(void);
static void Timeout_Error_Handler(void);
static uint16_t Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength);
void GPIO_Init(void);
int main(void)
{
HAL_Init();
GPIO_Init();
/* Configure LED3 and LED4 */
BSP_LED_Init(LED3);
BSP_LED_Init(LED4);
/*##-1- Configure the SPI peripheral #######################################*/
/* Set the SPI parameters */
SpiHandle.Instance = SPI4;
SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
SpiHandle.Init.Direction = SPI_DIRECTION_2LINES;
SpiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;
SpiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;
SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
SpiHandle.Init.CRCPolynomial = 7;
SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;
SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;
SpiHandle.Init.NSS = SPI_NSS_SOFT;
SpiHandle.Init.TIMode = SPI_TIMODE_DISABLE;
SpiHandle.Init.Mode = SPI_MODE_MASTER;
if(HAL_SPI_Init(&SpiHandle) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
/* Configure USER Button */
BSP_PB_Init(BUTTON_KEY, BUTTON_MODE_GPIO);
/* Wait for USER Button press before starting the Communication */
while (BSP_PB_GetState(BUTTON_KEY) != 1)
{
BSP_LED_Toggle(LED3);
HAL_Delay(40);
}
BSP_LED_Off(LED3);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_1, GPIO_PIN_RESET);
if( HAL_SPI_TransmitReceive(&SpiHandle, (uint8_t*)aTxBuffer, (uint8_t *)aRxBuffer, BUFFERSIZE, 5000) == HAL_OK)
{
if(Buffercmp((uint8_t*)aTxBuffer, (uint8_t*)aRxBuffer, BUFFERSIZE))
{
//HAL_GPIO_WritePin(GPIOE, GPIO_PIN_1, GPIO_PIN_SET);
/* Transfer error in transmission process */
Error_Handler();
}
/* Turn LED3 on: Transfer process is correct */
BSP_LED_On(LED3);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_1, GPIO_PIN_SET);
}
else
{
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_1, GPIO_PIN_SET);
Timeout_Error_Handler();
}
/* Infinite loop */
while (1)
{
}
}
static void Error_Handler(void)
{
/* Turn LED4 on */
BSP_LED_On(LED4);
while(1)
{
}
}
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
/* Turn LED4 on: Transfer error in reception/transmission process */
BSP_LED_On(LED4);
}
static void Timeout_Error_Handler(void)
{
/* Toggle LED4 on */
while(1)
{
BSP_LED_On(LED4);
HAL_Delay(500);
BSP_LED_Off(LED4);
HAL_Delay(500);
}
}
/**
* @brief Compares two buffers.
* @param pBuffer1, pBuffer2: buffers to be compared.
* @param BufferLength: buffer's length
* @retval 0 : pBuffer1 identical to pBuffer2
* >0 : pBuffer1 differs from pBuffer2
*/
static uint16_t Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength)
{
while (BufferLength--)
{
if((*pBuffer1) != *pBuffer2)
{
return BufferLength;
}
pBuffer1++;
pBuffer2++;
}
return 0;
}
void GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
__HAL_RCC_GPIOE_CLK_ENABLE();
//HAL_GPIO_WritePin(GPIOE, GPIO_PIN_1, GPIO_PIN_SET);
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_1, GPIO_PIN_SET);
}
Slave - main .c
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* SPI handler declaration */
SPI_HandleTypeDef SpiHandle;
/* Buffer used for transmission */
uint8_t aTxBuffer[] = "****SPI - Two Boards communication based on Polling **** SPI Message ******** SPI Message ******** SPI Message ****";
/* Buffer used for reception */
uint8_t aRxBuffer[BUFFERSIZE];
/* Private function prototypes -----------------------------------------------*/
static void Error_Handler(void);
static void Timeout_Error_Handler(void);
static uint16_t Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength);
int main(void)
{
HAL_Init();
/* Configure LED3 and LED4 */
BSP_LED_Init(LED3);
BSP_LED_Init(LED4);
/*##-1- Configure the SPI peripheral #######################################*/
/* Set the SPI parameters */
SpiHandle.Instance = SPI4;
SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
SpiHandle.Init.Direction = SPI_DIRECTION_2LINES;
SpiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;
SpiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;
SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
SpiHandle.Init.CRCPolynomial = 7;
SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;
SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;
SpiHandle.Init.NSS = SPI_NSS_HARD_INPUT;
SpiHandle.Init.TIMode = SPI_TIMODE_DISABLE;
SpiHandle.Init.Mode = SPI_MODE_SLAVE;
if(HAL_SPI_Init(&SpiHandle) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
/*##-2- Start the Full Duplex Communication process ########################*/
/* While the SPI in TransmitReceive process, user can transmit data through
"aTxBuffer" buffer & receive data through "aRxBuffer" */
/* Timeout is set to 5s */
if( HAL_SPI_TransmitReceive(&SpiHandle, (uint8_t*)aTxBuffer, (uint8_t *)aRxBuffer, BUFFERSIZE, 5000) == HAL_OK)
{
if(Buffercmp((uint8_t*)aTxBuffer, (uint8_t*)aRxBuffer, BUFFERSIZE))
{
/* Transfer error in transmission process */
Error_Handler();
}
/* Turn LED3 on: Transfer process is correct */
BSP_LED_On(LED3);
}
else
{
Timeout_Error_Handler();
}
/* Infinite loop */
while (1)
{
}
}
static void Error_Handler(void)
{
/* Turn LED4 on */
BSP_LED_On(LED4);
while(1)
{
}
}
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
/* Turn LED4 on: Transfer error in reception/transmission process */
BSP_LED_On(LED4);
}
static void Timeout_Error_Handler(void)
{
/* Toggle LED4 on */
while(1)
{
BSP_LED_On(LED4);
HAL_Delay(500);
BSP_LED_Off(LED4);
HAL_Delay(500);
}
}
/**
* @brief Compares two buffers.
* @param pBuffer1, pBuffer2: buffers to be compared.
* @param BufferLength: buffer's length
* @retval 0 : pBuffer1 identical to pBuffer2
* >0 : pBuffer1 differs from pBuffer2
*/
static uint16_t Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength)
{
while (BufferLength--)
{
if((*pBuffer1) != *pBuffer2)
{
return BufferLength;
}
pBuffer1++;
pBuffer2++;
}
return 0;
}
Slave gpio configuration
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/**
* @brief SPI MSP Initialization
* This function configures the hardware resources used in this example:
* - Peripheral's clock enable
* - Peripheral's GPIO Configuration
* @param hspi: SPI handle pointer
* @retval None
*/
void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{
GPIO_InitTypeDef GPIO_InitStruct;
/*##-1- Enable peripherals and GPIO Clocks #################################*/
/* Enable GPIO TX/RX clock */
__HAL_RCC_GPIOE_CLK_ENABLE();
/* Enable SPI clock */
__HAL_RCC_SPI4_CLK_ENABLE();
/*##-2- Configure peripheral GPIO ##########################################*/
/* SPI SCK GPIO pin configuration */
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI4;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
/* SPI MISO GPIO pin configuration */
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI4;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
/* SPI MOSI GPIO pin configuration */
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI4;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
/* SPI NSS GPIO pin configuration */
GPIO_InitStruct.Pin = GPIO_PIN_4;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI4;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
}