cancel
Showing results for 
Search instead for 
Did you mean: 

Unions and flash access

Clyde_S
Associate III

I am wishing to write two floating point values to flash memory at time.  I understand it is best to write 64 bits at a time, hence my writing two floats at once.

 

This question is about using a union to structure the data. This code won't compile for the STM32L412KB.  Could someone please show me where I am going wrong? error on line 17.  Thanks.

struct dual {
          float v1;
          float v2;
};

struct dual two_readings = {1.23, 4.56};

union gemini
{
        struct dual left;
        uint64_t right;
};

union gemini value;


value.right=0;

 

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Super User

@gbm I felt this was getting a bit too off-topic for the OP which is concerned about flash endurance so I posted a new questions and answer here:

How atomic are the STRD/LDRD instructions on Corte... - STMicroelectronics Community

Let me know if I've misinterpreted the result.

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

13 REPLIES 13
TDK
Super User

Are you doing "value.right = 0" at the global scope? That won't work. It needs to be within a function. Otherwise the code is fine. Global variables get initialized to 0 by default so the statement is not needed.

If you want to assign it explicitly at the global scope, do so in the definition:

union gemini value = { .right = 0 };

 

If you feel a post has answered your question, please click "Accept as Solution".
Clyde_S
Associate III

Thank you.  I have read conflicting statements on the internet about writing to a union.  I shall give this a try.

 

Am I correct that I should write 64 bits at a time to flash?  That is, won't writes of two single 32 bit sized floats count as two writes from an endurance standpoint?

> Am I correct that I should write 64 bits at a time to flash?

Kind of. The flash page size is 64 bits and it has ECC. Writing the entire flash page "at once" is the only option. However, the actual write operation is done as 2x 32bit writes. Splitting it into a union is not necessary here.

stm32l4xx-hal-driver/Src/stm32l4xx_hal_flash.c at f8e66b7f8db10809f91a4360c154b6304fab06ba · STMicroelectronics/stm32l4xx-hal-driver

 

This isn't an endurance thing. What you can't do is write 32 bits, then go off and do something else, then write 32 bits later on.

If you feel a post has answered your question, please click "Accept as Solution".
Clyde_S
Associate III

Ok, that was a big help, but I am not quite there yet.  I appreciate your patience.  (I am a hardware engineer.)    Moving the union access to a separate function was good, but I am getting an error still.  Perhaps you can see what I am trying to do and suggest an improvement.

 

void write_two (float v1, float v2)
{
	union gemini value;
	value.left.v1=v1;
	value.left.v2=v2;
	*ptr = (uint64_t) value;     // write to flash

}

 

../Core/Src/main.c:176:2: error: aggregate value used where an integer was expected
176 | *ptr = (uint64_t) value; // write to flash
| ^

The flash address setup and unlocking are done elsewhere.

gbm
Principal

use:

*ptr = value.right;     // write to flash

 

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice

Your goal here is misguided. You cannot write 64-bits to flash in a single atomic operation. There is no instruction that supports that. There are only 8, 16, and 32 bit write instructions. You can do it in a single C line, but it will be broken up into two 32-bit writes by the compiler. So your whole reason behind making the union doesn't do what you want it to do.

This will do the same thing:

volatile uint32_t* ptr = 0x08000000;
float v1 = 0.0;
float v2 = 1.0;
ptr[0] = *(uint32_t*)&v1;
ptr[1] = *(uint32_t*)&v2;

But if you just want to get rid of the error:

volatile uint64_t* ptr = ...;
*ptr = value.right;

 

Look at the disassembly code and see for yourself.

If you feel a post has answered your question, please click "Accept as Solution".
Clyde_S
Associate III

I recall reading in documentation, perhaps rm0432,  that the flash is 64 bits wide.  I would prefer to do a single write of a float value 32 bits.  The only reason I went to 64 bits at a crack was (possibly in error) because of endurance.  

 

I shall work some more at this.  Thanks.

Clyde_S
Associate III

from google...flash.PNG

@TDK Actually you can write 64 bits with a single ARM instruction - STRD. And the compilers do that! ;)

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice