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

IAR 9.30.1, как запретить оптимизировать чтение из FLASH?

Добрый день, коллеги Я не могу справится со следующей проблемой. Есть такие типы данных и объявление константы calInfo, которая расположена с выравниванием по границе FLASH-памяти STM32F051. Константа calInfo в процессе работы прибора перепрошивается записью во флеш-память. До уровня оптимизации Low всё работает прекрасно, а выше, оптимизатор, полагаясь на начальную инициализацию константы данными, оптимизирует чтение из неё.

#pragma pack(push, 2) // flash writing by 2 bytes only
struct GeneralCal {
    uint16_t z0;
    uint16_t z1;
    uint16_t z2;
    uint16_t z3;
    bool calibrated;
};
#pragma pack(pop)

#pragma pack(push, 1)
struct CalInfo {
    GeneralCal general;
    uint16_t tbl[4096];
};

const CalInfo calInfo @ ".calInfo" {
    {
        3502, 3318, 369, 184, // see readme.md
        false,
    },{
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
        0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0002,
        0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0003, 0x0003,
        0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0 и т.д.

Как видно, переменная calibrated изначально иницилизирована false. Так и должно быть. Потом там будет 1 в ходе эксплуатации. Но сейчас, читая вот таким кодом значение этой переменной, я получаю всегда 0. Даже, когда прибор откалиброван, и в памяти FLASH действительно! находится 1.

static bool isCalibrated() {
    return calInfo.general.calibrated;
}

Конкретно при запуске программы у меня должен загораться красный светодиод, если isCalibrated() == false. И вот, что видно в дизассемблере:

image.thumb.png.e1681380a3ba50b77df81f0fa5531762.png

Т.е. светодиод пождигается всегда! В независимости от значения переменной. Она даже не читается! Мне скажут: добавить volatile. И вроде это логично! Добавляю сюда:

image.thumb.png.fb4600893d308ea27b9bc874c60c6092.png

И линкер пытается разместить эту константу в ОЗУ. Не могу понять, почему?

Вот, что написано в скрипте линкера:

image.thumb.png.217ac09bc1212b7e72d8a2a8b373280e.png

Пробовал создать указатель типа, и использовать его вместо константы calInfo:

volatile GeneralCal * s_generalCal = &calInfo;

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

Т.е., фактически, чтение происходит в случае объявление volatile-указателя. Но значение не используется. Перерыл доку, перечитл stackoverflow, но не могу понять, что происходит?

 

Коротко, что мне надо! При прошивке микроконтроллера, там должна быть калибровочная таблица (приблизительная, но более-менее рабочая) с кучей данных и флаг калибровке == false. Потом, в процессе эксплуатации прибор калибруется и все эти данные просто перешиваются актуальными данными. И я хочу, чтобы программа микроконтроллера имела актуальные данные из таблицы, а не вычисленные оптимизатором.

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


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

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

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


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

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

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

Нет, по правилам Си у него volatile-объект типа структуры, поэтому доступ к любому члену не будет выкинут.
 

43 минуты назад, haker_fox сказал:

что происходит?

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

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

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


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

Пробовал)

image.thumb.png.ad45a2f96cbb5c88317ca7db9a9772b5.png

В R0 читается значение, но не используется.

image.thumb.png.7221257f17be5fa6ed51a4a6400ef558.png

1 minute ago, Arlleex said:

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

Я и говорю, что в ОЗУ эта константа не должна размещаться) Она должна лежать во флешь! Но если добавить volatile, то линкер в обход правил её туда пытается запихнуть.

6 minutes ago, Arlleex said:

А volatile законно указало, что оптимизировать нельзя, таблицу оставить как есть, линкер глянул на все это дело и высказал свое "фи".

Вы дописали своё сообщение. Увидел позже. Но я и не могу в этом разобраться. Я же приложил скрипт) Там явно указано, куда размещать эту огромную константу)

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


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

32 минуты назад, haker_fox сказал:

Я и говорю, что в ОЗУ эта константа не должна размещаться) Она должна лежать во флешь! Но если добавить volatile, то линкер в обход правил её туда пытается запихнуть.

Тут в деталях IAR я не специалист, конечно, но, как правило, есть еще такое понятие как дефолтные секции. У них есть приоритеты и правила обобщения (слияния), много чего есть. Возможно, у Вас так и получилось.

Но повторюсь, что 0x2838 линкер не сможет разместить в ROM, т.к. Вы очертили ее размер на 64 кБ, из которых секции .calInfo отдали 9 кБ. В эти 9 кБ 0x2838 байт впихнуть невозможно.

У Вас там в эту секцию, кроме структуры, еще что-то попало. Причем с первостепенным приоритетом.

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


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

Вообще непонятно.

image.thumb.png.c893f31ad2110e67b373f97313f0e978.png

Размер секции он посчитал верно: 9кБ. Но обозначил её как readwrite. Т.е. пытается разместить в ОЗУ. Но выше в сообщении пишет, что уже не может разместить 0x2838 байт, т.е. 10 206 байт, а это не 9 кБ. Блин. Вообще запутался.

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


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

Дайте линкеру побольше памяти для эксперимента. Пусть разместит всю структуру где угодно.

Потом посмотрите, сколько именно эта структура реально заняла в памяти?

В .map и, например, sizeof() по отладчиком (можно даже симулятором).

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


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

Чёт мне уже кажется, что я ничего не понимаю в инструменте...

image.thumb.png.e4ebb18e03275d3bf080920d9f4fc42c.png

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


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

А может, таки взять и запретить оптимизировать? Поставить прагму на функцию чтения флеши

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


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

Теперь внаглую увеличил объём ОЗУ, такого, конечно нет. И всё легло! Но во флешь!

define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
define symbol __ICFEDIT_region_RAM_end__   = 0x20002FFF;

image.png.a783846b26a6cb72a57762474eaeafca.png

1 minute ago, MrYuran said:

А может, таки взять и запретить оптимизировать? Поставить прагму на функцию чтения флеши

Там ни одна функция читает из этой константы... Да и хочу уже понять, а что такое происходит. Это же мой профессиональный рост...

P.S. Возникает ощущение, что блоку CAL_INFO_BLOCL назначается аттрибут rw, линкер смотрит на это и примеряет блок к ОЗУ. Не входит? Пофиг, что нужно реально класть по другому адресу. Выдаём ошибку. Увеличили ОЗУ. Блок входит. Но кладём в флешь по указанному адресу.

P.S.S. Секции он уложил во флешь. А саму переменную calInfo в ОЗУ!

calInfo                 0x2000'0000  0x200c  Data  Gb  main.o [1]

 

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


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

Может, по аналогии (опять же, я не гуру IAR), написать так

place at address mem: 0x0800D400 {readonly section .calInfo, block CAL_INFO_BLOCK}

а из определения блока пока что убрать эти атрибуты? Да и на время убрать fixed order.

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


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

Попробую. По сути блок нужен, чтобы занять N 1024-байтных страниц флеши. И не допустить попадания туда посторонней информации. Т.к. флешь стирается секторами. В принципе, этот блок необязателен. Ведь можно просто подрезать границы для readonly секции, куда помещается код и константы.

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


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

6 минут назад, haker_fox сказал:

По сути блок нужен, чтобы занять N 1024-байтных страниц флеши.

Это все понятно, просто определение только этого блока у Вас отличается от всех остальных, включая стек, кучу и т.д.:wink:

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


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

19 minutes ago, Arlleex said:

lace at address mem: 0x0800D400 {readonly section .calInfo, block CAL_INFO_BLOCK}

Нет. Бесполезно. Кладёт в ОЗУ(((

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


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

const uint32_t a = 0; - разместит во FLASH
uint32_t b = 0; - разместит во FLASH, при инициализации переложит в ОЗУ
Вы хотите заставить компилятор разместить изменяемую переменную во FLASH. Вряд ли это получится.

Quote

как запретить оптимизировать чтение из FLASH?


 uint32_t x = *(__IO uint32_t*) 0x08001000;

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


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

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

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

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

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

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

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

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

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

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