force pointer size - possible?

Hi all,

As you know, if you do something like this:

[b]uint8_t a = 123;[/b]

then [b]&a[/b] will be a 16 bit number which is the address of the variable "a" in memory.

What I need is a way to force 32 bit pointers. For example, if I do this:

[b]uint8_t a = 123;

[/b]

[b]&a[/b] may be something like [b]"0x21F7"[/b]. But what I need it to be is [b]"0x000021F7"[/b].

Is there a way to do this or force the compiler to do this?

What I need it for is this: My graphics display driver takes a pointer to bitmap data as [b]"*data"[/b] then does many [b]"pgm_read_byte (data + offsets)"[/b] to get the bitmap data to send to the display.

Of course, because pointers are only 16 bit, I cannot have bitmaps or font data ABOVE the 64K address line, else I can't get at it.

I know that I can use [b]"pgm_read_byte_far (32 bit address)"[/b] to access all of the PROGMEM, but I need to be able to do it using a pointer, not an explicit address.

I thought of using a [b]uint32_t[/b] instead of [b]uint8_t *[/b], but then I don't know how to pass it the address of a bitmap. The bitmap might be something like this:

static const uint8_t bitmap[] PROGMEM = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00,
    0x14, 0x7f, 0x14, 0x7f, 0x14, 0x00, 0x00,
    0x24, 0x2a, 0x7f, 0x2a, 0x12, 0x00, 0x00,
    0x23, 0x13, 0x08, 0x64, 0x62, 0x00, 0x00,
    0x36, 0x49, 0x56, 0x20, 0x50, 0x00, 0x00,
};

...but if it resides above the 64K mark, how do I access it?

Any ideas will be appreciated.

To what MCU are you referring? The ATMega328 can't address above 64K.

jremington:
To what MCU are you referring? The ATMega328 can't address above 64K.

The MEGA2560 (or for that matter any >64K AVR).

Use a union.

KeithRB:
Use a union.

How?

Maybe you need to use pgm_get_far_address ?

pgm_read_byte_far( pgm_get_far_address( data + offsets ) );

Maybe not (can't test yet) :stuck_out_tongue:

I thought you just wanted to skip 4 bytes instead of 2, the union can't fake a longer pointer.

I think you are intended to use 'unsigned long' (a.k.a. uint32_t) when storing far pointers. There is a typedef for it:

typedef uint32_t uint_farptr_t

guix:
Maybe you need to use pgm_get_far_address ?

pgm_read_byte_far( pgm_get_far_address( data + offsets ) );

Maybe not (can't test yet) :stuck_out_tongue:

I never knew about that function!!!

It's exactly what I need! Thank you! Karma++;

guix:
Maybe you need to use pgm_get_far_address ?

Let me ask you another question if I may... the function you pointed out to me works just fine. For example, if I have a bitmap that looks like this:

static const uint8_t bitmap[] PROGMEM = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00,
    0x14, 0x7f, 0x14, 0x7f, 0x14, 0x00, 0x00,
    0x24, 0x2a, 0x7f, 0x2a, 0x12, 0x00, 0x00,
    0x23, 0x13, 0x08, 0x64, 0x62, 0x00, 0x00,
    0x36, 0x49, 0x56, 0x20, 0x50, 0x00, 0x00,
};

Then I can do this:

    uint32_t address;
    address = pgm_get_far_address (bitmap);

and then "address" contains something like [b]"0x0000217B"[/b] which is (correct). It also works if the bitmap is above the 64K limit.

But now what I want to do is be able to PASS "[b]bitmap[/b]" to a function that contains "[b]pgm_get_far_address()[/b]" and then use it.

I can't seem to make it work. I've tried almost every data type and every referencing and dereferencing combinations I could come up with and none work.

The one(s) that are obvious and seem correct give me compile time errors "undefined reference to R30". (huh???)

Serious answers please. I'm not using an Uno and I know that an Uno only has 32K of flash... I'm talking about processors like the 2560 and others that have >64K flash.

Also, the IDE I'm using is not relevant because I'm using AVR-GCC 4.9.2 and compile either using the IDE or using a Makefile, so it has nothing to do with my IDE (which is, BTW, v1.0.6 with a lot of customizations).

Actually, ALL I need now is to know how to pass the address of a bitmap to a function which will in turn get it's address in PROGMEM and then make use of it. I can't use "pgm_get_far_address()" directly, I need to be able to send it the address.

Thanks.

Serious answers please.

Example that illustrates the problem please.

Did I not provide all the information necessary in the previous post?

Don't know. I am getting a different error message which indicates I have not reproduced the problem.

In any case, does this illustrate what you are trying to do...

void DoIt2( const uint8_t bitmap[] )
{
  uint32_t a;
  a = pgm_get_far_address (bitmap);
  Serial.print( pgm_read_byte_far( a ) );
}

void setup() 
{
  DoIt2( bitmap );
}

The macro requires a compile time constant, you cannot use it in a for loop like that.
Store the formatted address then add/subtract from it for an offset.

This works with your image data.

void setup() { Serial.begin(9600); }

void printImg( const uint_farptr_t img, unsigned count ){
  for( int i = 0 ; i < count ; ++i ){
    Serial.print( pgm_read_byte_far( img + i ), HEX );
    Serial.print( !i || (i+1) % 7 ? ", " : "\r\n" );
  }
}

void loop() {
  
  static const uint_farptr_t addr = pgm_get_far_address(bitmap[0]);
  
  printImg( addr, sizeof(bitmap) );
  Serial.print( "\r\n----------------------------\r\n\r\n" );
  delay(2000);
}

pYro_65:
The macro requires a compile time constant, you cannot use it in a for loop like that.
Store the formatted address then add/subtract from it for an offset.

It's difficult to provide a good example because if I post all the code, it will be way too large for here.

Let's see if I can explain it with snippets:

First of all, I have bitmap font data: (hd44780u.h)

#ifndef HD44780U_H
#define HD44780U_H

static const uint8_t hd44780u[] PROGMEM = {

    0x06, // width (base + 0)
    0x08, // height (base + 1)
    0x00, // horizontal gap (base + 2)
    0x00, // vertical gap (base + 3)
    0x20, // first char (base + 4)
    0x06, // bytes per char (base + 5)

    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x5f, 0x00, 0x00, 0x00,
    0x00, 0x07, 0x00, 0x07, 0x00, 0x00,

// ...... lots more ......

    0x00, 0x41, 0x7f, 0x54, 0x08, 0x00,
    0x0c, 0x51, 0x50, 0x51, 0x3c, 0x00,
};

#endif

Then I want to use it in my display driver:

void Noritake_VFD_GUU100::setFont (const uint8_t *fontPtr)
{
    _font = _fontStart = fontPtr;
    if (fontPtr != NULL) {
        _fontWidth =    pgm_read_byte (_font++);
        _fontHeight =   pgm_read_byte (_font++);
        _fontHGap =     pgm_read_byte (_font++);
        _fontVGap =     pgm_read_byte (_font++);
        _firstChar =    pgm_read_byte (_font++);
        _bytesPerChar = pgm_read_byte (_font++);
        _next_x =       _fontWidth  + _fontHGap;
        _next_y =       _fontHeight + _fontVGap;
    }
    // now global "_font" points to the first byte of font DATA
    // and "_fontStart" points to the first byte of font itself
    // (used to save and reload a font)
}

Finally, to use it I would (after instantiating an object called, for example, "VFD") I would setup the driver to use the font like this:

#include <Noritake_VFD_GUU100.h>
#include <fonts/allFonts.h>

static Noritake_VFD_GUU100 VFD;

/// startup code......

    VFD.setFont (hd44780u); // print text in the LCD font

/// lots more......

OK, so far so good?

Only problem is (and I ran into this while running a test that used ALL the fonts and resulted in a 98+K sketch), any font which ended up above the 64K mark could not be accessed. It's address, being a 16 bit pointer, looped around past 0xFFFF and ended up using whatever bytes were at "actual_address - 65536".

SO..... after reading about the "[b]pgm_get_far_address ()[/b]" function here, I thought my problems were solved.

Long story short, there seems to be no way to use "get_far_address" INSIDE my driver and pass the font pointer to it.

I tried changing my driver to accept a uint32_t as a font address and then sending it the address (from my sketch) using "[b]VFD.setFont ([/b][tt][b]pgm_get_far_address (hd44780u));[/b][/tt][b]" [/b]and it worked, but I think it's absurd to expect users to type "pgm_get_far_address".

Why can't I put "pgm_get_far_address" into the DRIVER and pass it the same pointer?

THAT'S what I'm trying to do.

pYro_65:
The macro requires a compile time constant, you cannot use it in a for loop like that.

A "compile time" constant?

That gives me an idea!!!

What if, in my FONT FILES, I do something like this:

#ifndef HD44780U_H
#define HD44780U_H

static const uint8_t _hd44780u[] PROGMEM = {
    //// all the font data
};

#define hd44780u pgm_get_far_address(_hd44780u) // <---- this line!

#endif

Now, the name "hd44780u" would equal a 32 bit number representing the address of the font!!!

(note that I added the underscore to the font name to avoid a duplicate definition error).

Do you think this would work? And, if "get_far_address" is ONLY compile time, then I assume the above it the ONLY way to do it?

Or could I possibly somehow use it on top IN PLACE of the "static const uint8_t" part?

That looks like a good idea.

It keeps the macro hidden from the user. Maybe to avoid any unforeseen problems with a macro, you could simply declare a const uint_farptr_t

pYro_65:
That looks like a good idea.

It keeps the macro hidden from the user. Maybe to avoid any unforeseen problems with a macro, you could simply declare a const uint_farptr_t

The type "farptr_t" is a typedef of uint32_t anyway. Would that make any difference?

No, not at all. Use either one.

I can reproduce a problem, possibly related.

static const byte bitmap[] PROGMEM = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
void DoIt2( const byte * foo)
{
  pgm_get_far_address (foo);
}
void setup()
{
  DoIt2( bitmap );
}
void loop() { }

IDE 1.6.4, target Mega2560.

Error:

In file included from /home/nick/Development/arduino-1.6.4/hardware/arduino/avr/cores/arduino/Arduino.h:28:0,
                 from sketch_jun17a.ino:1:
sketch_jun17a.ino: In function 'void DoIt2(const byte*)':
sketch_jun17a.ino:6:3: error: invalid 'asm': invalid expression as operand
sketch_jun17a.ino:6:3: error: invalid 'asm': invalid expression as operand
sketch_jun17a.ino:6:3: error: invalid 'asm': invalid expression as operand
invalid 'asm': invalid expression as operand