STM32 Advanced Peripherals : CANBus Part 2: CANBus Initialization

In part of the this guide series (here), we took a look at CANBus and it features, CANBus peripheral of STM32F446 and its feature.

In part two, we shall initialize the CANBus pins, CANBus and the filter to accept data with fixed identifier.

In this guide, we shall cover the following:

  • Required steps.
  • GPIO initialization and configuration.
  • CANBus initialization.
  • Filter Configuration.
  • CANBus start.

8.Required Steps:

  1. Enable Clock:
    • Enable the clock for the CAN peripheral.
  2. Initialization Mode:
    • Enter initialization mode for CAN configuration.
  3. Bit Timing Configuration:
    • Configure the bit timing parameters (BTR register) based on the required baud rate and other settings.
  4. Exit Initialization Mode:
    • Exit initialization mode to start normal CAN operation.
  5. Enable Interrupts (Optional):
    • If you want to use interrupts, enable the relevant interrupt sources in the CAN interrupt enable register (IER) and configure NVIC.
  6. Filter Configuration:
    • Enter filter initialization mode and configure CAN filter(s) (example values provided).
    • Exit filter initialization mode.
  7. Main Loop:
    • Enter the main application loop.
  8. Interrupt Handler (Optional):
    • If using interrupts, implement the interrupt handler to handle received messages.

Later, we shall see if the interrupt is necessary or not.

9. GPIO Initialization and Configuration:

From part 1, we shall use PB8 and PB9 for CANRX and CANTX respectively.

We start by enabling clock access to GPIOB:

Since the GPIOB is connected to AHB1 bus as shown in figure below:

We can enable clock access to GPIOB by setting the corresponding bit in AHB1ENR register:

Create new header file and source file with name of CANBus.h and CANBus.c respectively:

Within the source file:

Include the following:

#include "CANBus.h"
#include "stm32f4xx.h"

Declare the following function:

void CANBus_Pins_Init(void)

This function will initialize and configure the CANBus pins.

	/*Enable clock access to GPIOB*/
	RCC->AHB1ENR|=RCC_AHB1ENR_GPIOBEN;

Next, we shall set both PB8 and PB9 to alternate function as following:

	GPIOB->MODER|=GPIO_MODER_MODE8_1|GPIO_MODER_MODE9_1;
	GPIOB->MODER&=~(GPIO_MODER_MODE8_0|GPIO_MODER_MODE9_0);

Now, we need to find which AF responsible for CANBus:

From the figure below:

The required function is AF09

Create symbolic name as following:

#define CAN_AF 0x09

Configure the pin alternate function:

GPIOB->AFR[1]|=(CAN_AF<<GPIO_AFRH_AFSEL8_Pos)|(CAN_AF<<GPIO_AFRH_AFSEL9_Pos);

10. CANBus Initialization:

Declare a new function as following:

void CANBus_Init(void)

This function will initialize the CANBus:

We start off by enabling clock access to CANBus:

Since the CANBus is connected to APB1, we can enable the clock access to it by setting the corresponding bit in APB1ENR to 1:

	/*Enable Clock access to CAN1*/
	RCC->APB1ENR |= RCC_APB1ENR_CAN1EN;

In order to initialize the CANBus, we need to set it into initialization mode.

We can do this by setting INRQ bit in MCR register to 1:

    /* Enter Initialization mode*/
    CAN1->MCR |= CAN_MCR_INRQ;
    /*Wait until CANBus peripheral is in initialization mdoe*/
    while (!(CAN1->MSR & CAN_MSR_INAK));

Exit from sleep mode:

    // Enable CAN1 peripheral
    CAN1->MCR &= ~CAN_MCR_SLEEP;
    while ((CAN1->MSR & CAN_MSR_SLAK)!=0U);

Next, we shall configure the timing:

The parameters and results according to STM32CubeMX:

    /*Configure the timing with the following parameters
     * Normal mode.
     * Loop back mode is disabled.
     * Resynchronization jump width to 1 (value - 1).
     * Prescale of 10. (value - 1)
     * Time quanta segment 1 is 2 (value - 1)
     * Time quanta segment 2 is 1 (value - 1)
     * Baud is 400Kbps
     * */

    /*Reset the non-zero initial values*/
    CAN1->BTR&=~(CAN_BTR_TS1_Msk|CAN_BTR_TS2_Msk|CAN_BTR_SJW_Msk);

    CAN1->BTR=(1<<CAN_BTR_TS1_Pos)|(0<<CAN_BTR_TS2_Pos)
    		|(9U<<CAN_BTR_BRP_Pos);

The following parameters can be configured and set to disabled within this guide:

Other basic parameters can be configured according your application

* The following is the configuration:

* Time triggered communication is disabled.

* Automatic bus-off management is disabled.

* Automatic wake-up is disabled.

* Automatic retransmission is off.

* Receive FIFO lock mode is disabled.

* Transmit FIFO Priority is off

11. Filter Configuration:

We shall configure filter 18 and to accept data from identifier 0f 0x446:

void Filter_Configuration(void)
{
	/* Set the filter initialization mode*/
	CAN1->FMR |= CAN_FMR_FINIT;

	/*Set the slave Filter to start from 20*/
	CAN1->FMR &=~(CAN_FMR_CAN2SB_Msk);
	CAN1->FMR |=(20<<CAN_FMR_CAN2SB_Pos);

	CAN1->FA1R&=~(CAN_FA1R_FACT18);

    CAN1->FS1R |= CAN_FS1R_FSC18;  // Set to 1 for 32-bit scale configuration


    CAN1->FM1R &= ~CAN_FM1R_FBM18; // Set to 0 for identifier mask mode

    CAN1->sFilterRegister[18].FR1 = (0x446<<5) << 16; // Identifier

    CAN1->sFilterRegister[18].FR2 = (0x446<<5) << 16; // Identifier mask 
    
    /*Assign filter 18 to FIFO0*/
    CAN1->FFA1R&=~CAN_FFA1R_FFA18;

    // Activate filter 18
    CAN1->FA1R |= CAN_FA1R_FACT18;


    CAN1->FMR &= ~CAN_FMR_FINIT; // Clear the filter initialization mode

}

The steps as following:

Set the filter mode to initialization mode:

Since we are using filter 18 for this guide, we need to assign filter 20 to 27 for the slave CANBus (CAN2), this can be done using CANSB bits:

  • Clear related bits.
  • Set the buts to be 20.

Deactivate filter 18:

Set the scale to be single 32-bit:

Set the mode to be Mask mode:

Set the identifier and the mask to be 0x446

Assign filter 18 to FIFO0:

Finally, activate filter 18 and exit initialization mode.

12. CANBus start:

To start the CANBus, we need the following steps:

  • Exit Initialization mode.
  • Wait until the initialization is exited.

void CANBus_Start(void)
{
    // Leave Initialization mode
    CAN1->MCR &= ~CAN_MCR_INRQ;
    while (CAN1->MSR & CAN_MSR_INAK);


}

In part three, we shall transmit and receive data.

Stay tuned.

Happy coding 🙂

Add Comment

Your email address will not be published. Required fields are marked *