доступ к данным из структуры во флэш-памяти - PullRequest
0 голосов
/ 10 ноября 2018

Я использую Atmel AVR и пытаюсь получить доступ к данным из структуры, которая хранится во флэш-памяти (программе).

Структура:

typedef struct {
    uint8_t width;
    uint8_t height; // row number 0 to 5
    uint8_t images; // how many frames does this bitmap have
    uint8_t data[]; // the actual pixel data
} bitmap_t;

данные:

    __flash   static const bitmap_t bmp_stereo2  = {14,1,1,{126,129,60,66,24,36,60,60,36,24,66,60,129,126}};

Я пытаюсь получить доступ к данным с помощью (показан неполный код) ...

void lcd_bitmap2(const bitmap_t *bit, uint8_t id, uint8_t posx, uint8_t posy) {
    uint8_t x;
    uint8_t y;  

    const uint8_t bw  = pgm_read_byte(&bit->width);   // this works -- I can print out to serial
    const uint8_t bh  = pgm_read_byte(&bit->height);  //this also works -- I can print out to serial
    // this doesn't work
    const uint8_t  *data = pgm_read_word(&bit->data); // I get: - initialization makes pointer from integer without a cast [enabled by default] 

    const uint8_t  *data = (uint8_t *)pgm_read_word(&bit->data); // this also doen't work (no warning, but wrong data read out)

    //rest of function...

Таким образом, я могу получить доступ к переменной ширины, высоты и изображения, но не к части данных структуры. Все работает, если я не сохраняю во флэш-памяти - это мой поиск и проблема только с частью структуры массива данных (ширина, высота и изображение читаются нормально)

Ответы [ 2 ]

0 голосов
/ 10 ноября 2018

(независимо от ответа Джона Боллинджера)

Вы неправильно используете pgm_read_word до ->data член bitmap_t здесь, и код не будет работать, даже если структура будет определена, скажем, с data[14].

Пусть XXX - это объект байтового размера во флэш-памяти. Вы можете прочитать это с pgm_read_byte(& XXX) Таким образом, можно прочитать пиксель в позиции pixel_number (data[pixel_number] объект) следующим образом:

// just address of first byte in data[]
const uint8_t  *data = bit->data;

uint8_t  pixel = pgm_read_byte(&data[pixel_number]);

Тот же результат получается при прямом доступе к структуре

uint8_t  pixel = pgm_read_byte(&bit->data[pixel_number]);

Наконец, современные компиляторы avr-gcc (с ключевым словом __flash) могут делать это автоматически. Просто объявите все указатели с модификатором __flash (<avr/pgmspace.h> можно опустить):

void lcd_bitmap2(__flash const bitmap_t *bit, uint8_t id,
                 uint8_t posx, uint8_t posy)
{
    uint8_t x;
    uint8_t y;  

    const uint8_t bw  = bit->width;
    const uint8_t bh  = bit->height;
    __flash const uint8_t *data = bit->data;

    uint8_t pixel_number; // make calculations with id, bw, bh and positions

    uint8_t pixel = data[pixel_number];

    // or ditectly pixel = bit->data[pixel_number];

p.s. По моему опыту, avr-gcc обрабатывает неполную инициализацию массива (также во флэш-памяти) и осуществляет доступ так, как вы ожидали.

0 голосов
/ 10 ноября 2018

TL; DR : вы не можете безопасно сделать это в стандартном C.

Учитывая это определение ...

typedef struct {
    uint8_t width;
    uint8_t height; // row number 0 to 5
    uint8_t images; // how many frames does this bitmap have
    uint8_t data[]; // the actual pixel data
} bitmap_t;

... bitmap_t.data является «членом гибкого массива»:

Как особый случай, последний элемент структуры с более чем одним именованный член может иметь неполный тип массива; это называется член гибкого массива. В большинстве случаев член гибкого массива игнорируется . В частности, размер структуры такой, как если бы гибкий член массива был опущен, за исключением того, что он может иметь больше завершающий отступ, чем подразумевалось бы. Однако, когда . (или ->) оператор имеет левый операнд, который является (указателем) на структуру с гибким элементом массива, а правый операнд называет этот член, он ведет себя так, как будто этот член был заменен самым длинным массивом (с тем же типом элемента), который не увеличит структуру чем доступ к объекту [...].

[ C2011 6.7.2.1/18; выделение добавлено]

Примеры в стандарте поясняют, что предоставление инициализатора для гибкого члена массива недопустимо, поскольку ваш код пытается это сделать. Более того, нет никаких оснований ожидать, что вообще будет выделено какое-либо пространство для содержимого элемента гибкого массива объекта со статическим или автоматическим сроком хранения, например вашего. Гибкие члены массива полезны только в сочетании с динамически размещаемыми объектами, если только в реализации, которая дает обещания в этой области помимо тех, которые требуются стандартом.

Доступ к члену гибкого массива статически размещенного объекта, следовательно, приводит к неопределенному поведению. Это не имеет прямого отношения к фактическому местоположению хранилища, хотя возможно, что UB проявляется по-разному, когда он находится во флэш-памяти. (В конце концов, поведение undefined .) Чтобы использовать объекты типа bitmap_t так, как вы пытаетесь это сделать, вам нужно изменить этот тип так, чтобы его член data имел полный тип (т. е. фиксированные размеры).

...