This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

How to find the start address for writing to flash

There are two central sd_* methods for writing to flash - write and erase. The problem is I need to know where I can put my data without trashing something else that is already there and without reading every memory location and looking for the 'magic value'.

The examples do not help a bit, as they simply use the address of the last page. What if I need more than 1024 bytes?

Yes I know how to get the end of the memory. But that is a pretty stupid place to begin writing unless one writes backwards.

Clearly what the application writer wants is to find the start of free flash, so there is a maximum amount of flash available. 

How does one do this???

Why isn't there a method sd_get_start_address_of_free_flash()?  I think that was first suggested some six years ago.

Parents
  • Hi,

    The softdevice is a standalone built hex-file, completely separate from the application. The softdevice does not have any prerequisites to know where your application ends (apart from parsing flash and looking for empty pages), or know if some parts of flash are reserved for other purposes in your application.

    I do not understand why you are facing issues with knowing where the application flash space ends, you set the start of flash in you application, and the compiler tells you the size of the compiled application. This should allow you to know the area that is safe for writing. Softdevice and bootloader regions are described in the softdevice specifications and SDK documentation.

    If you want to be totally safe from overwriting the application, you can reduce the size of the application flash area in your project settings, to set aside the desired area of pages required for application flash area. Then the compiler will give you an error if it grows out of the allocated area at a later point in time.

    Best regards,
    Jørgen

  • brianreinhold said:
    I set the start of flash in my application? I guess I don't know where this done - I haven't implemented any code that does that. Of course I have inherited an old project s110. I have looked at some settings in the Keil project but all of those appear to be the entire size.

    In the example projects, the size is set to the full size of the flash, but this does not mean that it cannot be changed. You can reference this tutorial about RAM and Flash settings.

    brianreinhold said:
    I see in the 'target' options a start of IROM of 0x14000 and a size of 0x2B000 but I have no idea what that is for. I assumed it was the total size I have for the application and data but I am not sure.

    In a softdevice application, the softdevice is placed first in flash. The application project settings must leave room for the softdevice, so the start address should be set to the end of the softdevice size. The size of the softdevice is documented in the softdevice specifications, and the release notes for each version. In a non-softdevice application, the application starts at address 0x0.

    My suggestion about reducing the size of the application flash area will leave some room in flash where the linker will not place any application code. The application can write to any flash address anyway as this area is not reserved by the linker. If you reduce the IROM size for instance by 0x3000, you will have 12 kB flash "reserved" for flash writes.

    brianreinhold said:

    Does it mean that my application will be placed at 0x14000 and then I use the NRF_FICR->CODESIZE to find the end of my code?

    That doesn't make sense either since the flash write examples say NRF_FICR->CODESIZE - 1 is the last page. Last page? It sounds to me like NRF_FICR->CODESIZE is the entire size of flash. I must be missing a critical piece of information as none of this is making sense. Is the flash write top down?

     FICR is written during production and CODESIZE indicates the number of flash pages in the chip variant. The first pages starts at address 0x0 and ends at CODEPAGESIZE-1, next page starts at CODEPAGESIZE, and so on.

    To find the end of application, you must look at the size output from the IDE/compiler/linker/map-file and add this to the size of the softdevice (0x14000).

    brianreinhold said:
    I have seen some pretty maps in some of the later docs but that doesn't tell me how to get that information. Maybe the s110 is old enough that such info is not available, thus the cry for a  sd_get_start_address_of_free_flash() some 6 years ago?

    Memory map of the softdevice have been available in the softdevice specifications since (at least) S110 v1.0.0.

Reply
  • brianreinhold said:
    I set the start of flash in my application? I guess I don't know where this done - I haven't implemented any code that does that. Of course I have inherited an old project s110. I have looked at some settings in the Keil project but all of those appear to be the entire size.

    In the example projects, the size is set to the full size of the flash, but this does not mean that it cannot be changed. You can reference this tutorial about RAM and Flash settings.

    brianreinhold said:
    I see in the 'target' options a start of IROM of 0x14000 and a size of 0x2B000 but I have no idea what that is for. I assumed it was the total size I have for the application and data but I am not sure.

    In a softdevice application, the softdevice is placed first in flash. The application project settings must leave room for the softdevice, so the start address should be set to the end of the softdevice size. The size of the softdevice is documented in the softdevice specifications, and the release notes for each version. In a non-softdevice application, the application starts at address 0x0.

    My suggestion about reducing the size of the application flash area will leave some room in flash where the linker will not place any application code. The application can write to any flash address anyway as this area is not reserved by the linker. If you reduce the IROM size for instance by 0x3000, you will have 12 kB flash "reserved" for flash writes.

    brianreinhold said:

    Does it mean that my application will be placed at 0x14000 and then I use the NRF_FICR->CODESIZE to find the end of my code?

    That doesn't make sense either since the flash write examples say NRF_FICR->CODESIZE - 1 is the last page. Last page? It sounds to me like NRF_FICR->CODESIZE is the entire size of flash. I must be missing a critical piece of information as none of this is making sense. Is the flash write top down?

     FICR is written during production and CODESIZE indicates the number of flash pages in the chip variant. The first pages starts at address 0x0 and ends at CODEPAGESIZE-1, next page starts at CODEPAGESIZE, and so on.

    To find the end of application, you must look at the size output from the IDE/compiler/linker/map-file and add this to the size of the softdevice (0x14000).

    brianreinhold said:
    I have seen some pretty maps in some of the later docs but that doesn't tell me how to get that information. Maybe the s110 is old enough that such info is not available, thus the cry for a  sd_get_start_address_of_free_flash() some 6 years ago?

    Memory map of the softdevice have been available in the softdevice specifications since (at least) S110 v1.0.0.

Children
  • You say: (I don't know how to make the fancy quotes)

    To find the end of application, you must look at the size output from the IDE/compiler/linker/map-file and add this to the size of the softdevice (0x14000).

    Isn't that dynamic? That means I have to look it up every build? Then I find that my code size has grown and now goes over my start address and now I have to go back change the start address, rebuild and try again ... that seems a little absurd. Is that what one actually has to do or is there a means to obtain that value in code?

    Right now I am just saving bonding information - which is not very much and I could probably get away with using the last page cop-out of the example application. But eventually I want to save measurements taken 'offline' and that will take storage. How much I can store will depend upon how much flash I have. So in that case one wants to get as close to the start of free flash as one can.

    I will take a look at that tutorial. I could not find such a tutorial. I knew there probably was one but the search engines are pretty poor here - I always have to go and ask on this forum to find such items.

  • There is a helper symbol defined in app_util.h, CODE_END, which you can use to get the end of flash code in the application. This is assigned the size of the data and text sections in the linker script.

  • For the moment I am using the last code page so I don't have to search for a start address. Since I am only storing 0x34 bytes, this is not a problem. I want to get basic writes/reads working first, then I will worry about finding the start location.

    I read from flash before any Bluetooth activity takes place, and write when all Bluetooth activity is finished. I don't need to worry about radio/flash conflicts.

    That being said, I am having issues writing. I am not getting back the keys I have written. 

    So first addition is to add sd_softdevice_disable() as it would be a nightmare to handle events in a loop - there is no semaphore support here. So now I am wondering about NRF_BUSY  responses. Would the proper way to handle that be (for both erase and write)

        while(true)
        {
            err_code = sd_flash_page_erase(pg_num);
            if (err_code == NRF_SUCCESS)
            {
                break;
            }
            if (err_code != NRF_ERROR_BUSY)
            {
                APP_ERROR_CHECK(err_code);
            }
        }
        i = (size >= pg_size) ? (pg_size >> 2) : (size >> 2);     // four-byte hunks to write; size is evenly divisible by four
        while(true)
        {
            err_code = sd_flash_write(addr, ptr32, i);
            if (err_code == NRF_SUCCESS)
            {
                break;
            }
            if (err_code != NRF_ERROR_BUSY)
            {
                APP_ERROR_CHECK(err_code);
            }
        }

    What! I get a NRF_ERROR_SOFTDEVICE_NOT_ENABLED error! That does NOT jive with the documentation.

    Docs say

    If the SoftDevice is not enabled no event will be generated, and this call will return NRF_SUCCESS when the write has been completed

    And the NRF_ERROR_SOFTDEVICE_NOT_ENABLED is NOT one of the listed return values. What is going here?

    If I step through the above code using the debugger, it works. When I run it and stop at the end of the writing, it does not work. Any idea why?

Related