Testing CAN loopback mode on LPC11C24

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Testing CAN loopback mode on LPC11C24

1,615 Views
ainhoacortes
Contributor I

Hello All,

I have a problem testing the loop back mode for CAN controller on LPC11C24. I am using the can example of LPCopen. This example uses the on-chip CAN API mentioned in UM10398. I do not know how to configure the source code in order to work in loopback mode only as a first test. In fact, I'm not sure if the example is or not in this mode. When I debug the example, the system enters in the CAN_error callback. So, nothing is transmitted nor received. If the on-chip CAN is not in loopback mode, it's normal because I do not have connected any CAN node. But then, how can I configure the on-chip CAN registers to work in loopback mode using this on-chip CAN API? 

The code is this:

#include "board.h"
#include "cr_section_macros.h"

/*****************************************************************************
* Private types/enumerations/variables
****************************************************************************/

#define TEST_CCAN_BAUD_RATE 500000

//reserve CAN ROM-RAM 0x1000 0050 - 0x1000 00B9
__BSS(RESERVED) char CAN_driver_memory[0xC0];

/*****************************************************************************
* Private types/enumerations/variables
****************************************************************************/

#define TEST_CCAN_BAUD_RATE 500000

CCAN_MSG_OBJ_T msg_obj;
volatile unsigned short rx_counter=0; //receive counter
volatile unsigned short tx_counter=0; //transmit counter
/*****************************************************************************
* Public types/enumerations/variables
****************************************************************************/

/*****************************************************************************
* Private functions
****************************************************************************/
void baudrateCalculate(uint32_t baud_rate, uint32_t *can_api_timing_cfg)
{
uint32_t pClk, div, quanta, segs, seg1, seg2, clk_per_bit, can_sjw;
Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_CAN);
pClk = Chip_Clock_GetMainClockRate();

clk_per_bit = pClk / baud_rate;

for (div = 0; div <= 15; div++) {
for (quanta = 1; quanta <= 32; quanta++) {
for (segs = 3; segs <= 17; segs++) {
if (clk_per_bit == (segs * quanta * (div + 1))) {
segs -= 3;
seg1 = segs / 2;
seg2 = segs - seg1;
can_sjw = seg1 > 3 ? 3 : seg1;
can_api_timing_cfg[0] = div;
can_api_timing_cfg[1] =
((quanta - 1) & 0x3F) | (can_sjw & 0x03) << 6 | (seg1 & 0x0F) << 8 | (seg2 & 0x07) << 12;
return;
}
}
}
}
}

/* CAN receive callback */
/* Function is executed by the Callback handler after
a CAN message has been received */
void CAN_rx(uint8_t msg_obj_num) {
rx_counter++;
/* Determine which CAN message has been received */
msg_obj.msgobj = msg_obj_num;
/* Now load up the msg_obj structure with the CAN message */
LPC_CCAN_API->can_receive(&msg_obj);
if (msg_obj_num == 1) {
/* Simply transmit CAN frame (echo) with with ID +0x100 via buffer 2 */
msg_obj.msgobj = 2;
msg_obj.mode_id += 0x100;
LPC_CCAN_API->can_transmit(&msg_obj);
}
return;
}

/* CAN transmit callback */
/* Function is executed by the Callback handler after
a CAN message has been transmitted */
void CAN_tx(uint8_t msg_obj_num) {

tx_counter++;
return;
}

/* CAN error callback */
/* Function is executed by the Callback handler after
an error has occured on the CAN bus */
void CAN_error(uint32_t error_info) {
return;
}

/**
* @brief CCAN Interrupt Handler
* @return Nothing
* @note The CCAN interrupt handler must be provided by the user application.
* It's function is to call the isr() API located in the ROM
*/
void CAN_IRQHandler(void) {
LPC_CCAN_API->isr();
}

/*****************************************************************************
* Public functions
****************************************************************************/

/**
* @brief Main routine for CCAN_ROM example
* @return Nothing
*/
int main(void)
{
volatile unsigned int i,counter=0;
uint32_t CanApiClkInitTable[2];
/* Publish CAN Callback Functions */
CCAN_CALLBACKS_T callbacks = {
CAN_rx,
CAN_tx,
CAN_error,
NULL,
NULL,
NULL,
NULL,
NULL,
};
SystemCoreClockUpdate();
Board_Init();
baudrateCalculate(TEST_CCAN_BAUD_RATE, CanApiClkInitTable);

LPC_CCAN_API->init_can(&CanApiClkInitTable[0], TRUE);
/* Configure the CAN callback functions */
LPC_CCAN_API->config_calb(&callbacks);
//set loop back mode
//LPC_CAN->CNTL |= (1<<7);
//LPC_CCAN->TEST |= (1<<4);

/* Enable the CAN Interrupt */
NVIC_EnableIRQ(CAN_IRQn);

/* Send a simple one time CAN message */
msg_obj.msgobj = 0;
msg_obj.mode_id = 0x345; 
msg_obj.mask = 0x7F0;
msg_obj.dlc = 4;
msg_obj.data[0] = 'T'; // 0x54
msg_obj.data[1] = 'E'; // 0x45
msg_obj.data[2] = 'S'; // 0x53
msg_obj.data[3] = 'T'; // 0x54
LPC_CCAN_API->can_transmit(&msg_obj);

/* Configure message object 1 to receive all 11-bit messages 0x400-0x4FF */
msg_obj.msgobj = 1;
msg_obj.mode_id = 0x300;
msg_obj.mask = 0x7F0;
LPC_CCAN_API->config_rxmsgobj(&msg_obj);

while (1) {
__WFI(); /* Go to Sleep */
}
}

I do not find any helpful information. I have found another kind of problems related to on-chip CAN but it seems that people achieve working in loopback mode but not using on-chip CAN API.

Could anybody help me with this issue?

Thanks.

Labels (3)
0 Kudos
3 Replies

829 Views
kerryzhou
NXP TechSupport
NXP TechSupport

Hi AINHOA CORTES,

    Thank you for your interest in NXP LPC product, I would like to provide service for you!

    The CAN on chip drives have limitation, it doesn't support all the CAN functions..

    I have check the on chip can drives, the can initialization don't have the TEST mode configuration.

    But don't worry, you can combine with the CAN register control.

    If you want to enter loopback mode, you just need to control two registers:

1. CANCNTL[TEST] = 1, enable the test mode.

2. CANTEST[LBACK] =1, enable the loop back mode.

Now, let's based on the lpc11c24 lpcopen code periph_ccan_rom, add the loopback mode enable code.

1. include io_macros.h

#include "io_macros.h"

2. add CAN register define code.

typedef struct{
__REG32 INIT      : 1;
__REG32 IE        : 1;
__REG32 SIE       : 1;
__REG32 EIE       : 1;
__REG32           : 1;
__REG32 DAR       : 1;
__REG32 CCE       : 1;
__REG32 TEST      : 1;
__REG32           :24;
} __cancntl_bits;

/* CAN test register */
typedef struct{
__REG32           : 2;
__REG32 BASIC     : 1;
__REG32 SILENT    : 1;
__REG32 LBACK     : 1;
__REG32 TX        : 2;
__REG32 RX        : 1;
__REG32           :24;
} __cantest_bits;
__IO_REG32_BIT(CANCNTL,               0x40050000,__READ_WRITE ,__cancntl_bits);
__IO_REG32_BIT(CANTEST,               0x40050014,__READ_WRITE ,__cantest_bits);

3. in main() enable the loopback mode.

        CANCNTL |= 1<<7; // enable the test mode
        CANTEST |= 1<<4; // enable the loop back mode.

4. send the data ID in the range of 0x400-0x4ff.

        msg_obj.msgobj  = 0;
    msg_obj.mode_id = 0x400;
    msg_obj.mask    = 0x0;
    msg_obj.dlc     = 4;
    msg_obj.data[0] = 'T';    // 0x54
    msg_obj.data[1] = 'E';    // 0x45
    msg_obj.data[2] = 'S';    // 0x53
    msg_obj.data[3] = 'T';    // 0x54
    LPC_CCAN_API->can_transmit(&msg_obj);

I have attached my test ccam_rom.c for your reference.

After you download the code to your ccan_rom.c, and debug it, you will find even you don't add the CAN node, you also can receive the data. this is my test result on lpcxpresso lpc11c24 board.

pastedImage_1.png

You can receive the correct data.

Please try my code on your side.

If you still have question, just let me know.


Have a great day,
Kerry

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos

829 Views
ainhoacortes
Contributor I

Hi Kerry,

Thank you very much for your response. I think it's very clear and this confirms my thoughts.

Only one easy question. I don't find the io_macros.h file anywhere. Could you send me the file? I do not know why I don't have it in my project, but in the structure I downloaded this file doesn't exist. In fact, I don't find anywhere in the web. In the following figure, you can see the files I have related to LPC chip:

pastedImage_1.png

Best regards,

Ainhoa

0 Kudos

828 Views
kerryzhou
NXP TechSupport
NXP TechSupport

Hello Ainhoa,

   Sorry for my later reply.

io_macros.h is the file in the IAR install attachment.

  If you are using the lPCXpresso IDE,  you can refer to my attached header file: LPC11xx.h.

 Line 483:

typedef struct
{
  __IO uint32_t CNTL;                /* 0x000 */
  __IO uint32_t STAT;
  __IO uint32_t EC;
  __IO uint32_t BT;
  __IO uint32_t INT;
  __IO uint32_t TEST;
  __IO uint32_t BRPE;
       uint32_t RESERVED0;
  __IO uint32_t IF1_CMDREQ;            /* 0x020 */
  __IO uint32_t IF1_CMDMSK;
  __IO uint32_t IF1_MSK1;
  __IO uint32_t IF1_MSK2;
  __IO uint32_t IF1_ARB1;
  __IO uint32_t IF1_ARB2;
  __IO uint32_t IF1_MCTRL;
  __IO uint32_t IF1_DA1;
  __IO uint32_t IF1_DA2;
  __IO uint32_t IF1_DB1;
  __IO uint32_t IF1_DB2;
       uint32_t RESERVED1[13];
  __IO uint32_t IF2_CMDREQ;            /* 0x080 */
  __IO uint32_t IF2_CMDMSK;
  __IO uint32_t IF2_MSK1;
  __IO uint32_t IF2_MSK2;
  __IO uint32_t IF2_ARB1;
  __IO uint32_t IF2_ARB2;
  __IO uint32_t IF2_MCTRL;
  __IO uint32_t IF2_DA1;
  __IO uint32_t IF2_DA2;
  __IO uint32_t IF2_DB1;
  __IO uint32_t IF2_DB2;
       uint32_t RESERVED2[21];
  __I  uint32_t TXREQ1;                /* 0x100 */
  __I  uint32_t TXREQ2;
       uint32_t RESERVED3[6];
  __I  uint32_t ND1;                /* 0x120 */
  __I  uint32_t ND2;
       uint32_t RESERVED4[6];
  __I  uint32_t IR1;                /* 0x140 */
  __I  uint32_t IR2;
       uint32_t RESERVED5[6];
  __I  uint32_t MSGV1;                /* 0x160 */
  __I  uint32_t MSGV2;
       uint32_t RESERVED6[6];
  __IO uint32_t CLKDIV;                /* 0x180 */
} LPC_CAN_TypeDef;

Line 560:

#define LPC_CAN_BASE          (LPC_APB0_BASE + 0x50000)

#define LPC_CAN               ((LPC_CAN_TypeDef    *) LPC_CAN_BASE   )

#define CTRL_TEST        (1 << 7)

#define TEST_LOOPBACK        (1 << 4)

Then you can call CAN register like this:

LPC_CAN->CNTL |= CTRL_TEST ;

LPC_CAN->TEST |= TEST_LOOPBACK   ;

Wish it helps you!

      


Have a great day,
Kerry

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos