Este ultimo programa utiliza interrupciones para captar cuando el mensaje se ha transmitido por completo, mediante la función HAL_FDCAN_ActivateNotification se activa la interrupción cuando todos los buffers se vacían y después la interrupción manda llamar automáticamente la callback HAL_FDCAN_TxFifoEmptyCallback En esta función se transmite de nueva cuenta y se repite la operación otras tres veces para un total de 4 transmisiones en un espacio de 5 segundos, para que de nueva se repita la operación

#include "bsp.h"

/* structure type variables for USER CAN initialization */
FDCAN_HandleTypeDef CANHandler;
/*CAN header structure*/
FDCAN_TxHeaderTypeDef CANTxHeader;
/*message to send*/
uint8_t message[8] = {0x48, 0x31, 0x20, 0x57, 0x4F, 0x52, 0x4C, 0x44};
uint8_t msgs;

int main( void )
{
    HAL_Init(); /*Init HAL library*/
    
    /* FDCAN1 module to transmit up to 100Kbps and sample point of 75%
     fCAN = fHSI / CANHandler.Init.ClockDivider / CANHandler.Init.NominalPrescaler
     fCAN = 16MHz / 1 / 10 = 1.6Mhz
     Time quantas:
     Ntq = fCAN / CANbaudrate
     Ntq = 1.6Mhz / 100Kbps = 16 
     Sample point:
     Sp = ( CANHandler.Init.NominalTimeSeg1 +  1 / Ntq ) * 100
     Sp = ( ( 11 + 1 ) / 16 ) * 100 = 75% */
    CANHandler.Instance                 = FDCAN1;
    CANHandler.Init.Mode                = FDCAN_MODE_NORMAL;          /*CAN full operative, Tx and Rx*/
    CANHandler.Init.FrameFormat         = FDCAN_FRAME_CLASSIC;        /*Classic frame*/
    CANHandler.Init.ClockDivider        = FDCAN_CLOCK_DIV1;           /*No APB divider for FDCAN module*/
    CANHandler.Init.TxFifoQueueMode     = FDCAN_TX_FIFO_OPERATION;    /*Tx buffer in Fifo mode*/
    CANHandler.Init.NominalPrescaler    = 10;                         /*CAN clock divider by 10*/
    CANHandler.Init.NominalSyncJumpWidth = 1;                         /*SWJ of 1*/
    CANHandler.Init.NominalTimeSeg1     = 11;                         /*phase time seg1 + prop seg*/
    CANHandler.Init.NominalTimeSeg2     = 4;                          /*phase time seg2*/
    HAL_FDCAN_Init( &CANHandler);
    
    /* Change FDCAN instance from initialization mode to normal mode */
    HAL_FDCAN_Start( &CANHandler);

    /* set options to transmit the messages, 11 bits address, 8 bits data frame */
    CANTxHeader.IdType      = FDCAN_STANDARD_ID;    /*11 bits CAN ID*/
    CANTxHeader.FDFormat    = FDCAN_CLASSIC_CAN;    /*classic CAN format up to 8 bytes*/
    CANTxHeader.TxFrameType = FDCAN_DATA_FRAME;     /*type of frame, data*/
    CANTxHeader.Identifier  = 0x1EF;                /*can message ID*/
    CANTxHeader.DataLength  = FDCAN_DLC_BYTES_8;    /*8 bytes to transmit*/

    /*enable transmision interrupts when fifo0 is empty */
    HAL_FDCAN_ActivateNotification( &CANHandler, FDCAN_IT_TX_FIFO_EMPTY, FDCAN_TX_BUFFER0 );
    
    while( 1u )
    {
        /*set the first message on fifo0 to send it*/
        msgs = 0u;
        message[ 1u ] = 0x31u; 
        HAL_FDCAN_AddMessageToTxFifoQ( &CANHandler, &CANTxHeader, &message[0u] );
        /*wait five seconds, long enough for the ISR to trnasmit the rest of the messageso*/
        HAL_Delay( 5000u );
    }
}

/*This callback is called bu the HAL_FDCAN_IRQHandler every time a single message is transmitted*/
void HAL_FDCAN_TxFifoEmptyCallback( FDCAN_HandleTypeDef *hfdcan )
{
    /*send only another three messages more usinf this rutine*/
    if( msgs < 3u )
    {
        /*send another messages using interrupts*/
        message[ 1u ]++;
        HAL_FDCAN_AddMessageToTxFifoQ( hfdcan, &CANTxHeader, &message[0u] );
        msgs++;
    }
}

msps.c

/*This function is called in HAL_FDCAN_Init*/
void HAL_FDCAN_MspInit(FDCAN_HandleTypeDef *hfdcan)
{
    GPIO_InitTypeDef GpioCanStruct;

    /* Habilitamos los relojes de los perifericos GPIO y CAN */
    __HAL_RCC_FDCAN_CLK_ENABLE();
    __HAL_RCC_GPIOD_CLK_ENABLE();
    
    /* configuramos pin 0(rx) y pin 1(tx) en modo alterno para FDCAN1 */
    GpioCanStruct.Mode = GPIO_MODE_AF_PP;
    GpioCanStruct.Alternate = GPIO_AF3_FDCAN1;
    GpioCanStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1;
    GpioCanStruct.Pull = GPIO_NOPULL;
    GpioCanStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init( GPIOD, &GpioCanStruct );

    /*Enable vector interrupt to attend CAN IRQs */
    HAL_NVIC_SetPriority(TIM16_FDCAN_IT0_IRQn, 2, 0);
    HAL_NVIC_EnableIRQ(TIM16_FDCAN_IT0_IRQn);
}

ints.c

/*reference to FDCAN control structure handler*/
extern FDCAN_HandleTypeDef CANHandler;

/*Declare CAN interrupt service rutine as it is declare in startup_stm32g0b1xx.s file*/    
void TIM16_FDCAN_IT0_IRQHandler( void )
{
    /*HAL library functions that attend interrupt on CAN*/
    HAL_FDCAN_IRQHandler( &CANHandler );
}