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.

TMS570LC4357: CAN receive/send messages using interrupt/notification instead of polling

Part Number: TMS570LC4357
Other Parts Discussed in Thread: HALCOGEN

I'd like to use interrupts/notifications to receive or send CAN messages.

If I use messageBox 1, I've used Halcogen to link the "Enable Int" and "High Priority" contact points for Msg1 on canREG3.

I do

canEnableStatusChangeNotification(canREG3);

and have

canMessageNotification(node, messageBox)

populated as appropriate.

A breakpoint on canMessageNotification() never triggers, so interrupts are not happening.

This stuff currently works fine with polling, so I know data is transmitted by and received by the rx board (both polling).

I'm probably missing interrupt routing stuff.

Thanks for all help.

  • ... clarify: transmitted by the tx board and received by the rx board (both polling).

  • I enabled VIM channels 45 and 55 for CAN 3 High and Low, per the following post, but still no notification happening...

    https://community.element14.com/members-area/personalblogs/b/blog/posts/can-communication-with-hercules-safety-microcontroller---part-1-tryout

    Thanks.

  • Hi Peter,

    Are the IRQ and FIQ enabled?

    There are three "gates" before an interrupt request gets to the CPU:

    1. The module that generates an interrupt request has a register to enable each interrupt that it can generate.
    2. The Vectored Interrupt Manager (VIM) has registers to allow an interrupt request from a module to be forwarded to the CPU as per the priority scheme (lower channel number first).
    3. Finally the CPU itself must be configured to respond to the interrupt requests forwarded by the VIM (IRQ or FIQ).
  • Hi, it's hard for me to digest everything you are saying, especially in mapping items 1 through 3 to the TI facilities that implement them.  The _enable_IRQ() and _enable_FIQ() have been called and interrupts run, since I've got the buffered DMA SCI "driver" running in the project (which uses DMA completion notification), and am printing a dot periodically.

    1 - does canEnableStatusChangeNotification(canPort) do this?  I see IE1 and IE0 bits set in the canREG3->CTL register.

    2 - I believe the VIM channel 45 and 55 channels connected via Halcogen does this.

    3 - As described above.

    So I believe I've met all 3 conditions.  What am I missing?

    On a related note, I tried resurrecting the project mentioned before, to see CAN notifications working (in this case tx):

    https://community.element14.com/members-area/personalblogs/b/blog/posts/can-communication-with-hercules-safety-microcontroller---part-1-tryout

    but am stuck with a XDS110 USB Debug Probe message:

    Texas Instruments XDS110 USB Debug Probe/CortexR5 : Target must be connected before loading program.

    I've searched the e2e posts and saw no fix that works for me.

    The probe works fine, as I can run other projects using the probe without problem.  Without rebooting the PC or the target Launchpad.

    Thank you very much.

  • This post fixed the XDS110 probe issue.

    https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/759209/tm4c123gh6pm-programming-with-xds200-and-ccs/2804781#2804781

    I ran the TEST_CAN project and see the message notification happening (via debugger breakpoint).  Will need to examine what this program does, using CAN loopback.  At least one  more data point.

    Thanks.

  • Unfortunately, this example doesn't do much to show users how to configure the hardware in real operation,  Just calling canEnableLoopback() sets CTL into test mode and TEST into internal loopback, which also does a lot of other stuff like wiring MB1 to MB2 and enabling notification interrupts.  I commented out extraneous code, and canInit(), one canEnableLoopback(), and one canTransmit() is enough to cause canMessageNotification() to be called.

  • The module that generates an interrupt request has a register to enable each interrupt that it can generate.

    #1: Set IE0 and IE1 in canREG3->CTL. This is to enable DCAN0INT line and DCAN1INT line

    #2: Set SIE bit in canREG3->CTL. canEnableStatusChangeNotification() will do it. If SIE is set, a Status Change Interrupt will be generated at each CAN frame.

    #3: Set TxIE or RxIE bit in IFxMCTL register: the easy way is enable it using HAL GUI:

    • The Vectored Interrupt Manager (VIM) has registers to allow an interrupt request from a module to be forwarded to the CPU as per the priority scheme (lower channel number first).
    • Finally the CPU itself must be configured to respond to the interrupt requests forwarded by the VIM (IRQ or FIQ).

    1. Enable VIM channel 45 and channel 55  --> you already did

    2. Enable IRQ or FIQ or both --> you already did

  • Above is my CAN3 Mb1 set up.  The TX is overridden later to RX with canUpdateID().

    This is the code snippet I have to set up the CAN3 MessageBox1 (here, canMessageBox[n] is canMESSAGE_BOX1 and canPort is canREG3)...

    canUpdateID(canPort, canMessageBox[n], (0x0 << 29) | (id << 18)); // receive, 11-bit identifier
    printf("canUpdateID msgbx=%d val=0x%x id=0x%x\n", canMessageBox[n], (0x0 << 29) | (id << 18), id);

    ibuf2_t *ib2 = &ibuf2[0];
    ibuf_init(ib2, rx_data, 64, 32, 0);

    canEnableStatusChangeNotification(canPort);
    int ctl = canPort->CTL;
    printf("*** ctl=0x%x\n", ctl);
    //canPort->CTL |= (1 << 17) | (1 << 1); // IE1, IE0

    The output is...

    canUpdateID msgbx=1 val=0xc800000 id=0x320
    *** ctl=0x21406

    which shows IE1 and IE0 set in CTL register.

    I believe this is the exact configs you show for items 1, 2, and 3.

    Unfortunately, my canMessageNotification() function is never called.  Something is missing or incorrect.

    Thanks.

  • Don't know if you have access to the appropriate  hardware, but...

    I have uploaded my trimmed-down HL_sys_main.c to protonmail.  Unnecessary stuff is conditionalized out.  Will need a printf() function (or comment out and use debugger), and a fgetsn()/sscanf() function to pick up a unit number.  Alternatively, use two project source trees and hard-code unit number.

    Need two Launchpads with transceivers on CAN3 hooked to each other.  Can port can be easily changed.

    Unit 0 is polling transmitter.  Unit 1 is polling receiver.  Unit 3 is interrupt receiver (replacing 1); just breakpoint on canMessageNotification() in HL_notification.c.  0->1 is for sanity checking.  0->3 is test for interrupt/notification.

    Go to www.protonmail.com and sign in as shareuser1000 with password password.

    Thank you very much.

  • Can you add a breakpoint at the first line of void can3HighLevelInterrupt(void) function to check if you get any interrupt (error, status change, and msg box1 object)?

  • Peter,

    Attached please find a working example tested on TMS570LC43x HDK.

    1. CAN1 transmits data, and CAN2 receives data.

    2. CAN1_H is connected to CAN2_H, and CAN1_L is connected to CAN2_L

    3. Interrupt mode is used for both TX and RX

  • Yes, I get a can3HighLevelInterrupt() at the point when "*** ctl=..." is being displayed via polling sciSend().  The INT value is 0x8000, so canStatusChangeNotification() is called with ES_value 0x10 (RxOK).  If I contine-run in the debugger, the status change notification keeps recurring (My transmitter is continuous).  Should I be handling canStatusChangeNotification() instead of canMessageNotification()?

    I'll take a look at the project you just uploaded.

    Thank you very much.

  • Should I be handling canStatusChangeNotification() instead of canMessageNotification()?

    No, you should get the message notification. 

  • I looked at the CAN1_CAN2 project without running it (need to rewire boards), and don't see canMessageNotification() populated with USER code.  How does that project do the CAN receive?  I don't see any USER code in can2{High,Low}Interrupt() that would modify behavior.

    I noticed CAN1_CAN2 doing canEnableErrorNoification() and not canEnableStatusChangeNotification().  Tried that in my project and don't see the can3HighLevelInterrupt() happening.

    Thank you.

  • So, why am I getting 0x8000 in the ES register, which takes the status change path and not the message notification one?  One possible answer is my transmitter is overrunning the receiver (and new data either over-writing the message register or being thrown away).  This would not happen if the transmitter is "synchronized" with the receiver, as probably the case with the CAN1_CAN2 project.

    Thanks.

  • don't see canMessageNotification() populated with USER code

    The function is located in HL_sys_main.c. Because you don't get Message Notification, I just check it instead of checking status change. You can add status change notification to your project, it doesn't affect the generation of message notification.

    6170.HL_sys_main.c
    /** @file HL_sys_main.c 
    *   @brief Application main file
    *   @date 11-Dec-2018
    *   @version 04.07.01
    *
    *   This file contains an empty main function,
    *   which can be used for the application.
    */
    
    /* 
    * Copyright (C) 2009-2018 Texas Instruments Incorporated - www.ti.com  
    * 
    * 
    *  Redistribution and use in source and binary forms, with or without 
    *  modification, are permitted provided that the following conditions 
    *  are met:
    *
    *    Redistributions of source code must retain the above copyright 
    *    notice, this list of conditions and the following disclaimer.
    *
    *    Redistributions in binary form must reproduce the above copyright
    *    notice, this list of conditions and the following disclaimer in the 
    *    documentation and/or other materials provided with the   
    *    distribution.
    *
    *    Neither the name of Texas Instruments Incorporated nor the names of
    *    its contributors may be used to endorse or promote products derived
    *    from this software without specific prior written permission.
    *
    *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
    *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
    *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
    *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
    *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
    *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
    *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
    *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    *
    */
    
    
    /* USER CODE BEGIN (0) */
    /* USER CODE END */
    
    /* Include Files */
    
    #include "HL_sys_common.h"
    
    /* USER CODE BEGIN (1) */
    #include "HL_can.h"
    #include "HL_sys_core.h"
    
    #define D_COUNT  8
    
    uint32 cnt=0, error =0, tx_done =0;
    uint8 tx_data[D_COUNT][8] = {0};
    uint8 rx_data[D_COUNT][8] = {0};
    uint8 *tx_ptr = &tx_data[0][0];
    uint8 *rx_ptr = &rx_data[0][0];
    uint8 *dptr=0;
    
    void dumpSomeData();
    /* USER CODE END */
    
    /** @fn void main(void)
    *   @brief Application main function
    *   @note This function is empty by default.
    *
    *   This function is called after startup.
    *   The user can use this function to implement the application.
    */
    
    /* USER CODE BEGIN (2) */
    uint32_t numTXOK=0, numRXOK=0;
    
    
    /* USER CODE END */
    
    int main(void)
    {
    /* USER CODE BEGIN (3) */
        /* enable irq interrupt in Cortex R4 */
        _enable_interrupt_();
    
        /** - writing a random data in RAM - to transmit */
        dumpSomeData();
    
        /** - configuring CAN1 MB1,Msg ID-1 to transmit and CAN2 MB1 to receive */
        canInit();
    
        /** - enabling error interrupts */
        canEnableErrorNotification(canREG1);
        canEnableErrorNotification(canREG2);
        canEnableStatusChangeNotification(canREG1);
        canEnableStatusChangeNotification(canREG2);
    
        /** - starting transmission */
        for(cnt=0;cnt<D_COUNT;cnt++)
        {
              canTransmit(canREG1, canMESSAGE_BOX1, tx_ptr);  /* transmitting 8 different chunks 1 by 1 */
              while(tx_done == 0){};                          /* ... wait until transmit request is through        */
              tx_done=0;
              tx_ptr +=8;    /* next chunk ...*/
        }
    
        /** - check the received data with the one that was transmitted */
        tx_ptr = &tx_data[0][0];
        rx_ptr = &rx_data[0][0];
    
        for(cnt=0;cnt<63;cnt++)
        {
           if(*tx_ptr++ != *rx_ptr++)
           {
               error++; /* data error */
           }
        }
    
        while(1){}; /* wait forever after tx-rx complete. */
    /* USER CODE END */
    
        return 0;
    }
    
    
    /* USER CODE BEGIN (4) */
    /* can interrupt notification */
    /* Note-You need to remove canMessageNotification from notification.c to avoid redefinition */
    void canMessageNotification(canBASE_t *node, uint32 messageBox)
    {
         /* node 1 - transfer request */
         if(node==canREG1)
         {
           tx_done=1; /* confirm transfer request */
         }
         /* node 2 - receive complete */
         if(node==canREG2)
         {
            while(!canIsRxMessageArrived(canREG2, canMESSAGE_BOX1));
            canGetData(canREG2, canMESSAGE_BOX1, rx_ptr); /* copy to RAM */
            rx_ptr +=8;
         }
    }
    
    
    void canStatusChangeNotification(canBASE_t *node, uint32 notification)
    {
        if(node==canREG1)
        {
           numTXOK++;
        }
        /* node 2 - receive complete */
        if(node==canREG2)
        {
           numRXOK++;
        }
    }
    
    /* writing some data to ram  */
    void dumpSomeData()
    {
         uint32 tmp = 0x11;
    
         cnt = (D_COUNT*8)-1;
         dptr = &tx_data[0][0];
         *dptr = tmp;
    
         while(cnt--)
         {
            tmp = *dptr++;
            *dptr = tmp + 0x11;
         }
    }
    
    
    /* USER CODE END */
    

  • So, the "#pragma WEAK(canStatusChangeNotification)" in HL_notification.c tells the linker that user-provided code supersedes the ensuing "library/default" code.  Hence, the comment "Note-You need to remove canMessageNotification from notification.c to avoid redefinition" is obsolete.

    Thanks.

  • No, my assumption about "#pragma WEAK()" is apparently incorrect.  Just tried it and hit redefinition error.

  • Baffled.  The CAN1_CAN2 project has canMessageNotification() in both HL_notification.c and HL_sys_main.c and it builds fine.  When I try the same in my project, the build fails on the redefinition.  Using the same TI compiler tool chain for both.  Perhaps there's a build option that's different.

  • Well, this is more confusing.  The canMessageNotification() function called by can3HighLevelInterrupt() is the one in CAN_msg_lib.c, and not the one in HL_notification.c or HL_sys_main.c (if there is one).  Who's calling whom?  Linker tricks at work, or just a matter of build options (order)?

  • No sure what happens to your project.

    Can you try this compiling option: --gen_func_subsections=on ?

  • The compiler option did not "fix" the conflict in my project.  I'll take a look at what's used for the CAN1_CAN2 project...

    error #10056: symbol "canMessageNotification" redefined: first defined in "./canMsgLib/CAN_msg_lib.obj"; redefined in "./source/HL_sys_main.obj"
    error #10010: errors encountered during linking; "DCAN_RX.out" not built

    Thanks.

  • The CAN1_CAN2 project did not have that compiler option either.  The answer is fairly simple.  My project is using the canMessageNotification() in CAN_msg_lib.obj (which doesn't have WEAK) while yours is using the one in HL_notification.c (which has WEAK).

    === My linker command...

    Building target: "DCAN_RX.out"
    Invoking: ARM Linker
    "C:/ti/ccs1000/ccs/tools/compiler/ti-cgt-arm_20.2.0.LTS/bin/armcl" -mv7R5 --code_state=32 --float_support=VFPv3D16 -g --diag_warning=225 --diag_wrap=off --display_error_number --enum_type=packed --abi=eabi -z -m"DCAN_RX.map" --heap_size=0x800 --stack_size=0x800 -i"C:/ti/ccs1000/ccs/tools/compiler/ti-cgt-arm_20.2.0.LTS/lib" --reread_libs --diag_wrap=off --display_error_number --warn_sections --xml_link_info="DCAN_RX_linkInfo.xml" --rom_model --be32 -o "DCAN_RX.out" "./app/source/APP_CONSOLE.obj" "./app/source/APP_RCV_CONTROL.obj" "./app/source/APP_RCV_VEHICLE.obj" "./canMsgLib/CAN_msg_lib.obj" "./core/time/source/DCS_TIME.obj" "./database/source/DB.obj" "./database/source/ID.obj" "./source/HL_can.obj" "./source/HL_epc.obj" "./source/HL_errata.obj" "./source/HL_errata_SSWF021_45.obj" "./source/HL_esm.obj" "./source/HL_gio.obj" "./source/HL_het.obj" "./source/HL_nmpu.obj" "./source/HL_notification.obj" "./source/HL_pinmux.obj" "./source/HL_sci.obj" "./source/HL_sys_core.obj" "./source/HL_sys_dma.obj" "./source/HL_sys_intvecs.obj" "./source/HL_sys_main.obj" "./source/HL_sys_mpu.obj" "./source/HL_sys_pcr.obj" "./source/HL_sys_phantom.obj" "./source/HL_sys_pmm.obj" "./source/HL_sys_pmu.obj" "./source/HL_sys_startup.obj" "./source/HL_sys_vim.obj" "./source/HL_system.obj" "./stdio/dbuf.obj" "./stdio/input.obj" "./stdio/output.obj" "./stdio/printf.obj" "./stdio/scidma.obj" "./stdio/vsscanf.obj" "./utility/protocols/source/SAFE_STRING.obj" "./utility/protocols/source/TRANSCODE.obj" "./utils/ibuf.obj" "./utils/timer.obj" "./utils/umm_info.obj" "./utils/umm_integrity.obj" "./utils/umm_malloc.obj" "./utils/umm_poison.obj" "../source/HL_sys_link.cmd" -llibc.a

    === Your linker command...

    Building target: "TMS570LC43x_CAN1_CAN2.out"
    Invoking: ARM Linker
    "C:/ti/ccs1000/ccs/tools/compiler/ti-cgt-arm_20.2.0.LTS/bin/armcl" -mv7R5 --code_state=32 --float_support=VFPv3D16 -O1 --opt_for_speed=5 -g --diag_warning=225 --diag_wrap=off --display_error_number --enum_type=packed --abi=eabi -z -m"TMS570LC43x_CAN1_CAN2.map" --heap_size=0x800 --stack_size=0x800 -i"C:/ti/ccs1000/ccs/tools/compiler/ti-cgt-arm_20.2.0.LTS/lib" -i"C:/ti/ccs1000/ccs/tools/compiler/ti-cgt-arm_20.2.0.LTS/include" --reread_libs --diag_wrap=off --display_error_number --warn_sections --xml_link_info="TMS570LC43x_CAN1_CAN2_linkInfo.xml" --rom_model --be32 -o "TMS570LC43x_CAN1_CAN2.out" "./source/HL_can.obj" "./source/HL_epc.obj" "./source/HL_errata.obj" "./source/HL_errata_SSWF021_45.obj" "./source/HL_esm.obj" "./source/HL_gio.obj" "./source/HL_nmpu.obj" "./source/HL_notification.obj" "./source/HL_pinmux.obj" "./source/HL_rti.obj" "./source/HL_sci.obj" "./source/HL_spi.obj" "./source/HL_sys_core.obj" "./source/HL_sys_dma.obj" "./source/HL_sys_intvecs.obj" "./source/HL_sys_main.obj" "./source/HL_sys_mpu.obj" "./source/HL_sys_pcr.obj" "./source/HL_sys_phantom.obj" "./source/HL_sys_pmm.obj" "./source/HL_sys_pmu.obj" "./source/HL_sys_startup.obj" "./source/HL_sys_vim.obj" "./source/HL_system.obj" "../source/HL_sys_link.cmd" -lrtsv7R4_T_be_v3D16_eabi.lib

  • Just a little clarification.  The canMessageNotification() in CAN_msg_lib.obj does end up calling the one in HL_notification.c (since I added USER code there that does dispatch to my canMessageNotificationX() in HL_sys_main.c).

  • Hi Peter,

    I don't know how the compiler/linker and assembler handle the WEAK function in the user pre-compiled library. 

    Does your project include the runtime library rtsv7R4_T_be_v3D16_eabi.lib?

  • This CAN_msg_lib.c file/module is something my predecessor put in that has some statistics gathering and data decoding code.  I can't tell how complete or experimental the code is and have to decide to keep/modify it or just remove it.  I'm _VERY_ baffled by how the canMessageNotification() in CAN_msg_lib.c (which has no #pragma) ends up calling the canMessageNotification() in HL_notification.c.  I've got to do more digging/experimenting on this, even though it's low priority (for now).

    Much higher priority to get the interrupt/notification reception (then transmission) working.

    Thanks.

  • Hi Peter,

    You can consult the CCS/Compiler experts in SDTO e2e forum for this compiler related question.

    https://e2e.ti.com/support/tools/code-composer-studio-group/ccs/f/code-composer-studio-forum

  • Oh. Foolish me.   Since the notification stuff is not running, I couldn't tell that the canMessageNotification() in HL_notification.c is not linked in at all.  I have not been able to run the code enough in a debugger to be able to tell that _my_ code is not even in the .out file.   I just need to get rid of CAN_msg_lib.c, which is for some other purpose anyway.

    Puzzle solved.  Just a residue of picking up a project where I didn't know what was done before.

    Thanks.

  • I am wondering if there is any trick in compiler/linker settings to handle the WEAK functions defined in a library. It might be known issue or bug. It doesn't hurt to check with compiler/liner experts.

  • There is an interesting, but understandable behavior in the use of "#pragma (WEAK)".  Although the user's code (e.g., canMessageNotification() in HL_sys_main.c) _does_ supersede the default version (in HL_notification.c with pragma WEAK), any symbols in the default version (in the USER CODE section) still gets linked into the build (and will show up as undefined if the user does not supply such items (variables, functions, etc.).

    Anyway, I think this issue (pragma WEAK, and link module order) is now understood.

    Thank you very much.  This was really a red herring, although the comment about having to comment out the stub in HL_notification.c is now obsolete and misleading.

  • Hi, Have you had any chance to look at the INT=0x8000 issue, with one Launchpad CAN continually transmitting to another?  This is critical to my project.

    Thanks.

  • The sample code I sent you is not "complete" since the ibuf (interrupt buffer) code I have is not included or even needed.  At this point, there is no need to add USER code, since all I need to do is set an interrupt at canMessageNotification() and find if it's ever invoked, and it isn't.  Debugging back, it's clear that the can3HighLevelInterrupt() is consistently taking the status message notification path (because INT==0x8000 coming from the hardware), and hence canMessageNotification() is never called (since the hardware doesn't present incoming CAN message data).  Do you see the same sequence of events, if you have been able to do a two-Launchpad set-up running my HL_sys_main.c?

    Thank you very much.

  • Hi Peter,

    I don't have CAN transceiver adaptor for CAN communication test on launchpads. 

  • Hi,

    Do you have any time and interest to help debug this problem for me/us?  As I mentioned, this is critical to my project.

    If you have two XL2-570LC43 boards, then I could send you a pair of transceiver boards that would fit easily on the boards, so that you could run the HL_sys_main.c I sent you.

    Thank you very, very, much.

  • Can you please send me the latest HL_sys_main.c, and HAL file (*.hcg, and *.dil)? Thanks

  • I have uploaded the newest trimmed-down HL_sys_main.c and the .hcg and .dil files to protonmail.  Unnecessary stuff is conditionalized out.  Will need a printf() function (or comment out and use debugger).

    Need two Launchpads with transceivers on CAN3 hooked to each other.  CAN port can be easily changed.

    Unit 0 is polling transmitter.  Unit 1 is polling receiver.  Unit 3 is interrupt receiver (replacing 1).  Just breakpoint on canMessageNotification() in HL_notification.c, or can3HighLevelInterrupt() in HL_can.c.

    Unit 0->1 is for sanity checking.  Unit 0->3 is test for interrupt/notification.

    Go to www.protonmail.com and sign in as shareuser1000 with password password.

    Email subject is "package for CAN message receive using interrupt."

    Thank you very much.

  • Is there any problem if using CAN1 or CAN2? I can test it on 2 HDKs which has 2 transceivers for CAN1 and CAN2, but doesn't have transceiver for CAN3.

  • You just have to modify the code as necessary to use the connected CAN ports.  But, you need two Launchpads, since a large part of the exercise is the transmitter running full-blast on one board, while the receiver tries to receive.  In the Unit 0->1 both-polling scenario, messages are never lost at the receiver (which is supposed to be the case for interrupt-mode receiver as well).

    I use the same code base for both the tx node and rx node, since they are both wired up to CAN3.  If you use CAN1 on one node and CAN2 on the other, then you need to have two code bases, for CAN<n> tweaks.

    Note that the errors number bumps up 1 for each printf() message because this is running in blocking-SCI mode.  With my non-blocking-SCI-buffered mode (not included), the errors will not increment.

    Thank you very much.

  • The tweak to HL_sys_main.c is "canPort = canREGx;"

    Note that the .hcg doesn't have all CAN ports enabled/configured, so whatever port(s) you use, you will need to set up Halcogen appropriately.

    Thanks.

  • Hi,

    Can you send me the CAN_msg_lib.h? Where is DB_initialize() defined?

    Do two boards run the same code?

  • The CAN_msg_lib.h/.c is part of the code my predecessor put into the environment that hooked into the the APIs _before_ such files as HL_notification.c that caused the red-herring with the #pragma WEAK() issue.  He didn't understand the Halcogen infrastructure, where TI provides the first-level hardware-support code, to provide the Hardware Abstraction Layer.  The include for CAN_msg_lib.h and the call to DB_initialize() [ which collected some run CAN statistics ] can be commented out with no functional difference in the test code.  I should have already removed those lines.  I had already renamed the .c to CAN_msg_lib.c.notused, so the Launchpad build doesn't incorporate it.  I uploaded CAN_msg_lib.h  to protonmail, for your inspection.

    Yes.  In my set-up, the two boards run the same code base.  At run-time, the user types in the Unit Number to designate the functionality of the board. There is a curious behavior of running two Launchpads from the same host PC, in that the user can't actually tell which Launchpad is which unit (and I think the XDS110 probe does some kind of "random selection").  I've seen the sciREG1 switch PC COM ports in successive runs.  Hence, I have the LEDs lit to the Unit Number, so I can tell which physical board is tx and which rx.

    Just to be 100% sure, I will run my set-up with those lines commented out, to see if any (failing) behavior changes.

    Thank you very much.

  • I just commented out the 3 lines and the run behavior remains the same, with the INT register "stuck" at 0x8000.

    Thanks.

  • Okay, I will read your code first, then try to do a test with HDKs.

  • There is a curious behavior of running two Launchpads from the same host PC, in that the user can't actually tell which Launchpad is which unit (and I think the XDS110 probe does some kind of "random selection").  I

    You should be able select the XDS110 probe by serial number - see Debugging with Multiple XDS Debug Probes

    The xdsdfu utility described in the XDS110 Debug Probe User's Guide allows you to program a serial number if the launchpad doesn't have one programmed.

  • Thanks for the info on the XDS110, which I will keep in mind when I need it.  I did encounter the selection dialog box of XDS110 probe when starting up a new workspace, but wasn't sure if the selection is honored in subsequent invocations of the workspace.  I do know the serial port that uses the same USB cable(s) hops around; on my laptop COM4 is usually used by one XDS110/Launchpad while the other XDS/Launchpad comes up as COM6, COM8, COM11, etc., and sometimes the two Launchpads switch COM ports (can also tell because of LEDs).  I think serial ports themselves have no identifiers, so the "terminal" serial port(s) may have nothing to bind to.  Not sure what facilities Windows has to bind to COM  devices, but I recall doing this with the Udev stuff in Linux, for USB-serial.

    Part of the reason I think the (two+) XDS110 probes is doing some kind of "selection" is that if I only have one XDS110 plugged into the laptop, doing the "Debug" gets the laptop-XDS110 communication (to do flash erase and code download) going immediately.  If I have two XDS-110 plugged into the laptop, the "Debug" initiates a "search/scan" (green progress bar going back and forth) for some 15+ seconds before the comm will start.  Good thing is, two Debug sessions will _not_ collide on trying to use the same XDS110/Launchpad.

    In my particular test set-up, since the two Launchpads are symmetric/identical, I don't really care which board is tx and which rx.  The LEDs provide more identification, if I needed to know.

  • I filled in the "myunit == 2" code, which has the transmitter board running interrupt-driven, and it "just works," as expected.  It behaves like the "myunit == 0" code, which is the polling transmitter, and can be a direct replacement.  I could upload the code for inspection, if there is curiosity.

    Have you had the chance to get the "myunit == 1" code, which is the interrupt-driven receiver, running (while the other board is running "myunit == 0," the polling transmitter), to demonstrate the stuck INT == 0x8000 (with supplemental status RxOK)?

    Thanks.

  • I shuffled my code around, and was able to get the interrupt-mode receiver going.  Unfortunately, I think the Launchpad CAN has a shortcoming in its implementation of the CAN interrupts.

    I re-arranged my code a little, and did the following:

    = Ran Halcogen so canMessageBox1 is configured to interrupt on RX.  Generate code.

    = Disable IE1 and IE0 right after canInit();

    = Do canUpdateID() just as before, but with interrupts disabled now (noticed some interrupt activity when updating)

    = Enable IE1 and IE0 so interrupts can happen.

    The interrupt-mode receiver works properly now.  The real issue is the Halcogen configuration for messageBox to interrupt on TX _or_ RX.

    Unfortunately, when I try the same (new) set-up to run interrupt-mode transmit, the interrupt doesn't happen.  If I run Halcogen again to set up canMessageBox1 to interrupt on TX, then the interrupt-mode transmitter works, but the interrupt-mode receiver now breaks.  While canUpdateID() allows the user to change the messageBox's (tx/rx) direction after the code-generate, there doesn't seem to be any dynamic mechanism (API) to tell  the interrupt to follow the direction change.  Maybe there's some way to do this via direct register manipulation, but I don't know how this is done.

    In example code that use two messageBoxes to do external loopback, one box can be set up for TX interrupt and the other for RX interrupt via Halcogen code generation, so this "static" set-up works.

    I would think this interrupt-direction feature should be dynamically configurable (when I use canUpdateID() to set TX/RX direction), but the lack of a CAN API to do this (as far as I can tell) may indicate that the interrupt-direction is a static thing that can't be dynamically re-configured at will.

    Thanks for any help resolving this, which is my last CAN hurdle.

  • The problem is sort-of solved.  I ran Halcogen once with the RX-interrupt configuration, and once with the TX-interrupt configuration, and noticed the differences in the generated code, as shown below,  So, I just copied the hard-code for the tx case that works only for canREG3 to just before the call to canUpdateID() and the TX-interrupt works now.  Will need the formula to do this for any can port for completeness.  If there is already an API to do this dynamically, please let me know.

    LTWPNE1840A:~/Code/DCAN_RX_syscomm_txrx/source 40> diff HL_can.c HL_can.c.tx
    655,656c655,656
    < canREG3->IF1ARB = (uint32)0x80000000U | (uint32)0x00000000U | (uint32)0x00000000U | (uint32)((uint32)((uint32)1U & (uint32)0x000007FFU) << (uint32)18U);
    < canREG3->IF1MCTL = 0x00001000U | (uint32)0x00000400U | (uint32)0x00000000U | (uint32)0x00000000U | (uint32)8U;
    ---
    > canREG3->IF1ARB = (uint32)0x80000000U | (uint32)0x00000000U | (uint32)0x20000000U | (uint32)((uint32)((uint32)1U & (uint32)0x000007FFU) << (uint32)18U);
    > canREG3->IF1MCTL = 0x00001000U | (uint32)0x00000800U | (uint32)0x00000000U | (uint32)0x00000000U | (uint32)8U;