-2

I use STM32F0 mcu with emulated EEPROM. The EEPROM takes data as EE_WriteVariable(uint16_t VirtAddress, uint16_t Data) and returns them as EE_ReadVariable(uint16_t VirtAddress, uint16_t* Data) but my data are int16_t. So my question is, how do I write and read signed short?

muliku
  • 416
  • 3
  • 17

2 Answers2

2

Unfortunately the C language is being daft when it comes to things like hardware-related programming, such as EEPROM emulation. Therefore, the only reliable solution you can use is this:

uint16_t u16;
EE_ReadVariable(VirtAddress, &u16);
int16_t i16;
i16 = (int16_t)u16;

or alternatively:

memcpy(&i16, &u16, 2);

Anything else is unsafe and dangerous. In particular, you cannot do this:

EE_ReadVariable(VirtAddress, (uint16_t*)&i16); // BAD

Nor can you do i16 = *(int16_t*)&u16; // BAD.

More information about why, can be found here: What is the strict aliasing rule?

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Are you suggesting we don't type cast specifically for hardware modules like EEPROM and others? Or that in general `EE_ReadVariable(VirtAddress, (uint16_t*)&i16); ` is bad? If you check out clean-flight's source code `bt = (*(__IO uint32_t *) (BKPSRAM_BASE + 4)) ;` this is done for SRAM (but not a read/write method). https://github.com/cleanflight/cleanflight/blob/master/src/main/drivers/system_stm32f7xx.c#L200 – clamentjohn Aug 10 '18 at 05:56
  • @ClamentJohn It is bad in general. But in embedded systems, you must go between different types all the time, as in the case of EEPROM drivers. This was not a problem historically, since embedded compilers relied on non-standard extensions. But with the introduction of gcc in the embedded branch, systems break left and right because they contain strict aliasing violations. – Lundin Aug 10 '18 at 06:16
  • 1
    @ClamentJohn And yes, the "clean-flight" (whatever that is) is broken, in case the memory at those addresses contain anything else than what the compiler recognizes as either uint32_t variables or memory without a previously declared type. Upon further examination it appears to be raw addresses with no declared type, no there's no strict aliasing violation then. – Lundin Aug 10 '18 at 06:30
0

As per the application note The data is stored as 16-bit words in memory, so it's uint16_t. That's the underlying data type that anything your store in emulated EEPROM must be. Regardless of what you store, it has to have this type.

int16_t is guaranteed to have the same size as uint16_t. Use an intermediary variable of type uint16_t.

Thomas Jager
  • 4,836
  • 2
  • 16
  • 30
  • can you elaborate a little please? Do you mean something like `EE_WriteVariable(VirtAddress, (uint16_t *)myData)` and then `EE_ReadVariable(VirtAddress, (int16_t *)Data)`? – muliku Aug 09 '18 at 12:33
  • 3
    @muliku Assuming `myData` is defined like this: `int16_t myData`: The second argument to `EE_WriteVariable` is not a pointer so you need to cast it like this: `(uint16_t)myData`. The second argument to `EE_ReadVariable` expects an address of an `uint16_t` so you need to cast it like this: `(uint16_t *)&myData`. – Fiddling Bits Aug 09 '18 at 12:38
  • -1 for "cast your pointer" which will invoke undefined behavior and on gcc in particular, break the program. Similarly, the comment by @Fiddling Bits has the same strict aliasing bug. These things are important nowadays, since everyone is using gcc for embedded. – Lundin Aug 09 '18 at 13:27
  • @Lundin Removed that part – Thomas Jager Aug 09 '18 at 13:32