0
\$\begingroup\$

I want to use an SPI bus to transer a message between an STM32F4 discovery and a STM32F3 Discovery, using an half-duplex channel. Master is F4, slave is F3 and the communication is MOSI type. When I click the user push button on F4, it sends a message in blocking mode, F3 receives the message and it toggles a led using an interrupt. When F3 doesn't receivce any message, in polling mode it toggles another led every 500 ms, using a SysTick timer; in the meantime it shows the status of led toggled by interrupt. My problem is that the message is transmitted correctly but the interrupt led doesn't toggle. What is the problem? I show you my code... Master code:

#include "main.h"
#include "stm32f4xx_hal.h"

SPI_HandleTypeDef hspi1;

void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI1_Init(void);

int main(void)
{


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

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

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_SPI1_Init();

  /* USER CODE BEGIN 2 */
  char *msg={"Hello"};
  HAL_StatusTypeDef state;
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
      /* USER CODE END WHILE */

      if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)){
          while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0));
          HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
          switch(state=HAL_SPI_Transmit(&hspi1,(uint8_t*)msg,sizeof(msg),5000)){
          /*Only for debug*/
            case HAL_OK:
                printf("OK!");
              break;
            case HAL_ERROR:
              //hal error
              asm("bkpt 255");
                break;
            case HAL_BUSY:
              //hal error
              asm("bkpt 255");
                break;
            case HAL_TIMEOUT:
                //hal error
                asm("bkpt 255");
                break;
            default:
              asm("bkpt 255");
                break;
          }
      HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_SET);



  /* USER CODE BEGIN 3 */

  }
 /* USER CODE END 3 */

  }
}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{

  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;

    /**Configure the main internal regulator output voltage 
    */
  __HAL_RCC_PWR_CLK_ENABLE();

  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

/**Initializes the CPU, AHB and APB busses clocks 
*/
  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 = 4;
  RCC_OscInitStruct.PLL.PLLN = 96;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 7;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

    /**Initializes the CPU, AHB and APB busses clocks 
*/
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                          |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV2;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  /**Configure the Systick interrupt time 
   */
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

  /**Configure the Systick 
   */
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

 /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

/* SPI1 init function */
static void MX_SPI1_Init(void)
{

  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_1LINE;
  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_256;
  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(__FILE__, __LINE__);
  }

}

/** Configure pins as 
    * Analog 
    * Input 
    * Output
    * EVENT_OUT
    * EXTI
*/
static void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct;

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);

  /*Configure GPIO pin : PA0 */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pin : PB2  (CS SPI)*/
  GPIO_InitStruct.Pin = GPIO_PIN_2;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
  HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_SET);

}

Slave code (interrupt arrives when PB2 on master change value from 1 to 0):

#include "main.h"
#include "stm32f3xx_hal.h"


SPI_HandleTypeDef hspi1;
volatile GPIO_PinState currentstatepin=GPIO_PIN_RESET;

void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI1_Init(void);


int main(void)
{


  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_SPI1_Init();

  while (1)
  {
      HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_11);
      HAL_Delay(500);
      HAL_GPIO_WritePin(GPIOE,GPIO_PIN_9,currentstatepin);


  }

}

void SystemClock_Config(void)
{

  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;


  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = 16;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL12;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }


  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  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_1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

/* SPI1 init function */
static void MX_SPI1_Init(void)
{

  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_SLAVE;
  hspi1.Init.Direction = SPI_DIRECTION_1LINE;
  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.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 7;
  hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
  hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

}

static void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct;

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOF_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOE_CLK_ENABLE();


  /*Configure GPIO pin : PB2 */
  GPIO_InitStruct.Pin = GPIO_PIN_2;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pins : PE9 PE11 */
  GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_11;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);

  /* EXTI interrupt init*/
  HAL_NVIC_SetPriority(EXTI2_TSC_IRQn, 0, 7);
  HAL_NVIC_EnableIRQ(EXTI2_TSC_IRQn);

}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
    uint8_t msg;

    if(HAL_SPI_Receive_IT(&hspi1,&msg,sizeof(msg))==HAL_OK){
        HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_9);
        currentstatepin=HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_9);
        }
}
\$\endgroup\$
4
  • 4
    \$\begingroup\$ Just out of curiosity, why not just use a full UART? Seems more straightforward? \$\endgroup\$ – Scott Seidman Jun 22 '17 at 17:14
  • 1
    \$\begingroup\$ Calling an SPI receive function from an interrupt sounds like a very bad idea, especially as it may internally rely on interrupts or have interrupt-based timeout functionality. Why not poll the trigger or the SPI peripheral status in your main loop? Or use the interrupt to set a flag so that the main loop will attempt to receive. \$\endgroup\$ – Chris Stratton Jun 22 '17 at 17:14
  • 1
    \$\begingroup\$ Also what do you hope to accomplish by writing the pin in the main loop to what is hopefully the value already written to it by the ISR? Even before worrying about how that might not be working correctly, it's unclear what you hope it will accomplish. \$\endgroup\$ – Chris Stratton Jun 22 '17 at 17:15
  • \$\begingroup\$ @ScottSeidman, it is an exercise on SPI, next days I'll also use UART. \$\endgroup\$ – alukard990 Jun 23 '17 at 12:03
2
\$\begingroup\$

This portion of your code:

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
    uint8_t msg;

    if(HAL_SPI_Receive_IT(&hspi1,&msg,sizeof(msg))==HAL_OK){
        HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_9);
        currentstatepin=HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_9);
        }
}

Represents a complete misunderstanding of Interrupt-driven SPI reception.

The return value of HAL_SPI_Receive_IT() does not indicate if data has been received, but only if the SPI engine can be armed for reception (vs. being busy, stuck in an error state, or whatever). At best, success might indicate that this is the first attempt or that the previous attempt has finished, but that's a delayed way of doing things

Actual received data (or failure) would be delivered instead to the HAL_SPI_RxCpltCallback() which you would need to register for.

Additionally, you will need to figure out if it is workable to arm the reception only upon receipt of that GPIO trigger (which you are perhaps treating as a software slave select) or if doing so might be too late - if it is, you'll either need a greater delay between the trigger on the transmitter, or to be perpetually attempting to receive, and trigger everything off of the success of the reception.

As it stands, use of interrupts isn't justified in your code - you could better achieve your currently attempted functionality simply by polling in your main loop.

However, if this is an initial stepping stone to more complicated overall functionality, then trying to get the interrupt implementation sorted out can make sense.

\$\endgroup\$
1
  • \$\begingroup\$ This is an attempt to understand SPI and interrupt, when I'm more prepared, I'm going to implement something more sophisticated \$\endgroup\$ – alukard990 Jun 23 '17 at 12:12
-2
\$\begingroup\$

Change the priority of the interrupts. You had two interrupts running in the same ISR: 1. GPIO interrupts and the SPI receive interrupt. They are not happening at the same time. This is a bad idea to use multiple interrupts simultaneously, unless otherwise necessary. Try a SPI receive interrupt and from there initialize the timer to toggle the led of your interest.
Still if you want to try the idea you were planning, do a trial error basis change in the priority level from STM32CubeMx

\$\endgroup\$
4
  • 2
    \$\begingroup\$ You're going to need to be more specific or at least explain the goal of the change if this is going to count as an "answer" \$\endgroup\$ – Chris Stratton Jun 22 '17 at 17:59
  • \$\begingroup\$ edited the answer, @ChrisStratton \$\endgroup\$ – sbz Jun 22 '17 at 18:08
  • \$\begingroup\$ It's not an issue of priorites but of failing to understand and so misusing the functionality. Also, trying to do anything time consuming in an ISR would be a serious design mistake, even if it were possible, which with this API it is not. \$\endgroup\$ – Chris Stratton Jun 22 '17 at 18:24
  • \$\begingroup\$ Yes, It is a misuse of functionalities. My point was to help him solve his problem with his current idea. \$\endgroup\$ – sbz Jun 22 '17 at 20:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.