Search code examples
cpointerstypestype-conversioncortex-m

Read a double from 32-bit address flash memory


I have a 32-bit microcontroller and have just written a double to the flash memory. I now want to read the double back from memory, but I am doing something illegal as the microcontroller goes to the hard fault handler.

First I tried:

double Flash_Read64(uint32_t address)
{
    return *((double *) address);
}

but this did not work. Is it because address is 32-bit and the (double *) expect a 64-bit?

I then tried:

double Flash_Read64(uint32_t address)
{
    uint64_t temp;
    double * tempPtr = (double *) &temp;

    //Increment address.
    address += 4;

    //Get MSB.
    temp = (*((uint32_t *) (address)));

    //Shift MSB to upper half.
    temp = (temp << 32);

    //Decrement address.
    address -= 4;

    //Get LSB.
    temp |= (*((uint32_t *) address));

    return *tempPtr;
}

but still not working.

Any suggestions?

EDIT:

bool_t Flash_Write64Address(uint32_t address, double data)
{
    uint32_t MSB, LSB;
    uint32_t * tempPtr = (uint32_t *) &data;

    //Get LSB.
    LSB = tempPtr[0];

    //Write LSB to flash.
    flashStatus = FLASH_ProgramWord(address, LSB);
    if(flashStatus != FLASH_COMPLETE)
    {
        DEBUG("Failed to write to flash at address: %u", (unsigned int) address);
        return FALSE;
    }

    //Increment address.
    address += 4;

    //Get MSB.
    MSB =  tempPtr[1];

    //Write MSB to flash.
    flashStatus = FLASH_ProgramWord(address, MSB);
    if(flashStatus != FLASH_COMPLETE)
    {
        DEBUG("Failed to write to flash at address: %u", (unsigned int) address);
        return FALSE;
    }

    return TRUE;
}

Solution

  • To simplify and avoid alignment issues (which I think it is the alignment issue that is causing grief.)

    typedef union {
      double d;
      uint32_t u[2];
    } Xlate;
    
    bool_t Flash_Write64Address(uint32_t address, double data) {
       Xlate x;
       x.d = data;
       for (int i=0; i < 2; i++) {
         int flashStatus = FLASH_ProgramWord(address, x.u[i]);
         address += 4;
         if(flashStatus != FLASH_COMPLETE) {
            return FALSE;
         }
       return TRUE;
       }
    
    double Flash_Read64(uint32_t address) {
      Xlate x;
      x.u[0] = *((uint32_t *) address);
      x.u[1] = *((uint32_t *) (address + 4));
      return x.d;
    }
    

    [Edit]
    I am supposing that address represents an address with quad-byte alignment (its least 2 bits are 0). If address did not have 8-byte alignment (its least 3 bits are 0) and a double access required it, then

    return *((double *) address);
    // or 
    return *tempPtr;
    

    would cause a bus fault. If this is true, the above code should handle this issue.
    Alternatively code could insure address has 8-byte alignment.