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.

Flash usage in CC2640/50

Other Parts Discussed in Thread: SYSBIOS, CC2650

Hello,


I am running out of program Flash, so I'm looking into where it's being used, and I found out there's something weird going on with the linker.

Some information about my setup:

  • I'm using a Bootloader that uses one Flash page (4096 bytes), from address 0 to 0xFFF.
  • I removed some options from the BLE Stack (namely, the GAP Bond Manager), which reduced its Flash usage. After compiling, the Boundary tool (which executes successfully) ends up allocating 14 pages for the Stack (57344 bytes, or 56kB), and places the Stack at address 0x11000 (69632)

My questions:

  1. Since the BLE Stack starts at address 0x11000, and the Application starts at address 0x1000 (after the bootloader), I would expect the application to have 0x10000 bytes (64kB, or 65536). However, CCS only reports 61439 bytes (60kB) are available (under the Memory Allocation view), so I'm missing a whole page between the Application and the BLE Stack.
  2. Again, CCS reports only 56kB are available for the BLE Stack (under the Memory Allocation view). These 56kB, plus the 64kB allocated for the Application and the 4kB allocated for the Bootloader only add up to 124kB, so I'm missing another whole page of Flash at the end. I believe this might be related fo a "reserved page" the Boundary tool reports (which I don't know what it might be used for, there's something about the NV module, but I don't think any part of the program uses it).

Here is the output of the Boundary tool (with some parts hihghlighted by me):

///////////////////////////////////////////////////////////////////////
Processing Command Line Arguments -> Successful
///////////////////////////////////////////////////////////////////////
Processing Ccs
///////////////////////////////////////////////////////////////////////
Processing Linker Map File

[ Map File Data ]
Read Only Data Size = not_used
Read Only Code Size = 0x0000D25E (53854)
Read Write Data Size = 0x000003FC (1020)
Ram End Address = 0x200048E7 (536889575)

[ Stack Size Calculation ]
Stack Size = 0x0000D25E (53854)

Processing Linker Map File -> Successful
///////////////////////////////////////////////////////////////////////
Processing Lcf File

[ Lcf File Data ]
Chip Name = not_used
Nv Pages = not_used
Flash Size = 0x00020000 (131072)
Ram Size = 0x00005000 (20480)
Page Size = 0x00001000 (4096)
Reserved Pages = 0x00000001 (1)

[ Flash Boundary Calculation ]
Bytes Used In Last Page Of Image = 0x0000025E (606)
Bytes Unused In Last Page Of Image = 0x00000DA2 (3490)
Used Stack Pages = 0x0000000E (14)
NV Pages = 0x00000000 (0)
Reserved Pages = 0x00000001 (1)
Total Used Pages = 0x0000000F (15)
Flash Boundary Address = 0x00011000 (69632)

[ Ram Boundary Calculation ]
Margin Bytes = 0x002A (42)
Unadjusted Ram Start Address = 0x200044C1 (536888513)
Alignment Value = 0x04 (4)
Final Alignment Value = 0x01 (1)
Total Ram Size = 0x00000427 (1063)
Ram Boundary Address = 0x200044C0 (536888512)

[ Nv Boundary Calculation ]
Reserved Size = 0x00001000 (4096)
Reserved End = 0x0001FFFF (131071)
Reserved Start = 0x0001F000 (126976)
Nv Size = 0x00000000 (0)

Processing Lcf File -> Successful
///////////////////////////////////////////////////////////////////////
Processing Project Config Files

[ Compiler Config Settings ]
Compiler Flash Config Page = 0x00011000 (69632)
Compiler Flash Config Boundary Page Matches Expected Boundary

[ Linker Config Settings ]
Linker Flash Config Page = 0x00011000 (69632)
Linker Flash Config Boundary Page Matches Expected Boundary
Linker Ram Config Page = 0x200044C0 (536888512)
Linker Ram Config Boundary Page Matches Expected Boundary

Processing Project Config Files -> Successful
///////////////////////////////////////////////////////////////////////
Boundary Operation Complete
///////////////////////////////////////////////////////////////////////

It would be great if I could use these two pages that don't seem to be used. Thanks!

  • I've been doing some testing and reading of the linker scripts, and I believe I found part of the reason I'm seeing this:

    • The last page of the Flash seems to be destinated to the CCFG section, but .text, .const, etc, are still allowed to go there, and for some reason the Memory Allocation tool is not displaying this.

        // CCFG Page, contains .ccfg code section and some application code.
        FLASH_LAST_PAGE (RX) :  origin = FLASH_SIZE - 0x1000, length = 0x1000

        .text           :   >> FLASH | FLASH_LAST_PAGE
        .const          :   >> FLASH | FLASH_LAST_PAGE

    So I would expect the linker to work properly and put those sections there if the main FLASH area is full, but I'm not sure if my understanding is correct.

    • On the BLE Stack linker file, I found these lines:

    // Last page is reserved by Application for CCFG.
    #define NUM_RESERVED_PAGES      1
    #define RESERVED_SIZE           (NUM_RESERVED_PAGES * PAGE_SIZE)

        FLASH (RX) : origin = ICALL_STACK0_ADDR, length = FLASH_SIZE - RESERVED_SIZE - ICALL_STACK0_ADDR

    Which seem to be reserving memory for that same section, at the end of the Flash.

    If this is the case, and those unused bytes of the last page can still be filled with .text and .const, then that's fine by me. It would be great, however, if I could see those in the Memory Allocation view, or in some linker output file, so that I can monitor Flash usage.

    I have not yet found the cause of the missing page between the Application and the BLE Stack.

    Also, I found these lines on the Application linker file:

    #define APP_BASE                0x00000000
    FLASH (RX) : origin = APP_BASE, length = ICALL_STACK0_ADDR - APP_BASE - 1

    which seem to be wrong, since the Application should start at 0x1000, not 0x0000 (where the bootloader is). I created the bootloader project starting from the OAD one (the BIM_extflash proejct), and it's working properly, so I'm not sure why those lines look like that. Is there a problem in my linker script?


    Thanks!

  • Could someone give me a helping hand with this issue, or at least some guidance? I really need to solve this problem to continue development, and have not found any detailed information on this topic, either online or on the manuals.

    Thanks
  • Hi Nicolas,

    Both the first page (with resetVecs) and the last page (with CCFG) must be reserved for the bootloader. This is because if you lose power during erasure of either page, then the device will not start up, but either enter some lockup mode or the ROM bootloader.

    The APP side should have FLASH from 0x1010 until ICALL_STACK0_START, meaning the length is ICALL_START - 0x1010. There is probably no mystery here. The APP, however, should not include the CCFG page (last page) if it's being used with a bootloader.

    The STACK side should be from FLASH_START until FLASH_SIZE less one page for CCFG.

    You don't specify this, but it seems you are using BLE SDK v2.1.1 or earlier. What I specify for STACK above is for 2.2. And the reason it starts at 0 is that the linker is for 2.2 told to squeeze everything in the stack image as far towards the end as possible (via FLASH(HIGH)), and after that figure out what the ICALL_STACK0_START should be for the application to cut off its length. This also means you don't have to re-compile the stack in 2.2 if it suddenly changes its size.

    It seems to me that there is a problem with the map file for OAD used in BLESDK2.1, cc26xx_ble_app_oad.cmd

    MEMORY
    {
    // ...
        #ifdef ICALL_STACK0_ADDR
            FLASH (RX) : origin = APP_BASE, length = ICALL_STACK0_ADDR - (APP_BASE + PAGE_SIZE) - 1 // <-- Should only subtract APP_BASE.
        #else // default
            FLASH (RX) : origin = APP_BASE, length = 0x0000CFFF
        #endif
    

    Try not subtracting that extra PAGE_SIZE and you should see the memory allocation view show the correct and expected size.

    Best regards,
    Aslak

  • Hello Aslak! Thank you for your helpful response.

    You're right, I forgot to mention this, but I'm using the 2.1.1 BLE Stack. I was also looking at the wrong linker script (ble_app.cmd instead of ble_app_oad.cmd), so that's where part of my confusion was coming from. I have now successfully removed the extra PAGE_SIZE and recovered 4kB for the App, which is great!

    I have a couple extra questions regarding the Bootloader and the CCFG section. Looking at the Bootloader linker script, it looks like it's actually placed at the end of the Flash, not at the beginning as I suspected. Is it possible to put the Bootloader code on the first page, leaving the last page with just CCFG? And, if this is possible, is there a reason why I wouldn't be able to have the application also use that last page and fill CCFG itself, instead of relying on the bootloader to do so? This would greatly help with my code size problems.

    Once again, thanks!


    Edit: another quick question: the app linker script contains no directives for the .ccfg section, but it is being built and placed inside of the app region. Why is this happening? I thought the ccfg was built with the bootoloader and placed in the last page when using OAD?

  • Hi Nicolas,

    No, the CCFG section must have at least some content, otherwise the device will not know that the Flash content is valid and won't boot. You are right that you could overwrite the blank areas left over by the bootloader. But you will 'never' be able to erase this data, because then you risk bricking the device, if power goes out during erase, but before writing in new data.

    If the .ccfg section is not placed, then it will harmlessly end up somewhere in flash. You can exclude the ccfg.c file from the build to avoid this - it serves no purpose, and should not have been included in the build.

    Best regards,
    Aslak

  • Hello Aslak,

    I think I understand what you're saying, but I want to be 100% sure. What I've gathered is that I should be able to use the unused bytes of the Flash page where the .ccfg section is (assuming my data doesn't overlap with .ccfg) by erasing that page, writing my data and writing the original CCFG contents back. This would be very useful, since .ccfg is only 88 bytes long, and doing so would free up 4008 bytes.
    If I lose power before I write CCFG back, the device may end up bricked (which is understandable). Does the bootloader (which is pretty much a copy of BIM_extFlash) need CCFG to be present, or is that only required by the main App/BLE Stack? Because if it doesn't, I could simply make the rewriting of CCFG part of the firmware update process, meaning a power loss would simply cause the bootloader to reattempt writing the firmware (and CCFG) when power is restored.
    Thank you so much!
  • Hi Nicolas,

    You should be able to do that, yes. But you risk bricking the device, because the boot that happens before any user code runs actually checks CCFG. If not present, it will enter the ROM serial bootloader. So you can not recover from that except with cables.

    What you can do of course is identify some code that will never change and add this to the BIM project. You can then access this data via pointers, when you know the addresses. Or in your linker file add somthing like the below, pointing to known symbols in the BIM project, and access these as extern int myVariable or extern void *myFunction(int, char);
    myVariable = 0x1f0004;
    myFunction = 0x1f100 | 0x01; // Functions must have a 1 in the last addr bit to signify call in thumb mode

    Alternatively, go ahead and re-write either sector0 or sector31 but somehow make sure you have enough battery/power available when you do this.

    Best regards,
    Aslak
  • Hey Aslak,

    Thank you so much, you answers helped me better understand the problem, and I've now arrived at a solution that's more appropriate for my use case, using both the information provided here and on this other question: e2e.ti.com/.../449788

    What I ended up doing is:
    - I removed the KEEP_INTVECS symbol from the bootloader project, so it no longer uses page 0.
    - I changed APP_BASE on the App linker script from 0x1000 to 0x0000, so now the app uses page 0.
    - I changed M3Hwi.resetVectorAddress in appBLE.cfg to 0x0000 so that the device boots to the app's reset vectors
    - I changed the jump address in the bootloader project to 0x0004, as well as the address where new binary images must be copied
    - Since page 0 is now used by the app and not the bootloader, I reenabled the RTOS ROM implementation by adding these lines to appBLE.cfg:
    var ROM = xdc.useModule('ti.sysbios.rom.ROM');
    ROM.romName = ROM.CC2650;
    - I also deleted the ccfg file from the app project to save a few extra bytes.

    All in all, this increased the Flash space for my application by 10kB (4kB from the extra page, 6kB by using the RTOS directly from ROM).

    The result is that the 'bootloader' is no longer a bootloader, but a different application that performs the firmware update and needs to be called explicitly from the main app. The device boots directly to the main app. The only drawback is that a power loss while the 'bootloader' is erasing/writing the Flash will cause the device to be bricked, but that's a risk I'm willing to take.

    I believe this setup will work fine: if there's anything I'm missing that might cause issues, please let me know.

    Thanks