3

I have an ATMega328 and I'm using the <avr/eeprom.h> functions to use the inbuilt EEPROM.

I can use the EEPROM correctly but I don't understand the function arguments I pass to the EEPROM functions.

For example, to write different types of data I can use

void eeprom_update_byte (uint8_t *addr, uint8_t value);
void eeprom_update_word (uint16_t *addr, uint16_t value);
void eeprom_update_dword (uint32_t *addr, uint32_t value);
void eeprom_update_float (float *addr, float value);
  • But why does the pointer type for the address (the addr parameter) change depending on the function used? If addr just points to a valid EEPROM address why is the type different in each function?

  • Also, the use of the void * in the EEPROM function below is confusing me. I understand that a void * can point to any address, so I'm assuming the function simply writes byte by byte the data in src but I'm unsure if this is correct?

void eeprom_update_block (const void *src, void *dst, size_t n);

CS Student
  • 1,613
  • 6
  • 24
  • 40
  • @milleniumbug if I knew what it was and could link it to my problem then I wouldn't be asking the question... – CS Student Dec 05 '16 at 14:50
  • All data pointers in the language mostly "just point to a valid address". That still does not mean that type safety is useless and/or that all pointers in C programs should be just `void *`. In this case, if you want to call a function `eeprom_update_float`, make sure you supply a pointer to `float` (and not to `int` or somehting else). – AnT stands with Russia Dec 05 '16 at 14:55
  • The only reason I can think of is that it would allow you to do `eeprom_update_float(addr + i, value[i]);` in a loop. – Ian Abbott Dec 05 '16 at 14:58
  • @IanAbbott Since the caller owns `addr` pointer,`eeprom_update_float` might as well take `void*`. The caller wouldn't need to recompile the code, because all pointers convert to `void*` "for free". – Sergey Kalinichenko Dec 05 '16 at 15:06
  • @dasblinkenlight I was just trying to come up with a reason why the designer might have designed the interface this way rather than use `void *` for everything. – Ian Abbott Dec 05 '16 at 15:14

2 Answers2

3

The first four functions listed define the type of object being written. So internally the function might look like this:

void eeprom_update_float (float *addr, float value)
{
    *addr = value;
}

This offers type safety benefits (e.g. cannot write a float into a uint16_t) by ensuring that the destination pointer is the same as the source variable.

The final version void eeprom_update_block() simply writes an arbitrary block of memory to a given address. It probably uses something like memcpy underneath:

void eeprom_update_block (const void *src, void *dst, size_t n)
{
    memcpy(dst, src, n);
}

This version of the function doesn't have any type safety advantages, but can be used to write non-trivial data into memory. For example, a struct can be written like this:

eeprom_update_block(&myStruct, dst, sizeof(myStruct));
Karl Nicoll
  • 16,090
  • 3
  • 51
  • 65
1

There is no technical reason behind taking type-specific pointers in the first four APIs. These functions could be redefined with void* without the need to recompile code relying on them:

void eeprom_update_byte (void *addr, uint8_t value);
void eeprom_update_word (void *addr, uint16_t value);
void eeprom_update_dword (void *addr, uint32_t value);
void eeprom_update_float (void *addr, float value);

There is no special alignment requirements in EEPROM, so my guess is that Atmel team used type-specific pointers for aesthetic reasons.

Also, the use of the void* in the EEPROM function below is confusing me.

eeprom_update_block is an untyped version of type specific eeprom_update_XXX functions. Note that since the second parameter is void*, a third parameter specifying block size is now required, while eeprom_update_XXX functions imply the size from the type of their argument.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523