haker_fox 61 24 августа, 2023 Опубликовано 24 августа, 2023 · Жалоба Добрый день, коллеги Я не могу справится со следующей проблемой. Есть такие типы данных и объявление константы 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. И вот, что видно в дизассемблере: Т.е. светодиод пождигается всегда! В независимости от значения переменной. Она даже не читается! Мне скажут: добавить volatile. И вроде это логично! Добавляю сюда: И линкер пытается разместить эту константу в ОЗУ. Не могу понять, почему? Вот, что написано в скрипте линкера: Пробовал создать указатель типа, и использовать его вместо константы calInfo: volatile GeneralCal * s_generalCal = &calInfo; Тогда происходит чтение флага calibrated в регистр R0, но значение из этого регистра не используется для поджига светодиода))) Т.е. код, приведённый в дизассемблере выше - остаётся тем же самым. Только сверху добавляется пара строк: загружить адрес переменной в регистр, считать по этому адресу значение переменной... Т.е., фактически, чтение происходит в случае объявление volatile-указателя. Но значение не используется. Перерыл доку, перечитл stackoverflow, но не могу понять, что происходит? Коротко, что мне надо! При прошивке микроконтроллера, там должна быть калибровочная таблица (приблизительная, но более-менее рабочая) с кучей данных и флаг калибровке == false. Потом, в процессе эксплуатации прибор калибруется и все эти данные просто перешиваются актуальными данными. И я хочу, чтобы программа микроконтроллера имела актуальные данные из таблицы, а не вычисленные оптимизатором. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrYuran 21 24 августа, 2023 Опубликовано 24 августа, 2023 · Жалоба Думаю, магическое заклинание volatile надо применить ко всем полям структуры Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 172 24 августа, 2023 Опубликовано 24 августа, 2023 · Жалоба 5 минут назад, MrYuran сказал: Думаю, магическое заклинание volatile надо применить ко всем полям структуры Нет, по правилам Си у него volatile-объект типа структуры, поэтому доступ к любому члену не будет выкинут. 43 минуты назад, haker_fox сказал: что происходит? Думаю, для начала нужно разобраться, откуда накопилось 0x2838 байтов для размещения в секции, которая заведомо меньше этого размера. Почему он собирал без volatile - потому что компилятору были известны все значения из таблицы, поэтому он мог вместо нее разместить что угодно (вплоть до сжатия, уплотнения, выкидывания лишнего), а при доступе к этой структуре воспользоваться правилом "наблюдаемого поведения". Пользователю ведь все равно. А volatile законно указало, что оптимизировать нельзя, таблицу оставить как есть, линкер глянул на все это дело и высказал свое "фи". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 61 24 августа, 2023 Опубликовано 24 августа, 2023 · Жалоба Пробовал) В R0 читается значение, но не используется. 1 minute ago, Arlleex said: Думаю, для начала нужно разобраться, откуда накопилось 0x2838 байтов для размещения в секции, которая заведомо меньше этого размера. Я и говорю, что в ОЗУ эта константа не должна размещаться) Она должна лежать во флешь! Но если добавить volatile, то линкер в обход правил её туда пытается запихнуть. 6 minutes ago, Arlleex said: А volatile законно указало, что оптимизировать нельзя, таблицу оставить как есть, линкер глянул на все это дело и высказал свое "фи". Вы дописали своё сообщение. Увидел позже. Но я и не могу в этом разобраться. Я же приложил скрипт) Там явно указано, куда размещать эту огромную константу) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 172 24 августа, 2023 Опубликовано 24 августа, 2023 · Жалоба 32 минуты назад, haker_fox сказал: Я и говорю, что в ОЗУ эта константа не должна размещаться) Она должна лежать во флешь! Но если добавить volatile, то линкер в обход правил её туда пытается запихнуть. Тут в деталях IAR я не специалист, конечно, но, как правило, есть еще такое понятие как дефолтные секции. У них есть приоритеты и правила обобщения (слияния), много чего есть. Возможно, у Вас так и получилось. Но повторюсь, что 0x2838 линкер не сможет разместить в ROM, т.к. Вы очертили ее размер на 64 кБ, из которых секции .calInfo отдали 9 кБ. В эти 9 кБ 0x2838 байт впихнуть невозможно. У Вас там в эту секцию, кроме структуры, еще что-то попало. Причем с первостепенным приоритетом. 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 61 24 августа, 2023 Опубликовано 24 августа, 2023 · Жалоба Вообще непонятно. Размер секции он посчитал верно: 9кБ. Но обозначил её как readwrite. Т.е. пытается разместить в ОЗУ. Но выше в сообщении пишет, что уже не может разместить 0x2838 байт, т.е. 10 206 байт, а это не 9 кБ. Блин. Вообще запутался. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 172 24 августа, 2023 Опубликовано 24 августа, 2023 · Жалоба Дайте линкеру побольше памяти для эксперимента. Пусть разместит всю структуру где угодно. Потом посмотрите, сколько именно эта структура реально заняла в памяти? В .map и, например, sizeof() по отладчиком (можно даже симулятором). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 61 24 августа, 2023 Опубликовано 24 августа, 2023 · Жалоба Чёт мне уже кажется, что я ничего не понимаю в инструменте... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrYuran 21 24 августа, 2023 Опубликовано 24 августа, 2023 · Жалоба А может, таки взять и запретить оптимизировать? Поставить прагму на функцию чтения флеши Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 61 24 августа, 2023 Опубликовано 24 августа, 2023 · Жалоба Теперь внаглую увеличил объём ОЗУ, такого, конечно нет. И всё легло! Но во флешь! define symbol __ICFEDIT_region_RAM_start__ = 0x20000000; define symbol __ICFEDIT_region_RAM_end__ = 0x20002FFF; 1 minute ago, MrYuran said: А может, таки взять и запретить оптимизировать? Поставить прагму на функцию чтения флеши Там ни одна функция читает из этой константы... Да и хочу уже понять, а что такое происходит. Это же мой профессиональный рост... P.S. Возникает ощущение, что блоку CAL_INFO_BLOCL назначается аттрибут rw, линкер смотрит на это и примеряет блок к ОЗУ. Не входит? Пофиг, что нужно реально класть по другому адресу. Выдаём ошибку. Увеличили ОЗУ. Блок входит. Но кладём в флешь по указанному адресу. P.S.S. Секции он уложил во флешь. А саму переменную calInfo в ОЗУ! calInfo 0x2000'0000 0x200c Data Gb main.o [1] Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 172 24 августа, 2023 Опубликовано 24 августа, 2023 · Жалоба Может, по аналогии (опять же, я не гуру IAR), написать так place at address mem: 0x0800D400 {readonly section .calInfo, block CAL_INFO_BLOCK} а из определения блока пока что убрать эти атрибуты? Да и на время убрать fixed order. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 61 24 августа, 2023 Опубликовано 24 августа, 2023 · Жалоба Попробую. По сути блок нужен, чтобы занять N 1024-байтных страниц флеши. И не допустить попадания туда посторонней информации. Т.к. флешь стирается секторами. В принципе, этот блок необязателен. Ведь можно просто подрезать границы для readonly секции, куда помещается код и константы. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 172 24 августа, 2023 Опубликовано 24 августа, 2023 · Жалоба 6 минут назад, haker_fox сказал: По сути блок нужен, чтобы занять N 1024-байтных страниц флеши. Это все понятно, просто определение только этого блока у Вас отличается от всех остальных, включая стек, кучу и т.д. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 61 24 августа, 2023 Опубликовано 24 августа, 2023 · Жалоба 19 minutes ago, Arlleex said: lace at address mem: 0x0800D400 {readonly section .calInfo, block CAL_INFO_BLOCK} Нет. Бесполезно. Кладёт в ОЗУ((( Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vit496 0 24 августа, 2023 Опубликовано 24 августа, 2023 · Жалоба const uint32_t a = 0; - разместит во FLASH uint32_t b = 0; - разместит во FLASH, при инициализации переложит в ОЗУ Вы хотите заставить компилятор разместить изменяемую переменную во FLASH. Вряд ли это получится. Quote как запретить оптимизировать чтение из FLASH? uint32_t x = *(__IO uint32_t*) 0x08001000; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться