cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F303xC CAN configuration.

ArturasV
Senior
Posted on June 20, 2014 at 17:12

Hello everyone, i am trying to implement CAN on my application. It is the first time i am dealing with it. I've read a lot about protocol itself, and looked through a lot of examples which are posted in this forum. This is a piece of code which i copied from one topic. 

  //================================================================

  CAN_Filter_InitStructure.CAN_FilterIdHigh = 0x0000; // ?

  CAN_Filter_InitStructure.CAN_FilterIdLow = 0x0000; // ?

  CAN_Filter_InitStructure.CAN_FilterMaskIdHigh = 0x0000; // ?

  CAN_Filter_InitStructure.CAN_FilterMaskIdLow = 0x0000; // ?

  CAN_Filter_InitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0; // ?

  CAN_Filter_InitStructure.CAN_FilterNumber = 0; // ?

  CAN_Filter_InitStructure.CAN_FilterMode = CAN_FilterMode_IdMask; // ?

  CAN_Filter_InitStructure.CAN_FilterScale = CAN_FilterScale_32bit; // ?

  CAN_Filter_InitStructure.CAN_FilterActivation = ENABLE; 

  

  CAN_FilterInit(&CAN_Filter_InitStructure); // Write values to the registers

  //================================================================

However, i can't find in any documentation which woul have these commands explained. I know this configuration works. But to be honest, i don't understand why it is configured like this and what would change, changing values of this structure. So if anyone could point me to some literature which would be explaining how to understand these commands, or if anyone could explain how to understant every line in this configuration, i would be trully grateful.

#can-filter
4 REPLIES 4
Posted on June 20, 2014 at 19:10

I did an analysis of this once, and concluded most of the examples and explanations of them were probably wrong. As I understand it's actual functionality the message id is in the high order bits. The masks AND with the inbound data, and there are comparators behind them. This allows you to identify specific, or ranges of messages.

Do you want to see all the traffic? If yes, the most promiscuous mode and lax filtering should work fine.

The reason to have filters, and direct messages to specific mailboxes is to deal with the priority, and necessity of messages of different classes, to nodes on the bus. For example the door lock control, or the sun roof actuator, really isn't interested in messages about motor RPM or fuel consumption/flow, and thus at a bus level ignores them and only stores and interrupts the processor when some salient messages arrive, ie unlock passenger door, open sun roof, etc.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
jpeacock2399
Associate II
Posted on June 20, 2014 at 21:27

Filters are an invaluable feature when implementing a CAN protocol, especially when the message ID contains a protocol field.

FIlterID is the exact match after the incoming message ID is masked by FilterMaskID, which are either 16 (for 11 bitmessage ID)or 32 bit (for 29 bit message ID)depending on FilterMode and FilterScale. The FIFO assignment directs the matching incoming message to one of the two message FIFOs. Typically the two FIFOs are used for separate high and low priority messages, so that high priority is handled first. The Filter Number identifies which filter slot is being configured (out of 14 or 28 possible slots). Activation turns on the filter, enabling matching messages to beinserted in the message FIFOs as they arrive. Filtering works especially well for the CANopen protocol, which works out to one filter for each CANopen service (NMT, SYNC, TIME, EMCY, PDOs, SDO, etc.). In my CANopen stack I allocate a filter to each service, so that nodes which do not need a particular service can filter out the corresponding messages. The CANopen service is identified by the high 4 bits in the 11 bit message ID, followed by a 7 bit node address. I set up the filter mask to select the top four bits, and then set the filter ID to matcha service number. Messages are automatically prioritized depending on the service (i.e.EMCY emergency and SRDO safety related messages are always processed first from FIFO0, lower priority from FIFO1).

/** 
* Set up filter to receive SYNC service messages 
* The SYNC RX service accepts incoming SYNC messages from the configured SYNC producer node. 
* The SYNC RX service always accepts SYNC messages from global producer node 0. 
*/ 
xCanFilter.Filter = COP_SYNC_FILTER; // service filter for SYNC 
xCanFilter.Activate = SET; // enable service rx 
// SYNC RX (no RTR, must match producer) 
xCanFilter.FilterMaskIdLow.Group = COP_COBID_GROUP; // match function group 
xCanFilter.FilterMaskIdLow.Node = COP_COBID_NODE; // match SYNC producer node ID 
xCanFilter.FilterMaskIdLow.Rtr = SET; // match RTR for RX 
xCanFilter.FilterMaskIdLow.Ide = SET; // match for standard ID 
xCanFilter.FilterMaskIdLow.Extid = 0; // unused 
xCanFilter.FilterIdLow.Group = COP_FUNC_SYNC; // SYNC service 
xCanFilter.FilterIdLow.Node = cop_SyncCOBID & COP_COBID_NODE; // SYNC producer node ID 
xCanFilter.FilterIdLow.Rtr = RESET; // not a remote request 
xCanFilter.FilterIdLow.Ide = RESET; // standard ID 
xCanFilter.FilterIdLow.Extid = 0; // unused 
// SYNC RX fixed node ID 0x00 
xCanFilter.FilterMaskIdHigh.Group = COP_COBID_GROUP; // match function group 
xCanFilter.FilterMaskIdHigh.Node = COP_COBID_NODE; // match node, one node response 
xCanFilter.FilterMaskIdHigh.Rtr = SET; // match RTR for TX request 
xCanFilter.FilterMaskIdHigh.Ide = SET; // match for standard ID 
xCanFilter.FilterMaskIdHigh.Extid = 0; // unused 
xCanFilter.FilterIdHigh.Group = COP_FUNC_SYNC; // SYNC service 
xCanFilter.FilterIdHigh.Node = 0x00; // SYNC global node ID 
xCanFilter.FilterIdHigh.Rtr = RESET; // not a remote request 
xCanFilter.FilterIdHigh.Ide = RESET; // standard ID 
xCanFilter.FilterIdHigh.Extid = 0; // unused 
// enable filter to start receiving SYNC messages 
iosize = sizeof(CANFilter); 
i = Iob->Link( Iob, &xCanFilter, &iosize, CAN_IOCMD_FILTER, blocking); // enable SYNC service incoming

This is an example of how I configure a filter for the CANopen SYNC service. The call at the end (Iob->Link) includes the ST library call to configure the filter. Jack Peacock
ArturasV
Senior
Posted on June 21, 2014 at 16:44

Thank you Jack Peacock and Clive1 for your answers. Really appreciate your effort trying to explain this one for me. 

ArturasV
Senior
Posted on June 27, 2014 at 14:00

So going deeper into this, i am trying to get CAN to work. According to RM0316 28.5.2 When CAN is configured in Loop back mode, ''The transmitted messages can be monitored on the CANTX pin'' . I can see that loop back mode works, because i check the values of Rx message registers, and they change, but i can't see anything on CAN Tx pin with oscilloscope. Pointing out what i'm missing would be great. Thanks

#include ''stm32f30x.h''

RCC_ClocksTypeDef RCC_ClockFreq;

CAN_InitTypeDef CAN_InitStructure;

CAN_FilterInitTypeDef CAN_Filter_InitStructure;

GPIO_InitTypeDef GPIO_InitStructure;

CanTxMsg TxMessage;

CanRxMsg RxMessage;

void CAN_configuration(void);

void GPIO_configuration(void);

void RCCClocks_configuration(void);

void CAN1_Tx(void);

uint32_t clock;

uint8_t TransmitMailbox;

int main(void)

{

  RCCClocks_configuration();

  GPIO_configuration();

  CAN_configuration();

  CAN1_Tx();

 

 /* Get clock source (used to observe system) */

 clock = RCC_GetSYSCLKSource();

 /* possible clock variable values */

   /* 

     0x00: HSI used as system clock

     0x04: HSE used as system clock  

     0x08: PLL used as system clock

   */

  RCC_GetClocksFreq(&RCC_ClockFreq); // Get clock frequency (used to observe system)

  

  

  while(1)

  {

  }

}

void CAN_configuration(void)

  /* Reset CAN peripheral registers to default values */

  CAN_DeInit(CAN1);

  CAN_StructInit(&CAN_InitStructure);

  

  /* CAN_BaudRate = CAN_Clock / (CAN_Prescaler * (CAN_SJW + CAN_BS1 + CAN_BS2)) */

  /* Time quantum = CAN_SJW + CAN_BS1 + CAN_BS2 */

  /* Time quantum = 1+10+7 = 18 */

  /* CAN_BaudRate = 36000000 / (16*18) */

  /* CAN_BaudRate = 125kbps */

  

  /* Configure CAN structure */

  /* CAN_Clock = PCLK1_Frequency = 36MHz */

  /* CAN_Prescaler = 36000000/ ( 18*125000 )  = 16 */

  CAN_InitStructure.CAN_Prescaler = RCC_ClockFreq.PCLK1_Frequency / ( 18*125000); // CAN_Prescaler = 16

  CAN_InitStructure.CAN_Mode = CAN_Mode_LoopBack;

  CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;  // 1 time quantum

  CAN_InitStructure.CAN_BS1 = CAN_BS1_10tq; // 6 time quantum

  CAN_InitStructure.CAN_BS2 = CAN_BS2_7tq;  // 7 quantum time

  CAN_InitStructure.CAN_TTCM = DISABLE;     // Disable TTCM ( Time-triggered communication mode)

  CAN_InitStructure.CAN_ABOM = DISABLE;     // Disable ABOM ( Automatic buss-off managament )

  CAN_InitStructure.CAN_AWUM = DISABLE;     // Disable AWUM ( Automatic wake-up mode )

  CAN_InitStructure.CAN_NART = DISABLE;     // Disable NART ( Non-automatic retransmission mode )

  CAN_InitStructure.CAN_RFLM = DISABLE;     // Disable RFLM ( Receive FIFO locked mode )

  CAN_InitStructure.CAN_TXFP = DISABLE;     // Disable TXFP ( Transmit FIFO priority )

  /* Write values to CAN registers */

  CAN_Init(CAN1, &CAN_InitStructure);

 

  /* CAN filter structure */

  /*  Examine these commands. This configuration sees all data flow. */

  //===================================================================================================

  CAN_Filter_InitStructure.CAN_FilterIdHigh = 0x0000;

  CAN_Filter_InitStructure.CAN_FilterIdLow = 0x0000;

  CAN_Filter_InitStructure.CAN_FilterMaskIdHigh = 0x0000; 

  CAN_Filter_InitStructure.CAN_FilterMaskIdLow = 0x0000;

  CAN_Filter_InitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;

  CAN_Filter_InitStructure.CAN_FilterNumber = 0;

  CAN_Filter_InitStructure.CAN_FilterMode = CAN_FilterMode_IdMask; 

  CAN_Filter_InitStructure.CAN_FilterScale = CAN_FilterScale_32bit;

  CAN_Filter_InitStructure.CAN_FilterActivation = ENABLE; 

  

  CAN_FilterInit(&CAN_Filter_InitStructure); // Write values to the registers

  //====================================================================================================

}

void CAN1_Tx(void)

{

  

  TxMessage.StdId = 0x124; // Standard identifier of the message. Value has to be between [0 - 0x7FF]. 11-bits long.

  TxMessage.ExtId = 0x000; // Extended identifier of the message. Value has to be between [0 - 1FFFFFFF]. 29-bits long.

  TxMessage.RTR = CAN_RTR_Data; // RTR - Remote transmission request. CAN_RTR_Data - carries regular data. 

  /* CAN_RTR_Remote - used to request the transmission of a DATA FRAME with the same ID */

  TxMessage.IDE = CAN_Id_Standard; // IDE - identifier. Use standart identifier of the message ( 11-bits ).

  TxMessage.DLC = 8; // Data lenght frame, which will be transmitted. 8 = eight bytes will be transmitted.

  

   volatile unsigned int i;

  

  /* Data to be send on CAN bus. 8 bytes. It ranges from 0 to 0xFF */                     

  TxMessage.Data[0] = 0xAA;

  TxMessage.Data[1] = 0x22;

  TxMessage.Data[2] = 0x33;

  TxMessage.Data[3] = 0x33;

  TxMessage.Data[4] = 0xDD;

  TxMessage.Data[5] = 0xCC;

  TxMessage.Data[6] = 0xBB;

  TxMessage.Data[7] = 0xAA;

  

   TransmitMailbox = CAN_Transmit(CAN1, &TxMessage);

      i = 0;

      while((CAN_TransmitStatus(CAN1, TransmitMailbox) != CANTXOK) && (i != 0xFFFFFF)) // Wait on Transmit

      {

        i++;

      }

}

void GPIO_configuration(void)

{

  /* Configure CAN Rx and Tx */

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;    // Use 0 and 1 pins

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;              // Pins are in alternate-function mode.

  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;            // Output type - Push-pull

  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;          // No pull-up resistors

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;         // Maximum GPIO toggling speed = 50MHz

  GPIO_Init(GPIOD, &GPIO_InitStructure);                    // Write values to the registers

 

  /* Connect CAN Rx and Tx to GPIO Pins */

  GPIO_PinAFConfig(GPIOD, GPIO_PinSource0, GPIO_AF_7); // CAN1_Rx = PD.00

  GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_7); // CAN1_Tx = PD.01

}

void RCCClocks_configuration(void)

{

  /* Enable clocks for PORT D */

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOD, ENABLE); 

  /* Enable clocks for CAN1 */

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); 

}