Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save tdowgielewicz/25136aa6fab2ebaee184 to your computer and use it in GitHub Desktop.
Save tdowgielewicz/25136aa6fab2ebaee184 to your computer and use it in GitHub Desktop.
User friendly CAN usage toutorial - CooCox LandTiger LPC1768 Cortex M3
// ================== CAN1 and CAN2 LPC1768 test ===========================//
//CooCox IDE
/* "I was just starting my journey with uC and CAN so it was real PIA to understand whole stuff.
* This example have much more rich comments so it will be easier for newbie to understand what is going on
* Ensure that before you start with this example you know how CAN work. I also assume that you are already
* after GPIO basics chapter
This example was build on LandTiger v2.0 board (LPC1768). In this board there are CAN 2 controllers
with transceivers are available:
CAN1:
P0.0 TD1
P0.1 RD1
CAN2:
P0.4 TD2
P0.5 RD2
Thats why in init function there are LPC_PINCON->PINSEL lines.
You can find this and many more info in official NXP documents
The idea of this example is simple:
1. Program is running and blinking LEDs (Rule#1 blinking LEDs are always awesome)
2. When Button is Pressed CAN message is sent from CAN1 to CAN2 also LED1 turns on
3. CAN2 interrupt function is called LED2 turns on
4. Send message is compared with received message
a) If messages are the same LED3 turns on
b) If messages are different LED4 turns off
5.If button is not pressed LEDs go down (expect blinking one, remember about rule#1)
Hardware preparation:
This example was created on LandTiger 2.0 So it have all transceivers and 120hm resistors.
Only thing you need to do is to connect CAN1H with CAN2H and CAN1L with CAN2L (by external wire)
If you have different hardware please compare it with LAndTiger to clarify doubts
*/
// Example added by Tomasz Dowgielewicz {~
#include "lpc17xx_can.h"
#include "lpc17xx_libcfg_default.h"
#include "lpc17xx_pinsel.h"
/** CAN variable definition **/
CAN_MSG_Type TXMsg, RXMsg;
uint32_t CANRxCount, CANTxCount = 0;
void pin_off(int pin){
LPC_GPIO2->FIOPIN &= ~ (1 << pin);
}
void pin_on(int pin){
LPC_GPIO2->FIOPIN |= 1 << pin;
}
/************************** PRIVATE FUNCTIONS *************************/
void CAN_IRQHandler(void);
void CAN_InitMessage(void);
Bool Check_Message(CAN_MSG_Type* TX_Msg, CAN_MSG_Type* RX_Msg);
int my_can_init(void) {
//Setup GPIO port 2 first 8 bits as output
LPC_GPIO2->FIODIR |= 0xff ;
// SETUP GPIO port 1 pin number 26 as input
LPC_GPIO1->FIODIR &= (1 << 25);
// SETING PIN FUNCTIONS
// PINSEL function role and understanding is really important to configure your uC
//properly. To learn more please go to the:
// http://www.microbuilder.eu/Tutorials/LPC2148/PINSEL.aspx
// and http://nanohome.be/nxp/LPC1768_Pins.php
// Easy way to do it is usage of "lpc17xx_pinsel.h" library:
PINSEL_CFG_Type PinCfg;
// CAN1 RD is on Port0 and pin0. Function number for CAN RD is 1
PinCfg.Funcnum = 1;
PinCfg.OpenDrain = 0;
PinCfg.Pinmode = 0;
PinCfg.Pinnum = 0;
PinCfg.Portnum = 0;
PINSEL_ConfigPin(&PinCfg); //CAN1RD
// CAN1 TD is on Port0 and pin1 function number for CAN TD is 1
PinCfg.Pinnum = 1;
PINSEL_ConfigPin(&PinCfg); //CAN1TD
PinCfg.Funcnum = 2;
PinCfg.Pinnum = 4;
PinCfg.Portnum = 0;
PINSEL_ConfigPin(&PinCfg);
PinCfg.Pinnum = 5;
PINSEL_ConfigPin(&PinCfg);
//You can also do it in hard way:
// setup CAN1
// P0.0~1, function 0x01, Pin46 RxD1, Pin47 TxD1
//LPC_PINCON->PINSEL0 &=~0x0F; //clear P0.0~1
//LPC_PINCON->PINSEL0 |= 0x05; //set b0101
// CAN2:
// P0.4~5, function 0x01, Pin81 RxD2, Pin80 TxD2
//LPC_PINCON->PINSEL0 &=~(0x0F<<8); //clear P0.4~5
//LPC_PINCON->PINSEL0 |= (0x0A<<8); //set b1010
CAN_Init(LPC_CAN1, 125000); // Setup baud rate for CAN1
CAN_Init(LPC_CAN2, 125000); // Setup baud rate for CAN2
/* Enable normal mode */
CAN_ModeConfig(LPC_CAN1, CAN_OPERATING_MODE, ENABLE); //Read NXP manual about CAN controller modes
CAN_ModeConfig(LPC_CAN2, CAN_OPERATING_MODE, ENABLE);
/* Enable Interrupt */
//Enable interrupt. Every time CAN2 receive something CAN_IRQHandler() will be called:
CAN_IRQCmd(LPC_CAN2, CANINT_RIE, ENABLE);
//Enable interrupt. Every time CAN2 transmit something CAN_IRQHandler() will be called:
//CAN_IRQCmd(LPC_CAN2, CANINT_TIE1, ENABLE);
/* Enable CAN Interrupt */
NVIC_EnableIRQ(CAN_IRQn);
CAN_SetAFMode(LPC_CANAF,CAN_AccBP); //Read about can controller filters, we don't need any for this example
CAN_InitMessage(); //Something need to be sent
}
/*********************************************************************//**
* @brief CAN_IRQ Handler, control receive message operation
* param[in] none
* @return none
**********************************************************************/
void CAN_IRQHandler()
{
pin_on(1);
uint8_t IntStatus;
/* Get CAN status */
IntStatus = CAN_GetCTRLStatus(LPC_CAN2, CANCTRL_STS);
/* check receive buffer status */
if((IntStatus>>0)&0x01)
{
CAN_ReceiveMsg(LPC_CAN2,&RXMsg);
/* Validate received and transmitted message */
if(Check_Message(&TXMsg, &RXMsg))
{}
else
{}
}
}
/*********************************************************************//**
* @brief Initialise transmit and receive message for Bypass operation
* @param[in] none
* @return none
**********************************************************************/
void CAN_InitMessage(void) {
//Great structure out of library. After reading about CAN it is self explaining
TXMsg.format = EXT_ID_FORMAT;
TXMsg.id = 0x00001234;
TXMsg.len = 8;
TXMsg.type = DATA_FRAME;
TXMsg.dataA[0] = TXMsg.dataA[1] = TXMsg.dataA[2] = TXMsg.dataA[3] = 0x12;
TXMsg.dataB[0] = TXMsg.dataB[1] = TXMsg.dataB[2] = TXMsg.dataB[3] = 0x34;
RXMsg.format = 0x00;
RXMsg.id = 0x00;
RXMsg.len = 0x00;
RXMsg.type = 0x00;
RXMsg.dataA[0] = RXMsg.dataA[1] = RXMsg.dataA[2] = RXMsg.dataA[3] = 0x00000000;
RXMsg.dataB[0] = RXMsg.dataA[1] = RXMsg.dataA[2] = RXMsg.dataA[3] = 0x00000000;
}
/*********************************************************************//**
* @brief Compare two message
* @param[in] Tx_Msg transmit message
* @param[in] Rx_Msg receive message
* @return Bool should be:
* - TRUE: if two message is the same
* - FALSE: if two message is different
**********************************************************************/
Bool Check_Message(CAN_MSG_Type* TX_Msg, CAN_MSG_Type* RX_Msg)
{
uint8_t i;
if((TXMsg.format != RXMsg.format)|(TXMsg.id != RXMsg.id)|(TXMsg.len != RXMsg.len)\
|(TXMsg.type != RXMsg.type))
return FALSE;
for(i=0;i<4;i++)
{
if((TXMsg.dataA[i]!=RXMsg.dataA[i])|(TXMsg.dataB[i]!=RXMsg.dataB[i])) {
pin_on(3); // Show that CAN does not match
return FALSE;
}
}
pin_on(2); // Show that CAN does match
return TRUE;
}
void wait_ms(int ms)
{
int i;
INT_32 k;
for (i=0;i< ms;i++){
for(k=0;k<8600;) k++; //experimental
}
}
int main(void)
{
my_can_init();
while(1)
{
if ( LPC_GPIO1->FIOPIN & ( 1 << 26))
{
pin_off(0); // button pressed
pin_off(1); // CAN2 interrupt occurred
pin_off(2); // MSG equal
pin_off(3); // MSG NOT equal
}
else
{
pin_on(0);
CAN_SendMsg(LPC_CAN1, &TXMsg);
wait_ms(1);// Some sleep is needed after CAN transmission
}
//Wait for interrupt and show that soft is running
pin_on(6);
wait_ms(25);
pin_off(6);
wait_ms(25);
}
}
@Mithun199
Copy link

Hi Tomasz Dowgielewicz,

Firstly thank you so much for the example code you have provided .

I tried to execute your code on lpc1768 board but i am seeing can is entering to RESET mod. i mean after sending a message i.e when LPC_CAN1->CMR = 0x21 as soon as this instruction the LPC_CAN1->MOD register is getting set with the value 1.

please let me know where i am going wrong , i tried my maximum to debug but still i couldn't able to find the root cause.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment