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.

28377, eCAN, and ECanRegs structure

Other Parts Discussed in Thread: CONTROLSUITE

28335 device support has everything needed to handle can predefined in DSP2833x_ECan.h include file.

It has "ECanaRegs" defined to access all bits in the all eCAN regisrers and threra are lots of nits there.

28377 device support does not have any structure similar to "ECanaRegs" defined.

Where did it go? Do I suppose to create it myself?

Gasha

  • The F28377 has a different CAN module. You can look at the controlSUITE example projects to see how to use it.
  • What was wrong with 28335 CAN controller ? Now I have to redo all CAN interface code from my 28335 application!
    So much for hardware upgrade. Also, I would like to configure setup of the controller myself, not to let TI CAN_Init() function
    decides on hardware configuration based on pseudo-random search of what parameters fit the baud rate. TI should be providing structures
    to access control registers like for all other peripherals. Ultimately, the user should decide if he/she trust TI choice for hardware
    initialization or not. I do not.

    I am in the middle of reading about new controller and I do not like it. In my 28335 app, all message boxes were dedicated to one message only.
    I set up address in the initialization and controller just read/wrote data in the real time. I tried to minimize CAN based GUI overhead on the controller. 
    It seems to me that the new way always creates the whole message buffer content from the scratch. Two 32 bit reads/writes are no a whole function!
    That is inefficient when I am after every microsecond of control frame. Am I right on this one?

    I like the speed, CLA, TMU, fast sin and cos functions, but I do not like TI "improvements" on CAN controller. It seems to me
    it was redesigned for dummies, but power users are paying the price. Not a good job TI! 

    Gasha

  • Gasha,

    I'm sorry the new CAN module (D_CAN) is causing you trouble. We switched to D_CAN for several reasons, among them compatibility with the TMS570 and LM4S product lines. It's the same module that was used on the C2000 Concerto microcontrollers. D_CAN was designed by Bosch, not TI.

    We do provide header files for writing your own code. Due to the byte-based register addressing, we only have the newer style that is used in our new driver libraries. You can find them in the controlSUITE device_support\...\F2837xD_common directory under inc\ and driverlib\.

    D_CAN message objects can be concatenated to form a FIFO buffer. Reading from and writing to message objects should only take a few cycles. You can read more about this in the TRM.
  • Gasha,

                The DCAN module in 28377 offers the following features, which were not available in the eCAN module:

     

    • Parity check mechanism for all RAM modules. This was a key care-about for many safety applications.

    • Automatic Retransmission (upon loss of arbitration) can be disabled.

    • Silent mode (Node listens passively)

    • Mailbox RAM may be combined to form FIFO buffers.

  • That is not it. You provide bunch of #define constants, not the structures that match registers.
    I am working on it. So here is an example of what you should be providing:

    union CanBtrUnion {
    unsigned int all;
    struct CanBtrRegStruct {
    unsigned int BPR:6;
    unsigned int SJW:2;
    unsigned int TSEG1:4;
    unsigned int TSEG2:3;
    unsigned int reserved1:1;
    unsigned int BRPE:4;
    unsigned int reserved2:12;
    } bit;
    };

    I want to be able to set all parameters shown in the structure myself. What you provide does not allow me to that in an elegant way
    when use a structure above.


    My second point is inefficiency of new approach. Here is API Msg read function.
    Do you see how big it is? It will not be "few cycles"

    void CANMessageGet(uint32_t ui32Base, uint32_t ui32ObjID, tCANMsgObject *pMsgObject,
    bool bClrPendingInt)
    {
    uint32_t ui32CmdMaskReg;
    uint32_t ui32MaskReg;
    uint32_t ui32ArbReg;
    uint32_t ui32MsgCtrl;

    // Check the arguments.
    ASSERT(CANBaseValid(ui32Base));
    ASSERT((ui32ObjID <= 32) && (ui32ObjID != 0));

    // This is always a read to the Message object as this call is setting a
    // message object.
    ui32CmdMaskReg = (CAN_IF2CMD_DATA_A | CAN_IF2CMD_DATA_B |
    CAN_IF2CMD_CONTROL | CAN_IF2CMD_MASK | CAN_IF2CMD_ARB);

    // Clear a pending interrupt and new data in a message object.
    if(bClrPendingInt)
    {
    ui32CmdMaskReg |= CAN_IF2CMD_CLRINTPND | CAN_IF2CMD_TXRQST;
    }

    // Set up the request for data from the message object.
    HWREGH(ui32Base + CAN_O_IF2CMD + 2) = ui32CmdMaskReg >> 16;

    // Transfer the message object to the message object specified by ui32ObjID.
    HWREGH(ui32Base + CAN_O_IF2CMD) = ui32ObjID & CAN_IF2CMD_MSG_NUM_M;

    // Wait for busy bit to clear
    while(HWREGH(ui32Base + CAN_O_IF2CMD) & CAN_IF2CMD_BUSY)
    {
    }

    // Read out the IF Registers.
    ui32MaskReg = HWREG(ui32Base + CAN_O_IF2MSK);
    ui32ArbReg = HWREG(ui32Base + CAN_O_IF2ARB);
    ui32MsgCtrl = HWREG(ui32Base + CAN_O_IF2MCTL);
    pMsgObject->ui32Flags = MSG_OBJ_NO_FLAGS;

    // Determine if this is a remote frame by checking the TXRQST and DIR bits.
    if((!(ui32MsgCtrl & CAN_IF2MCTL_TXRQST) && (ui32ArbReg & CAN_IF2ARB_DIR)) ||
    ((ui32MsgCtrl & CAN_IF2MCTL_TXRQST) && (!(ui32ArbReg & CAN_IF2ARB_DIR))))
    {
    pMsgObject->ui32Flags |= MSG_OBJ_REMOTE_FRAME;
    }

    // Get the identifier out of the register, the format depends on size of
    // the mask.
    if(ui32ArbReg & CAN_IF2ARB_XTD)
    {
    // Set the 29 bit version of the Identifier for this message object.
    pMsgObject->ui32MsgID = ui32ArbReg & CAN_IF2ARB_ID_M;

    pMsgObject->ui32Flags |= MSG_OBJ_EXTENDED_ID;
    }
    else
    {
    // The Identifier is an 11 bit value.
    pMsgObject->ui32MsgID = (ui32ArbReg &
    CAN_IF2ARB_STD_ID_M) >> CAN_IF2ARB_STD_ID_S;
    }

    // Indicate that we lost some data.
    if(ui32MsgCtrl & CAN_IF2MCTL_MSGLST)
    {
    pMsgObject->ui32Flags |= MSG_OBJ_DATA_LOST;
    }

    // Set the flag to indicate if ID masking was used.
    if(ui32MsgCtrl & CAN_IF2MCTL_UMASK)
    {
    if(ui32ArbReg & CAN_IF2ARB_XTD)
    {
    // The Identifier Mask is assumed to also be a 29 bit value.
    pMsgObject->ui32MsgIDMask = (ui32MaskReg & CAN_IF2MSK_MSK_M);

    // If this is a fully specified Mask and a remote frame then don't
    // set the MSG_OBJ_USE_ID_FILTER because the ID was not really
    // filtered.
    if((pMsgObject->ui32MsgIDMask != 0x1fffffff) ||
    ((pMsgObject->ui32Flags & MSG_OBJ_REMOTE_FRAME) == 0))
    {
    pMsgObject->ui32Flags |= MSG_OBJ_USE_ID_FILTER;
    }
    }
    else
    {
    // The Identifier Mask is assumed to also be an 11 bit value.
    pMsgObject->ui32MsgIDMask = ((ui32MaskReg & CAN_IF2MSK_MSK_M) >>
    18);

    // If this is a fully specified Mask and a remote frame then don't
    // set the MSG_OBJ_USE_ID_FILTER because the ID was not really
    // filtered.
    if((pMsgObject->ui32MsgIDMask != 0x7ff) ||
    ((pMsgObject->ui32Flags & MSG_OBJ_REMOTE_FRAME) == 0))
    {
    pMsgObject->ui32Flags |= MSG_OBJ_USE_ID_FILTER;
    }
    }

    // Indicate if the extended bit was used in filtering.
    if(ui32MaskReg & CAN_IF2MSK_MXTD)
    {
    pMsgObject->ui32Flags |= MSG_OBJ_USE_EXT_FILTER;
    }

    // Indicate if direction filtering was enabled.
    if(ui32MaskReg & CAN_IF2MSK_MDIR)
    {
    pMsgObject->ui32Flags |= MSG_OBJ_USE_DIR_FILTER;
    }
    }

    // Set the interrupt flags.
    if(ui32MsgCtrl & CAN_IF2MCTL_TXIE)
    {
    pMsgObject->ui32Flags |= MSG_OBJ_TX_INT_ENABLE;
    }
    if(ui32MsgCtrl & CAN_IF2MCTL_RXIE)
    {
    pMsgObject->ui32Flags |= MSG_OBJ_RX_INT_ENABLE;
    }

    // See if there is new data available.
    if(ui32MsgCtrl & CAN_IF2MCTL_NEWDAT)
    {
    // Get the amount of data needed to be read.
    pMsgObject->ui32MsgLen = (ui32MsgCtrl & CAN_IF2MCTL_DLC_M);

    // Don't read any data for a remote frame, there is nothing valid in
    // that buffer anyway.
    if((pMsgObject->ui32Flags & MSG_OBJ_REMOTE_FRAME) == 0)
    {
    // Read out the data from the CAN registers.
    CANDataRegRead(pMsgObject->pucMsgData,
    (uint32_t *)(ui32Base + CAN_O_IF2DATA),
    pMsgObject->ui32MsgLen);
    }

    // Now clear out the new data flag.
    HWREGH(ui32Base + CAN_O_IF2CMD + 2) = CAN_IF2CMD_TXRQST >> 16;

    // Transfer the message object to the message object specified by
    // ui32ObjID.
    HWREGH(ui32Base + CAN_O_IF2CMD) = ui32ObjID & CAN_IF2CMD_MSG_NUM_M;

    // Wait for busy bit to clear
    while(HWREGH(ui32Base + CAN_O_IF2CMD) & CAN_IF2CMD_BUSY)
    {
    }

    // Indicate that there is new data in this message.
    pMsgObject->ui32Flags |= MSG_OBJ_NEW_DATA;
    }
    else
    {
    // Along with the MSG_OBJ_NEW_DATA not being set the amount of data
    // needs to be set to zero if none was available.
    pMsgObject->ui32MsgLen = 0;
    }
    }

    Here is a piece of my old 28335 function:

    void RxCanMessages()
    {
    if (ECanaRegs.CANRMP.bit.RMP16 == 1) { // Mbox16 - RX Controll Msg
    CAN_RX_ControlMsg.Data.Word.W0 = ECanaMboxes.MBOX16.MDL.word.HI_WORD;
    CAN_RX_ControlMsg.Data.Word.W1 = ECanaMboxes.MBOX16.MDL.word.LOW_WORD;
    CAN_RX_ControlMsg.Data.Word.W2 = ECanaMboxes.MBOX16.MDH.word.HI_WORD;
    CAN_RX_ControlMsg.Data.Word.W3 = ECanaMboxes.MBOX16.MDH.word.LOW_WORD;
    CAN_RX_ControlMsg.flag = 1;
    ECanaRegs.CANRMP.bit.RMP16 = 1;
    }

    .........
    }
    What do you think, which one runs faster and how much faster?

    I personally do not care about Hercules controllers, ARM core is to slow for what I need, so making 28377 compatible with Hercules was a bad move. 28377 intent is to replace 28335, not Hercules. So, you should have kept it compatible with 28335 as much as possible. But, it is all empty talk now. It is all over.
    Thank you.
  • 1. Can is reliable itself. It ahs 16 bit CRC built in and I never had any issue with receiving bad CAN message that has not been rejected by CAN controller.
    2. What do I care about it? It is good think that message is being retransmitted if no node acknowledges it.
    3. I am not building a CANalyzer using 28377. If I want this feature I will buy Vector CANalyzer.
    4. FIFO is the only think that is better now then before. Everything else sucks about D_CAN.

    This is real time controller that has to run as fast as possible. The overhead of CAN API will just make background task to run out of time sooner. Our GUI is using about 30ish different messages. Most of the background task is consumed by GUI. You just extended the requirement of background task time by factor of 10 may be even more (compare msg read functions in my previous post). If you have a way for me to read a message in 6 C lines using new D_CAN, I am all EARS.
    Thank you.
    Gasha
  • I forgot. Please close the post. I am not going to click green button for the answer I do not like. And there is no option "Close the post despite the answer". :)
    Gasha
  • OMG! I just saw this:

    // Wait for busy bit to clear
    while(HWREGH(ui32Base + CAN_O_IF2CMD) & CAN_IF2CMD_BUSY)
    {
    }

    This is absolute NO-NO in real time controllers. YOU NEVER HANG UP A PROCESS BECAUSE SOMETHING WENT WRONG!
    This will never pass FAA certification! You check busy flag, if it is busy, you skip, and do other things. If it stays busy after a while, you set a fault and KEEP DOING other things. I do not trust your API anymore.

    Gasha
  • Unfortunately, the byte addressing scheme prevents bit field structures from working correctly.

    I don't have time to test this today, but for a quick message read you should be able to do something like:

    1. Check the CAN_NDAT21 register to see whether data is available in a message object
    2. Write to CAN_IF1CMD to copy the message object into the interface registers and clear the New Data flag.
    3. Wait a few cycles for the copy to complete (Busy flag goes low).
    4. Read the CAN_IF1DATA and CAN_IF1DATB registers to get the data.

    That's 3-4 register reads and one register write. You can probably do it faster with IF3, which copies the message object into the interface register automatically. I haven't played with IF3 very much, so I can't give you an exact register sequence today.
  • What do you mean by "byte addressing scheme". I thought memory on 28xx is 16 bit wide, e.g. one increment in address is new 16 bits.

    Are you saying that one address is 8 bits on 28377?

    I just checked page 79 , Table 6-1 C28x Memory Map od 28377 data sheet.

    MEMORY      SIZE      START ADDRESS     END ADDRESS

    M0 RAM    1K x 16     0x0000 0000       0x0000 03FF

    This would mean that memory is still 16 bit wide since 0x400 = 1024 = 1K.

    Am I missing something? This has big implication on GUI when it calculates address offsets.

    Gasha

  • The C28x addressing is still the same. A byte (char) is still 16 bits. But the CAN and USB modules on the F2837x use byte addressing for their registers. It's a little hard to explain, but section 23.3.4 (Address/Data Bus Bridge) of the TRM (lit no. SPRUHM8) should hopefully clear things up. My understanding is that this was done for backwards compatibility with existing D_CAN software.

    I've passed your other concerns on to our software team.