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

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

[avr-libc-dev] Far addresses in flash


From: Carlos Lamas
Subject: [avr-libc-dev] Far addresses in flash
Date: Wed, 01 Jun 2005 22:24:58 -0000

Hello,

This is a proposal to include a mechanism to access the true address of data in Flash ROM (23 bits for the AVR specification) from C code. The "address-of" operator '&' does not suffice with its 16 bit limited precision to 16 bit to read data beyond the low 64K of memory.

There are, for instance, many users programming bootloaders for the ATmega128 asking for a way to cleanly access data in flash from C code without knowing absolute data addresses at compile time.

The following macro is the proposed solution:


#ifndef __STRINGIFY
#define __STRINGIFY(str) #str
#endif


#define GET_FAR_ADDRESS(var)                                    \
({                                                              \
    uint32_t tmp;                                               \
                                                                \
    __asm__ __volatile__(                                       \
            "ldi    %C0, hh8(" __STRINGIFY(var) ")"   "\n\t"    \
            "clr    %D0"                              "\n\t"    \
        :                                                       \
            "=d" (tmp)                                          \
        :                                                       \
            "0" (&var)                                          \
    );                                                          \
    tmp;                                                        \
})



This is a simple example of use. To test the code with true FAR (>64K) addresses .text section must be moved to a higher place in memory in the linker command.


#include <stdint.h>
#include <avr/pgmspace.h>

static uint8_t st[] PROGMEM = "This is a flash memory string";

int main (void)
{
    uint32_t address;
    uint8_t c;

    address = GET_FAR_ADDRESS(st);
    address += 4 * sizeof (uint8_t);
    while ((c = pgm_read_byte_far(address++))) {
        foo(c);
    }

    for(;;)
        ;

    return 0;
}



COMMENTS

- The overhead is minimal and it's mainly due to the 32 bit size operation.

- 24 bit sizes guarantees the code compatibility for use in future devices.

- hh8() is an undocumented feature but seems to give the third significant byte of a 32 bit data and accepts symbols, complementing the functionality of hi8() and lo8().

- __STRINGIFY(var) could be replaced by #var and the __STRINGIFY() macro removed, but the nested macro sequence allows the preprocessor to replace the identifier 'var' when itself is also a macro.

- 'var' has to be resolved at linking time as an existing symbol, i.e, a simple type variable name (not a constant), an array name (not an indexed element of the array), a struct name (not a field of the struct), a function identifier, a linker defined identifier,...

- The input and output operands in the asm instruction are different sizes and both share the same storage. Particularly the output operand 'tmp' is bigger than the input operand '&var'. I haven't extensively tested this.

- The & operator passes part of the job to the compiler and is valid for every identifier, even for array and function identifiers.

- The input operand informs the compiler that the data is in use, to avoid used static data removal. The stringifying conversion in the middle of the instruction doesn't notify of the use.

- The natural place for this macro should be the header pgmspace.h and the name... pgm_get_far_address?


Regards

--
Carlos Lamas





reply via email to

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