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: CAN bus usage from Flash

Part Number: LAUNCHXL-F28379D
Other Parts Discussed in Thread: TEST2, C2000WARE, TMS320F28377D

I have an application which is a slightly modified version of can_ex10_mask (switch to CANB since that's what's on the dev board, changed the extended ID to match my CAN bus traffic and added some printf's) that works when I run it from RAM but it never indicates receiving a CAN message when run from flash. Neither the mbox bit in NDAT_21 nor the RXOK bit in ES gets set when running from flash.

I assume something isn't right with linker script but I can't figure out what the issue is. I've tried moving the .cinit section to FLASHF from FLASHB as FLASHB isn't big enough if you use printf's in the app. (Getting rid of the printf's and using the stock linker script doesn't make the app work.)

I've included (hopefully!) my main.c and I'm currently using the stock can_ex10_mask/2837xD_FLASH_lnk_cpu1.cmd linker script.

Any ideas on how to track down what I'm doing wrong?

#include <stdio.h>
#include "driverlib.h"
#include "device.h"

//
// Defines
//
#define MSG_DATA_LENGTH    8    // "Don't care" for a Receive mailbox
#define RX_MSG_OBJ_ID      1    // Use mailbox 1

//
// Globals
//
uint16_t rxMsgData[8];          // Buffer for received data
volatile uint16_t X, Y, Dim;

#define LED_SET_WARM_PWM        0x08280000
#define LED_SET_COOL_PWM        0x08280001
#define LED_SET_RED_PWM         0x08280002
#define LED_SET_GREEN_PWM       0x08280003
#define LED_SET_BLUE_PWM        0x08280004


/**
 * hello.c
 */
int main(void)
{
    int i;
    uint16_t warm, cool, red, green, blue;

    //
    // If running from flash copy RAM only functions to RAM   
    //
#ifdef _FLASH
    memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
#endif      

    //
    // Initialize device clock and peripherals
    //
    Device_init();

    //
    // Initialize GPIO
    //
    Device_initGPIO();

    //printf("CAN Bus test: DEVICE_SYSCLK_FREQ = %ld\n", DEVICE_SYSCLK_FREQ);
	
    //
    // Configure GPIO pins for CANTX/CANRX
    //
/*     GPIO_setPinConfig(DEVICE_GPIO_CFG_CANRXA); */
/*     GPIO_setPinConfig(DEVICE_GPIO_CFG_CANTXA); */
    GPIO_setPinConfig(GPIO_12_CANTXB);
    GPIO_setPinConfig(GPIO_17_CANRXB);

    //
    // Initialize the CAN controller
    //
    CAN_initModule(CANB_BASE);

    //
    // Set up the CAN bus bit rate to 500kbps for each module
    // Refer to the Driver Library User Guide for information on how to set
    // tighter timing control. Additionally, consult the device data sheet
    // for more information about the CAN module clocking.
    //
    CAN_setBitRate(CANB_BASE, DEVICE_SYSCLK_FREQ, 1000000, 10);

    //CAN_setBitTiming(CANB_BASE, 5, 1, 7, 4, 2);
    //
    // Initialize the receive message object used for receiving CAN messages.
	// Possible flags: CAN_MSG_OBJ_NO_FLAGS, CAN_MSG_OBJ_USE_EXT_FILTER,
	//                 CAN_MSG_OBJ_USE_DIR_FILTER
    // Message Object Parameters:
    //      CAN Module: A
    //      Message Object ID Number: 1
    //      Message Identifier: 0x1F9FFFFA
    //      Message Frame: Extended
    //      Message Type: Receive
    //      Message ID Mask: 0x1F000000
    //      Message Object Flags: UMask, MXtd, MDir
    //      Message Object flag CAN_MSG_OBJ_USE_ID_FILTER enables usage 
    //       of msgIDMask parameter for Message Identifier based filtering
    //      Message Data Length: "Don't care" for a Receive mailbox
    CAN_setupMessageObject(CANB_BASE, RX_MSG_OBJ_ID, 0x1555aab4,
                           CAN_MSG_FRAME_EXT, CAN_MSG_OBJ_TYPE_RX, 
			   0x1555aab4, CAN_MSG_OBJ_NO_FLAGS,
			   MSG_DATA_LENGTH);

    //
    // Start CAN module A operations
    //
    CAN_startModule(CANB_BASE);

    //printf("CANB started\n");
	
    //
    // Start reception - Just wait for data from another node
    //
    while (1) {
        //
        // Poll bit0 in CAN_NDAT_21 register to check completion of Reception
        //
        //if(((HWREGH(CANB_BASE + CAN_O_ES) & CAN_ES_RXOK)) == CAN_ES_RXOK) { 
	if ((HWREG_BP(CANB_BASE + CAN_O_NDAT_21) & (1 << (RX_MSG_OBJ_ID - 1))) != 0) {
            //
            // Get the received message
            //
            asm("  NOP");
            CAN_readMessage(CANB_BASE, RX_MSG_OBJ_ID, rxMsgData);
	    X = (rxMsgData[0] << 8) + rxMsgData[1];
	    Y = (rxMsgData[2] << 8) + rxMsgData[3];
	    Dim = (rxMsgData[4] << 8) + rxMsgData[5];
/* 	    for (i = 0 ; i < MSG_DATA_LENGTH ; i++) */
/* 		printf("[%d]: 0x%04x\n", i, rxMsgData[i]); */
	    //printf("%u: %u, %u, %u\n", rxMsgData[6], X, Y, Dim);

#if 0
	    xy_to_tdrgb(X / 65535.0f, Y / 65535.0f, Dim / 65535.0f,
			&warm, &cool, &red, &green, &blue);

	    printf("(   => (%5u, %5u, %5u, %5u, %5u)\n", 
		   warm, cool, red, green, blue);

#if 0
	    SendLED(fixture->fd, LED_SET_WARM_PWM,      warm);
	    SendLED(fixture->fd, LED_SET_COOL_PWM,      cool);
	    SendLED(fixture->fd, LED_SET_RED_PWM,       red);
	    SendLED(fixture->fd, LED_SET_GREEN_PWM,     green);
	    SendLED(fixture->fd, LED_SET_BLUE_PWM,      blue);
#endif
#endif
	}
    }

    return 0;
}

  • It appears your code works when it is flashed and executed with the JTAG debug probe still connected (or) it works from RAM, but not from flash. The golden rule when booting stand-alone (i.e. from Flash) is to ensure that the program does not require anything pre-loaded/initialized in RAM for it to function. Any initialized data in RAM should be coming from flash and the runtime C libraries will take care of this before program reaches main(). Inspect your map file for all the sections that are being loaded into RAM and see if there are initialized locations for program to function. If yes, then they need to be moved to flash into a .cinit section. Similar to the RAMFUNCS sections for which the main code does a memcpy(), which is for any function that need to be run from RAM, there will be a copy for the initialized data as well. The following posts gives more insights:

    https://e2e.ti.com/support/microcontrollers/c2000/f/171/p/655030/2408221#2408221

    https://e2e.ti.com/support/microcontrollers/c2000/f/171/t/757590 

    One more thing to look at is whether Watchdog is expiring before reaching main() in Standalone mode. Have you tried disabling WD in codestartbranch.asm?

  • My code only works when the build configuration is set to CPU1_RAM. If I set the build configuration to CPU1_FLASH, it runs but doesn't receive any CAN messages. It's inside main() in the "while (1) {}" loop waiting for a message to be received.

    The only global variable I have is "uint16_t rxMsgData[8];". If I'm reading the map file correctly, it gets allocated to RAMM1 as uninitialized data in the BSS section. So I don't have any initialized C variables. It appears only the TI run time has any.

    I've increased the stack size to 0x200 and that makes no difference. I've also increase the heap but it doesn't look like anything uses the heap, ie no malloc().

    I've removed all of the dead code from main.c so it's cleaner. I've attached it and the map file in case you can spot something stupid I'm doing.

    Mike

  • Mike,

    I will try this myself. Give me a day or two. BTW, I was unable to download the file you attached. 

  • I tried to attach two files: main.c and Test2.map. When I tried to submit the reply, I kept getting "An error has occurred. Try again later or contact your administrator." I tried with 3 different web browsers. Finally after 12 hours, Safari "succeeded" but I noticed that the two files were replaced by one empty placeholder.

    So let's see if a ZIP file of the whole project will work:

    Test2.zip

  • I was able to download the file. The problem might have been with the linker command file (xxxxx.cmd). Many firewalls block files with that extension, since Windows Command Scripts have the same extension.

  • Mike,

                  I tried this on my setup and it worked without any problem. It is custom-hardware (not the Launchpad), but that should make no difference. I tried can_ex4_simple_transmit in C:\ti\c2000\C2000Ware_3_02_00_00\driverlib\f2837xd\examples\cpu1\can directory. I first ran it from RAM and then changed the Build configuration to Flash. I ensured the boot-mode jumpers are set for Get Mode. I disconnected JTAG and power cycled the board and it worked fine.

  • After you changed the Build configuration to Flash, did you see the flash being programmed? This will take longer compared to loading in RAM, since the flash needs to be erased and programmed (you would see messages to that effect). Also, when you stop code execution, the PC should point to a location in flash, not RAM. You could verify this in the Disassembly window. Note that the directory in which your COFF file (can_ex4_simple_transmit.out, in my case) gets stored will change depending on whether your build config is RAM (in which case it is stored in \CPU1_RAM) or flash (\ CPU1_FLASH). You need to be careful which COFF file you are loading for debug. Can you please double-check this?

  • Can you tell me how you know it works if you've disconnected the JTAG? My app doesn't provide any indication that it received the CAN message. I set a breakpoint before the call to CAN_readMessage().

    As for custom hardware, this project was created from the Resource Center->Software->C2000Ware 2.02.00.00->English->Devices->F2837XD->F28379D->Examples->Driverlib Empty CPU1 Example. I then copied can_ex10_mask/can_ex10_mask.c to main.c and went from there. I believe I copied over the 2837xD_FLASH_lnk_cpu1.cmd file too. The only example I could find that's explicitly for the LaunchPad is the preinstalled blinking light/ADC demo and it uses the older interface routines instead of Device_init(), et al.

    When I run can_ex4_simple_transmit from RAM, it keeps failing an assert in can.c, line 487. When I step thru in the debugger, msgCtrl is 136 and msgLen is 8 so it shouldn't be failing the assertion!

    Could I have a bad board/MCU?

  • I am monitoring the CAN traffic with a CAN bus analyzer connected to my PC. That is how I know my code works fine. 

    It appears you have executed many steps that may not be necessary. It is fairly simple and straightforward. All you need to do is to import the project, change the GPIO config, compile and run it. To run from flash, you need to change the build config. We may have to take this offline.

  • Sorry for the delay. I had to go get a root canal this afternoon!

    It's highly likely that I'm doing things the hard/wrong way as this is my first CCS/C2000 project. I've mostly done other manufacturer's ARM Cortex-M4 projects. We're using the TMS28377d solely for the high precision PWM signals. My only previous experience with the C2X family was about 30 years ago. I do have Linux and Android experience on the OMAP 3, 4, 5, & 6 family of CPUs.

    I did import the can_ex10_mask and can_ex4_simple_transmit examples from the resource center but those are all for the bare chip and not the LaunchPad configuration. For instance, they use CANA by default the the LaunchPad has CANB connected to the external pins.

    So ,yes, I think it would be good to do a direct call. I'll accept your webbed invite tomorrow morning once I can move my jaw.

  • Mike,

    If you are new to C2000 or CCS, please review the workshops at https://training.ti.com/c2000-mcu-device-workshops . TI has invested considerable resources to develop these self-paced workshops and most questions can be answered by reviewing the workshop material for your specific device family or its closest equivalent. The workshops are an excellent introduction to the basics of C2000 MCUs and the process of writing and running your first example. Good introductory videos about CCS are available at https://www.youtube.com/user/CodeComposerStudio .

     I have sent you a friendship request. Only after you accept it will I be able to send details of the Webex/call.

  • The MDW slides helped a little with understanding the targetConfigs. It doesn't help in creating a project that uses the driverlib.

    So I went back to the beginning and

    1) "imported" the "Empty CPU1 Example CCS Project".

    2) renamed the project "Test4"

    3) renamed targetConfigs/TMS320F28377D.ccxml to Test4.ccxml

    4) changed targetConfigs/Test4.ccxml to be for the f28379D processor instead of the default 77D.

    5) deleted the default empty main file from Test4 and copied my main.c into Test4

    6) added _LAUNCHXL_F28379D to the predefined symbols for the C compiler

    7) added RAMGS1 to .text and RAMGS2 to .data sections

    8) compile, load, and run my app

    9) fix assertion error caused by missing change from CANA to CANB in the CAN_setupMessageObject() calls for my output CAN message.

    10) recompile, load, and run - Works! From RAM!!

    11) switch Build Configuration to CPU1_FLASH (took about 4 hours as Test4 didn't initially get created with a flash configuration. Everything I tried would link with both the FLASH and RAM linker cmd files, giving 65 errors that all of the memory sections were being defined twice. Eventually deleted the project, tried to reimport the empty driver lib project, which fails because C2000-3.03 just came out, so installed it, then imported the empty driver lib project, which now has a FLASH build config, and repeat steps 1-10)

    12) compile. fix linker errors by adding FLASHC to the .cinit section

    13) compile, load, run my app. Doesn't see any incoming CAN messages. Scratch head. Bang head against wall. Notice _LAUNCHXL_F28379D isn't defined for the build.

    14) add _LAUNCHXL_F28379D to the C compiler's predefined symbols

    15) compile, load, run my app. It works!! From FLASH!!

    16) Pour a very large margarita! Consume.

    There's got to be an easier, less prone way to do this.

     

  • As indicated in my previous post, please accept my friendship request. We can get on a Webex and examine where you had difficulty.