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.

Doubts Setting CANB Mail Box



Hello,

After having the basic CAN communication ( Using the Example to implement CAN comm from CANA to CANB), i am trying to implement some mailboxes.

I've read the TI documents about CAN and i understand the concept but i'm having trouble putting it to practise.

My intention was to configure one mailbox to receive a message and generate a interrupt signal when it receives. On the interrupt i want to read the content of the MB.

There are no good examples about how to work with mailbox for F28377S. Can someone give me some tips about how can i implement that?

The code i'm using now its the attached.

Thank you all

Bruno

//###########################################################################
//
// FILE:   can_external_transmit.c
//
// TITLE:  Example to demonstrate CAN external transmission
//
//! \addtogroup cpu01_example_list
//! <h1>CAN-A to CAN-B External Transmit (can_external_transmit)</h1>
//!
//! This example initializes CAN module A and CAN module B for external
//! communication. CAN-A module is setup to transmit incrementing data for "n"
//! number of times to the CAN-B module, where "n" is the value of TXCOUNT.
//! CAN-B module is setup to trigger an interrupt service routine (ISR) when
//! data is received. An error flag will be set if the transmitted data doesn't
//! match the received data.
//!
//! \note Both CAN modules on the device need to be
//!       connected to each other via CAN transceivers.
//!
//! \b External \b Connections \n
//!  - CANA is on GPIO31 (CANTXA) and GPIO30 (CANRXA)
//!  - CANB is on GPIO8 (CANTXB) and GPIO10 (CANRXB)
//!
//! \b Watch \b Variables \n
//!  - TXCOUNT - Adjust to set the number of messages to be transmitted
//!  - txMsgCount - A counter for the number of messages sent
//!  - rxMsgCount - A counter for the number of messages received
//!  - txMsgData - An array with the data being sent
//!  - rxMsgData - An array with the data that was received
//!  - errorFlag - A flag that indicates an error has occurred
//!
//
//###########################################################################
// $TI Release: F2837xS Support Library v200 $
// $Release Date: Tue Jun 21 13:52:16 CDT 2016 $
// $Copyright: Copyright (C) 2014-2016 Texas Instruments Incorporated -
//             http://www.ti.com/ ALL RIGHTS RESERVED $
//###########################################################################

//
// Included Files
//
#include "F28x_Project.h"     // Device Headerfile and Examples Include File
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_can.h"
#include "driverlib/can.h"

//
// Defines
//
#define TXCOUNT  500
#define MSG_DATA_LENGTH    8
#define TX_MSG_OBJ_ID    1
#define RX_MSG_OBJ_ID    1

//
// Globals
//
volatile unsigned long i;
volatile uint32_t txMsgCount = 0;
volatile uint32_t rxMsgCount = 0;
volatile uint32_t errorFlag = 0;
unsigned char txMsgData[8];
unsigned char rxMsgData[8];
tCANMsgObject sTXCANMessage;
tCANMsgObject sRXCANMessage;

//
// Function Prototypes
//
__interrupt void canbISR(void);




//
// Main
//
void main(void)
{
    //
    // Initialize System Control:
    // PLL, WatchDog, enable Peripheral Clocks
    //
    InitSysCtrl();

    //
    // Initialize GPIO and configure GPIO pins for CANTX/CANRX
    // on module A and B
    //
    InitGpio();

    //
    // Setup GPIO pin mux for CAN-A TX/RX and CAN-B TX/RX


    GPIO_SetupPinMux(70, GPIO_MUX_CPU1, 5); //CANRXA
    GPIO_SetupPinOptions(70, GPIO_INPUT, GPIO_ASYNC);
    GPIO_SetupPinMux(71, GPIO_MUX_CPU1, 5); //CANTXA
    GPIO_SetupPinOptions(71, GPIO_OUTPUT, GPIO_PUSHPULL);
    GPIO_SetupPinMux(21, GPIO_MUX_CPU1, 3); //CANRXB
    GPIO_SetupPinOptions(721, GPIO_INPUT, GPIO_ASYNC);
    GPIO_SetupPinMux(20, GPIO_MUX_CPU1, 3);  //CANTXB
    GPIO_SetupPinOptions(21, GPIO_OUTPUT, GPIO_PUSHPULL);

    //
    // Initialize the CAN controllers
    //
    CANInit(CANA_BASE);
    CANInit(CANB_BASE);

    //
    // Setup CAN to be clocked off the PLL output clock
    //
    CANClkSourceSelect(CANA_BASE, 0);   // 500kHz CAN-Clock
    CANClkSourceSelect(CANB_BASE, 0);   // 500kHz CAN-Clock

    //
    // Set up the CAN bus bit rate to 500kHz for each module
    // 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.
    // Additionally, consult the device data sheet for more information about
    // the CAN module clocking.
    //
    CANBitRateSet(CANA_BASE, 200000000, 500000);
    CANBitRateSet(CANB_BASE, 200000000, 500000);

    //
    // Enable interrupts on the CAN B peripheral.
    //
    //    CANIntEnable(CANB_BASE, CAN_INT_MASTER | CAN_INT_ERROR | CAN_INT_STATUS);

    //
    // Clear all interrupts and initialize PIE vector table:
    // Disable CPU interrupts
    //
    DINT;

    //
    // Initialize the PIE control registers to their default state.
    // The default state is all PIE interrupts disabled and flags
    // are cleared.
    //
    InitPieCtrl();

    //
    // Disable CPU interrupts and clear all CPU interrupt flags
    //
    IER = 0x0000;
    IFR = 0x0000;

    //
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    // This will populate the entire table, even if the interrupt
    // is not used in this example.  This is useful for debug purposes.
    //
    InitPieVectTable();


    //
    // Interrupts that are used in this example are re-mapped to
    // ISR functions found within this file.
    // This registers the interrupt handler in PIE vector table.
    //
    EALLOW;
//    PieVectTable.CANB0_INT = canbISR;
    EDIS;

    //
    // Enable the CAN-B interrupt on the processor (PIE).
    //
//    PieCtrlRegs.PIEIER9.bit.INTx7 = 1;
//    IER |= M_INT9;
    EINT;

    //
    // Enable the CAN-B interrupt signal
    //
    CANGlobalIntEnable(CANB_BASE, CAN_GLB_INT_CANINT0);

    //
    // Initialize the transmit message object used for sending CAN messages.
    // Message Object Parameters:
    //      Message Identifier: 0x5555
    //      Message ID Mask: 0x0
    //      Message Object Flags: None
    //      Message Data Length: 4 Bytes
    //      Message Transmit data: txMsgData
    //
    sTXCANMessage.ui32MsgID = 0x5555;
    sTXCANMessage.ui32MsgIDMask = 0;
    sTXCANMessage.ui32Flags = 0;
    sTXCANMessage.ui32MsgLen = MSG_DATA_LENGTH;
    sTXCANMessage.pucMsgData = txMsgData;

    //
    // Initialize the receive message object used for receiving CAN messages.
    // Message Object Parameters:
    //      Message Identifier: 0x5555
    //      Message ID Mask: 0x0
    //      Message Object Flags: Receive Interrupt
    //      Message Data Length: 4 Bytes
    //      Message Receive data: rxMsgData
    //
    sRXCANMessage.ui32MsgID = 0x5555;
    sRXCANMessage.ui32MsgIDMask = 0;
    sRXCANMessage.ui32Flags = MSG_OBJ_RX_INT_ENABLE;
    sRXCANMessage.ui32MsgLen = MSG_DATA_LENGTH;
    sRXCANMessage.pucMsgData = rxMsgData;
    CANMessageSet(CANB_BASE, RX_MSG_OBJ_ID, &sRXCANMessage,
                 MSG_OBJ_TYPE_RX);

    //
    // Initialize the transmit message object data buffer to be sent
    //
    txMsgData[0] = 0x01;
    txMsgData[1] = 0x02;
    txMsgData[2] = 0x04;
    txMsgData[3] = 0x08;
    txMsgData[4] = 0x16;
    txMsgData[5] = 0x32;
    txMsgData[6] = 0x64;
    txMsgData[7] = 0x00;

    //
    // Start CAN module A and B operations
    //
    CANEnable(CANA_BASE);
    CANEnable(CANB_BASE);

    //
    // Transmit messages from CAN-A to CAN-B
    //
    for(i = 0; i < TXCOUNT; i++)
    {
        //
        // Check the error flag to see if errors occurred
        //
        if(errorFlag)
        {
            asm("   ESTOP0");
        }

        //
        // Verify that the number of transmitted messages equal the number of
        // messages received before sending a new message
        //
       if(txMsgCount == rxMsgCount)
       {
            //
            // Transmit Message
            //
            CANMessageSet(CANA_BASE, TX_MSG_OBJ_ID, &sTXCANMessage,
                          MSG_OBJ_TYPE_TX);

            txMsgCount++;
        }
        else
      {
            errorFlag = 1;
        }

        //
        // Delay 0.25 second before continuing
        //
        DELAY_US(1000 * 250);



        //
        // Increment the value in the transmitted message data.
        //
        txMsgData[0] += 0x01;
        txMsgData[1] += 0x01;
        txMsgData[2] += 0x01;
        txMsgData[3] += 0x01;
        txMsgData[4] += 0x01;
        txMsgData[5] += 0x01;
        txMsgData[6] += 0x01;
        txMsgData[7] += 0x01;
    }

    //
    // Stop application
    //
    asm("   ESTOP0");
}

//
// CAN B ISR - The interrupt service routine called when a CAN interrupt is
//             triggered on CAN module B.
//

__interrupt void
canbISR(void)
{
    uint32_t status;

    //
    // Read the CAN-B interrupt status to find the cause of the interrupt
    //
    status = CANIntStatus(CANB_BASE, CAN_INT_STS_CAUSE);


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

        //
        // Check to see if an error occurred.
        //
        if(((status  & ~(CAN_ES_RXOK)) != 7) &&
           ((status  & ~(CAN_ES_RXOK)) != 0))
        {
            //
            // Set a flag to indicate some errors may have occurred.
            //
            errorFlag = 1;
        }
    }
    //
    // Check if the cause is the CAN-B receive message object 1
    //
    else if(status == RX_MSG_OBJ_ID)
    {
        //
        // Get the received message
        //
        CANMessageGet(CANB_BASE, RX_MSG_OBJ_ID, &sRXCANMessage, true);

        //
        // Getting to this point means that the RX interrupt occurred on
        // message object 1, and the message RX is complete.  Clear the
        // message object interrupt.
        //
        CANIntClear(CANB_BASE, RX_MSG_OBJ_ID);

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

        //
        // Since the message was received, clear any error flags.
        //
        errorFlag = 0;
    }
    //
    // If something unexpected caused the interrupt, this would handle it.
    //
    else
    {
        //
        // Spurious interrupt handling can go here.
        //
    }

    //
    // Clear the global interrupt flag for the CAN interrupt line
    //
    CANGlobalIntClear(CANB_BASE, CAN_GLB_INT_CANINT0);

    //
    // Acknowledge this interrupt located in group 9
    //
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP9;
}

//
// End of File
//

Thank you all.

  • Hi Bruno,

    Check this thread for interrupt based eCAN: e2e.ti.com/.../343388

    This device is equipped with DCan and not eCan.

    Regards,
    Gautam

  • Hi Gautam,

    Thank you. That will be usefull.

    But first things first.

    I don't know why but i cant access the registers. On the technical reference manual from f28377S states that i could access the can registers through CAN_REGS, but when i try it doesn't shows anything.

    What am i Missing ?

    Thanks.

    Bruno
  • Bruno Duarte28 said:
    I don't know why but i cant access the registers. On the technical reference manual from f28377S states that i could access the can registers through CAN_REGS, but when i try it doesn't shows anything.

    Can you be more specific? Where is this scenario - in debug window or editor itself? Paste the extract for clear indication.

  • In the editor.

    I am trying to configure the CAN_REGS but the compiler didnt recognize the register.
    I've tried CanbRegs instead but the same result. I'm working over the example code "can_external_transmit_cpu01" from F28377S dsp.


    thank you.

    Bruno
  • Bruno,

    For F2837xS, there isn't any bitfield header support, you use the provided driver library for the CAN. Within controlSUITE->device_support->F2837xS->v200->doc there is a "F2837xS-DRL-UG.pdf" that provides details on using the CAN API.

    The example you referenced provides the functionality you mentioned you want. Use the CANMessageSet() to setup your mailbox and associated flags, such as an interrupt on receive. Within the interrupt, CANMessageGet() reads the content of the data received and places it into your receive message object struct buffer.

    Best Regards
    Chris
  • Dear Christopfer,

    I've studied the document you pointed me to and i have a couple of doubts:

    - How do i calculate the value of the ulMsgIdMask ? in the example, for a message with 0x400 ID they use 0x7f8. I didnt understood how to get to the correct value;

    - I need to configure 2 receive messages, with the corresponding masks. In the flag do i need to configure as MSG_OBJ_USE_ID_Filter only? or do i need to add also the MSG_OBJ_FIFO or MSG_OBJ_RX_INT_ENABLE ?

    - as for the interrupt, do i need to have any special interrupt ? or canbISR works ? i only need, when the interrupt is generated to use CANMessageGet() to read, from both os the messages ?

    Thank you.

  • ---UPDATE---

    I found in another post a link where explains in more detail the mask logic, so using sRXCANMsgIDMask = 0x7f2 ; i'm allowing the IDs 0x10 and 0x11;


    For the configuration currently i have it like this:

        sRXCANMessage.ui32MsgID = 0x010;
        sRXCANMessage.ui32MsgIDMask = 0x7f2; // acpet 0x010 and 0x011;
        sRXCANMessage.ui32Flags = MSG_OBJ_RX_INT_ENABLE | MSG_OBJ_USE_ID_FILTER ;
        sRXCANMessage.ui32MsgLen = MSG_DATA_LENGTH;
        sRXCANMessage.pucMsgData = rxMsgData;
     
        CANMessageSet(CANB_BASE, 1, &sRXCANMessage, MSG_OBJ_TYPE_RX); // configure the first adress for the 0x10;
        CANMessageSet(CANB_BASE, 2, &sRXCANMessage, MSG_OBJ_TYPE_RX); // Configure the second adress to receive only the data with ID 0x11;

    The interrupt is configured like this :

    interrupt void canbISR(void)
    {
        uint32_t status;
        uint32_t ID_obj;
     
     
        //
        // Read the CAN-B interrupt status to find the cause of the interrupt
        //
        status = CANIntStatus(CANB_BASE, CAN_INT_STS_CAUSE);
        ID_obj = CANIntStatus(CANB_BASE, CAN_INT_STS_OBJECT);
     
     
        //
        // If the cause is a controller status interrupt, then get the status
        //
        if(status == CAN_INT_INT0ID_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.
            //
            status = CANStatusGet(CANB_BASE, CAN_STS_CONTROL);
     
            //
            // Check to see if an error occurred.
            //
            if(((status  & ~(CAN_ES_RXOK)) != 7) &&
               ((status  & ~(CAN_ES_RXOK)) != 0))
            {
                //
                // Set a flag to indicate some errors may have occurred.
                //
                errorFlag = 1;
            }
        }
        //
        // Check if the cause is the CAN-B receive message object 1
        //
        else
        {
            if(status == 0x01) //here i wanted to process the information depending on the Msg ID
            {
                //
                // Get the received message
                //
                CANMessageGet(CANB_BASE, RX_MSG_OBJ_ID, &sRXCANMessage, true);


                FlagCanReceived = true;
     
                // Getting to this point means that the RX interrupt occurred on
                // message object 1, and the message RX is complete.  Clear the
                // message object interrupt.
                //
                CANIntClear(CANB_BASE, RX_MSG_OBJ_ID);
     
                //
                // Increment a counter to keep track of how many messages have been
                // received. In a real application this could be used to set flags to
                // indicate when a message is received.
                //

     
                //
                // Since the message was received, clear any error flags.
                //
                errorFlag = 0;
            }
     
            //
            // If something unexpected caused the interrupt, this would handle it.
            //
            else
            {
     
                //
                // Spurious interrupt handling can go here.
                //
            }
        }
        //
        // Clear the global interrupt flag for the CAN interrupt line
        //
        CANGlobalIntClear(CANB_BASE, CAN_GLB_INT_CANINT0);
     
        //
        // Acknowledge this interrupt located in group 9
        //
        PieCtrlRegs.PIEACK.all = PIEACK_GROUP9;
    }

  • Bruno,

    You need to call CANMessegeSet() for each message object you want to setup. Each message should have it's own setup struct unless they will have the same message ID and message data buffers. Your RX messages are identical and won't handle the acceptance as detailed in your comments.

    CAN has two interrupt lines, you can assign certain message objects to whichever line and particular ISR handler for each line.

    "status = CANIntStatus(CANB_BASE, CAN_INT_STS_CAUSE); " returns the status of a status interrupt or the highest priority message object interrupt. Your ISR is only checking message object 1. Refer to how the "can_loopback_interrupts" example handles the TX and RX message objects. The current CANMessageGet only reads the message object number defined in "RX_MSG_OBJ_ID".

    Best Regards
    Chris