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.

123f CAN on port F

Other Parts Discussed in Thread: TM4C123FH6PM, ISO1050

I am having trouble bring up CAN on a 123F part.  I have used simple_tx from the Tivaware examples as a starting point and modified to remove UART (no Uart on board) and move to prt F since that is where the CAN transciever is connected.

 

Transciever is properly terminated and their is another device on the CAN bus (A pc monitoring dongle).

 

I am not able to get anything from the CAN, when checking with 'scope and logic analyser I get DC lines, no transitions. 

The main loop is running once a second (I can visually observe an LED toggle) but there is no signal on the TX line and the interrupt does not fire (I am assuming that I should get output even w/o the interrupt firing, that it not firing is just further indication something is not set up right).

It appears to be behaving as if it is not enabled or not directed t othe appropraite pins.  I am including a copy of the code below.

Any thoughts as to what I have missed?

Robert

 

/*****************************************************************************
//
*****************************************************************************/

#include <stdbool.h>
#include <stdint.h>
#include "inc/tm4c123fh6pm.h"
/*#include "inc/hw_can.h"*/
/*#include "inc/hw_ints.h"*/
#include "inc/hw_memmap.h"
#include "driverlib/can.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "startup.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.
*****************************************************************************/
/*lint -esym(960,8.7) could move to block scope */
/*lint -esym(551,g_ui32MsgCount) Not accessed */
static volatile uint32_t g_ui32MsgCount = 0u;

/*****************************************************************************
 A flag to indicate that some transmission error occurred.
*****************************************************************************/
static volatile bool g_bErrFlag = false;

/*****************************************************************************
 This function provides a 1 second delay using a simple polling method.
*****************************************************************************/
static void SimpleDelay(void)
{
    /* Delay cycles for 1 second */
    SysCtlDelay(16000000u / 3u);
}

/******************************************************************************
 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 CAN0_ISR(void)
{
    uint32_t ui32Status;

    /* Read the CAN interrupt status to find the cause of the interrupt  */
    ui32Status = CANIntStatus(CAN0_BASE, CAN_INT_STS_CAUSE);

    GPIO_PORTB_DATA_R &= ~0x40u;
    GPIO_PORTB_DATA_R |= 0x40u;
    GPIO_PORTB_DATA_R &= ~0x40u;
    GPIO_PORTB_DATA_R |= 0x40u;
    GPIO_PORTB_DATA_R &= ~0x40u;
    GPIO_PORTB_DATA_R |= 0x40u;
    GPIO_PORTB_DATA_R &= ~0x40u;
    GPIO_PORTB_DATA_R |= 0x40u;
    GPIO_PORTB_DATA_R &= ~0x40u;
    GPIO_PORTB_DATA_R |= 0x40u;

    /* If the cause is a controller status interrupt, then get the status */
    if(ui32Status == 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. */
         /*ui32Status =*/
  (void)CANStatusGet(CAN0_BASE, CAN_STS_CONTROL);

        /* 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(ui32Status == 1u) {
        /* 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_ui32MsgCount++;

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

    /* Otherwise, something unexpected caused the interrupt.  This should
     never happen. */
    else {
        /* Spurious interrupt handling can go here. */
         }
}

/*****************************************************************************
 Configure the CAN and enter a loop to transmit periodic CAN messages.
*****************************************************************************/
int main(void)
{
    tCANMsgObject sCANMessage;
    uint32_t ui32MsgData;
    /*uint8_t *pui8MsgData;*/

    /*pui8MsgData = (uint8_t *)&ui32MsgData;*/

  /* Set up clock (80MHz with 16MHz crystal.) 200MHz PLL/2.5 */
    SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
     SYSCTL_XTAL_16MHZ);

         /* Enable the GPIO ports for the indicator LED. */
    SYSCTL_RCGC2_R = SYSCTL_RCGC2_GPIOD | SYSCTL_RCGC2_GPIOB;

     /* Do a dummy read to insert a few cycles after enabling the
    peripheral. */
    SYSCTL_RCGC2_R;

     /* Enable the GPIO pin for the LED (PD6) . Set the direction as
           output, and  enable the GPIO pin for digital function. */
    GPIO_PORTD_DIR_R = 0x40u;
    GPIO_PORTD_DEN_R = 0x40u;
    GPIO_PORTB_DIR_R = 0x40u;
    GPIO_PORTB_DEN_R = 0x40u;

 /* CAN0 is used with RX and TX pins on port F0 and F3. */
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

    /* 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.*/
    GPIOPinConfigure(GPIO_PF0_CAN0RX);
    GPIOPinConfigure(GPIO_PF3_CAN0TX);

    /* Enable the alternate function on the GPIO pins. */
    GPIOPinTypeCAN(GPIO_PORTF_BASE, GPIO_PIN_0 | GPIO_PIN_3);

    /* 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. */
    (void)CANBitRateSet(CAN0_BASE, SysCtlClockGet(), 500000);

    /* Enable interrupts on the CAN peripheral.  */
    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);

    /* 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. */
    ui32MsgData = 0u;
    sCANMessage.ui32MsgID = 1u;
    sCANMessage.ui32MsgIDMask = 0u;
    sCANMessage.ui32Flags = MSG_OBJ_TX_INT_ENABLE;
    sCANMessage.ui32MsgLen = sizeof(ui32MsgData);
    /*lint -e925 pointer to pointer cast. C++ rule. Probably should clean up library */
    sCANMessage.pui8MsgData = (void *)&ui32MsgData;

    /* 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 uint32_t
     and incremented by one each time. */
    for (;;) {
      /* Toggle the LED. on port D */
         if( (GPIO_PORTD_DATA_R & 0x40u) != 0){
              GPIO_PORTD_DATA_R &= ~0x40u;
              }
         else {
              GPIO_PORTD_DATA_R |= 0x40u;
              }         

        /* 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. */
        CANMessageSet(CAN0_BASE, 1, &sCANMessage, MSG_OBJ_TYPE_TX);

        /* Now wait 1 second before continuing */
        SimpleDelay();

        /* Check the error flag to see if errors occurred */
        if(g_bErrFlag) {
            /* Space to report error */
             }
        else {
            /* Space to report success */
             }

        /* Increment the value in the message data. */
        ui32MsgData++;
         }
}

  • OK, just found a note in the GPIO section that pin 0 on port F is locked.  I rather thought the TivaWare SW was supposed to take care of such details but I now have an output bit.  Only one but it is a start.

     

    Robert

  • And the remaining problem was a failed ISO1050

     

    Robert

  • Hi --

    Can you explain how you proceeded to unlock the pins?  Are all the pins locked in their use --- I would like to use PE4 and PE5 for CAN0Rx and Tx respectively.  

    Thanks,

    David

  • Answering myself perhaps, another thread suggests: 

       //================ CAN0 on Port E ================
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);        //enable PortF
        HWREG(GPIO_PORTE_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY_DD;
        HWREG(GPIO_PORTE_BASE + GPIO_O_CR) |= GPIO_PIN_5;
        HWREG(GPIO_PORTE_BASE + GPIO_O_AFSEL) |= ~0x80;
        GPIOPinTypeGPIOInput(GPIO_PORTE_BASE, GPIO_PIN_4);
        HWREG(GPIO_PORTE_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY_DD;
        HWREG(GPIO_PORTE_BASE + GPIO_O_CR) &= ~0x80;
        HWREG(GPIO_PORTE_BASE + GPIO_O_LOCK) = 0;

        GPIOPinConfigure(GPIO_PE4_CAN0RX);        //PE4->CAN0Rx ,PE5->CAN0Tx
        GPIOPinConfigure(GPIO_PE5_CAN0TX);
        GPIOPinTypeCAN(GPIO_PORTE_BASE,  GPIO_PIN_4|GPIO_PIN_5);        //PE4->CAN0Rx ,PE5->CAN0Tx

    Messy, but will it work?

    Thanks again, David 

  • Hi David,

    Only Ports C0-C3, D7 and F0 are locked pins

    Regards

    Amit

  • The "default" of several port pins - beyond "normal" JTAG/SWD - into "NMI" continues to fester - trap the unsuspecting/inadequate datasheet reviewing.

    For years now - several here have requested that such, "most always" unwelcome, "default behavior" be far better emphasized w/in hallowed MCU manual.  More than 100 have repeated this folly (here) likely many times that have also fallen victim.  And yet the MCU manuals persist in their "inadequate" alerting.

    One expects that "reality" would bit better/sooner "intrude" upon powers here - and that necesary (very much required) "corrections" would be emplaced - perhaps avoiding further, "culling of this herd!"