In this program, a message is sent using interrupts with the HAL_SPI_Transmit_IT( ) function. Interrupt vector function SPI1_IRQHandler is called every time a single byte is transmitted but only when the message has been completely transmitted the callback function HAL_SPI_TxCpltCallback() is called.

#include "bsp.h"

SPI_HandleTypeDef SpiHandle;        /*Structure to handle SPI*/
GPIO_InitTypeDef GPIO_InitStruct;   /*Structure to init GPIOs*/

uint8_t TxBuffer[31];               /*Buffer to store data to send through SPI*/
uint8_t messageTransmitted = 0;     /*Flag that indicates a message has been transmitted completely*/

int main(void)
{
    HAL_Init();           /*Library Initialization*/

    __GPIOD_CLK_ENABLE(); /*Enable port D clock*/

    GPIO_InitStruct.Pin   = GPIO_PIN_9;                    /*CS pin to start/finish SPI transmition */
    GPIO_InitStruct.Mode  = GPIO_MODE_OUTPUT_PP;           /*Output push-pull Type                  */
    GPIO_InitStruct.Pull  = GPIO_NOPULL;                   /*Pin without pull-up or pull-down       */
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;           /*Pin in low speed                       */
    /*Initialize pins with the previous parameters*/
    HAL_GPIO_Init( GPIOD, &GPIO_InitStruct );
    
    /*Configuration of SPI in master mode, Full-Duplex communication, Clock polarity in Low, clock phase in rising edge 
    and CLK frecc of 4 MHz*/
    SpiHandle.Instance            = SPI1;                        /*SPI instance according MOSI,MISO,CLK and CS lines*/
    SpiHandle.Init.Mode           = SPI_MODE_MASTER;             /*Master mode selected to transmmit data from master*/
    SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;  /*Prescaler selected according slave work freccuency*/
    SpiHandle.Init.Direction      = SPI_DIRECTION_2LINES;        /*Number of lines of transmition (Full-Duplex)*/
    SpiHandle.Init.CLKPhase       = SPI_PHASE_1EDGE;             /*CLK Phase selected in rising edge */
    SpiHandle.Init.CLKPolarity    = SPI_POLARITY_LOW;            /*CLK polarity selected in rising edge, Idle state in 0*/
    SpiHandle.Init.DataSize       = SPI_DATASIZE_8BIT;           /*Zise of data to be transmitted*/
    SpiHandle.Init.FirstBit       = SPI_FIRSTBIT_MSB;            /*Selected the MSB as first bit to be transmitted*/
    SpiHandle.Init.NSS            = SPI_NSS_SOFT;                /*NSS-CS configured by software*/
    SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED; /*Specifies if the CRC calculation is enabled or not*/
    SpiHandle.Init.TIMode         = SPI_TIMODE_DISABLED;         /*TI protocol master mode disabled*/

    /*Ensures slave is disabled pin D9 high*/
    HAL_GPIO_WritePin( GPIOD, GPIO_PIN_9, SET );
    /*Apply configuration to SPI1*/
    HAL_SPI_Init( &SpiHandle );
    
    /*Enable writing instructions in the eeprom memory by sending a 0x06, SPI_Transmit_IT() function 
    needs as argument the structure to handle spi, amount of data to transmit and buffer where data is 
    stored, when the transmission ends we will use the callback to disable Chip Select*/
    HAL_GPIO_WritePin( GPIOD, GPIO_PIN_9, RESET );      /*Start transmition pulling down CS pin state*/
    TxBuffer[0] = 0x06;                                 /*WREN Instruction value for eeprom*/
    HAL_SPI_Transmit_IT( &SpiHandle, TxBuffer, 1 );      /*Function to transmmit the data */
    
    /*Send a 31 byte frame to write to the eeprom memory with the HAL_SPI_Transmit_IT() function. Once data 
    have been transmitted, we will use the callback to disable Chip Select*/
    HAL_GPIO_WritePin( GPIOD, GPIO_PIN_9, RESET );      /*Start transmition pulling down CS pin state*/
    TxBuffer[0] = 0x02;                                 /*Write instruction */
    TxBuffer[1] = 0x00;                                 /*16 bit - address  */
    TxBuffer[2] = 0x00;                                 /*16 bit - address  */
    
    /*Setting values in TxBuffer to be sended and writtend in the eeprom memory, the first values introduced
    are the write instruction in cero position, 16 bit address with 8 MSB on position number one and 8 LSB
    of address in position number two, once included, we start entering values from the third position*/
    for( uint8_t i = 3 ; i < 31 ; i++ )
    {
        TxBuffer[i] = i;
    }                                 
    /* Send TxBuffer from 0 position to 30 position */
    HAL_SPI_Transmit_IT( &SpiHandle, TxBuffer, 31 );
  
    while (1)
    {
        if( messageTransmitted == 1u )
        {
            /* At this point data was sended completely and it will take 5 ms to the eeprom memory to write data in it*/ 
        }
    }
}

/*This callback function is called by the HAL_SPI_IRQHandler every time a message has been transmitted completely*/
/*To calculate the approximate time that the transfer will take, we use the SPI opperation frequency: 
  SPI Opperation Frequency = Clock frequency / SPI baudrate prescaler = 16 MHz / 4 = 4MHz 
  Transfer Time = Amount of Bytes / frequency = 31 Bytes / 4MHz = 8 us */
void HAL_SPI_TxCpltCallback( SPI_HandleTypeDef *hspi )
{
    /* Disable transmission pulling high Chip Select*/
    HAL_GPIO_WritePin( GPIOD, GPIO_PIN_9, SET );
    
    /*We can enable a flag to know when data were transmitted completely */
    /*At this point the eeprom memory has received all the data and needs 5 ms to write data to itself*/
    messageTransmitted = 1u;
}

msps.c

/*This function will be called inside the HAL_SPI_Init function*/
void HAL_SPI_MspInit( SPI_HandleTypeDef *hspi )
{
    /* pins D8, D6 and D5 in alternate function spi1 for CLK, MOSI and MISO*/
    GPIO_InitTypeDef GPIO_InitStruct;
    __GPIOD_CLK_ENABLE();
    __SPI1_CLK_ENABLE();

    GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_6 | GPIO_PIN_5; /*Function of pin: CLK , MOSI , MISO */ 
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;                     /*Alternate Function mode for pins*/
    GPIO_InitStruct.Pull = GPIO_PULLUP;                         /*Pull-Up activation for selected pins*/
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;               /*High speed selected for pins*/
    GPIO_InitStruct.Alternate = GPIO_AF1_SPI1;                  /*Alternate function for selected pins*/
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
    
    /*Enable vector interrupt to attend SPI IRQs */
    HAL_NVIC_SetPriority( SPI1_IRQn, 2, 0 );
    HAL_NVIC_EnableIRQ( SPI1_IRQn );
}

ints.c

/*reference to SPI control structure handler*/
extern SPI_HandleTypeDef SpiHandle;        

/*Declare interrupt service rutine as it is declare in startup_stm32g0b1xx.s file,
Program will jump here every time a single byte is transmitted*/
void SPI1_IRQHandler( void )
{
    /*Process the SPI interrupt and call the corresponding callback functions*/
    HAL_SPI_IRQHandler( &SpiHandle );
}