Leaving a data array (Font) in FLASH - PROGMEM in AVR GCC

Ahhh, PROGMEM, pointers, pointers to pointers, addresses of pointers ... My head hurts.

I have a dataset for the font in question

const uint8_t dejaVuSans9ptBitmaps[] = { /* @0 ' ' (5 pixels wide) */ 0x00, /* */ 0x00, /* */ ... 

to which I added PROGMEM

 const uint8_t dejaVuSans9ptBitmaps[] PROGMEM = 

This refers to another structure, for example:

 const FONT_INFO dejaVuSans9ptFontInfo = { 13, ' ', '~', dejaVuSans9ptDescriptors, dejaVuSans9ptBitmaps, }; 

The structure is defined as:

 typedef struct { const uint8_t height; const uint8_t startChar; const uint8_t endChar; const FONT_CHAR_INFO* charInfo; const uint8_t* data; } FONT_INFO; 

Do I correctly assume that this needs to be changed:

 typedef struct { const uint8_t height; const uint8_t startChar; const uint8_t endChar; const FONT_CHAR_INFO* charInfo; const PGM_P data; } FONT_INFO; 

When I do this, he complains that

 warning: pointer targets in initialization differ in signedness 

For this particular line in the variable FONT_INFO;

 const FONT_INFO dejaVuSans9ptFontInfo = { 13, ' ', '~', dejaVuSans9ptDescriptors, --> dejaVuSans9ptBitmaps, <-- }; 

Then, drawing is performed using the function;

 void drawString(uint16_t x, uint16_t y, uint16_t color, const FONT_INFO *fontInfo, char *str) { ... drawCharBitmap(currentX, y, color, &fontInfo->data[charOffset], charWidth, fontInfo->height); ... 

What finally draws a glyph,

 void drawCharBitmap(const uint16_t xPixel, const uint16_t yPixel, uint16_t color, const uint8_t *glyph, uint8_t cols, uint8_t rows) { ... if (glyph[indexIntoGlyph] & (0X80)) drawPixel(currentX, currentY, color); ... 

I am above my head: / Can someone give me some direction? I spent hours trying to use PGM_P, and pgm_read_byte etc., but to no avail - I always get garbage on the screen.

Save me!

+4
source share
2 answers

Well, I think I understand what is happening here.

Firstly, const uint8_t* data is a pointer to the data stored in PROGMEM.

In function void drawString(uint16_t x, uint16_t y, uint16_t color, const FONT_INFO *fontInfo, char *str) we pass a pointer to fontInfo .

To continue, it is important to understand the following:

 fontInfo.data (*ptr_to_fontInfo).data ptr_to_fontInfo->data 

all are the same. Therefore ptr_to_fontInfo->data returns data (not an address)

Then, using the & operator, we pass the "address" of this data to the next function

 drawCharBitmap(currentX, y, color, &fontInfo->data[charOffset], charWidth, fontInfo->height) 

This address is stored in the unint8_t *glyph pointer variable unint8_t *glyph here;

 void drawCharBitmap(const uint16_t xPixel, const uint16_t yPixel, uint16_t color, const uint8_t *glyph, uint8_t cols, uint8_t rows) 

Keeping this in mind

 int *ptr; int a; ptr = &a; 

Then the character now points to the same address as fontInfo->data[charOffset] .

The next thing to know:

a [b] in C is just a fancy way of writing * (a + b)

Thus, the glyph is a pointer, when used as glyph[indexIntoGlyph] it matches *(glyph + indexIntoGlyph) , and the dereference operator * means that we get data at this address.

From there we can use the pgm rules, as described by wex,

If the variable is in PROGMEM, you use pgm_read_byte () as a replacement for the dereference operator *. For "normal" variables in RAM, you can always write * (& a) instead of just returning the value of the variable a; therefore, to return an 8-bit variable width from progmem, you write pgm_read_byte (& x).

I hope this explanation is correct and helps people (beginners like me!) To understand this a little better.

+1
source

I got great support at AVRfreaks.net and thought I'd post the answer here for future reference by this community. Thanks 'wek'!

'wek' determined that based on the information I gave, I needed to send a few bytes, starting with &fontInfo->data[charOffset] in drawCharBitmap() .

If the variable is in PROGMEM, you use pgm_read_byte() as a replacement for the dereference operator * . For "normal" variables in RAM, you can always write *(&a) instead of a to return the value of the variable a ; so to return an 8-bit variable width from progmem you write pgm_read_byte(&x) .

Recall that a[b] in C is just a fancy way of writing *(a + b) (where a is a pointer pointing to the first element of the array, therefore pointer arithmetic rules apply). So, in drawCharBitmap you can change glyph[indexIntoGlyph] either pgm_read_byte(&(glyph[indexIntoGlyph])) or pgm_read_byte(glyph + indexIntoGlyph) .

I'm still trying to figure out the links here, but it was such a great answer that he deserves to be put on. Thanks to everyone who took the time to look at this.

0
source

Source: https://habr.com/ru/post/1383155/


All Articles