STM32F40x CAN controller

Keywords: Embedded system stm32 can STM32F4

1, Introduction to CAN controller

STM32 comes with a basic extended CAN peripheral, also known as bxCAN. The features of bxCAN are as follows:

  • Support CAN protocol 2.0A and 2.0B active mode

  • Baud rate up to 1Mbps

  • Support time triggered communication

  • Has 3 send mailboxes

  • 2 receive FIFO s with 3 levels of depth

  • Variable filter groups (also known as filter groups, up to 28)
    CAN bus mode:
    1. Working mode

  • Initialization mode (INRQ=1, SLEEP=0)

  • Normal mode (INRQ=0, SLEEP=0)

  • Sleep mode (SLEEP=1)

2. Test mode

  • Silent mode (LBKM=0, SILM=1)

  • Loopback mode (LBKM=1, SILM=0)

  • Loopback silent mode (LBKM=1, SILM=1)

3. Debug mode
CAN controller block diagram:
**CAN sending process: * * the program selects an empty mailbox (TME=1) - > sets the identifier (ID), data len gt h and sending data - > sets CAN_ TXRQ bit of tixr is 1, request sending - > mailbox registration (waiting to become the highest priority) - > scheduled sending (waiting for bus idle) - > sending - > mailbox vacancy.

CAN receiving process: FIFO empty - > receive valid message - > register_ 1 (a mailbox stored in FIFO, which is controlled by hardware and we don't need to pay attention to it) - > receive valid message - > register_ 2 - > receive valid message - > register_ 3 - > valid message received - > overflow.

**Note: * * message FIFO has locking function (controlled by CAN_MCR and RFLM bit). After locking, new data will be discarded. If not locked, new data will replace old data
CAN bit timing of STM32:

STM32F103,set up TS1=8,TS2=7,BRP=3,Baud rate=36000/[(9+8+1)*4]=500Kbps. 
STM32F407,set up TS1=6,TS2=5,BRP=5,Baud rate=42000/[(7+6+1)*6]=500Kbps. 

2, CAN register of STM32

1. CAN main control register (CAN#u MCR)

Set INRQ=0 to enable CAN to enter normal operation mode from initialization mode.
Set INRQ=1 to enable CAN to enter initialization mode from normal operation mode.
Note: During CAN initialization, first set INRQ=1 to enter the initialization mode for initialization (especially the setting of CAN_BTR, which must be set before CAN normal operation), and then set INRQ=0 to enter the normal operation mode.
2. CAN bit timing register (CAN_BTR)
3. CAN receive FIFO register (CAN_RF0R\CAN_RF1R)

4. CAN send mailbox identifier register (CAN_TIxR, where x=0~2)

5. CAN send mailbox data length and timestamp register (CAN_TDTxR, where x=0~2)

6. CAN send mailbox data register (CAN_TDLxR/CAN_TDHxR, where x=0~2)

7. CAN receive FIFO mailbox identifier register (CAN_RIxR, where x=0/1)

8. CAN receive FIFO mailbox data length and timestamp register (CAN_RDTxR, where x=0/1)

9. CAN receive FIFO mailbox data register (CAN_RDLxR/CAN_RDHxR, where x=0/1)

10. CAN filter mode register (CAN#u fm1r)
Note: this register sets the working mode of the filter, which must be configured when can(u fMR register FINIT=1. For STM32F103ZET6, only [13:0] bits are valid, and for interconnection STM32F1 or STM32F407, all are valid.
11. CAN filter scale register (CAN#u fs1r)

Note: this register is used to set the bit width of the filter. It must be configured when can(u fMR register FINIT=1. For STM32F103ZET6, only [13:0] bits are valid. For interconnection STM32F1 or STM32F407, all bits are valid.
12. CAN filter FIFO Association register (CAN#u ffa1r)

Note: this register sets the FIFO stored after the message passes through the filter group. If the corresponding bit is 0, it will be stored in FIFO0; if it is 1, it will be stored in FIFO1. This register can only be configured when the filter is in initialization mode (FINIT=1 of CAN_FMR register).
13. CAN filter activation register (CAN_FA1R)

Note: this register is used to set the opening and closing of the filter group. For the corresponding position 1, the corresponding filter group is opened; set 0 to close the filter group.
14. CAN filter group i register x (CAN_FiRx, where i=0~27, x=1/2)

3, CNA bus initialization process

  • ① Configure the multiplexing function of relevant pins to enable the CAN clock.
    To use CAN, first enable the clock of CAN. The clock of CAN is set through the 25th bit of APB1ENR. Secondly, set the relevant pin of CAN as multiplex output. Here, we need to set PA11 as pull-up input (CAN_RX pin) and PA12 as multiplex output (CAN_TX pin), and enable the clock of PA port
  • ② Set CAN working mode, baud rate, etc.
    First set the INRQ bit of the CAN_MCR register to let the CAN enter the initialization mode, and then set other relevant control bits of the CAN_MCR. Then set the baud rate and working mode (normal mode / loopback mode) through the CAN_BTR.
    Finally, set INRQ to 0 and exit the initialization mode.
  • ③ Set the filter.
    We will use filter group 0 and work in 32-bit identifier mask bit mode. First set the FINIT bit of CAN_FMR to enter initialization mode, then set the working mode of filter group 0, identifier ID and mask bit. Finally, activate the filter and exit initialization mode.

4, Code display

//CAN initialization
//tsjw: resynchronize jump time unit. Range: CAN_SJW_1tq~ CAN_SJW_4tq
//tbs2: time unit of time period 2. Range: CAN_BS2_1tq~CAN_BS2_8tq;
//tbs1: time unit of time period 1. Range: CAN_BS1_1tq ~CAN_BS1_16tq
//brp: baud rate divider. Range: 1~1024; tq=(brp)*tpclk1
//Baud rate = Fpclk1/((tbs1+1+tbs2+1+1)*brp);
//mode:CAN_Mode_Normal, normal mode; CAN_Mode_LoopBack, loopback mode;
//The clock of Fpclk1 is set to 42M during initialization. If CAN1_Mode_Init(CAN_SJW_1tq,CAN_BS2_6tq,CAN_BS1_7tq,6,CAN_Mode_LoopBack) is set;
//Baud rate: 42M/((6+7+1)*6)=500Kbps
//Return value: 0, initialization OK;
//    Other, initialization failed; 


u8 CAN1_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)
{

  	GPIO_InitTypeDef GPIO_InitStructure; 
	  CAN_InitTypeDef        CAN_InitStructure;
  	CAN_FilterInitTypeDef  CAN_FilterInitStructure;
#if CAN1_RX0_INT_ENABLE 
   	NVIC_InitTypeDef  NVIC_InitStructure;
#endif
    //Enable correlation clock
	  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//Enable PORTA clock	                   											 

  	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//Enable CAN1 clock	
	
    //Initialize GPIO
	  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11| GPIO_Pin_12;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//Reuse function
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//Push pull output
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//Pull up
    GPIO_Init(GPIOA, &GPIO_InitStructure);//Initialize PA11,PA12
	
	  //Pin multiplexing mapping configuration
	  GPIO_PinAFConfig(GPIOA,GPIO_PinSource11,GPIO_AF_CAN1); //GPIOA11 multiplexed to CAN1
	  GPIO_PinAFConfig(GPIOA,GPIO_PinSource12,GPIO_AF_CAN1); //GPIOA12 multiplexed to CAN1
	  
  	//CAN unit settings
   	CAN_InitStructure.CAN_TTCM=DISABLE;	//Non time triggered communication mode   
  	CAN_InitStructure.CAN_ABOM=DISABLE;	//Software automatic offline management	  
  	CAN_InitStructure.CAN_AWUM=DISABLE;//SLEEP mode wakes up through software (clear SLEEP bit of can - > MCR)
  	CAN_InitStructure.CAN_NART=ENABLE;	//Automatic message transmission is prohibited 
  	CAN_InitStructure.CAN_RFLM=DISABLE;	//The message is not locked, and the new one overwrites the old one  
  	CAN_InitStructure.CAN_TXFP=DISABLE;	//The priority is determined by the message identifier 
  	CAN_InitStructure.CAN_Mode= mode;	 //Mode setting 
  	CAN_InitStructure.CAN_SJW=tsjw;	//The resynchronization jump width (Tsjw) is tsjw+1 time unit CAN_SJW_1tq~CAN_SJW_4tq
  	CAN_InitStructure.CAN_BS1=tbs1; //Tbs1 range CAN_BS1_1tq ~CAN_BS1_16tq
  	CAN_InitStructure.CAN_BS2=tbs2;//Tbs2 range CAN_BS2_1tq~ 	 CAN_BS2_8tq
  	CAN_InitStructure.CAN_Prescaler=brp;  //The frequency division coefficient (Fdiv) is brp+1	
  	CAN_Init(CAN1, &CAN_InitStructure);   // Initialize CAN1 
    
		//Configure filter
 	  CAN_FilterInitStructure.CAN_FilterNumber=0;	  //Filter 0
  	CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; 
  	CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32 bit 
  	CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;32 position ID
  	CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
  	CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//32-bit MASK
  	CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
   	CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//Filter 0 is associated to FIFO0
  	CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //Activate filter 0
  	CAN_FilterInit(&CAN_FilterInitStructure);//Filter initialization
		
#if CAN1_RX0_INT_ENABLE
	
	  CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);//FIFO 0 message registration interrupt allowed		    
  
  	NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;     // The primary priority is 1
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;            // The secondary priority is 0
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  	NVIC_Init(&NVIC_InitStructure);
#endif
	return 0;
}   
 
#if CAN1_RX0_INT_ENABLE 	// Enable rx0 interrupt
//Interrupt service function			    
void CAN1_RX0_IRQHandler(void)
{
  	CanRxMsg RxMessage;
	int i=0;
    CAN_Receive(CAN1, 0, &RxMessage);
	for(i=0;i<8;i++)
	printf("rxbuf[%d]:%d\r\n",i,RxMessage.Data[i]);
}
#endif

//can sends a group of data (fixed format: ID 0X12, standard frame, data frame)	
//len: data length (max. 8)				     
//msg: data pointer, maximum 8 bytes
//Return value: 0, successful;
//		 Others, failure;
u8 CAN1_Send_Msg(u8* msg,u8 len)
{	
  u8 mbox;
  u16 i=0;
  CanTxMsg TxMessage;
  TxMessage.StdId=0x12;	 // The standard identifier is 0
  TxMessage.ExtId=0x12;	 // Set extension identifier (29 bits)
  TxMessage.IDE=0;		  // Use extended identifier
  TxMessage.RTR=0;		  // The message type is data frame, 8 bits per frame
  TxMessage.DLC=len;							 // Send two frames of information
  for(i=0;i<len;i++)
  TxMessage.Data[i]=msg[i];				 // First frame information          
  mbox= CAN_Transmit(CAN1, &TxMessage);   
  i=0;
  while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))i++;	//Wait for sending to end
  if(i>=0XFFF)return 1;
  return 0;		

}
//can port receiving data query
//buf: data buffer;	 
//Return value: 0, no data received;
//		 Other, length of received data;
u8 CAN1_Receive_Msg(u8 *buf)
{		   		   
 	u32 i;
	CanRxMsg RxMessage;
    if( CAN_MessagePending(CAN1,CAN_FIFO0)==0)return 0;		//No data received, exit directly 
    CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);//Read data	
    for(i=0;i<RxMessage.DLC;i++)
    buf[i]=RxMessage.Data[i];  
	return RxMessage.DLC;	
}

Posted by sone_br on Mon, 27 Sep 2021 03:48:21 -0700