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

Can't read from flash beyond 0x10000

I have a large array of uint16_t data to use as a lookup table, which is defined in flash. It's 4002 bytes in size, and I can set where in flash it is saved. I'm accessing it both as value = array[index]; and as pointer_to_array += index; value = *pointer_to_array; both with the same result.

The result is that if any element of the array is beyond 0x10000, reading it back results in 0xFFFF. Looking at it in 'Memory' in keil, it has the correct value; it's only when reading from it in code that it fails.

What could be causing this?

It can't be the keil code size limit, as that's 32k and the code size is just over 16k.

I've tried looking at the Memory Protection Unit, but as far as I can tell, readback protection applies to the whole of a flash region, not individual blocks. Could write/erase protection be affecting this somehow?

Can individual blocks of flash be powered on and off individually? So far I've only found this with RAM, but given 0x10000 is on the boundary of a flash block it seems plausible.

Or could something be preventing reading from higher than 16 bit flash addresses somehow?

Any help appreciated!

  • Are you ending up in the hard fault handler? If so, I believe this is caused by a non-word aligned pointer accessing flash area.

    Doing like this will not be allowed:

    uint8_t my_var = *(uint8_t *) 0x10000001;
    

    Same goes for:

    uint16_t my_var = *(uint16_t *) 0x10000002;
    

    Valid read:

    uint32_t my_var = *(uint32_t *) 0x10000000;
    

    -H

  • I don't think it can be that. I don't end up in the hard fault handler, I just get a value of 0xFFFF.

    I've currently got the array starting at 0xF400, so that the last ~kB is past 0x10000. I can read back the correct values for the first 3 kB, but as soon as I try to read from 0x10000 I get 0xFFFF. Up to that point I'm reading uint16_ts, so presumably I am doing non-word-aligned reads perfectly fine (which in itself might be worrying).

    I did try making everything uint32_t, but the only difference was I read back 0xFFFFFFFF.

    Is there some reason non-aligned reads are allowed below 0x10000 but not above?

  • One more thing: if I step through the code in keil, the reads are fine. If I run to the next breakpoint, they come back as 0xFFFF. Could it be something to do with NRF_MPU->DISABLEINDEBUG?

  • Turns out this was my own stupid fault: we have data storage code which can optionally write to flash. The writing to flash is disabled, as the soft device interferes with the NVMC, but it was still being initialised, which means it was erasing all flash pages from, you guessed it, 0x10000 onwards.

    I'm still not sure why a) this didn't show up in the Memory display, and b) how single stepping through the code still returned the 'right' (i.e. non-erased) value, though...

  • Since you're not accessing addresses by de-referencing the pointer to the address, I would assume that the compiler does some magic :-)

    1. Could you try accessing the data by de-referencing a pointer to that specific address? uint32_t test = *(uint32_t *) 0x10000; Does it give you the correct value?

    2. Could you attach a simplified version of the project so I can have a look?

Related