Jump to content

    

Узнать в run-time занимаемую память приложения

Приветствую!

Среда Keil uVision, версия 5.25.2.0 (не думаю, что это важно).

Хочу сделать в своем GUI маленький такой раздел с ресурсными параметрами самого МК: сколько занимает прошивка во Flash, сколько выделено ОЗУ, а также разные финтиклюшки (процент загрузки CPU и т.д.). Возможно ли средствами линкера (или как еще?) разместить в две константные ячейки Flash количество занимаемых байт памяти во Flash (образ прошивки) и ОЗУ?

После компиляции эти параметры известны (пишутся в build output): .text, .bss и т.д., но вот как бы их еще из run-time выцыганить...

Share this post


Link to post
Share on other sites
27 минут назад, Arlleex сказал:

Возможно ли средствами линкера (или как еще?) разместить в две константные ячейки Flash количество занимаемых байт памяти во Flash (образ прошивки) и ОЗУ?

После компиляции эти параметры известны (пишутся в build output): .text, .bss и т.д., но вот как бы их еще из run-time выцыганить...

Можно конечно. В чём проблема? Забыли как слово const пишется?  :wink2:

Вычисление размера памяти: расположить в конце и в начале региона памяти определённые секции и вычислить разницу между ними. Не знаю как в Keil, но в IAR файл .icf:

define block IMAGE_HEAD with fixed order {section .intvec, section .checksum,
  section .codehead, section .intvecTail, section .codebegin};
place in RAM_regionB {ro, first block IMAGE_HEAD, last section .codetail,
  section .rodataInternal, section .textInternal, section .constFast};
define block IMAGE_HEAD_EXT with fixed order {section .codeheadExt};
place in SDRAM_regionA {
  first block IMAGE_HEAD_EXT,
  section .codeSignature,
  section .fnt,
  ...
  last section .codetailExt
};

Файл .asm:

SECTION  .codeheadExt:CONST:ROOT(0)
SECTION  .codetailExt:CONST:ROOT(0)

Файл .cpp:

__noreturn int main()
{
  #pragma section=".intvec"
  #pragma section=".codetail"
  #ifdef _CODE_SDRAM
  #pragma section=".codeheadExt"
  #pragma section=".codetailExt"
  #endif //_CODE_SDRAM
  ...
  LogCR0("Program image size: %u bytes",
    #ifdef _CODE_SDRAM
    (u32)__section_end(".codetailExt") - (u32)__section_begin(".codeheadExt") +
    #endif //_CODE_SDRAM
    (u32)__section_end(".codetail") - (u32)__section_begin(".intvec"));
  ...
}

Это пример для более сложного случая - когда программа разделена на 2 несмежных региона памяти. Если всё одним куском - будет ещё проще.

В моём случае - отладочная сборка для выполнения в SDRAM состоит из двух регионов (как видно выше) и _CODE_SDRAM - defined. При сборке во флешь _CODE_SDRAM будет - undef.

 

PS: Секции ".codeheadExt" и ".codetailExt" - пустые. 0-го размера. Как создать пустые секции в .cpp я не знаю, поэтому они в .asm.

PPS: У IAR-а (7.80.4) есть какой-то глюк с расположением секций в начале региона (first section ...) - почему-то это не всегда срабатывает. А вот "first block" - срабатывает всегда. Поэтому в моём примере пришлось сделать отдельный блок IMAGE_HEAD_EXT только с одной секцией.

Share this post


Link to post
Share on other sites
18 минут назад, jcxz сказал:

Можно конечно.

То что нужно, похоже. Попутно накопал еще топик для размышления.

Спасибо!

Share this post


Link to post
Share on other sites

Не скажу за все среды, но если сборка идёт с использованием командной строки LD, то можно использовать для него "скрипты" - там можно выводить в глобальные переменные константы-адреса секций и результаты операций над ними, можно добавлять новые секции и модифицировать существующие. Можно даже в два прохода компоновку делать - на первом допустим размер пользовательской секции задан нулевой, а на втором - как результат разбора файла от первого этапа с учётом получившихся размеров/адресов.

Share this post


Link to post
Share on other sites
10 hours ago, Arlleex said:

. . . После компиляции эти параметры известны (пишутся в build output): .text, .bss и т.д., но вот как бы их еще из run-time выцыганить...

Посмотрите список макро-переменных препроцессора, возможно там есть "сегментные" 

Predefined macros

Share this post


Link to post
Share on other sites

Благодарю всех за комментарии. Выбор мой пал, все-таки, на средства линкер-скрипта.

Share this post


Link to post
Share on other sites
6 hours ago, Arlleex said:

Благодарю всех за комментарии. Выбор мой пал, все-таки, на средства линкер-скрипта.

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

Я предпочитаю сканировать память и выводить инфу о чистых кусках по факту:

    // Проверяем заполнение памяти
    uint8_t  *str_addr = (uint8_t *)0x00000000;
    uint8_t  *addr;
    uint8_t  *end_addr = (uint8_t *)0x003FFFFF;
    uint8_t  *end = 0;
    uint32_t  empt_bl_sz = 0;

    addr = str_addr;
    do
    {
      if (*addr != 0xFF)
      {
        if (empt_bl_sz > 256)
        {
          MPRINTF("Empty flash memory from %08X to %08X\r\n", (uint32_t)end - empt_bl_sz , (uint32_t)end);
        }
        empt_bl_sz = 0;
      }
      else
      {
        end = addr;
        empt_bl_sz++;
      }
      addr++;

    } while (addr <= end_addr);

    if (empt_bl_sz > 256)
    {
      MPRINTF("Empty flash memory from %08X to %08X\r\n", (uint32_t)end - empt_bl_sz , (uint32_t)end);
      MPRINTF("Occupied flash memory size  %d\r\n", (uint32_t)end - empt_bl_sz - (uint32_t)str_addr);
    }
    else
    {
      MPRINTF("Occupied flash memory size  %d\r\n", (uint32_t)end_addr - (uint32_t)str_addr);
    }

Таким образом не пропустите опасный мусор и другие чудесные артефакты. 

Share this post


Link to post
Share on other sites
18 часов назад, AlexandrY сказал:

Я предпочитаю сканировать память и выводить инфу о чистых кусках по факту...

Я думал о таком варианте, но в ней есть свои минусы:

1. Я не всегда стираю полностью все сектора при программировании. Я стираю только те, что нужны под приложение. Да, бывает и стираю полностью (но гарантии нет, что это у меня дэ-факто).

2. Время выполнения этой функции сильно зависит от объема занятой памяти.

3. С ОЗУ такой вариант уже не прокатит...

 

Плюс, конечно, в том, что не надо заморачиваться и вспоминать, что там загрузчик еще где-то может существовать и т.д. Но, ИМХО, программист должен это учитывать при написании целевого приложения и уменьшать реальный объем доступной памяти. Например, если в устройстве предусмотрен загрузчик (и пусть занимает он 16кб), то для МК с объемом Flash 2 Мб достаточно сказать линкеру, что реальной памяти, отведенной приложению, осталось 2Мб - 16кб.

Share this post


Link to post
Share on other sites
2 hours ago, Arlleex said:

1. Я не всегда стираю полностью все сектора при программировании. Я стираю только те, что нужны под приложение. Да, бывает и стираю полностью (но гарантии нет, что это у меня дэ-факто).

Нестертые сектора и есть довольно опасный  мусор. Эт вы наверно, как и я поняли когда запустили этот код. :biggrin:
Время на 4 Мбайтах занимает меньше секунды. Так что переживать не о чем. 
 

Share this post


Link to post
Share on other sites
15 часов назад, AlexandrY сказал:

Время на 4 Мбайтах занимает меньше секунды. Так что переживать не о чем. 

А если секунда - это недопустимо большое время для старта ПО данного устройства? не думали?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now