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.

LAUNCHXL-F28379D: controlSUITE/can_loopback_bitfields的CAN通信例程有问题

Part Number: LAUNCHXL-F28379D
Other Parts Discussed in Thread: CONTROLSUITE

can寄存器操作版例程使用问题。

例程来源:C:\ti\controlSUITE\device_support\F2837xD\v210\F2837xD_examples_Cpu1\can_loopback_bitfields;

根据控制板的CANB引脚修改相关配置,包括:

-- 时钟配置修改set clock for CANB not CANA,即ClkCfgRegs.CLKSRCCTL2.bit.CANBBCLKSEL = 0;

-- 把canaRegs全部改成canbRegs,包括:

     --用InitCANB() 替换 InitCAN() 

     -- setupMessageObject(); 

     -- sendCANMessage();   

     -- getCANMessage(); 

-- 屏蔽lookback功能语句:

   -- // CanbRegs.CAN_CTL.bit.Test = 1;
   -- // CanbRegs.CAN_TEST.bit.EXL = 1;

-- 屏蔽发送接收对比上报ERRO的语句:

   -- /*if((*(unsigned long *)ucTXMsgData) != (*(unsigned long *)ucRXMsgData))
   -- {
   -- errFlag++;
   -- asm(" ESTOP0");
   -- }*/

但是最后还是无法从CAN适配器读取到发送的数据。详细代码如下:

//###########################################################################
//
// FILE:   can_loopback_bitfields.c
//
// TITLE:  Example to demonstrate basic CAN setup and use.
//
//! \addtogroup cpu01_example_list
//! <h1>CAN External Loopback Using Bitfields (can_loopback_bitfields)</h1>
//!
//! IMPORTANT: CAN Bitfield headers require compiler v16.6.0.STS and newer!
//!
//! This example, using bitfield headers, shows the basic setup of CAN in
//! order to transmit and receive messages on the CAN bus.  The CAN
//! peripheral is configured to transmit messages with a specific CAN ID.
//! A message is then transmitted once per second, using a simple delay
//! loop for timing.  The message that is sent is a 4 byte message that
//! contains an incrementing pattern.
//!
//! This example sets up the CAN controller in External Loopback test mode.
//! Data transmitted is visible on the CAN0TX pin and can be received with
//! an appropriate mailbox configuration.
//!
//
//###########################################################################
// $TI Release: F2837xD Support Library v210 $
// $Release Date: Tue Nov  1 14:46:15 CDT 2016 $
// $Copyright: Copyright (C) 2013-2016 Texas Instruments Incorporated -
//             http://www.ti.com/ ALL RIGHTS RESERVED $
//###########################################################################

//
// Included Files
//
#include "F28x_Project.h"

//
// Defines
//
#define CAN_MSG_ID              0x1111
#define CAN_TX_MSG_OBJ          1
#define CAN_RX_MSG_OBJ          2
#define CAN_MAX_BIT_DIVISOR     (13)   // The maximum CAN bit timing divisor
#define CAN_MIN_BIT_DIVISOR     (5)    // The minimum CAN bit timing divisor
#define CAN_MAX_PRE_DIVISOR     (1024) // The maximum CAN pre-divisor
#define CAN_MIN_PRE_DIVISOR     (1)    // The minimum CAN pre-divisor
#define CAN_BTR_BRP_M           (0x3F)
#define CAN_BTR_BRPE_M          (0xF0000)


//
// Globals
//
unsigned char ucTXMsgData[4] = {0x1, 0x2, 0x3, 0x4}; // TX Data
unsigned char ucRXMsgData[4] = {0, 0, 0, 0};         // RX Data
uint32_t messageSize = sizeof(ucTXMsgData);          // Message Size (DLC)
volatile unsigned long msgCount = 0; // A counter that keeps track of the
                                     // number of times the transmit was
                                     // successful.
volatile unsigned long errFlag = 0;  // A flag to indicate that some
                                     // transmission error occurred.

static const uint16_t canBitValues[] =
{
    0x1100, // TSEG2 2, TSEG1 2, SJW 1, Divide 5
    0x1200, // TSEG2 2, TSEG1 3, SJW 1, Divide 6
    0x2240, // TSEG2 3, TSEG1 3, SJW 2, Divide 7
    0x2340, // TSEG2 3, TSEG1 4, SJW 2, Divide 8
    0x3340, // TSEG2 4, TSEG1 4, SJW 2, Divide 9
    0x3440, // TSEG2 4, TSEG1 5, SJW 2, Divide 10
    0x3540, // TSEG2 4, TSEG1 6, SJW 2, Divide 11
    0x3640, // TSEG2 4, TSEG1 7, SJW 2, Divide 12
    0x3740  // TSEG2 4, TSEG1 8, SJW 2, Divide 13
};

typedef enum
{
        //! Transmit message object.
        MSG_OBJ_TYPE_TRANSMIT,

        //! Receive message object.
        MSG_OBJ_TYPE_RECEIVE
}
msgObjType;

//
// Function Prototypes
//
uint32_t setCANBitRate(uint32_t sourceClock, uint32_t bitRate);
void  setupMessageObject(uint32_t objID, uint32_t msgID, msgObjType msgType);
void sendCANMessage(uint32_t objID);
bool getCANMessage(uint32_t objID);
void InitCANB(void);
//
// Main
//
int
main(void)
{
    //
    // Initialize System Control:
    // PLL, WatchDog, enable Peripheral Clocks
    // This example function is found in the F2837xD_SysCtrl.c file.
    //
    InitSysCtrl();

    //
    // Initialize GPIO:
    // This example function is found in the F2837xD_Gpio.c file and
    // illustrates how to set the GPIO to its default state.
    //
    InitGpio();
    GPIO_SetupPinMux(17, GPIO_MUX_CPU1, 1);  //GPIO30 - CANRXA
    GPIO_SetupPinMux(12, GPIO_MUX_CPU1, 1);  //GPIO31 - CANTXA
    GPIO_SetupPinOptions(17, GPIO_INPUT, GPIO_ASYNC);
    GPIO_SetupPinOptions(12, GPIO_OUTPUT, GPIO_PUSHPULL);

    //
    // Initialize the CAN-A controller
    //
//    InitCAN();
    InitCANB();

    //
    // Setup CAN to be clocked off the SYSCLKOUT
    //
//    ClkCfgRegs.CLKSRCCTL2.bit.CANABCLKSEL = 0;
    ClkCfgRegs.CLKSRCCTL2.bit.CANBBCLKSEL = 0;
    //
    // Set up the bit rate for the CAN bus.  This function sets up the CAN
    // bus timing for a nominal configuration.
    // In this example, the CAN bus is set to 500 kHz.
    //
    // Consult the data sheet for more information about
    // CAN peripheral clocking.
    //
    uint32_t status = setCANBitRate(200000000, 500000);

    //
    // If values requested are too small or too large, catch error
    //
    if(status == 0)
    {
        errFlag++;
        ESTOP0;         // Stop here and handle error
    }

    //
    // Step 3. 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.
    // This function is found in the F2837xD_PieCtrl.c file.
    //
    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.
    // The shell ISR routines are found in F2837xD_DefaultIsr.c.
    // This function is found in F2837xD_PieVect.c.
    //
    InitPieVectTable();

    //
    // Enable test mode and select external loopback
    //
//    CanbRegs.CAN_CTL.bit.Test = 1;
//    CanbRegs.CAN_TEST.bit.EXL = 1;

    //
    // Initialize the message object that will be used for sending CAN
    // messages.
    //
    setupMessageObject(CAN_TX_MSG_OBJ, CAN_MSG_ID, MSG_OBJ_TYPE_TRANSMIT);

    //
    // Initialize the message object that will be used for receiving CAN
    // messages.
    //
    setupMessageObject(CAN_RX_MSG_OBJ, CAN_MSG_ID, MSG_OBJ_TYPE_RECEIVE);

    //
    // Enable the CAN for operation.
    //
    CanbRegs.CAN_CTL.bit.Init = 0;

    //
    // 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(;;)
    {
        //
        // 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.
        //
        sendCANMessage(CAN_TX_MSG_OBJ);

        //
        // Now wait 1 second before continuing
        //
        DELAY_US(1000*1000);

        //
        // Get the receive message
        //
        getCANMessage(CAN_RX_MSG_OBJ);

        //
        // Ensure the received data matches the transmitted data
        //
        /*if((*(unsigned long *)ucTXMsgData) != (*(unsigned long *)ucRXMsgData))
        {
            errFlag++;
            asm(" ESTOP0");
        }*/

        //
        // Increment successful message count and the value in the
        // transmitted message data.
        //
        msgCount++;
        (*(unsigned long *)ucTXMsgData)++;
    }
}

void InitCANB(void)
{
    int16_t iMsg;

    //
    // Place CAN controller in init state, regardless of previous state.  This
    // will put controller in idle, and allow the message object RAM to be
    // programmed.
    //
    CanbRegs.CAN_CTL.bit.Init = 1;
    CanbRegs.CAN_CTL.bit.SWR = 1;

    //
    // Wait for busy bit to clear
    //
    while(CanbRegs.CAN_IF1CMD.bit.Busy)
    {
    }

    //
    // Clear the message value bit in the arbitration register.  This indicates
    // the message is not valid and is a "safe" condition to leave the message
    // object.  The same arb reg is used to program all the message objects.
    //
    CanbRegs.CAN_IF1CMD.bit.DIR = 1;
    CanbRegs.CAN_IF1CMD.bit.Arb = 1;
    CanbRegs.CAN_IF1CMD.bit.Control = 1;

    CanbRegs.CAN_IF1ARB.all = 0;

    CanbRegs.CAN_IF1MCTL.all = 0;

    CanbRegs.CAN_IF2CMD.bit.DIR = 1;
    CanbRegs.CAN_IF2CMD.bit.Arb = 1;
    CanbRegs.CAN_IF2CMD.bit.Control = 1;

    CanbRegs.CAN_IF2ARB.all = 0;

    CanbRegs.CAN_IF2MCTL.all = 0;

    //
    // Loop through to program all 32 message objects
    //
    for(iMsg = 1; iMsg <= 32; iMsg+=2)
    {
        //
        // Wait for busy bit to clear
        //
        while(CanbRegs.CAN_IF1CMD.bit.Busy)
        {
        }

        //
        // Initiate programming the message object
        //
        CanbRegs.CAN_IF1CMD.bit.MSG_NUM = iMsg;

        //
        // Wait for busy bit to clear
        //
        while(CanbRegs.CAN_IF2CMD.bit.Busy)
        {
        }

        //
        // Initiate programming the message object
        //
        CanbRegs.CAN_IF2CMD.bit.MSG_NUM = iMsg + 1;
    }

    //
    // Acknowledge any pending status interrupts.
    //
    volatile uint32_t discardRead = CanbRegs.CAN_ES.all;

}

//
// setCANBitRate - Set the CAN bit rate based on device clock (Hz)
//                 and desired bit rate (Hz)
//
uint32_t setCANBitRate(uint32_t sourceClock, uint32_t bitRate)
{
    uint32_t desiredRatio;
    uint32_t canBits;
    uint32_t preDivide;
    uint32_t regValue;
    uint16_t canControlValue;

    //
    // Calculate the desired clock rate.
    //
    desiredRatio = sourceClock / bitRate;

    //
    // Make sure that the Desired Ratio is not too large.  This enforces the
    // requirement that the bit rate is larger than requested.
    //
    if((sourceClock / desiredRatio) > bitRate)
    {
        desiredRatio += 1;
    }

    //
    // Check all possible values to find a matching value.
    //
    while(desiredRatio <= CAN_MAX_PRE_DIVISOR * CAN_MAX_BIT_DIVISOR)
    {
        //
        // Loop through all possible CAN bit divisors.
        //
        for(canBits = CAN_MAX_BIT_DIVISOR;
            canBits >= CAN_MIN_BIT_DIVISOR;
            canBits--)
        {
            //
            // For a given CAN bit divisor save the pre divisor.
            //
            preDivide = desiredRatio / canBits;

            //
            // If the calculated divisors match the desired clock ratio then
            // return these bit rate and set the CAN bit timing.
            //
            if((preDivide * canBits) == desiredRatio)
            {
                //
                // Start building the bit timing value by adding the bit timing
                // in time quanta.
                //
                regValue = canBitValues[canBits - CAN_MIN_BIT_DIVISOR];

                //
                // To set the bit timing register, the controller must be
                // placed
                // in init mode (if not already), and also configuration change
                // bit enabled.  The state of the register should be saved
                // so it can be restored.
                //
                canControlValue = CanbRegs.CAN_CTL.all;
                CanbRegs.CAN_CTL.bit.Init = 1;
                CanbRegs.CAN_CTL.bit.CCE = 1;

                //
                // Now add in the pre-scalar on the bit rate.
                //
                regValue |= ((preDivide - 1) & CAN_BTR_BRP_M) |
                            (((preDivide - 1) << 10) & CAN_BTR_BRPE_M);

                //
                // Set the clock bits in the and the bits of the
                // pre-scalar.
                //
                CanbRegs.CAN_BTR.all = regValue;

                //
                // Restore the saved CAN Control register.
                //
                CanbRegs.CAN_CTL.all = canControlValue;

                //
                // Return the computed bit rate.
                //
                return(sourceClock / ( preDivide * canBits));
            }
        }

        //
        // Move the divisor up one and look again.  Only in rare cases are
        // more than 2 loops required to find the value.
        //
        desiredRatio++;
    }
    return 0;
}

//
// setupMessageObject - Setup message object as Transmit or Receive
//
void setupMessageObject(uint32_t objID, uint32_t msgID, msgObjType msgType)
{
    //
    // Wait for busy bit to clear.
    //
    while(CanbRegs.CAN_IF1CMD.bit.Busy)
    {
    }

    //
    // Clear and Write out the registers to program the message object.
    //
    CanbRegs.CAN_IF1CMD.all = 0;
    CanbRegs.CAN_IF1MSK.all = 0;
    CanbRegs.CAN_IF1ARB.all = 0;
    CanbRegs.CAN_IF1MCTL.all = 0;

    //
    // Set the Control, Mask, and Arb bit so that they get transferred to the
    // Message object.
    //
    CanbRegs.CAN_IF1CMD.bit.Control = 1;
    CanbRegs.CAN_IF1CMD.bit.Arb = 1;
    CanbRegs.CAN_IF1CMD.bit.Mask = 1;
    CanbRegs.CAN_IF1CMD.bit.DIR = 1;

    //
    // Set direction to transmit
    //
    if(msgType == MSG_OBJ_TYPE_TRANSMIT)
    {
        CanbRegs.CAN_IF1ARB.bit.Dir = 1;
    }

    //
    // Set Message ID (this example assumes 11 bit ID mask)
    //
    CanbRegs.CAN_IF1ARB.bit.ID = msgID;
    CanbRegs.CAN_IF1ARB.bit.MsgVal = 1;

    //
    // Set the data length since this is set for all transfers.  This is
    // also a single transfer and not a FIFO transfer so set EOB bit.
    //
    CanbRegs.CAN_IF1MCTL.bit.DLC = messageSize;
    CanbRegs.CAN_IF1MCTL.bit.EoB = 1;

    //
    // Transfer data to message object RAM
    //
    CanbRegs.CAN_IF1CMD.bit.MSG_NUM = objID;
}

//
// sendCANMessage - Transmit data from the specified message object
//
void sendCANMessage(uint32_t objID)
{
    //
    // Wait for busy bit to clear.
    //
    while(CanbRegs.CAN_IF1CMD.bit.Busy)
    {
    }

    //
    // Write data to transfer into DATA-A and DATA-B interface registers
    //
    uint16_t index;
    for(index = 0; index < messageSize; index++)
    {
        switch(index)
        {
            case 0:
                CanbRegs.CAN_IF1DATA.bit.Data_0 = ucTXMsgData[index];
                break;
            case 1:
                CanbRegs.CAN_IF1DATA.bit.Data_1 = ucTXMsgData[index];
                break;
            case 2:
                CanbRegs.CAN_IF1DATA.bit.Data_2 = ucTXMsgData[index];
                break;
            case 3:
                CanbRegs.CAN_IF1DATA.bit.Data_3 = ucTXMsgData[index];
                break;
            case 4:
                CanbRegs.CAN_IF1DATB.bit.Data_4 = ucTXMsgData[index];
                break;
            case 5:
                CanbRegs.CAN_IF1DATB.bit.Data_5 = ucTXMsgData[index];
                break;
            case 6:
                CanbRegs.CAN_IF1DATB.bit.Data_6 = ucTXMsgData[index];
                break;
            case 7:
                CanbRegs.CAN_IF1DATB.bit.Data_7 = ucTXMsgData[index];
                break;
        }
    }

    //
    // Set Direction to write and set DATA-A/DATA-B to be transfered to
    // message object
    //
    CanbRegs.CAN_IF1CMD.all = 0x830000;

    //
    // Set Tx Request Bit
    //
    CanbRegs.CAN_IF1CMD.bit.TXRQST = 1;

    //
    // Transfer the message object to the message object specified by
    // objID.
    //
    CanbRegs.CAN_IF1CMD.bit.MSG_NUM = objID;
}

//
// getCANMessage - Check the message object for new data.
//                 If new data, data written into array and return true.
//                 If no new data, return false.
//
bool getCANMessage(uint32_t objID)
{
    bool status;

    //
    // Set the Message Data A, Data B, and control values to be read
    // on request for data from the message object.
    //
    CanbRegs.CAN_IF2CMD.all = 0;
    CanbRegs.CAN_IF2CMD.bit.Control = 1;
    CanbRegs.CAN_IF2CMD.bit.DATA_A = 1;
    CanbRegs.CAN_IF2CMD.bit.DATA_B = 1;

    //
    // Transfer the message object to the message object IF register.
    //
    CanbRegs.CAN_IF2CMD.bit.MSG_NUM = objID;

    //
    // Wait for busy bit to clear.
    //
    while(CanbRegs.CAN_IF2CMD.bit.Busy)
    {
    }

    //
    // See if there is new data available.
    //
    if(CanbRegs.CAN_IF2MCTL.bit.NewDat == 1)
    {
        //
        // Read out the data from the CAN registers.
        //
        uint16_t index;
        for(index = 0; index < messageSize; index++)
        {
            switch(index)
            {
                case 0:
                    ucRXMsgData[index] = CanbRegs.CAN_IF2DATA.bit.Data_0;
                break;
                case 1:
                    ucRXMsgData[index] = CanbRegs.CAN_IF2DATA.bit.Data_1;
                break;
                case 2:
                    ucRXMsgData[index] = CanbRegs.CAN_IF2DATA.bit.Data_2;
                break;
                case 3:
                    ucRXMsgData[index] = CanbRegs.CAN_IF2DATA.bit.Data_3;
                break;
                case 4:
                    ucRXMsgData[index] = CanbRegs.CAN_IF2DATB.bit.Data_4;
                break;
                case 5:
                    ucRXMsgData[index] = CanbRegs.CAN_IF2DATB.bit.Data_5;
                break;
                case 6:
                    ucRXMsgData[index] = CanbRegs.CAN_IF2DATB.bit.Data_6;
                break;
                case 7:
                    ucRXMsgData[index] = CanbRegs.CAN_IF2DATB.bit.Data_7;
                break;
            }
        }

        //
        // Clear New Data Flag
        //
        CanbRegs.CAN_IF2CMD.bit.TxRqst = 1;

        //
        // Wait for busy bit to clear.
        //
        while(CanbRegs.CAN_IF2CMD.bit.Busy)
        {
        }

        //
        // Transfer the message object to the message object IF register.
        //
        CanbRegs.CAN_IF2CMD.bit.MSG_NUM = objID;

        status = true;
    }
    else
    {
        status = false;
    }

    return(status);
}

//
// End of file
//

我有看过英文论坛上的类似问题,但是无人解答(TMS320F28379D: Running can_loopback_bitfields_cpu01 example on Launchpad -- CAN traffic not present - C2000 microcontrollers forum - C2000Tm︎ microcontrollers - TI E2E support forums),尝试了500k乘以2或者除以2的通信频率依旧不行。

最后,尝试了不屏蔽lookback相关代码,并且控制板上的CANH和CANL短接和不短接都试验,结果也无法实现回环测试(即接收发送不相等,导致跳转到ERRO中)