2011-02-10 2 views
5

У меня есть некоторые постоянные данные, которые я хочу хранить в ПЗУ, поскольку их достаточно, и я работаю с встроенным устройством ARM7 с ограниченным объемом памяти. Я пытаюсь сделать это с помощью структур, которые выглядят примерно так:Сохранение структур в ПЗУ на устройстве ARM

struct objdef 
{ 
    int x; 
    int y; 
    bool (*function_ptr)(int); 
    some_other_struct * const struct_array; // array of similar structures 
    const void* vp; // previously ommittted to shorten code 
} 

, который я затем создать и инициализировать, как глобалов:

const objdef def_instance = { 2, 3, function, array, NULL }; 

Однако это съедает совсем немного оперативной памяти, несмотря на const в начале. Более конкретно, это значительно увеличивает количество данных RW и в конечном итоге заставляет устройство блокироваться, если создаются достаточные экземпляры.

Я использую uVision и компилятор ARM вместе с ядром RTX реального времени.

Кто-нибудь знает, почему это не работает или не знает лучшего способа хранения структурированных гетерогенных данных в ПЗУ?

Update

Спасибо всем за ваши ответы, и мои извинения за не получить обратно к вам, ребята, раньше. Итак, вот оценка до сих пор и некоторые дополнительные наблюдения с моей стороны.

К сожалению, __attribute__ имеет нулевой эффект на ОЗУ против ПЗУ и то же самое для static const. Я еще не успел попробовать маршрут сборки.

Мои коллеги и я обнаружили еще более необычное поведение.

Во-первых, я должен отметить, что для простоты я не упомянул, что моя структура objdef содержит поле const void*. Поле иногда присваивается значение из строки таблицы определяется как

char const * const string_table [ROWS][COLS] = 
{ 
    { "row1_1", "row1_2", "row1_3" }, 
    { "row2_1", "row2_2", "row2_3" }, 
... 
} 

const objdef def_instance = { 2, 3, function, array, NULL };//->ROM 
const objdef def_instance = { 2, 3, function, array, string_table[0][0] };//->RAM 

string_table находится в ПЗУ, как ожидалось. И вот кикер: экземпляры objdef попадают в ПЗУ, пока одно из значений в string_table не будет присвоено этому полю const void*. После этого экземпляр структуры перемещается в ОЗУ.

Но когда string_table изменяются на

char const string_table [ROWS][COLS][MAX_CHARS] = 
{ 
    { "row1_1", "row1_2", "row1_3" }, 
    { "row2_1", "row2_2", "row2_3" }, 
... 
} 

const objdef def_instance = { 2, 3,function, array, NULL };//->ROM 
const objdef def_instance = { 2, 3, function, array, string_table[0][0] };//->ROM 

те случаи objdef помещаются в ПЗУ, несмотря на это const void* распайки. Я понятия не имею, почему это имеет значение.

Я начинаю подозревать, что Дэн прав, и что наша конфигурация где-то испорчена.

+0

Попробуйте объявить как 'static const'. Я заметил, что некоторые компиляторы будут копировать данные из ПЗУ в стек, если он объявлен только как 'const'; прямой доступ к ПЗУ возникает, когда применяется «статический const». –

+0

C++ 'const' не означает« физически только для чтения ». У вас может быть const_cast, с одной стороны. –

+0

Я знаю, что вы всегда можете выполнить const_cast, но я наткнулся на ряд ресурсов в Интернете, которые предложили использовать 'const' для получения данных, хранящихся в ROM. Помимо этого, я узнал из опыта, что 'const' иногда, но не всегда имеет этот эффект. Очевидно, я не совсем понимаю, когда и почему. :) – dandan78

ответ

1

Вы всегда можете попробовать использовать язык ассемблера.

Поместите информацию с помощью DATA и опубликуйте (опубликуйте) стартовые адреса данных.

По моему опыту, большие данные только для чтения были объявлены в исходном файле как static const. Простая глобальная функция внутри исходного файла вернет адрес данных.

+0

Я позабочусь о первых предложениях с утра. Благодарю. – dandan78

+0

Раздел .data обычно считывает данные записи, поэтому он всегда будет загружен в ram – doron

1

Я предполагаю, что у вас есть файл рассеяния, который разделяет разделы RAM и ROM.То, что вы хотите сделать, - указать вашу структуру с атрибутом, для какого раздела он будет размещен, или поместить его в свой собственный объектный файл, а затем указать, что в разделе вы хотите, чтобы он находился в файле рассеяния.

__attribute__((section("ROM"))) const objdef def_instance = { 2, 3, function, array }; 

: C «Уст» ключевое слово на самом деле не заставит компилятор положить что-то в тексте или константную разделе. Это позволяет компилятору предупреждать вас о попытках его изменения. Совершенно верно, чтобы получить указатель на объект const, передать его неконстантированному и записать на него, а компилятор должен его поддерживать.

+0

Да, у меня есть файл рассеяния, и я считаю, что он настроен правильно. Я дважды проверю это и попробую ваше решение. Благодарю. – dandan78

+1

это не «отлично». Это Undefined Behavior, и компилятор имеет полное право размещать переменную 'const' в ПЗУ. – MSalters

1

Если вы делаете материал на ARM, вы, вероятно, используете двоичный формат ELF. Файлы ELF содержат несколько разделов, но постоянные данные должны найти свой путь в секциях .rodata или .text двоичного файла ELF. Вы должны проверить это с помощью утилиты GNU readelf или утилиты RVCT fromelf.

Теперь, предполагая, что символы находятся в правильной части файла эльфа, теперь вам нужно выяснить, как выполняет загрузчик RTX. Также нет причин, по которым экземпляры не могут использовать одну и ту же постоянную память, но это будет зависеть от загрузчика. Если исполняемый файл хранится в rom, он может быть запущен на месте, но все равно может быть загружен в оперативную память. Это также зависит от загрузчика.

+0

Я использую uVision и компилятор ARM в Windows, а установка Cygwin - это не то, что я хотел бы сделать на моей машине разработки. Я только что проверил свой выходной каталог и нет .elf. У меня есть bin, который я могу загрузить непосредственно с uVision или используя пользовательский загрузчик, который находится на устройстве. – dandan78

2

Ваше мнение правильное и разумное. Я использовал Keil/uVision (это был v3, может быть, 3 года назад?), И он всегда работал так, как вы ожидали этого, т. Е. Он помещал данные const во флеш-память.

Я подозреваю вашу конфигурацию компоновщика/скрипт. Я попытаюсь вернуться к своей старой работе & посмотрю, как я ее настроил. Мне не нужно было добавлять #pragma или __attribute__ директивы, я только что разместил его .const & .text во флэш-памяти. Я установил конфигурацию компоновщика/карту памяти совсем недавно, поэтому, к сожалению, мой отзыв не очень свежий.

(Я немного смущен людьми, которые говорят о литье & константных указателей и т. Д. Вы ничего не спросили об этом &, вы, кажется, понимаете, как работает «const». инициализированные данные во флэш/ПЗУ для сохранения ОЗУ (а не ПЗУ-> ОЗУ при запуске), не говоря уже о небольшом ускорении во время загрузки, правильно? Вы не спрашиваете, можно ли изменить его или что-то еще ...)

EDIT/UPDATE:

Я просто заметил, что последнее поле в (сопзЬ) структуры является some_other_struct * const (постоянный указатель на some_other_ структура). Вы можете попытаться сделать его постоянным указателем на константу some_other_struct [some_other_struct const * const] (предполагая, что он указывает на действительно постоянный). В этом случае это может сработать. Я не помню специфику (см. Тему здесь?), Но это начинает казаться знакомым. Даже если ваш указатель-указатель не является элементом-константой, и вы не можете в конечном итоге это сделать, попробуйте изменить определение структуры &, инициализируя его указателем на const, и просто посмотрите, удаляет ли это его в ПЗУ. Несмотря на то, что у вас есть указатель const, и он не может измениться после создания структуры, я, кажется, что-то помню, где, если цель не является также константой, компоновщик не считает, что ее можно полностью инициализировать во время соединения & отменяет инициализацию, когда выполняется запуск кода запуска C, вкл. ROM в RAM-копию инициализированной памяти RW.

+0

Спасибо, я уже пробовал указатель const для подхода типа const, но без везения. Однако наблюдалось другое странное поведение. Посмотрите мое обновление на вопрос, когда сможете. – dandan78

0

Полный пример был бы лучшим.Если я что-то вроде этого:

 
typedef struct 
{ 
    char a; 
    char b; 
} some_other_struct; 

struct objdef 
{ 
    int x; 
    int y; 
    const some_other_struct * struct_array; 
}; 

typedef struct 
{ 
    int x; 
    int y; 
    const some_other_struct * struct_array; 
} tobjdef; 


const some_other_struct def_other = {4,5}; 
const struct objdef def_instance = { 2, 3, &def_other}; 
const tobjdef tdef_instance = { 2, 3, &def_other}; 

unsigned int read_write=7; 

И скомпилировать его с последним CodeSourcery облегченного

 
arm-none-linux-gnueabi-gcc -S struct.c 

Я получаю

 
    .arch armv5te 
    .fpu softvfp 
    .eabi_attribute 20, 1 
    .eabi_attribute 21, 1 
    .eabi_attribute 23, 3 
    .eabi_attribute 24, 1 
    .eabi_attribute 25, 1 
    .eabi_attribute 26, 2 
    .eabi_attribute 30, 6 
    .eabi_attribute 18, 4 
    .file "struct.c" 
    .global def_other 
    .section .rodata 
    .align 2 
    .type def_other, %object 
    .size def_other, 2 
def_other: 
    .byte 4 
    .byte 5 
    .global def_instance 
    .align 2 
    .type def_instance, %object 
    .size def_instance, 12 
def_instance: 
    .word 2 
    .word 3 
    .word def_other 
    .global tdef_instance 
    .align 2 
    .type tdef_instance, %object 
    .size tdef_instance, 12 
tdef_instance: 
    .word 2 
    .word 3 
    .word def_other 
    .global read_write 
    .data 
    .align 2 
    .type read_write, %object 
    .size read_write, 4 
read_write: 
    .word 7 
    .ident "GCC: (Sourcery G++ Lite 2010.09-50) 4.5.1" 
    .section .note.GNU-stack,"",%progbits 

С помеченным, как .rodata, который я взял бы на себя желательно. Тогда это зависит от сценария компоновщика, чтобы убедиться, что данные ro помещены в ром. И обратите внимание, что переменная read_write после переключения с .rodata на .data, которая читается/записывается.

Таким образом, чтобы сделать это полное бинарное и посмотреть, если он будет помещен в ПЗУ или ОЗУ (.text или .data), то

start.s

 

.globl _start 
_start: 
    b reset 
    b hang 
    b hang 
    b hang 

    b hang 
    b hang 
    b hang 
    b hang 

reset: 
hang: b hang 

Тогда

 
# arm-none-linux-gnueabi-gcc -c -o struct.o struct.c 
# arm-none-linux-gnueabi-as -o start.o start.s 
# arm-none-linux-gnueabi-ld -Ttext=0 -Tdata=0x1000 start.o struct.o -o struct.elf 
# arm-none-linux-gnueabi-objdump -D struct.elf > struct.list 

И мы получаем

 

Disassembly of section .text: 

00000000 <_start>: 
    0: ea000006 b 20 <reset> 
    4: ea000008 b 2c <hang> 
    8: ea000007 b 2c <hang> 
    c: ea000006 b 2c <hang> 
    10: ea000005 b 2c <hang> 
    14: ea000004 b 2c <hang> 
    18: ea000003 b 2c <hang> 
    1c: ea000002 b 2c <hang> 

00000020 <reset>: 
    20: e59f0008 ldr r0, [pc, #8] ; 30 <hang+0x4> 
    24: e5901000 ldr r1, [r0] 
    28: e5801000 str r1, [r0] 

0000002c <hang>: 
    2c: eafffffe b 2c <hang> 
    30: 00001000 andeq r1, r0, r0 

Disassembly of section .data: 

00001000 <read_write>: 
    1000: 00000007 andeq r0, r0, r7 

Disassembly of section .rodata: 

00000034 <def_other>: 
    34: 00000504 andeq r0, r0, r4, lsl #10 

00000038 <def_instance>: 
    38: 00000002 andeq r0, r0, r2 
    3c: 00000003 andeq r0, r0, r3 
    40: 00000034 andeq r0, r0, r4, lsr r0 

00000044 <tdef_instance>: 
    44: 00000002 andeq r0, r0, r2 
    48: 00000003 andeq r0, r0, r3 
    4c: 00000034 andeq r0, r0, r4, lsr r0 

И это достигло желаемого результата. Переменная read_write находится в ram, структуры находятся в rom. Необходимо удостовериться, что объявления const находятся в правильных местах, компилятор не дает никаких предупреждений о том, что нужно положить const на какой-либо указатель на другую структуру, которую он не может определить во время компиляции как const, и даже со всем этим скрипт компоновщика (если вы его используете) для работы по желанию может принести определенные усилия. например, этот, как представляется, работает:

 

MEMORY 
{ 
    bob(RX) : ORIGIN = 0x0000000, LENGTH = 0x8000 
    ted(WAIL) : ORIGIN = 0x2000000, LENGTH = 0x8000 
} 

SECTIONS 
{ 
    .text : { *(.text*) } > bob 
    .data : { *(.data*) } > ted 
} 

+0

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

+0

Мой плохой, извините, не видел ссылку на компилятор. Какой компилятор? Keil? RVCT? или старше ADS, или ранее, чем я не могу вспомнить его имя (SBT?). По крайней мере, в ADS-дни техническая поддержка ARM была очень хорошей (нужно было получить что-то за деньги, заплаченные за эти инструменты). они обеспечивали понимание? –

Смежные вопросы