Выход из массива данных (Font) во FLASH - PROGMEM в AVR GCC - PullRequest
4 голосов
/ 26 ноября 2011

Аааа, PROGMEM, указатели, указатели на указатели, адреса указателей ... Моя голова поражает.

У меня есть массив данных для рассматриваемого шрифта

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

к которому я добавил PROGMEM

const uint8_t dejaVuSans9ptBitmaps[] PROGMEM =

На это ссылаются в другой структуре, например:

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

Структура определяется как;

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;

Правильно ли я считаю, что это должно измениться на;

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;

Когда я так поступаю, он жалуется, что

warning: pointer targets in initialization differ in signedness

Для этой конкретной строки в переменной FONT_INFO;

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

Затем рисуется с помощью функции;

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);
    ...

Что, наконец, рисует глиф;

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);
   ...

Я нахожусь над моей головой: / Кто-нибудь может дать мне какое-то руководство? Я потратил часы, пытаясь использовать PGM_P, pgm_read_byte и т. Д. Безрезультатно - я всегда получаю мусор на экране.

Спаси меня!

Ответы [ 2 ]

1 голос
/ 28 ноября 2011

ОК, думаю, я понимаю, что здесь происходит.

Во-первых, const uint8_t* data - это указатель на данные, хранящиеся в PROGMEM.

В function void drawString(uint16_t x, uint16_t y, uint16_t color, const FONT_INFO *fontInfo, char *str) мы передаем указатель на fontInfo.

Для продолжения важно понять следующее:

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

все одинаковые. Так ptr_to_fontInfo->data возвращает данные (не адрес)

Затем, используя оператор &, мы передаем «адрес» этих данных следующей функции

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

Этот адрес хранится в объявленной переменной указателя unint8_t *glyph здесь;

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

Имея это в виду;

int *ptr;
int a;

ptr = &a;

Тогда глиф теперь указывает на тот же адрес, что и fontInfo->data[charOffset].

Следующее, что нужно знать;

a [b] в C - просто причудливый способ написания * (a + b)

Таким образом, глиф, являющийся указателем, когда используется как это glyph[indexIntoGlyph], это то же самое, что и *(glyph + indexIntoGlyph), а оператор разыменования * означает, что мы получаем данные по этому адресу.

Оттуда мы можем использовать правила pgm, как описано в wex;

Если переменная находится в PROGMEM, вы используете pgm_read_byte () как замена для оператора разыменования *. Для "нормальных" переменных в RAM вы всегда можете написать * (& a) вместо просто a, чтобы вернуть значение переменной а; поэтому, чтобы вернуть переменную 8-битной ширины из Progmem напишите pgm_read_byte (& x).

Надеюсь, это объяснение верное и поможет людям (новичкам, таким как я!) Понять его немного лучше.

0 голосов
/ 28 ноября 2011

Я получил отличную поддержку на AVRfreaks.net и решил опубликовать ответ здесь для дальнейшего использования этим сообществом. Спасибо, wek!

'wek' определил, что на основании предоставленной мной информации мне нужно было отправить несколько байтов, начиная с &fontInfo->data[charOffset] в drawCharBitmap().

Если переменная находится в PROGMEM, вы используете pgm_read_byte() как замена оператора разыменования *. Для "нормальных" переменных в оперативной памяти вы всегда можете написать *(&a) вместо простого значение переменной a; так что возвращать 8-битную переменную шириной из прогмем ты пишешь pgm_read_byte(&x).

Теперь вспомните, что a[b] в C это просто модный способ написания *(a + b) (где a - указатель, указывающий на первый член массива, таким образом применяются правила арифметики указателей). Так что в drawCharBitmap вы можно изменить glyph[indexIntoGlyph] либо на pgm_read_byte(&(glyph[indexIntoGlyph])) или pgm_read_byte(glyph + indexIntoGlyph).

Я все еще пытаюсь понять ссылки здесь, но это был такой великолепный ответ, что он заслуживал того, чтобы быть здесь. Спасибо всем, кто нашел время, чтобы посмотреть на это.

...