This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

LM4F232 CAN Tx problem

Other Parts Discussed in Thread: LM3S8962, SN65HVD232

Hi

 I am using the simple_tx code provided in the LM4F232 evaluation kit for testing the CAN functionality of the board. I am using the graphics display for debugging. I am using port E pins 4 and 5 for CAN0 functionality. i have also added the CANIntHandler in the startup code. i am getting the following errors in the CAN interrupt handler
(i have used #1 and #2 to indicate the error code location)

- #1 = 0x8000
-#2 = 0x63

and it doesnt come out of the interrupt.

i have interconnected the pins 4 and 5 using a wire.
 when the wire is shaken #2 becomes 0xe2 and comes out of the interrupt.


Kindly help me understand what i am doing wrong with this setup.

Thank you

Richin Johns

//*****************************************************************************
//
// simple_tx.c - Example demonstrating simple CAN message transmission.
//
//
//*****************************************************************************

#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_can.h"
#include "inc/hw_ints.h"
#include "driverlib/can.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"

#include "grlib/grlib.h"
#include "drivers/cfal96x64x16.h"
#include "utils/ustdlib.h"

//#include "driverlib/debug.h"
//#include "driverlib/systick.h"

//*****************************************************************************
//
// A counter that keeps track of the number of times the TX interrupt has
// occurred, which should match the number of TX messages that were sent.
//
//*****************************************************************************
volatile unsigned long g_ulMsgCount = 0;

//*****************************************************************************
//
// A flag to indicate that some transmission error occurred.
//
//*****************************************************************************
volatile unsigned long g_bErrFlag = 0;
volatile unsigned long g_bMsgObjSent = 0;

//*****************************************************************************
//
// This function sets up Graphics Display to be used for displaying information
// as the example is running.
//
//*****************************************************************************
char disp_buffer[20];
tContext sContext;
unsigned char ucXCenter;

void
InitDisplay(void)
{
     //
     // Initialize the display driver.
     //
    CFAL96x64x16Init();

    //
    // Initialize the graphics context.
    //
    GrContextInit(&sContext, &g_sCFAL96x64x16);
    GrContextForegroundSet(&sContext, ClrWhite);
    GrContextFontSet(&sContext, g_pFontFixed6x8);

    ucXCenter = GrContextDpyWidthGet(&sContext) / 2;
}

//*****************************************************************************
//
// This function prints some information about the CAN message to the
// graphics display for information purposes only.
//
//*****************************************************************************
void
DisplayInfo(char * contents, unsigned char ucX, unsigned char ucY)
{
    GrStringDraw(&sContext, contents, -1, ucX, ucY, true);
}

//*****************************************************************************
//
// This function is the interrupt handler for the CAN peripheral.  It checks
// for the cause of the interrupt, and maintains a count of all messages that
// have been transmitted.
//
//*****************************************************************************
void
CANIntHandler(void)
{
    unsigned long ulStatus;

    GrStringDraw(&sContext, "In INT", -1, 10, 14, true);
    //
    // Read the CAN interrupt status to find the cause of the interrupt
    //
    ulStatus = CANIntStatus(CAN0_BASE, CAN_INT_STS_CAUSE);
    usnprintf(disp_buffer, sizeof(disp_buffer), "Error = %x", ulStatus);
    DisplayInfo(disp_buffer, 10, 44);                            <-------------------------------------- #1

    //
    // If the cause is a controller status interrupt, then get the status
    //
    if(ulStatus == CAN_INT_INTID_STATUS)
    {
        //
        // Read the controller status.  This will return a field of status
        // error bits that can indicate various errors.  Error processing
        // is not done in this example for simplicity.  Refer to the
        // API documentation for details about the error status bits.
        // The act of reading this status will clear the interrupt.  If the
        // CAN peripheral is not connected to a CAN bus with other CAN devices
        // present, then errors will occur and will be indicated in the
        // controller status.
        //
        ulStatus = CANStatusGet(CAN0_BASE, CAN_STS_CONTROL);
        usnprintf(disp_buffer, sizeof(disp_buffer), "Error = %x", ulStatus);  <--------------#2
        if(ulStatus == CAN_STATUS_BUS_OFF){
            DisplayInfo("1", 10, 54);
        }
        else if(ulStatus == CAN_STATUS_EWARN){
            DisplayInfo("2", 10, 54);
        }
        else if(ulStatus == CAN_STATUS_EPASS){
            DisplayInfo("3", 10, 54);
        }
        else if(ulStatus == CAN_STATUS_RXOK){
            DisplayInfo("4", 10, 54);
        }
        else if(ulStatus == CAN_STATUS_TXOK){
            DisplayInfo("5", 10, 54);
        }
        else if(ulStatus == CAN_STATUS_LEC_MSK){
            DisplayInfo("6", 10, 54);
        }
        else if(ulStatus == CAN_STATUS_LEC_NONE){
            DisplayInfo("7", 10, 54);
        }
        else if(ulStatus == CAN_STATUS_LEC_STUFF){
            DisplayInfo("8", 10, 54);
        }
        else if(ulStatus == CAN_STATUS_LEC_FORM){
            DisplayInfo("9", 10, 54);
        }
        else if(ulStatus == CAN_STATUS_LEC_ACK){
            DisplayInfo("10", 10, 54);
        }
        else if(ulStatus == CAN_STATUS_LEC_BIT1){
            DisplayInfo("11", 10, 54);
        }
        else if(ulStatus == CAN_STATUS_LEC_BIT0){
            DisplayInfo("12", 10, 54);
        }
        else if(ulStatus == CAN_STATUS_LEC_CRC){
            DisplayInfo("13", 10, 54);
        }
        else{
            //UARTprintf("rage\n");
            DisplayInfo(disp_buffer, 10, 54);
        }
        //
        // Set a flag to indicate some errors may have occurred.
        //
        g_bErrFlag = 1;
    }

    //
    // Check if the cause is message object 1, which what we are using for
    // sending messages.
    //
    else if(ulStatus == 1)
    {
        //GrStringDraw(&sContext, "Msg TX'ing", -1, 10, 54, true);
        DisplayInfo("Msg TX'ing", 10, 54);
        //
        // Getting to this point means that the TX interrupt occurred on
        // message object 1, and the message TX is complete.  Clear the
        // message object interrupt.
        //
        CANIntClear(CAN0_BASE, 1);

        //
        // Increment a counter to keep track of how many messages have been
        // sent.  In a real application this could be used to set flags to
        // indicate when a message is sent.
        //
        g_ulMsgCount++;

        //
        // Since the message was sent, clear any error flags.
        //
        g_bErrFlag = 0;
        g_bMsgObjSent = 1;
    }

    //
    // Otherwise, something unexpected caused the interrupt.  This should
    // never happen.
    //
    else
    {
        //
        // Spurious interrupt handling can go here.
        //
        //UARTprintf("other\n");
        DisplayInfo("Not In INT", 10, 14);
    }
}

//*****************************************************************************
//
// This function sets up CAN Pins for CAN Rx and CAN Tx operation with dynamic
// interrupt handling enabled.
//
//*****************************************************************************
void
CAN_Initialize(void)
{
    //
    // For this example CAN0 is used with RX and TX pins on port E4 and E5.
    // The actual port and pins used may be different on your part, consult
    // the data sheet for more information.
    // GPIO port D needs to be enabled so these pins can be used.
    // TODO: change this to whichever GPIO port you are using
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);

    //
    // Configure the GPIO pin muxing to select CAN0 functions for these pins.
    // This step selects which alternate function is available for these pins.
    // This is necessary if your part supports GPIO pin function muxing.
    // Consult the data sheet to see which functions are allocated per pin.
    // TODO: change this to select the port/pin you are using
    //
    GPIOPinConfigure(GPIO_PE4_CAN0RX);
    GPIOPinConfigure(GPIO_PE5_CAN0TX);

    //
    // Enable the alternate function on the GPIO pins.  The above step selects
    // which alternate function is available.  This step actually enables the
    // alternate function instead of GPIO for these pins.
    // TODO: change this to match the port/pin you are using
    //
    GPIOPinTypeCAN(GPIO_PORTE_BASE, GPIO_PIN_4 | GPIO_PIN_5);

    //
    // The GPIO port and pins have been set up for CAN.  The CAN peripheral
    // must be enabled.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN0);

    //
    // Initialize the CAN controller
    //
    CANInit(CAN0_BASE);

    //
    // Set up the bit rate for the CAN bus.  This function sets up the CAN
    // bus timing for a nominal configuration.  You can achieve more control
    // over the CAN bus timing by using the function CANBitTimingSet() instead
    // of this one, if needed.
    // In this example, the CAN bus is set to 500 kHz.  In the function below,
    // the call to SysCtlClockGet() is used to determine the clock rate that
    // is used for clocking the CAN peripheral.  This can be replaced with a
    // fixed value if you know the value of the system clock, saving the extra
    // function call.  For some parts, the CAN peripheral is clocked by a fixed
    // 8 MHz regardless of the system clock in which case the call to
    // SysCtlClockGet() should be replaced with 8000000.  Consult the data
    // sheet for more information about CAN peripheral clocking.
    //
    CANBitRateSet(CAN0_BASE, SysCtlClockGet(), 500000);

    //
    // Enable interrupts on the CAN peripheral.  This example uses static
    // allocation of interrupt handlers which means the name of the handler
    // is in the vector table of startup code.  If you want to use dynamic
    // allocation of the vector table, then you must also call CANIntRegister()
    // here.
    //
    //CANIntRegister(CAN0_BASE, CANIntHandler); // if using dynamic vectors//?
    //
    CANIntEnable(CAN0_BASE, CAN_INT_MASTER | CAN_INT_ERROR | CAN_INT_STATUS);

    //
    // Enable the CAN interrupt on the processor (NVIC).
    //
    IntEnable(INT_CAN0);

    //
    // Enable the CAN for operation.
    //
    CANEnable(CAN0_BASE);
    IntMasterEnable();
}

//*****************************************************************************
//
// This function provides a 1 milli-second delay using a simple polling method.
//
//*****************************************************************************

void delay_ms(int del)
{
    del = (SysCtlClockGet()/3.0)*del/1000.0;
    SysCtlDelay(del);
}

//*****************************************************************************
//
// Configure the CAN and enter a loop to transmit periodic CAN messages.
//
//*****************************************************************************
void
main(void)
{
    tCANMsgObject sCANMessage;
    unsigned char ucMsgData[4];
    //unsigned char ucYCenter = GrContextDpyHeightGet(&sContext) / 2;

    //
    // Set the clocking to run directly from the external crystal/oscillator.
    // TODO: The SYSCTL_XTAL_ value must be changed to match the value of the
    // crystal on your board.
    //
    SysCtlClockSet(SYSCTL_SYSDIV_4|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);

    //
    // Set up the graphic display to use for displaying messages.
    //
    InitDisplay();

    //
    // Set up the CAN Port-E pins 4 and 5 for Rx and Tx
    //
    CAN_Initialize();

    //
    //Display Program Name
    //
    DisplayInfo("CAN TX", ucXCenter - 15, 4);

    //
    // Initialize the message object that will be used for sending CAN
    // messages.  The message will be 4 bytes that will contain an incrementing
    // value.  Initially it will be set to 0.
    //
    *(unsigned long *)ucMsgData = 0;
    sCANMessage.ulMsgID = 1;                        // CAN message ID - use 1
    sCANMessage.ulMsgIDMask = 0;                    // no mask needed for TX
    sCANMessage.ulFlags = MSG_OBJ_TX_INT_ENABLE;    // enable interrupt on TX
    sCANMessage.ulMsgLen = sizeof(ucMsgData);       // size of message is 4
    sCANMessage.pucMsgData = ucMsgData;             // ptr to message content

    //
    // Enter loop to send messages.  A new message will be sent once per
    // second.  The 4 bytes of message content will be treated as an unsigned
    // long and incremented by one each time.
    //
    for(;;)
    {
        //
        // Print a message to the display showing the message count and the
        // contents of the message being sent.
        //
        usnprintf(disp_buffer, sizeof(disp_buffer), "0x %02X %02X %02X %02X", ucMsgData[0], ucMsgData[1], ucMsgData[2], ucMsgData[3]);
        DisplayInfo(disp_buffer, 10, 24);

        //
        // Send the CAN message using object number 1 (not the same thing as
        // CAN ID, which is also 1 in this example).  This function will cause
        // the message to be transmitted right away.
        //
        g_bMsgObjSent = 0;
        //CANIntClear(CAN0_BASE, CAN_INT_INTID_STATUS);
        //CANIntClear(CAN0_BASE, 1);

        CANMessageSet(CAN0_BASE, 1, &sCANMessage, MSG_OBJ_TYPE_TX);

        //
        // Now wait 1 second before continuing
        //
        delay_ms(1000);

        while(!g_bMsgObjSent)
        {
            DisplayInfo("In Loop", 10, 34);
        }
        DisplayInfo("Outside Loop", 10, 34);

        //
        // Check the error flag to see if errors occurred
        //
        if(g_bErrFlag)
        {
            DisplayInfo("error - cable connected?", 10, 34);
        }
        else
        {
            //
            // If no errors then print the count of message sent
            //
            usnprintf(disp_buffer, sizeof(disp_buffer), "tc = %u", g_ulMsgCount);
            DisplayInfo(disp_buffer, 10, 44);
        }

        //
        // Increment the value in the message data.
        //
        (*(unsigned long *)ucMsgData)++;
    }

    //
    // Return no errors
    //
    //return(0);
}

  • Hi,

    You need to construct first a "CAN bus" - i.e. a transmission line closed to both end by its characteristic impedance and have two nodes connected to that bus (i.e. this requires to double your equipment…). Linking CAN_Tx pin to CAN_Rx pin does not work, since part of protocol is/must be accomplished by the interface circuit (you must add it if not existent on your board).

    Petrei

  • Can you please explain?

    do you mean to say that i need to use a CAN Transceiver module or i need two evaluation boards interconnected?

    if you saying about using a transceiver then is the diagram correct?

    it will be really helpful if u can tell if the code is correct or  i need to add anything else to it.

  • Hi,

    Your electrical diagram is correct. What you have here is only one "CAN node" and you need at least two nodes to make a transaction. What would be the second one is less important, but still be useful to control it very well (i.e. to know some insides of it - since maybe you need to modify/debug the second one also - I used first two nodes and when got a good message change I added a third one).

    About the software - did not checked - (not enough time till end of the week). One more word: when posting such long codes, please attach a file instead. (Old StellarisWare for LM3S8962 had two boards (two nodes) and separate application example for each board).

    Petrei

  • Thank you Petrei for your time and fast reply.

    Just need some more clarification. I have with me only 1 LM4F232 evaluation kit. so can i use another port of this board with the same diagram to use as a receiver or I will have to get another evaluation board to use a 2nd node.

    Is there any way to check CAN Operation like CAN Rx with just one LM4F232? Give any suggestions as I have only 1 LM4F232 to work with.

    If you know any website which can give me good tutorial on CAN with Stellaris Hardware and software implementation please tell me.

    Richin

  • Hi,

    There are some hardware/software tools to work with, such as this:
    and this: CANalyzer
    All depends on the resources allocated to the project.
    The first one was suggested/asked by a user in this thread:
    although I am reserved on its use as second node. The second option is more expensive, but more featured.
    Using a second node will be the best option since the bus problems can be easily spotted - i started with a physical bus of 6 ft in length.
    As examples - I used this: http://www.ti.com/tool/sw-ek-lm3s8962 - the evaluation package had two boards, different micros on each one and a good working applications for both boards.
    Petrei
  • Hi,

    Just forgot to mention the more elaborated CANopen package from DanK, here:

    http://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/p/68824/797737.aspx#797737

    Petrei

  • Petrei's done a great job here - yet there may be room for your, "one only LX4F232 board" - work-around...

    Indeed - as Petrei states - you'll need 2 CAN xcvrs and 2 CAN Peripheral Ports.  Now - you should be able to construct a small "add-on" board which holds 2 CAN xcvrs - wired together properly - and each xcvr being fed from a separate CAN Port instantiation - both w/in your "single" LX4F232 MCU!  This saves you the cost of a 2nd board.  (although such can be a low cost launchpad - so long as that launch (not much, BTW) MCU carries CAN Port)

    As Petrei mentions - suggest that you follow, "simple CAN TX & RX code examples" which appear w/in StellarisWare.  (under Examples/Peripherals/)   We've done just that w/multiple LX4F devices - and can report CAN operation success...

  • Thank you all for valuable suggestions. I was able to make it work.


    - I was able to check the simple_Tx code without a second CAN channel or node by setting one of the CAN register to test mode and also setting Loopback mode in another register in the CAN API.

    - I used two channels and configured one as output and other as input on the same board and was able to successfully retrieve the information from the Rx Channel which I sent using the Tx Channel.

    I am really grateful for all your help.

    The only thing i noticed is that the interrupts are occurring in the wrong order(Rx-Tx-Rx-Tx )
    But the output is correct.

  • Glad you've made progress - but advise against your, "Release of congratulatory cigars" from so limited a test/verify effort.   (i.e. read select MCU registers)

    That (properly) terminated CAN transmission line - transceiver to transceiver mating - and "real exchange between 2 "valid" CAN Ports - is really the "gold standard" for CAN confirmation. 

    Indeed you've saved some time/effort/funds thru lesser implementation - yet I'd hesitate to, "invite investors" and demo your, "multi-drop CAN bus" implementation - with so abbreviated a, "test/verify." 

    A CAN chip Eval board (or pair of such) - connected as herein past detailed - seems a far superior way to perform more, "normal/customary" CAN connection & evaluation...

  • thank you cb1

    but my second test using two CAN channels is similar to your advice.

    - I have Set CAN0 to Transmit and CAN1 to Receive. Then I connected a seperate CAN Transceiver(SN65HVD232) to both CAN0 and CAN1 then I interconnected the two transceivers using wires with 120ohm resistor between CANH and CANL. with this setup I was able to receive the correct data which I transmitted through CAN0. Is this test enough to verify CAN implementation or do I need more testing?

  • Richin Abraham said:
    I was able to check the simple_Tx code without a second CAN channel

    Your previous post (quoted above) stuck with me - yet that same post went on, "I used 2 channels - "TX & RX" - (same board - credit cb1, that) - and realized success.  Thus my fear that you had performed too limited a test appears mistaken.

    As for the (apparent) disorder w/CAN Interrupts - does that occur during your full, 2 CAN channel "mating" - and while running both Simple CAN TX & Simple CAN RX?  And - if such proves true - might it be that the TX interrupt is not issued until some RX activity (i.e. RX interrupt) occurs?  (I've not used simple RX/TX in awhile - unsure...)  You may wish to describe just "how" you detect the order of such interrupts, too...

  • Yes it happening in 2 CAN channel and i have integrated the simple Tx and Rx in one main such that one CAN0 and CAN1 is initialized as receiver and transmitter respectively. then in while i am sending the data using CANMessageSet() followed by a delay of 1 second and CANMessageGet() for receiving.

    To the check the order i have given UARTPrint in the beginning of the interrupt to indicate in which interrupt it is currently in.

    Thats how I was able to conclude the order -> Rx-Tx-Rx-Tx then result.

  • Your method of analysis seems valid.  And - like you - findings appear unexpected to me, too.

    Give me a day/two to dig up pair of our boards running simple TX/RX - see if we can confirm your results...