Перейти к содержанию
    

Инициализовать массив во Flash-памяти

MDR32F1QI. Программа использует калибровочную таблицу переменной длины, под которую отводится страница памяти во Flash-области.

В выделенной под таблицу секции памяти необходимо проинициализировать нулевыми значениями переменную — текущую длину таблицы, а так же сами данные.

Соответствующий участок C-кода выглядит так:

// Максимальное количество записей в таблице
#define MAX_TABLE_SIZE 500

// Структура записи в таблице
typedef struct {
  uint32_t value;
  uint32_t corr;
} record_t;
  
// Текущее количество записей в таблице
const volatile size_t table_sz
  __attribute__((section(".table"))) = 0;
// Массив стуктур
const volatile record_t table[MAX_TABLE_SIZE]
  __attribute__((section(".table"))) = { {0, 0} };

Далее привожу соответствующий scatter-файл:

LR_IROM1 0x00000000 0x00012000  {    ; load region size_region
  ER_IROM1 0x00000000 0x00010000  {  ; load address = execution address
    *.o (RESET, +First)
    *(InRoot$$Sections)
    .ANY (+RO)
  }
  RW_IRAM1 0x20000000 0x00008000  {  ; RW data
    .ANY (+RW +ZI)
  }
  RW_IRAM2 0x20100000 0x00004000  {
    mdr32f9qx_eeprom.o
    eeprom.o (+RO)
    .ANY (+RW +ZI)
  }
}
}
LR_IROM2 0x00013000 0x00001000  {    ; load region size_region
  ER_IROM2 0x00013000 0x00001000  {  ;
    * (.table)
  }
}

Компилирую и собираю (ARMCC 5.06), после чего с помощью objdump смотрю выходной файл. И здесь начинается волшебство:

Содержимое раздела ER_IROM2:
 13000 01ff01ff 01ff01ff 01ff01ff 01ff01ff  ................
 13010 01ff01ff 01ff01ff 01ff01ff 01ff01b3  ................

Далее, пытаюсь уменьшить длину массива в объявлении (MAX_TABLE_SIZE = 20). И, о чудо!
 

Содержимое раздела ER_IROM2:
 13000 00000000 00000000 00000000 00000000  ................
 13010 00000000 00000000 00000000 00000000  ................
 13020 00000000 00000000 00000000 00000000  ................
 13030 00000000 00000000 00000000 00000000  ................
 13040 00000000 00000000 00000000 00000000  ................
 13050 00000000 00000000 00000000 00000000  ................
 13060 00000000 00000000 00000000 00000000  ................
 13070 00000000 00000000 00000000 00000000  ................
 13080 00000000 00000000 00000000 00000000  ................
 13090 00000000 00000000 00000000 00000000  ................
 130a0 00000000                             ....     

Опытным путем обнаружил, что максимальное работающее значение MAX_TABLE_SIZE равно 36. Тогда и переменная, отвечающая за текущую длину массива, и сам массив аккуратно в зануленном виде появляются в соответствующей секции. Иначе — мусор, подобный тому, что выше. Например, при MAX_TABLE_SIZE = 37 соответствующая секция выглядит так (вообще одно значение):

Содержимое раздела ER_IROM2:
 13000 01ff012d                             ...-       

Помогите разобраться с этим "волшебством". Сразу скажу, что при использовании GCC и ld никаких проблем не возникает. Массив и переменная в аккурат инициализируются в том количестве, какое задано. А вот с Keil у меня засада. Но необходимо делать код рабочим под оба компилятора.

Есть, конечно, еще workaround: массив ведь можно заменить указателем относительно адреса переменной —- текущей его длины (что и было сделано в самом первоначальной версии), причем инициализация нулями его элементов необязательна — нулевая начальная длина (в соответствующей переменной) вполне достаточна для правильной работы программы. Но последующие считывание и запись в массив будут происходить тоже через смещения указателя относительно базового адреса переменной. Это, как мне кажется, не совсем удобно. Тем более, когда в GCC и ld все прекрасно работает.

Посему в силу моего небольшого опыта прошу помочь разобраться с этой странной проблемой в Keil. Заранее спасибо за помощь.

Изменено пользователем tathagata

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

14 минут назад, tathagata сказал:
const volatile record_t

в чем прикол делать таблицу констант волатильной?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

 

5 минут назад, AlexRayne сказал:

в чем прикол делать таблицу констант волатильной?

Если она в процессе работы перешивается, например. Чтобы компилятор не подумал, что там всегда нули как во время компиляции и не соптимизировал доступ к ней.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот наткнулся на доп. команду линкера: --keep=''*.o(mysection)''

https://habr.com/ru/articles/685028/

 

Проверил ваш код в компиляторе/линкере v6.19, все прекрасно работает и размещается где нужно, 

а вот если убрать из misc опций вот эту строку --keep=''*.o(tables)'' (на картинке пример),

Spoiler

ce33f2f3742e378ba1288fa4dab502c1.png.569388ccef3d7fe5d2c5f31a60cfe979.png

 

 

то начинает сразу ругаться:

Quote

warning: L6329W: Pattern *.o(tables) only matches removed unused sections.

конечно, дело в том, что в основном коде нигде не используются эти массивы и линкер просто из вырезал, эта команда помогает их сохранить

если использовать их в коде явно, но они никуда не деваются и эта команда --keep не требуется

Подобное полезно для размещения неких структур, доступ к которым производится косвенно, по конкретным адресам без указания названий этих структур, иначе линкер молча их вырежет и вы получите по этим адресам мусор.

Например, нужно разместить образ некой прошивки некой плис по фиксированному адресу.

Полезная фича ))

 

 

для проверки использовал такое содержимое скрипта линкера:

LR_IROM1 0x08000000 0x80000  {    ; load region size_region
  ER_IROM1 0x08000000 0x70000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
  ER_IROM2 0x08070000 0x1000  {  ;
    *.o (tables)
  }
 
  RW_IRAM1 0x20000000 0x00010000  {  ; RW data
   .ANY (+RW +ZI)
  }
}

 

ну и ваш код:

// Текущее количество записей в таблице
const volatile size_t table_sz
  __attribute__((section("tables"))) = 0;

// Массив стуктур
const volatile record_t table[MAX_TABLE_SIZE]
  __attribute__((section("tables"))) = { {0, 0} };

 

 

Ну и выписка из map файла:

Quote

    table_sz                                 0x08070000   Data           4  application.o(tables)
    table                                    0x08070004   Data        4000  application.o(tables)

 

26 minutes ago, AlexRayne said:

в чем прикол делать таблицу констант волатильной?

Попробовал из любопытства убрать volatile из объявления:

// Текущее количество записей в таблице
const  size_t table_sz
  __attribute__((section("tables"))) = 0;

// Массив стуктур
const  record_t table[MAX_TABLE_SIZE]
  __attribute__((section("tables"))) = { {0, 0} };

 

и линкер тут же начал ругаться на отсутствующую секцию:

Quote

 Warning: L6319W: Ignoring --keep command. Cannot find section *.o(tables).

warning: L6314W: No section matches pattern *.o(tables).

 

по ходу volatile обладает некой "магией" 😉

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Эксперименты показали, что ARMCLANG (6.18 в моем случае) правильно размещает массив на Flash. В то время как ARMCC (5.06), на котором и строился проект, имеет такой неприятный баг.

Выбор компилятора в моем случае осложняется тем, что при использовании миландровских библиотек ARMCLANG при сборке выдает много странных ошибок, которые я отношу на совесть разработчиков пакета драйверов для Milandr. Для экспериментов собирать пришлось, в качестве устройства выбрав в обоих случаях стандартный ARMCM0P (ARM Cortex M0 plus).

Если кто-то подскажет рабочее решение для увы устаревшего ARMCC v5.06, буду очень признателен.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

25 minutes ago, tathagata said:

Если кто-то подскажет рабочее решение для увы устаревшего ARMCC v5.06, буду очень признателен.

Или писать разрабам в миландр чтобы переделали свои либы под нормальные компиляторы или делать это вручную, самостоятельно

Есть третий вариант - вообще не пользоваться либами миландра, а максимум лишь их h-файлами (регистры и структуры).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 часа назад, tathagata сказал:

MDR32F1QI

А это же 1986ВЕ1, а он Cortex-M1(или 2? не помню - ядро ARM Cortex для ПЛИС)

Вот, нашел, собирал его проекты как Cortex-M1.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 часов назад, Forger сказал:

по ходу volatile обладает некой "магией" 😉

А ваш код вобще использует этот массив? или функции его использовашие выброшены?
Куда он вообще положил вашу таблицу? видимо не в секцию `tables` а во text?

Изменено пользователем AlexRayne

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...