El programa anterior manda configurar el modulo FDCAN en modo can classic en el cual solo se mandan 8 bytes por frame, se establece una velocidad de 100kpbs y un sample point de 75%, el ID es de 11 bytes. El programa manda 8 bytes de información cada segundo sin hacer uso de interrupciones, solo con propósitos ilustrativos. Es importante revisar muy bien la frecuencia que alimenta el modulo CAN y como se calculan las time quantas y el sample point ( revisar comentarios en el código ), para poder analizar los datos mandados es necesario usar candump el cual es parte de las , configurar la velocidad para que coincidan con el modulo del micro. Hay que tomar en cuenta que la función HAL_FDCAN_AddMessageToTxFifoQ solo carga la información a mandar en el buffer de salida e inicia su transmisión, pero cuando la función retorna no quiere decir que la información ya se mando por completo.

#include "bsp.h"

/* structure type variables for USER CAN initialization */
FDCAN_HandleTypeDef CANHandler;

int main( void )
{
    /*CAN header structure*/
    FDCAN_TxHeaderTypeDef CANTxHeader;
    /*message to send*/
    uint8_t message[8] = {0x48, 0x31, 0x20, 0x57, 0x4F, 0x52, 0x4C, 0x44};

    HAL_Init(); /* Inicializamos libreria HAL */
    
    /* 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 Classic mode*/
    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 option to transmit the messages */
    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*/
    
    while( 1u )
    {
        /*Colocanmos el mensaje en el buffer de salida y activamos el envio*/
        HAL_FDCAN_AddMessageToTxFifoQ( &CANHandler, &CANTxHeader, message );
        /*esperamos un segundo*/
        HAL_Delay( 1000u );
    }
}

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 );
}