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-F280039C: Questions about build generated CRC over flash

Part Number: LAUNCHXL-F280039C

First, I'm new to the C2000 products and CCS. I'm exploring options for build-generated CRC value over the flash memory and I'd like to get some feedback.
I've read through many questions and guides for similar behavior with different MCUs with different memory layouts and functionality. I've found examples with generating tables from code-defined memory regions. But I haven't found an example for creating a value across all flash memory. On this MCU flash memory range is 80000:AFFFF. Since the last row is already declared "reserved" due to execution limitations, I feel the AFFF0 row would be a great location to stuff a CRC. I'm researching if this is truly "reserved"or just unavailable for code.

I've been working from a basic example project trying to get the linker to generate a CRC using its built-in functions. The project is configured using the flash linker file, I've tried to generate CRC from the memory declaration using crc funciton and in the sections declaration using crc_table but so far the linker isn't cooperating.  I've run into problems when creating a group in the memory section because the group range overlaps with the 4k flash sections defined in the file. It seems I can't declare a group just as a range reference.

Are there any good examples for how to have the linker generate a CRC over the entire flash memory on this MCU?

  • Hello JJ,

    The last row is "reserved" due to the behavior of the instruction prefetch logic. A data word such as a CRC is probably fine to store here.

    Please provide a copy of your linker command file so I can attempt to find out why you're having issues.

    Best regards,

    Ibukun

  • Additional questions which I might as well ask since I'm not distracted by responses from my initial question.

    These are in reference to the 2 example projects found in the CCS examples for the 280003x for CRC using BGCRC: cpuinterrupt and cpubasic (not the CLA examples)

    Why do the linker files define the address of flash memory (Bank 0 sector 0) origin at 0x80002 rather than 0x80000? I wasn't able to find the answer in datasheet or TR, is this a reserved value location? 

    These example project include linker files for both RAM and flash, in both the flash memory is split up into both banks (0.1.2) and sectors (0-15) most 4K in size.
    I can understand why this would be important when managing erasing flash. But don't understand why it matters for the linker. What's the reason? Can't memory be accessed across sector boundaries without issue?

  • thanks for the reply, I was writing a follow up as you were replying.
    I understood the instruction prefetch, so thanks for confirming it should be find for crc table data.  

    For the linker command file, I've been plugging away with various different attempts. I don't really have anything that works, so I don't know how helpful these guesses would be. 


    I fear sharing this because it's just several crappy hacks to try and get something working. The only thing which showed any promise (but didn't work) is the final lines in the end of the SECTION declaration. 

    Seriously... if you look at this forget about what you saw as soon as you're done reading.
    I guess it's worth noting, this is the 28003x_generic_flash_lnk.cmd from the /bgcrc_ex1_cpuinterrupt example project modified to test generating CRC.
     

    MEMORY
    {
       BEGIN            : origin = 0x00080000, length = 0x00000002
       BOOT_RSVD        : origin = 0x00000002, length = 0x00000126
    
       RAMM0            : origin = 0x00000128, length = 0x000002D8
       RAMM1            : origin = 0x00000400, length = 0x000003F8
       // RAMM1_RSVD       : origin = 0x000007F8, length = 0x00000008 /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */
    
       RAMLS0           : origin = 0x00008000, length = 0x00000800
       RAMLS1           : origin = 0x00008800, length = 0x00000800
       RAMLS2           : origin = 0x00009000, length = 0x00000800
       RAMLS3           : origin = 0x00009800, length = 0x00000800
       RAMLS4           : origin = 0x0000A000, length = 0x00000800
       RAMLS5           : origin = 0x0000A800, length = 0x00000800
       RAMLS6           : origin = 0x0000B000, length = 0x00000800
       RAMLS7           : origin = 0x0000B800, length = 0x00000800
    
       RAMGS0           : origin = 0x0000C000, length = 0x00001000
       RAMGS1           : origin = 0x0000D000, length = 0x00001000
       RAMGS2           : origin = 0x0000E000, length = 0x00001000
       RAMGS3           : origin = 0x0000F000, length = 0x00000FF8
       // RAMGS3_RSVD      : origin = 0x0000FFF8, length = 0x00000008 /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */
    
       BOOTROM          : origin = 0x003F8000, length = 0x00007FC0
       SECURE_ROM       : origin = 0x003F2000, length = 0x00006000
    
       RESET            : origin = 0x003FFFC0, length = 0x00000002
    
       /* Flash sectors */
       /* BANK 0 */
       FLASH_BANK0_SEC0  : origin = 0x080002, length = 0x000FFE
       FLASH_BANK0_SEC1  : origin = 0x081000, length = 0x001000
       FLASH_BANK0_SEC2  : origin = 0x082000, length = 0x001000
       FLASH_BANK0_SEC3  : origin = 0x083000, length = 0x001000
       FLASH_BANK0_SEC4  : origin = 0x084000, length = 0x001000
       FLASH_BANK0_SEC5  : origin = 0x085000, length = 0x001000
       FLASH_BANK0_SEC6  : origin = 0x086000, length = 0x001000
       FLASH_BANK0_SEC7  : origin = 0x087000, length = 0x001000
       FLASH_BANK0_SEC8  : origin = 0x088000, length = 0x001000
       FLASH_BANK0_SEC9  : origin = 0x089000, length = 0x001000
       FLASH_BANK0_SEC10 : origin = 0x08A000, length = 0x001000
       FLASH_BANK0_SEC11 : origin = 0x08B000, length = 0x001000
       FLASH_BANK0_SEC12 : origin = 0x08C000, length = 0x001000
       FLASH_BANK0_SEC13 : origin = 0x08D000, length = 0x001000
       FLASH_BANK0_SEC14 : origin = 0x08E000, length = 0x001000
       FLASH_BANK0_SEC15 : origin = 0x08F000, length = 0x001000
    
       /* BANK 1 */
       FLASH_BANK1_SEC0  : origin = 0x090000, length = 0x001000
       FLASH_BANK1_SEC1  : origin = 0x091000, length = 0x001000
       FLASH_BANK1_SEC2  : origin = 0x092000, length = 0x001000
       FLASH_BANK1_SEC3  : origin = 0x093000, length = 0x001000
       FLASH_BANK1_SEC4  : origin = 0x094000, length = 0x001000
       FLASH_BANK1_SEC5  : origin = 0x095000, length = 0x001000
       FLASH_BANK1_SEC6  : origin = 0x096000, length = 0x001000
       FLASH_BANK1_SEC7  : origin = 0x097000, length = 0x001000
       FLASH_BANK1_SEC8  : origin = 0x098000, length = 0x001000
       FLASH_BANK1_SEC9  : origin = 0x099000, length = 0x001000
       FLASH_BANK1_SEC10 : origin = 0x09A000, length = 0x001000
       FLASH_BANK1_SEC11 : origin = 0x09B000, length = 0x001000
       FLASH_BANK1_SEC12 : origin = 0x09C000, length = 0x001000
       FLASH_BANK1_SEC13 : origin = 0x09D000, length = 0x001000
       FLASH_BANK1_SEC14 : origin = 0x09E000, length = 0x001000
       FLASH_BANK1_SEC15 : origin = 0x09F000, length = 0x001000
    
      /* BANK 2 */
       FLASH_BANK2_SEC0  : origin = 0x0A0000, length = 0x001000
       FLASH_BANK2_SEC1  : origin = 0x0A1000, length = 0x001000
       FLASH_BANK2_SEC2  : origin = 0x0A2000, length = 0x001000
       FLASH_BANK2_SEC3  : origin = 0x0A3000, length = 0x001000
       FLASH_BANK2_SEC4  : origin = 0x0A4000, length = 0x001000
       FLASH_BANK2_SEC5  : origin = 0x0A5000, length = 0x001000
       FLASH_BANK2_SEC6  : origin = 0x0A6000, length = 0x001000
       FLASH_BANK2_SEC7  : origin = 0x0A7000, length = 0x001000
       FLASH_BANK2_SEC8  : origin = 0x0A8000, length = 0x001000
       FLASH_BANK2_SEC9  : origin = 0x0A9000, length = 0x001000
       FLASH_BANK2_SEC10 : origin = 0x0AA000, length = 0x001000
       FLASH_BANK2_SEC11 : origin = 0x0AB000, length = 0x001000
       FLASH_BANK2_SEC12 : origin = 0x0AC000, length = 0x001000
       FLASH_BANK2_SEC13 : origin = 0x0AD000, length = 0x001000
       FLASH_BANK2_SEC14 : origin = 0x0AE000, length = 0x001000
       FLASH_BANK2_SEC15 : origin = 0x0AF000, length = 0x000FF0
    
    // FLASH_BANK0_SEC15_RSVD     : origin = 0x0AFFF0, length = 0x000010  /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */
    
    	FLASH_MEM_CRC32      : origin = 0x0AFFF0, length = 0x000010  /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */
    
    // this crap just doesn’t work, ignore:
    //	GROUP(FlashTest)
    //	{
    //	  F: origin = 0x8A0000, length = 0x000FF0
    //	} crc(flash_CRC32, algorithm=CRC32_PRIME)
    }
    
    
    SECTIONS
    {
       codestart        : > BEGIN, ALIGN(8)
       .text            : >> FLASH_BANK0_SEC2 | FLASH_BANK0_SEC3 | FLASH_BANK0_SEC4,   ALIGN(8)
       .cinit           : > FLASH_BANK0_SEC1,  ALIGN(8)
       .switch          : > FLASH_BANK0_SEC1,  ALIGN(8)
       .reset           : > RESET,                  TYPE = DSECT /* not used, */
    
    // This was a hack to see if I could trick the linker to view all memory as one space, this should be ignored
       .all_flash		: >> FLASH_BANK0_SEC0 | FLASH_BANK0_SEC1 | FLASH_BANK0_SEC2 | FLASH_BANK0_SEC3 | FLASH_BANK0_SEC4 | FLASH_BANK0_SEC5 | FLASH_BANK0_SEC6 | FLASH_BANK0_SEC7 | \
       						 FLASH_BANK0_SEC8 | FLASH_BANK0_SEC9 | FLASH_BANK0_SEC10 | FLASH_BANK0_SEC11 | FLASH_BANK0_SEC12 | FLASH_BANK0_SEC13 | FLASH_BANK0_SEC14 | FLASH_BANK0_SEC15 | \
       						 FLASH_BANK1_SEC0 | FLASH_BANK1_SEC1 | FLASH_BANK1_SEC2 | FLASH_BANK1_SEC3 | FLASH_BANK1_SEC4 | FLASH_BANK1_SEC5 | FLASH_BANK2_SEC6 | FLASH_BANK1_SEC7 | \
       						 FLASH_BANK2_SEC8 | FLASH_BANK1_SEC9 | FLASH_BANK1_SEC10 | FLASH_BANK1_SEC11 | FLASH_BANK1_SEC12 | FLASH_BANK1_SEC13 | FLASH_BANK1_SEC14 | FLASH_BANK1_SEC15 | \
       						 FLASH_BANK2_SEC0 | FLASH_BANK2_SEC1 | FLASH_BANK2_SEC2 | FLASH_BANK2_SEC3 | FLASH_BANK2_SEC4 | FLASH_BANK2_SEC5 | FLASH_BANK2_SEC6 | FLASH_BANK2_SEC7 | \
       						 FLASH_BANK2_SEC8 | FLASH_BANK2_SEC9 | FLASH_BANK2_SEC10 | FLASH_BANK2_SEC11 | FLASH_BANK2_SEC12 | FLASH_BANK2_SEC13 | FLASH_BANK2_SEC14 | FLASH_BANK2_SEC15, TYPE = DSECT
       .stack           : > RAMM1
    
    #if defined(__TI_EABI__)
       .init_array      : > FLASH_BANK0_SEC1,  ALIGN(8)
       .bss             : > RAMLS5
       .bss:output      : > RAMLS3
       .bss:cio         : > RAMLS0
       .data            : > RAMLS5
       .sysmem          : > RAMLS5
       .const           : > FLASH_BANK0_SEC4,  ALIGN(8)
    #else
       .pinit           : > FLASH_BANK0_SEC1,  ALIGN(8)
       .ebss            : > RAMLS5
       .esysmem         : > RAMLS5
       .cio             : > RAMLS0
       .econst          : > FLASH_BANK0_SEC4,  ALIGN(8)
    #endif
    
        ramgs0 : > RAMGS0
        ramgs1 : > RAMGS0
    
        /*  Allocate IQ math areas: */
       IQmath           : > FLASH_BANK0_SEC1, ALIGN(8)
       IQmathTables     : > FLASH_BANK0_SEC2, ALIGN(8)
    
       .TI.ramfunc      : LOAD = FLASH_BANK0_SEC1,
                          RUN = RAMLS0,
                          LOAD_START(RamfuncsLoadStart),
                          LOAD_SIZE(RamfuncsLoadSize),
                          LOAD_END(RamfuncsLoadEnd),
                          RUN_START(RamfuncsRunStart),
                          RUN_SIZE(RamfuncsRunSize),
                          RUN_END(RamfuncsRunEnd),
                          ALIGN(8)
    // This is about the only thing which looked promising (ie didn’t crash the build), but it is not correct and doesn’t do anything
    // originally used the .data section instead of .all_flash
       .TI.crctab: > FLASH_MEM_CRC32
       .data_2b_checked: {bgcrc_ex1_cpuinterrupt.obj(.all_flash);} > FLASH_MEM_CRC32, crc_table(_linkerCrcTable, algorithm = CRC32_PRIME)
    //    .TI.memcrc > FLASH_CRC32
    }
    
    
    

  • OK, I am not as familiar with the linker CRC feature, so I will refer you to our compiler tools team to help you further on this question. But from what I can tell in the documentation, the 16 bytes allocated may not be enough to contain the table. So that may be contributing to your challenges here.

    The actual linker output messages would also be helpful.

    Best regards,
    Ibukun

  • The CRC table for the entire block of flash should be just one entry. Unless I missed something with sizing the whole range should be allowed, but maybe not. The documentation and examples from other C2000 parts is unclear. But I didn't miss the origin of BANK_0_SEC0 being 0x80002 and not 0x80000 will be a problem since addresses need to be aligned to 128 words (0x80) and 0x80002 would get aligned up to 0x80080 not down to 0x80000.

    I look forward to what the compiler suggests for getting this done. 

    Is this really not something done by everyone? It's hard for me to believe in designs these parts are used that there aren't require integrity checks over flash. That just seems odd.

  • Hi,

    As Ibukun pointed out, the CRC table would be longer and is not a single entry. It would contain the address and size info along with the crc value

    Regards,

    Veena

  • Venna, I'm sorry, I don't understand for two reasons:
    1) Is this about fitting a CRC record structure into the last row of flash? (ie 16 16-bit words?)
    2) I don't understand why you say the CRC table would be "longer and not a single entry". Whiy would you say that? If we treat flash as one contiguous block of memory and compute a CRC over that memory, is that one record? Why do we need more than a single entry?

  • You can refer to the .map file to get the actual size of the crc table. 

    Were you facing any allocation issue while trying to place the crctable in those last reserved flash area?

    Regards,

    Veena 

  • So I don't have a CRC table... nothing has been generated yet. So nothing has been placed anywere because I can't get the linker to generate a value for the range, this was one of my open questions.

    I also have an open question about where to get the MCU specific defined values for flash memory, where is the base address and size defined? We're bringing up code on a launchpad for the F280039C, but our target is the F280037. I know they have different memory layouts, so what are the defines needed in code to get the base address of flash memory and its size? I was unable to find this documented. 

  • You can find the actual flash banks available for each of the part numbers in the device datasheet

    Regards,

    Veena

  • Thanks, but one could say that about every target-specific define in all header files, right?

    One purpose of header file defined values is to be able to move from target_A to target_B and let the compiler handle changes to addresses. For example: GPIO_16 is bit-X of Register_?, and Register_? has a memory location of X these values can be different on two targets but if the code uses the defined labels the source code doesn't change between targets, the compiler and linker resolve the differences. 

    Are you saying TI doesn't have a labels that define Flash base address and Flash memory size? The *_headers_*.cmd linker file appears to have some of that information but not exactly what's needed. I don't understand the TI way of organizing this information I can only search and haven't found what's needed. 

    If one wants the base address of M0 RAM, M1 RAM, GS0 RAM, LS0 RAM or any other RAM base addresses they are defined with driverlib names (M0_RAM_BASE, M1_RAM_BASE, GS0_RAM_BASE, LS0_RAM_BASE, etc). But the same is not true for Flash memory, or at least I can't find if they are. The same is true for Flash_CTRL_REGS and FLASH_ECC_REGS.  Why are there not similar defines for the flash memory base and size?

    These are different on each MCU and should be defined by TI in conventional ways for use by the developer. If this is not correct, why? 

  • Pinging looking for a follow up on the still unaddressed questions.

    I'd like to point out there are very similar questions in this 2 year old thread:
    TMS320F280025: HW CRC programming or code - C2000 microcontrollers forum - C2000Tm︎ microcontrollers - TI E2E support forums

    Things are different now and we're using different MCU(s) (280037 or the 280039C(for launchpad)). But the questions raised in that thread run in parallel to getting it working on the latest version of CWare2000.

    Still open, is there built-in support for the bootloader (bootROM) to do a Flash CRC verification on Flash Boot? Seems like basic behavior even with ECC Flash. 

    How to configure the linker cmd file to generate ONE record over the entire flash? Seems the way it's done with the the default F28003x linker cmd file is with 48 4K word sectors (IIRC). The documented methods in that old thread are not current and it's not clear what the recommended process is today.

    If I can get a single entry CRC table that should fit in the final row of Flash, but if there are 48 CRC records, those will require a larger (unprotected) region and that presents additional risk.

    Just to point out, there are so many inconsistencies found on the forums and Web regarding VCRC support and how to use the VCRC extensions. Even many online (and e2e support) links are broken (including: TI blog entries, TI how-to-references, and TI training resources) to TI internal hosted resources. But they are no longer accessible because things have been moved. It would be nice if the TI servers were configured for auto-redirects when things are changed). In addition, the number of and types of CRC that are mentioned are often no longer available or have built-in support with VCRC. I've seen C28_CHECKSUM_16 described as the "default" CRC for the linker, but the same is true for CRC32_PRIME. The crc_defines.h (at least for 28003x) doesn't list C28_CHECKSUM_16 so what exactly is that configuration? The examples I've seen for CRC32 in STL_crc seem to use a "non-standard" flavor of settings. At least make the IV 0xFFFFFFFF with not reflections and no exit XOR is at least a standard configuration. Same configuration with IV of 0x00000000 is not. Moving forward it would be helpful to keep a consistent process so any new support remains backward compatible with the old methods previously shared on this e2e forum and in outdated documentation that google knows and TI continues to actively host on its servers.

    Have developers really decided that verifying flash memory on startup isn't required? Is the consensus that ECC (and its related issues) is good enough for safety critical applications?

  • I think I've figured out most of my questions, important to note the built in CRC32_PRIME is a "non-standard" configuration as IV 0, no reflection in/out and no xor out. Good to know, if attempting to generate you own values. 

    Can use a group in the memory region with crc() function to get a composite CRC over the smaller sections. The crc()'s output memrange_crc_table includes a composite CRC over all sections. The crc_table does not include the same composite CRC. While there is information in the assembler documentation this was not an obvious location to check and the information could be presented better.   

    The generated tables are a little strange too because unlike data streams, the values in the table entries are static and known by the developer. This feels inefficient use of limited memory resources.