avr-libc-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [avr-libc-dev] New pgm_read_ptr() macro?


From: David Brown
Subject: Re: [avr-libc-dev] New pgm_read_ptr() macro?
Date: Thu, 03 Jun 2010 09:03:14 +0200
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.9) Gecko/20100317 Lightning/1.0b1 Thunderbird/3.0.4

Hi,

Are there any opinions about whether a macro such as the one I gave below should be part of avrlibc? It's not as clear-cut as Dean's pgm_read_ptr() macro, which follows the existing patterns in the headers. Macros like mine are more like template programming than the fixed-size macros, and thus are a slight change in philosophy.

If the idea of a generic pgm_read(&x) macro does appeal, then the same tricks can be used for other accesses such as wrapping an access in "volatile", reading and writing eeprom, and atomically accessing data.

mvh.,

David



How about a more general solution based on typeof and sizeof?

#define pgm_read(v) ((typeof(*v)) \
(__builtin_choose_expr(sizeof(*v) == 1, pgm_read_byte(v), \
__builtin_choose_expr(sizeof(*v) == 2, pgm_read_word(v), \
__builtin_choose_expr(sizeof(*v) == 4, pgm_read_dword(v), \
({ char error[((sizeof(*v) == 1) || (sizeof(*v) == 2) || \
(sizeof(*v) == 4)) ? 1 : -1]; error[0]; }) \
)))))


The macro above looks a bit ugly, but it's not too hard to follow.
Basically, we are using sizeof(*v) to figure out the size of the data
you are wanting, and using it to pick the correct pgm_read_xxx function
for the data size. We use __builtin_choose_expr instead of ?: to avoid
any unwanted expression evaluations or side effects, as well as to allow
different sized return values. The "char error[...]" part is a way to
force a compile-time error if the macro is used with something whose
size is not 1, 2 or 4 bytes.

The result is that you can write:

char x;
char* PROGMEM FlashPointer = &x;
char* FlashPtr = pgm_read(&FlashPointer);

You can equally write:

static const PROGMEM uint8_t x8 = 8;
static const PROGMEM uint16_t x16 = 16;
static const PROGMEM uint32_t x32 = 32;

void test(void) {
volatile uint8_t y8 = pgm_read(&x8);
volatile uint16_t y16 = pgm_read(&x16);
volatile uint32_t y32 = pgm_read(&x32);
}


Now your pgm_read's are independent of the type, assuming they have a
compatible size.


Personally, my preference would be to change the semantics to remove the
"&", so that you would write:

char* FlashPtr = pgm_read(FlashPointer);

This is just a small change to the macro, but I think it's neater - you
are reading an object from flash, rather than reading data from an
address in flash. But such a change would require a name change to avoid
accidents.

mvh.,

David





_______________________________________________
AVR-libc-dev mailing list
address@hidden
http://lists.nongnu.org/mailman/listinfo/avr-libc-dev





reply via email to

[Prev in Thread] Current Thread [Next in Thread]