15
votes

I am trying to setup CAN communication between a couple of LPC device nodes. My setup includes a couple of CAN nodes writing on to the CAN bus. For example LPC 2292 CAN controller can write on to the CAN bus and the LPC1758 can receive the data. This works perfectly fine. Now LPC1758 has 2 CAN controllers and I have setup one for receiving data and the other for transmitting data on the bus as a response. I also setup interrupt handlers for LPC 1758 CAN 1 transmit & receive and CAN 2 transmit & receive. ( I dont have code for LPC 2292. its not under my control)

My problem is at the LPC1758 side. Here the CAN 1 receiver is able to get the data from the other CAN nodes as I can see the interrupt vector handler being called. The problem is when the the LPC 1758 CAN 2 tranmistter writes to the bus . It gets a bus error . More specificially "Start of Frame " error . ( I use a Ulink2 debugger). Now reading the CAN specs I know the start frame of the CAN message should start with a low ( dominant) bit CAN specs ; See page 3

How do I go about fixing this error ? Its not a configurable register that I can set the first bit to 0 or 1. I run the default LPC 1758 CAN code that comes with KEIL C:\Keil_v5\ARM\Boards\Keil\MCB1700\CAN I think the code is fine because when I run the code in simulation mode of KEIL I can see the CAN commnication work well.

Is this "Start of Frame" a by product of some other configurations that I am missing ?

Update Code : 

I run the default LPC 1758 CAN code that comes with KEIL C:\Keil_v5\ARM\Boards\Keil\MCB1700\CAN I think the code is fine because when I run the code in simulation mode of KEIL I can see the CAN communication work well. Also I did not make any changes to the code except the baudrate. CAN setup :

/*----------------------------------------------------------------------------
  setup CAN interface.  CAN controller (1..2)
 *----------------------------------------------------------------------------*/
void CAN_setup (uint32_t ctrl)  {
  LPC_CAN_TypeDef *pCAN = (ctrl == 1) ? LPC_CAN1 : LPC_CAN2;

  if (ctrl == 1) {
    LPC_SC->PCONP       |=  (1 << 13);           /* Enable power to CAN1 block */
    LPC_PINCON->PINSEL0 |=  (1 <<  0);           /* Pin P0.0 used as RD1 (CAN1) */
    LPC_PINCON->PINSEL0 |=  (1 <<  2);           /* Pin P0.1 used as TD1 (CAN1) */

    NVIC_EnableIRQ(CAN_IRQn);                    /* Enable CAN interrupt */
  } else {
    LPC_SC->PCONP       |=  (1 << 14);           /* Enable power to CAN2 block */
    LPC_PINCON->PINSEL4 |=  (1 << 14);           /* Pin P2.7 used as RD2 (CAN2) */
    LPC_PINCON->PINSEL4 |=  (1 << 16);           /* Pin P2.8 used as TD2 (CAN2) */

    NVIC_EnableIRQ(CAN_IRQn);                    /* Enable CAN interrupt */
  }

  LPC_CANAF->AFMR = 2;                           /* By default filter is not used */
  pCAN->MOD   = 1;                               /* Enter reset mode */
  pCAN->IER   = 0;                               /* Disable all interrupts */
  pCAN->GSR   = 0;                               /* Clear status register */
  CAN_cfgBaudrate(ctrl, /*250000*/ 100000);                 /* Set bit timing */
  pCAN->IER   = 0x0003;                          /* Enable Tx and Rx interrupt */
    //pCAN->IER   = 0x7FF;

}

Here is my code to transmit and receive:

/*----------------------------------------------------------------------------
  wite a message to CAN peripheral and transmit it.  CAN controller (1..2)
 *----------------------------------------------------------------------------*/
void CAN_wrMsg (uint32_t ctrl, CAN_msg *msg)  {
  LPC_CAN_TypeDef *pCAN = (ctrl == 1) ? LPC_CAN1 : LPC_CAN2;
  uint32_t CANData;

  CANData = (((uint32_t) msg->len) << 16)     & 0x000F0000 | 
            (msg->format == EXTENDED_FORMAT ) * 0x80000000 |
            (msg->type   == REMOTE_FRAME)     * 0x40000000;

  if (pCAN->SR & (1<<2))  {                      /* Transmit buffer 1 free */
    pCAN->TFI1  = CANData;                       /* Write frame informations */
    pCAN->TID1 = msg->id;                        /* Write CAN message identifier */
    pCAN->TDA1 = *(uint32_t *) &msg->data[0];    /* Write first 4 data bytes */
    pCAN->TDB1 = *(uint32_t *) &msg->data[4];    /* Write second 4 data bytes */
    //pCAN->CMR  = 0x31;                           /* Select Tx1 for Self Tx/Rx */
    pCAN->CMR  = 0x21;                           /* Start transmission without loop-back */ -- Here is when "Start of Frame " error happens

  }
}

Receive code is fine but still posting

/*----------------------------------------------------------------------------
  read a message from CAN peripheral and release it.  CAN controller (1..2)
 *----------------------------------------------------------------------------*/
void CAN_rdMsg (uint32_t ctrl, CAN_msg *msg)  {
  LPC_CAN_TypeDef *pCAN = (ctrl == 1) ? LPC_CAN1 : LPC_CAN2;
  uint32_t CANData;

                                                 /* Read frame informations */
  CANData = pCAN->RFS;
  msg->format   = (CANData & 0x80000000) == 0x80000000;
  msg->type     = (CANData & 0x40000000) == 0x40000000;
  msg->len      = ((uint8_t)(CANData >> 16)) & 0x0F;

  msg->id = pCAN->RID;                           /* Read CAN message identifier */

  if (msg->type == DATA_FRAME)  {                /* Read the data if received message was DATA FRAME  */ 
    *(uint32_t *) &msg->data[0] = pCAN->RDA;
    *(uint32_t *) &msg->data[4] = pCAN->RDB;
  }
}

Baudrate Calculation:

/*----------------------------------------------------------------------------
  configure the requested baudrate.  CAN controller (1..2)
 *----------------------------------------------------------------------------*/
static void CAN_cfgBaudrate (uint32_t ctrl, uint32_t baudrate)  {
  LPC_CAN_TypeDef *pCAN = (ctrl == 1) ? LPC_CAN1 : LPC_CAN2;
  uint32_t result = 0;
  uint32_t nominal_time;

  /* Determine which nominal time to use for PCLK */
  if (((PCLK / 1000000) % 6) == 0) {
    nominal_time = 12;                   /* PCLK based on  72MHz CCLK */
  } else {
    nominal_time = 10;                   /* PCLK based on 100MHz CCLK */
  }

  /* Prepare value appropriate for bit time register */
  result  = (PCLK / nominal_time) / baudrate - 1;
  result &= 0x000003FF;
  result |= CAN_BIT_TIME[nominal_time];

  pCAN->BTR  = result;                           /* Set bit timing */
}
1
Baudrate configuration is correct?Swanand
@Swanand I have been told that the other nodes on the CAN bus are at 100KBps . Hence i programmed my new LPC 1758 to be 100KBPS as well and i am able to receive messages from the other LPC nodes. I just cant send out any from my LPC 1758. Do i also need to check the CAN clocks ? values in the SJW, TSEG1 & TSEG2 registers etc? Do they need to be same across all boards? I dont have the configuration for other boards . I only know the baudrate. Any hints ? The main objective is that my new CAN node would be sort of plug and play into the existing CAN network. Thanks for help !rockstar
can you show some code?gj13
Can you post a CAN trace and the data frame you try to transmit? Are you sure the CAN bus is IDLE while you try to send - i.e. in which interval does your LPC2292 send data?Constantin
You should enter normal mode after setting the baudrate: LPC_CAN1->MOD = 0x00; And you should check the other 2 transmit buffers.gj13

1 Answers

2
votes

I am finally able to get rid of the "Start of Frame " error that had being bogging me down. I had a discussion with some of our other CAN bus code authors and he suggested i use the same CAN controller for sending and receiving. In short this:

** Does not work** : 
LPC 2292 : CAN 1 Rx & CAN 2 Tx
LPC 1750 : CAN 1 Rx & CAN 2 TX 

** WORKS** :
LPC 2292 : CAN 1 Rx & CAN 1 Tx
LPC 1750 : CAN 1 Rx & CAN 1 TX 

Being a newbie i may have made this mistake. But the default code provided by KEIL shows using alternate CAN controllers for sending and transmitting. I hope this helps someone .