cancel
Showing results for 
Search instead for 
Did you mean: 

SPI2 global interrupt routine does not get fired upon transmission complete

PPopo
Senior

Hello,

I'm trying to do a project which involves using both UART and SPI to better understand these protocols as well as the HAL drivers.

I have generated the project with the cubeMX and for the first step I'm trying to send some data via SPI2 in interrupt mode when I press a button.

The code logic is like this: The program cyclicly checks in an endless while loop whether I press the user button or not. If I do it's going to start the process of sending some data via SPI in interrupt mode.

I have configured my controller on the board(NUCLEO F401RE) in master full-duplex but I have not connected any cables to any other device/board yet as I just want to test the sending in interrupt mode first.

I put some code which lights up the user LED in the 'SPI2_IRQHandler'(global interrupt that should be fired when transmission is completed if I understood corectly from the datasheet) if which in turn calls HAL function 'HAL_SPI_IRQHandler' which takes care of clearing flags etc.

void SPI2_IRQHandler(void)
{
 HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
 
 HAL_SPI_IRQHandler(&hspi2);
}

The above function is in the 'stm32f4xx_it.c' generated by cubeMX.

The configuration(generated from cubeMX) is like this:

  • Motorola Frame Format
  • 8 bits data size
  • MSB first
  • 2 prescaler for baud rate
  • clock polarity CPOL
  • Clock Phase CPHA
  • CRC calculation disabled
  • NSS Signal Type SOFTWARE
  • Device configured as SPI master full-duplex

This is the main code:

char* data_to_sent = "a";
 
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_SPI2_Init();
  /* USER CODE BEGIN 2 */
 
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
 
  HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
 
  HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
 
  SPI2->CR1 |= ( 1 << 8 ); //NSS high
  //HAL_SPI_Transmit_IT(&hspi2, (uint8_t*)data_to_sent, 1);
  while (1)
  {
 
      if( HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin) == 0 )
      {
       //Send the command in SPI interrupt mode
       HAL_SPI_Transmit_IT(&hspi2, (uint8_t*)data_to_sent, 1);
      }
 
  }
}

The code gets into the 'HAL_SPI_Transmit_IT' and seems to be doing everything fine but the interrupt routine does not get fired.

However the SPI2 isr routine does not get called(the led does not light up).

I have configured the NSS signal type to be controlled in software. So I have also tried doing this in the code:

SPI1->CR1 |= ( 1 << 8 );

Because if I understood corectly in the datasheet this bit has to be 1 when NSS is controlled in software in order for the SPI to generate clock(and send data properly) and I did not find anything in the generated code where that is done. However it did not change anything.

Please help me fix this issue. Thanks for reading my post!

Edit: Added the code which I forgot. Also changed the title and the explanation as the previous problem was solved(SPI was busy due to me a hex address instead of the address of the SPI handle) and now there is a new problem in the code(ISR does not get triggered).

1 ACCEPTED SOLUTION

Accepted Solutions
PPopo
Senior

@Community member​ the problem was indeed that the NVIC corresponding interrupt was not enabled.

I have added these two lines of code in the MSP spi2 initialisation function and now it works:

NVIC_SetPriority(SPI2_IRQn, 0);
 
NVIC_EnableIRQ(SPI2_IRQn);
 
 

thanks for the answer!

View solution in original post

7 REPLIES 7
Bob S
Principal

Oops - looks like your code snippet didn't post. Try again as the code is pretty important for us to help you. As for SPI, the SPI master does not need to have anything connected to the SPI bus. The master will (should) send whatever data you tell it to send. Unlike I2C, there is not ACK/NAK from the slave built in to the SPI protocol.

yes I must've forgot. I have edited the original post to include the code. Also changed the title since there is new issue in the code :D

Bob S
Principal

(1) It would also help to see your SPI init code - MX_SPI2_Init() and HAL_SPI_MspInit() functions. Please post these in a new post, don't go back and edit your original one 🙂

(2) You are replacing the HAL SPI interrupt function with your own- don't do that. SPI2_IRQHandler() should loook like this:

void SPI2_IRQHandler(void)
{
   HAL_SPI_IRQHandler(&hspi2);
}

And that should have already existed in your stm32f4xx_it.c file. If you want notification when the SPI transfer is complete, put your code inside HAL_SPI_TxCpltCallback().

(3) I'm not sure about this one, but I **THINK** you don't need to bother with the CR1 SSI bit if you are in master mode and NOT on a multi-master SPI bus. But that perhaps depends on how you have the SPI configured (see item (1) above).

Hello again and thanks again for your answer ;).

I have did the following:

switched the NSS management to 'NSS output enabled' because the datasheet says at section 26.3.5 that NSS management can be handled both in software and hardware. If you handle it in software as I was doing previously you have to enable the device via the SSI bit value in register SPIx_CR1. So in order to get rid of that thing that I have to do(not entirely sure I had to) I have chosen hardware NSS output enable. The datasheet says this about this mode: NSS output enable (SSM=0,SSOE = 1): this configuration is only used when the MCU is set as master. The NSS pin is managed by the hardware. The NSS signal is driven low as soon as the SPI is enabled in master mode (SPE=1), and is kept low until the SPI is disabled (SPE =0). I'm not entirely sure about this the NSS signal was always a pain in my back but this seems the right mode for what I need(transmit only in master mode for this device).

Here is the MX_SPI2_Init() defined in main.c:

static void MX_SPI2_Init(void)
{
 
  /* USER CODE BEGIN SPI2_Init 0 */
 
  /* USER CODE END SPI2_Init 0 */
 
  /* USER CODE BEGIN SPI2_Init 1 */
 
  /* USER CODE END SPI2_Init 1 */
  /* SPI2 parameter configuration*/
  hspi2.Instance = SPI2;
  hspi2.Init.Mode = SPI_MODE_MASTER;
  hspi2.Init.Direction = SPI_DIRECTION_2LINES;
  hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi2.Init.NSS = SPI_NSS_HARD_OUTPUT;
  hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi2.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI2_Init 2 */
 
  /* USER CODE END SPI2_Init 2 */
 
}

Here is the HAL_SPI_MspInit() defined in stm32f44xx_hal_msp.c:

void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(hspi->Instance==SPI2)
  {
  /* USER CODE BEGIN SPI2_MspInit 0 */
 
  /* USER CODE END SPI2_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_SPI2_CLK_ENABLE();
  
    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**SPI2 GPIO Configuration    
    PC2     ------> SPI2_MISO
    PC3     ------> SPI2_MOSI
    PB10     ------> SPI2_SCK 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
  /* USER CODE BEGIN SPI2_MspInit 1 */
 
  /* USER CODE END SPI2_MspInit 1 */
  }
 
}

In stm..it.c file I have changed back the spi2 global function as it was in the first place:

void SPI2_IRQHandler(void)
{
 HAL_SPI_IRQHandler(&hspi2);
}

And in main.c I have implemented HAL_SPI_TxCpltCallback() in which I'm (trying to) light up an led to confirm data interrupt routine was fired and data was sent:

//this function gets called when transmission of spi frame is completed
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
	HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
}

The led still won't light up for some reason :(.

 It would appear my interrupt routine won't fire up upon transmission.

  • using oscilloscope/LA, do you see clock being output on SCK?
  • read out and check the SPI registers' content
  • check that the interrupt is enabled both in SPI (yes Cube should've taken care of this but trust nobody) and NVIC (that's your responsibility)
  • check in disasm that the ISR's proper address is at the proper position in the vector table
  • if you compile in C++ mode watch out for name mangling

Bob,

If you set SSM, then SSI determines the input value of the internal NSS signal of the SPI module. If SSI is zero, it immediately turns the module from Mater to Slave.

JW

Thanks for the tips I will try that tomorrow night when I get home.

PPopo
Senior

@Community member​ the problem was indeed that the NVIC corresponding interrupt was not enabled.

I have added these two lines of code in the MSP spi2 initialisation function and now it works:

NVIC_SetPriority(SPI2_IRQn, 0);
 
NVIC_EnableIRQ(SPI2_IRQn);
 
 

thanks for the answer!