extern and the PROGMEM with a library folder

Go To Last Post
19 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

'cause I didn't know any better, I had put 2 big PROGMEM arrays in the .H files and battled with "defined mutiple times" errors.

Now that I'm better instructed... my program won't make.

My header file looks like:

FontTahoma12.h

#ifndef FONTTAHOMA12_H_
#define FONTTAHOMA12_H_

#include 
#include 

extern const uint8_t Tahoma15x15[] PROGMEM ;

#endif /* FONTTAHOMA12_H_ */

And my Tahoma12.c file says:

#include "FontTahoma12.h"


const uint8_t Tahoma15x16[] PROGMEM = {
	0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
(ad nauseum)

I added both the .h and .c to the program (as links).

Made sure it's included:

#include "Config.h"
#include "LCD.h"
#include "FontTahoma12.h"
#include "FontTahoma24.h"
#include 

But FontTahoma15x16 is undefined here:

int LCDPrintChTahoma12( int x, int y, char c, uint16_t color, uint16_t Background)
{
	uint16_t p = ((int)c-32)*31;
	uint16_t pxWide = pgm_read_byte(&Tahoma15x16[p]);

Did I mention that FontTahoma12.h and FontTahoma12.c are in a library folder?

If you don't know my whole story, keep your mouth shut.

If you know my whole story, you're an accomplice. Keep your mouth shut. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Compare the names in the *.c and *.h files. :wink:

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

BTW look at __flash, then you can drop the use of pgm_read_byte() and just do:

uint16_t pxWide = Tahoma15x16[p]; 

The compiler(*) will generate LPM for this.

(*) >= 4.7.x

BTW not only do you have 15x16 versus 15x15 issues as noted above but you appear to be defining the size 15 font in the size 12 font file?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

indianajones11 wrote:
Compare the names in the *.c and *.h files. :wink:

Ah! Told you I blundered!

If you wonder what it's like being dyslexic, imagine commonly mistaking a small b with a small p. And don't even ask about d and q!

If you don't know my whole story, keep your mouth shut.

If you know my whole story, you're an accomplice. Keep your mouth shut. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
BTW look at __flash, then you can drop the use of pgm_read_byte() and just do:

uint16_t pxWide = Tahoma15x16[p]; 

The compiler(*) will generate LPM for this.

(*) >= 4.7.x

BTW not only do you have 15x16 versus 15x15 issues as noted above but you appear to be defining the size 15 font in the size 12 font file?

I saw something about __flash. Been wanting to know how to use that. Guess now's as good a time as any. Let's see, the compiler doesn't complain about it, and .... IT WORKS!

Yes, it's a mix... When I used GLCD font creator to give me 12pt Tahoma, it made the file say 12pt, but the constant said 16px. Time to edit that too.

If you don't know my whole story, keep your mouth shut.

If you know my whole story, you're an accomplice. Keep your mouth shut. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello, I don't know if I should create a new post, but I am having problems like that.

In my case I have 3 different fonts that I wish to load .
the Current form is the following:
for each font a header .h file and a "source" .c.
Furthermore I wish to ADD this: In each font I wish to have a flash constant string that holds the user-friendly name of the font. So the .h should publice 2 things :
1) a pointer to flash, where the byte array is with the font bitmap data, and a pointer to flash where the font name string resides.

A nice option to have would be to create a general header "Fonts.h" that will include all font headers. So when main includes "Fonts.h", it will be aware of 6 pointers to flash: 3 for font-name strings and 3 for actual font data arrays.

Hopefully whatever way I use to implement this, it will ALSO be able to address font data at addresses >64K (for my xmega128). Reading the notes in pgmspace.h it mentions that macros that have "_P" appended will not work for addresses > 64K. SO I suppose to create the pointers i described, PGM_P is not good?

until now I have been using a more simple scheme that worked:

the single font header (courier_new_10cw.h):

#ifndef _COURIER_NEW_10CW_INCLUDED_
#define _COURIER_NEW_10CW_INCLUDED_

#include 
const char  CourierNew10[] PROGMEM ;

#endif

and the font data file (courier_new_10cw.c):

#include "courier_new_10cw.h"

const char CourierNew10[] PROGMEM =
{

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00,//many more bytes ..........


};

Things That I tryed to achieve what I describe in the beginning of my post, failed , so I could use some advise here please.

Thank you
Alex

There are 10 kinds of people... those who digg binary and those who don't

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Alex,

In that case your issue is not really related to the subject of this thread. There are many prior threads about PROGMEM data exceeding 64K. You will read about morepgmspace.h as a solution to pointers wider than 16bit. Suggest you search out and read some of those.

Moderator

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, to be honest, my main concern is not how to find the appropriate macros for far calls. I am searching for some advise from the ones who have experience in flash data , on what way should I best follow...
For instance, I am not sure yet, what the details
between using macros such as PROGMEM , or the __flash attribute are, or even if these can be safely mixed.

I suppose the "user font" is a popular subject by it's self, when various fonts are needed for graphics.
I am already reading and searching a lot but any advise is appreciated.

Alex

There are 10 kinds of people... those who digg binary and those who don't

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

__flash is a replacement for PROGMEM and is better in almost every way. Both end up with data in flash that requires LPM access and while you could pgm_read*() data in __flash I don't really see the point.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So, I have two print functions, one for string in ram and one for string in flash. I say "Str" for ram and "Txt" for flash.

int LCDPrintTxtTahoma12(int x, int y, const char *str, uint16_t color, uint16_t Background)
{
	uint16_t cx = x ;
	uint8_t i = 0 ;
	uint8_t c = pgm_read_byte(&str[i++]) ;
	while (c)
	{
		cx += LCDPrintChTahoma12(cx,y,c,color, Background)+1;
		c = pgm_read_byte(&str[i++]);
		
	}
	return cx ;
}

How do I tell it that str is a pointer into flash so it will use lpm to fetch the character?

Alex,

Yes, I want to do similar thing, but don't yet know how. I want to make "LCDPrintStr" and "LCDPrintTxt" where you just pass the font you want, so I need to make some structure in flash that contains the character dimensions and pointer to the data block in flash. So, instead I have LCDPrintTextTahoma12 and LCDPrintTextTahoma24.

They do look pretty nice on screen.

Attachment(s): 

If you don't know my whole story, keep your mouth shut.

If you know my whole story, you're an accomplice. Keep your mouth shut. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Torby, hi

the quick thing that came to my mind, and it is a stupid one, might help you ...
how about if you had 2 pointers, one for ram, one for flash, an use the one that is not NULL? for flash <64K it's small overhead. Example not tested!!!:

typedef struct fType; /* a structure that holds the font details*/
void PrintMessage(PGM_P fPT,char* rPT,fType font)
{
char c;
if(fPT==NULL)
{
while(*rPT)
{
PrintChar(*rPT++,font);
}
}
else
{
while(c=pgm_read_byte(fPR))
{
PrintChar(c,font);
fPR++;
}
}
}

Since you would have to prepare that *magic* pointer for the message anyway before calling PrintMessage, this would not seriously change your code.. I assume.
you can also look into another thing, which might work for you, but I don't know enough to make examples. It is the weak alias for function declaration. Someone might let us know id the weak attribute allows / achieves different function signatures for the same function.

Alex

There are 10 kinds of people... those who digg binary and those who don't

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Now there's an idea. Wonder if I have the gumption to dive in and investigate it.

If you don't know my whole story, keep your mouth shut.

If you know my whole story, you're an accomplice. Keep your mouth shut. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

How do I tell it that str is a pointer into flash so it will use lpm to fetch the character?


__memx is a pointer type that holds info of whether it is a RAM or __flash pointer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Doing my own tests, I bumped into a weird thing...
I did use morepgmspace, and it all worls fine.
I set a font data byte array in 0x20000 flash, and I load it just fine.
The only problem is that if I wish to copy the whole array in ram. Before moving to high address, memcpy_P worked pefrct.
now I use memcpy_PF, but it masks src adress with 0xffff. It is supposed to accept a 32bit number as source address, but it won't.

// don't need to pay attention until the >>>>HERE
unsigned char* GetFontChar(char c)
{
		unsigned int i, j,k;
		unsigned long offset;
		unsigned char *fnt;
		unsigned long stp;
		uint_farptr_t fptr;
		stp =(unsigned long)cfnt.fontO.fontfile;	
		stp+=4;
		offset=stp;
		if(cfnt.fontO.ConstWidth==0)
		{
		for(k=0;k8)
				{
					i-=8;
					j++;			
				} 
				j*=(unsigned int)cfnt.fontO.FontHeight;
				offset+=(unsigned long)j;
			}
			offset += (unsigned long)cfnt.EndC;		
		}
		else
		{
			i=cfnt.fontO.FontWidth;
			j=1;
			while (i>8)
			{
				i-=8;
				j++;			
			} 
			j*=(unsigned int)cfnt.fontO.FontHeight;
			offset+=(unsigned long)((unsigned long)j * (unsigned long)(c-cfnt.StartC));			
		}
		cfnt.fwidth=GetCharWidthSys(cfnt.chr);
		i=(unsigned int)cfnt.fwidth;
		for(j=1;i>8;i-=8){j++;}
		j*=(unsigned int)cfnt.fontO.FontHeight;
		cfnt.bcnt=j;

// >>>>>>>>>>>>>>>>>>>>>>>> HERE is the problem!
// offset holds the absolute address of the data in flash that I need to load
// j says how many bytes to load
// the following code works for any address <64K with just A
// B and C were added to check all possible ways
// with address > 64K  only C works
// with address > 64K , A and B load data from flash address (offset & 0xffff)

		memcpy_PF(fnt,offset,j);   //       A

		  
		fptr=(uint_farptr_t)offset;		
		memcpy_PF(fnt,fptr,j);     //        B

		for(i=0;i

There are 10 kinds of people... those who digg binary and those who don't

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There was a thread about just that issue the other day. Look for posts by "wek".

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you, I will do now, I was looking at the dissasembly. The 32bit address IS loaded to registers for calling memcpy_PF correcly, but inside the memcpy_PF, RAMPX is never loaded with what it should, the high part of the address is ignored...

There are 10 kinds of people... those who digg binary and those who don't

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Seen that post, studied the references.. .and to be honest I don't feel confident to tweak libraries, or include local copies etc... I don't have the knowledge nor the experience for that. I tryed to use the assembly definition of pgm_byte_read_far , to make one of my own that reads many bytes with an assembly loop. My conclusion is that if you want to be on the safe side, as you load bytes, you have to load RAMPZ on each itterration. So if I did my own assembly for that, or used a good version of memcpy_PF , I would end up with nearly the same code. So in terms of speed and memory, I would not have much to gain compared with just a C loop with pgm_byte_read_far. If the C loop counter is optimized then the only extra code generated is the save/restore of RAMPZ at each call.

I will stick with this for now, and I will try to make a "naked" pgm_byte_read_far in this fashion:

1) inline asm save RAMPZ, then cli
2)loop byte_count times on the naked pgm_byte_read_far
3)inline asm restore RAMPZ, then sei

Feel free to comment on this though.

Alex

There are 10 kinds of people... those who digg binary and those who don't

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ok... update, wrong idea, since RAMPZ HAS to be restored, in order to return the byte to ram.... so I stick with the original pgm_byte_read_far..

There are 10 kinds of people... those who digg binary and those who don't

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There is no need for SEI / CLI. ISR will care for RAMPZ.

If the device das RAMPD, set RAMPZ to 0 after usage. Otherwise, you need not to restore RAMPZ.

avrfreaks does not support Opera. Profile inactive.