Управление размещением данных и функций в памяти путем вставки прагм

Для некоторых приложений можно использовать прагмы и другие украшения кода для управления размещением данных (глобальных переменных) и определений функций в памяти. Для примера файл строения linker может задавать именованные разделы в SECTIONS директива и сопоставить каждый раздел с областью значений адресов памяти. В код С вы включаете прагмы, которые присваивают глобальные переменные и функции этим именованным разделам и, кроме того, областям значений памяти. Управляя размещением памяти, можно:

  • Сгенерируйте код, который более эффективен для вашего оборудования.

  • Модулируйте код приложения для более легкого обслуживания и изменения позже в процессе разработки и после развертывания.

С Embedded Coder® и разделы памяти, можно:

  • Примените прагмы по умолчанию или другие украшения к категориям данных моделей и функциям точки входа. Для настройки этих параметров по умолчанию используйте редактор Отображения. Для примера можно:

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

    • Применить прагму по умолчанию к категориям сгенерированных функций, включая функции точки входа, такие как model_step.

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

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

Вставьте прагмы при помощи разделов памяти

В этом примере вы конфигурируете размещение памяти по умолчанию для всех данных и функций алгоритма, представленного примером модели rtwdemo_roll. Затем для некоторых данных сигнала вы переопределяете размещение по умолчанию.

Исследуйте модель примера и смотрите Сгенерированный код по умолчанию

  1. Откройте пример модели.

    open_system('rtwdemo_roll')
    

    Модель сконфигурирована, чтобы сгенерировать эффективный производственный код. Например, значение параметра конфигурации Default parameter behavior устанавливается на Inlined.

  2. В Apps галерее под Code generation нажмите Embedded Coder. Откроется вкладка C Code. Сгенерируйте код из модели.

  3. В отчете о генерации кода проверьте файл rtwdemo_roll.h. Файл определяет типы структур, которые представляют данные, необходимые алгоритму. Например, файл задает тип структуры, который представляет состояния блока, такие как состояния Discrete-Time Integrator блоков.

    /* Block signals and states (default storage) for system '<Root>' */
    typedef struct {
      real32_T FixPtUnitDelay1_DSTATE;     /* '<S7>/FixPt Unit Delay1' */
      real32_T Integrator_DSTATE;          /* '<S1>/Integrator' */
      int8_T Integrator_PrevResetState;    /* '<S1>/Integrator' */
    } DW;
    

    Файл также объявляет функции точки входа для модели.

    /* Model entry point functions */
    extern void rtwdemo_roll_initialize(void);
    extern void rtwdemo_roll_step(void);
  4. Осмотрите rtwdemo_roll.c. Этот файл задает переменные глобальной структуры для хранения данных. Файл также определяет функции.

В этом примере предположим, что ваш файл строения linker задает именованные разделы MYALGORITHM_DATA и MYALGORITHM_CODE в SECTIONS директива. Можно сконфигурировать модель так, чтобы сгенерированный код включал прагмы, помещая память, выделенную для данных и функций, в эти именованные разделы.

  • Для глобальной переменной с именем myVarсинтаксис прагмы следующий:

    #pragma SEC_MYALGORITHM_DATA("myVar")
    
    double myVar;

  • Для функции с именем myFunction, синтаксис прагмы тот же, кроме имени раздела:

    #pragma SEC_MYALGORITHM_CODE("myFunction")
    
    void myFunction(void)

Создание разделов памяти

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

  1. Откройте приложение Embedded Coder. На вкладке C Code выберите Code Interface > Embedded Coder Dictionary.

  2. В диалоговом окне Embedded Coder Dictionary выберите вкладку Memory Sections и нажмите кнопку Add.

  3. Для нового раздела памяти установите следующие опции:

    • Name с MYALGORITHM_DATA.

    • Statements Surround с Each variable.

    • Pre Statement с #pragma SEC_MYALGORITHM_DATA("$N"). Область лексемы $N обозначает имя каждой переменной, которая использует раздел памяти.

  4. Создайте другой, аналогичный раздел памяти, который соответствует MYALGORITHM_CODE.

Сконфигурируйте прагмы по умолчанию для данных и функций

  1. На вкладке C Code выберите Code Interface > Default Code Mappings или Code Interface > Individual Element Code Mappings

  2. На вкладке Data Defaults разверните Inports and Outports, Signals и Parameters.

  3. В таблице выберите Inports строку.

  4. В Property Inspector установите Memory Section равным MYALGORITHM_DATA.

  5. Для других строк таблицы установите Memory Section равным MYALGORITHM_DATA.

  6. В разделе Function Defaults для каждой строки таблицы установите Memory Section равным MYALGORITHM_CODE.

  7. В текущей папке удалите существующие slprj папка.

  8. Сконфигурируйте модель, чтобы сгенерировать только код. Выберите параметр конфигурации Configuration Parameters > Generate code only.

  9. Нажмите Generate Code.

Теперь, rtwdemo_roll.c файл применяет прагмы к определениям структурных переменных и функций. Для каждой категории данных и функций, настроенных в редакторе Code Mappings, код применяет прагму. Например, код применяет MYALGORITHM_DATA прагма для каждой из структур, которые хранят состояния блока, входы корневого уровня и выходы корневого уровня.

/* Block signals and states (default storage) */
#pragma SEC_MYALGORITHM_DATA("rtDW")

DW rtDW;

/* External inputs (root inport signals with default storage) */
#pragma SEC_MYALGORITHM_DATA("rtU")

ExtU rtU;

/* External outputs (root outports fed by signals with default storage) */
#pragma SEC_MYALGORITHM_DATA("rtY")

ExtY rtY;

Сохраните раздел памяти по умолчанию после применения класса памяти по умолчанию или шаблона функции

В редакторе Code Mappings можно использовать столбцы Storage Class и Function Customization Template для управления внешним видом данных и функций по умолчанию в сгенерированном коде. Когда вы используете эти столбцы для применения настройки кроме DefaultРедактор Отображения отбрасывает раздел памяти, который вы применили в Property Inspector. Чтобы сохранить раздел памяти, используйте словарь Embedded Coder Dictionary, чтобы создать класс памяти или шаблон функции, а затем примените раздел памяти к этому классу памяти или шаблону функции.

В этом примере вы конфигурируете непараметрические данные модели, такие как сигналы и состояния, так чтобы они появлялись в одной структуре путем создания класса памяти. Чтобы сохранить MYALGORITHM_DATA раздел памяти, вы применяете раздел памяти к классу памяти.

  1. В словаре Embedded Coder для модели выберите вкладку Storage Classes и нажмите кнопку Add.

  2. Для нового класса хранения задайте:

    • Name с STRUCT_DATA.

    • Storage Type с Structured.

    • Memory Section с MYALGORITHM_DATA.

  3. В редакторе Отображения, в разделе Data Defaults, в столбце Storage Class, выберите STRUCT_DATA для следующих строк:

    • Inports

    • Outports

    • Signals, states and internal data

  4. Сгенерируйте код из модели.

  5. Осмотрите rtwdemo_roll.c. Теперь файл задает одну структурную переменную, которая содержит непараметр данные, применяя прагму к этой переменной.

    /* Storage class 'STRUCT_DATA' */
    #pragma SEC_MYALGORITHM_DATA("STRUCT_DATA_rtwdemo_roll")
    
    rtwdemo_roll_STRUCT_DATA STRUCT_DATA_rtwdemo_roll;

Включите раздел памяти по умолчанию в класс памяти для индивидуального отображения

Чтобы переопределить классы памяти по умолчанию, заданные в Code Mappings - C > Data Defaults, примените класс памяти непосредственно к элементу данных с помощью редактора Отображения. Непосредственное применение класса памяти, отличного от Auto или Model default обходит раздел памяти по умолчанию, заданный в Data Defaults. Чтобы сохранить раздел памяти, создайте класс памяти в словаре Embedded Coder Dictionary и примените к нему нужный раздел памяти. Затем примените класс памяти к отдельным элементам данных в редакторе Отображения. Другие модели не могут получить доступ к классу памяти и разделу памяти, которые вы задаете в словаре Embedded Coder. Чтобы поделиться разделами раздела класса памяти и памяти между другими моделями, сохраните словарь Embedded Coder в данных словаря данных Simulink (sldd) вне вашей модели. Затем поделитесь словарем между целевыми моделями. Для получения дополнительной информации смотрите Миграция определений из файла модели в словарь разделяемых данных.

В rtwdemo_roll, в BasicRollMode подсистема, три блока Gain представляют параметры алгоритма управления ПИД. В разделе "Сохранение памяти по умолчанию" После применения класса памяти по умолчанию или шаблона функции "сконфигурируйте непараметрические данные модели, такие как сигналы и состояния, так, чтобы они появились в той же структуре, применив класс памяти по умолчанию STRUCT_DATA. В этом примере вы конфигурируете выходные сигналы блоков Gain так, чтобы сгенерированный код выделял им память в MYALGORITHM_DATA раздел, но не отображается в структуре класса памяти по умолчанию. Определите новый класс памяти myStore в словаре Embedded Coder и примените нужный раздел памяти MYALGORITHM_DATA к нему. Затем непосредственно примените класс памяти к выходным сигналам блоков Gain.

  1. В словаре Embedded Coder Dictionary модели выберите вкладку Storage Classes и нажмите кнопку Add.

  2. Для нового класса хранения задайте:

    • Name с myStore.

    • Storage Type с Structured.

    • Memory Section с MYALGORITHM_DATA.

  3. В модели перейдите в BasicRollMode подсистема. Сигналы подсистемы не заполняются автоматически редактором Отображения. Вам нужно вручную добавить сигналы путем паузы на эллипсисе, который появляется выше или ниже сигнальной линии, чтобы открыть панель действий. Нажмите кнопку Add Signal. Кнопка также доступна в редакторе Отображения на вкладке Signals/States.

  4. После добавления выходных сигналов блоков Gain, строки сигнала появляются на вкладке Code Mappings -C > Signals/States . Откройте Property Inspector, выбрав строки сигнала. В секции кода задайте следующие свойства:

    • Storage Class с myStore.

    • Identifier к именам блоков.

  5. Сгенерируйте код из модели.

  6. Проверьте сгенерированный файл rtwdemo_roll.c. Файл задает структурную переменную myStore_rtwdemo_roll и применяет прагму к переменной.

    /* Storage class 'myStore' */
    #pragma SEC_MYALGORITHM_DATA("myStore_rtwdemo_roll")
    
    rtwdemo_roll_myStore myStore_rtwdemo_roll;

  7. Проверьте сгенерированный файл rtwdemo_roll.h. Структурная переменная содержит выходные сигналы блоков Gain. Сигналы выхода теперь находятся в отличной структуре, но сохранены в том же MYALGORITHM_DATA раздел памяти.

/* Storage class 'myStore', for system '<Root>' */
typedef struct {
  real32_T DispGain;                   /* '<S1>/DispGain' */
  real32_T RateGain;                   /* '<S1>/RateGain' */
  real32_T IntGain;                    /* '<S1>/IntGain' */
} rtwdemo_roll_myStore;

Сконфигурируйте Pragma, чтобы окружать группы определений

Если ваш набор инструментов сборки требует, чтобы прагма или другое украшение окружали сразу несколько определений переменных или функций, в словаре Embedded Coder или Custom Storage Class Designer установите Statements surround Group of variables (значение по умолчанию в Custom Storage Class Designer).

Переопределите размещение памяти по умолчанию для отдельных элементов данных

После настройки параметров раздела памяти по умолчанию в редакторе Отображения (см. «Настройка генерации кода C по умолчанию для категорий элементов данных и функций»), чтобы переопределить эти настройки по умолчанию для отдельных элементов данных (сигналов, параметров и состояний), создайте класс памяти и все необходимые разделы памяти с помощью словаря Embedded Coder. Для получения дополнительной информации смотрите, Выбор места для создания и хранения раздела памяти Определение. Когда вы создаете класс памяти, установите свойство Memory section на соответствующий раздел памяти. Затем используйте редактор Отображения, чтобы применить класс памяти к отдельным элементам данных.

Выберите, где создать и сохранить определение раздела памяти

Чтобы определить раздел памяти, необходимо выбрать, где его создать: в словаре Embedded Coder или в общем словаре Simulink.

  • Если вам нужно использовать раздел памяти только в редакторе Code Mappings, задайте раздел памяти в словаре Embedded Coder.

    Если вам нужно использовать раздел памяти только в редакторе Code Mappings и хотите поделиться им с другими моделями, задайте раздел памяти в словаре данных Simulink ® (sldd). Для получения дополнительной информации смотрите Совместное определение словаря Embedded Coder между моделями.

  • Если вам нужно использовать раздел памяти вне редактора Отображения, задайте раздел памяти в пакете. Для примера задайте разделы памяти в пакете, чтобы сконфигурировать разделы памяти атомарной Подсистемы. Для получения дополнительной информации см. Раздел «Переопределение памяти» для атомарной подсистемы.

Разделите определение раздела памяти между моделями

Переопределите размещение памяти по умолчанию для функций подсистемы и данных

Когда вы используете атомарные подсистемы для разбиения сгенерированного кода на функции (см. «Генерация кода подсистемы как отдельной функции и файлов»), можно применить различные разделы памяти к функциям и данным каждой подсистемы. Можно также указать, что подсистема не использует раздел памяти.

Переопределение секции памяти для атомарной подсистемы

Разделы памяти, которые вы задаете для подсистемы, переопределяют значения по умолчанию уровня модели, заданные в редакторе Отображения. Используйте этот метод для агрегирования данных и кода команды для стандартных подпрограмм или подкомпонентов (представленных подсистемами) в различные области памяти. Чтобы применить раздел памяти непосредственно к атомарной подсистеме, задайте раздел памяти в пакете с помощью Custom Storage Class Designer. Вы не можете использовать раздел памяти, который вы задаете в словаре Embedded Coder. Затем загрузите пакет в модель и сконфигурируйте параметры блоков подсистемы, чтобы задать раздел памяти.

Чтобы создать раздел памяти:

  1. В текущей папке создайте папку с именем +myPackage. Папка определяет пакет с именем myPackage. Для получения дополнительной информации см. раздел «Создание пакета класса данных».

    Чтобы сделать пакет доступным вне текущей папки, вы можете добавить папку, содержащую +myPackage папка в путь MATLAB.

  2. Откройте Custom Storage Class Designer.

    cscdesigner('myPackage');
    
  3. В Custom Storage Class Designer выберите вкладку Memory Section.

  4. Нажмите New.

  5. Для нового раздела памяти установите следующие опции:

    • Name с MYALGORITHM_DATA.

    • Statements surround с Each variable.

    • Pre statement с #pragma SEC_MYALGORITHM_DATA("$N").

  6. Нажмите Apply и Save.

  7. Установите текущую папку в папку, содержащую +myPackage папка.

Для применения раздела памяти в атомарной подсистеме:

  1. Сконфигурируйте словарь Embedded Coder Dictionary модели, чтобы загрузить целевой пакет, как описано в Reference to Генерация Кода Definitions in a Package.

  2. Чтобы сконфигурировать целевую подсистему, чтобы задать раздел памяти, откройте диалоговое окно параметров подсистемы. На вкладке Code Generation:

    • Установите Function packaging значение Nonreusable function или Reusable function (для кода повторного входа).

    • Если вы задаете Function packaging Nonreusable function, чтобы включить строение секций памяти для данных подсистемы, выберите Function with separate data. Если вы не выбираете Function with separate data, данные подсистемы наследуют разделы памяти от модели или, если применимо, родительской подсистемы.

    • Как применить MYALGORITHM_DATA раздел памяти непосредственно к функциям подсистемы и данным, используйте следующие параметры блоков:

      • Memory section for initialize/terminate functions

      • Memory section for execution functions

      • Memory section for constants

      • Memory section for internal data

      • Memory section for parameters

Укажите, что атомарная подсистема не использует раздел памяти

По умолчанию функции подсистемы и данные наследуют разделы памяти уровня модели, которые вы задаете для соответствующих категорий функций и данных в редакторе Отображения. Для примера, если вы задаете шаблон индивидуальной настройки функции для категории Execution, и этот шаблон содержит раздел памяти, раздел памяти применяется к функциям выполнения подсистемы, а также к функциям выполнения точки входа модели.

Чтобы указать, что подсистема не использует раздел памяти, откройте диалоговое окно параметров подсистемы. На вкладке Code Generation установите эти параметры равными Default:

  • Memory section for initialize/terminate functions

  • Memory section for execution functions

  • Memory section for constants

  • Memory section for internal data

  • Memory section for parameters

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

Ограничения и другие факторы

  • Настройки, которые вы задаете для атомарной, не используемой повторно подсистемы с отдельными данными, применяются только к данным и функциям этой подсистемы, а не к данным в аналогично настроенных дочерних подсистемах. Атомарные, не переиспользуемые дочерние подсистемы с отдельными данными могут наследовать разделы памяти от содержащей модели, а не от родительской подсистемы.

  • Если вы используете Build This Subsystem или Build Selected Subsystem, чтобы сгенерировать код для атомарной подсистемы, которая задает разделы памяти, генератор кода игнорирует спецификации уровня подсистемы и использует вместо этого спецификации уровня модели. Для получения информации о создании подсистем смотрите Сгенерировать код и исполняемые файлы для отдельных подсистем.

Совместное использование раздела памяти между пакетами (только разделы памяти пакета)

Пакеты могут получить доступ и использовать разделы памяти, которые определены в других пакетах, включая пользовательские пакеты и встроенные пакеты, такие как Simulink. В пакете, который его определяет, существует только одна копия раздела памяти. Другие пакеты относятся к разделу памяти, указывая на него в его исходном местоположении. Изменения в разделе памяти, включая изменения во встроенном разделе памяти в более позднем MathWorks® релизы продуктов, сразу доступны в каждом ссылочном пакете.

Чтобы сконфигурировать пакет для обращения к разделу памяти, определенному в другом пакете:

  1. Откройте Custom Storage Class Designer. В командной строке введите cscdesigner.

  2. Выберите вкладку Раздел памяти.

  3. Используйте Select Package, чтобы выбрать пакет, в котором вы хотите ссылаться на класс или раздел, определенный в каком-либо другом пакете.

  4. На панели Определения разделов памяти выберите существующее определение, ниже которого необходимо вставить ссылку.

  5. Щелкните Создать ссылку (New Reference).

    Новая ссылка с именем по умолчанию и свойствами появится под ранее выбранным определением. Выбирается новая привязка, и появляется вкладка Ссылка (Reference), показывающая начальные свойства привязки.

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

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

  8. Установите ссылку на раздел памяти, чтобы указать раздел памяти, на который будет ссылаться.

  9. Нажмите кнопку ОК или Применить, чтобы сохранить изменения в памяти. Чтобы сохранить изменения навсегда, нажмите кнопку Save.

Управляйте внешним видом раскрывающегося списка раздела памяти (только разделы памяти пакета)

Когда вы применяете раздел памяти пакета, вы выбираете раздел памяти из выпадающего списка. Чтобы контролировать порядок разделов памяти в списке, в Custom Storage Class Designer используйте кнопки Up и Down. Порядок разделов памяти в раскрывающихся списках совпадает с порядком в Custom Storage Class Designer.

Защитите определения разделов памяти пакета (только разделы памяти пакета)

Когда вы нажимаете Save в Custom Storage Class Designer, Designer сохраняет определения раздела памяти и пользовательских классов памяти в csc_registration.m файл в папке пакета. Чтобы определить местоположение этого файла, в Custom Storage Class Designer проверьте значение Filename.

Можно предотвратить изменения в определениях разделов памяти всего пакета, преобразовав csc_registration.m файл из файла MATLAB в P-файл. Используйте pcode функция.

Лучшая практика - сохранить csc_registration.m и csc_registration.p в папке пакета. Таким образом, если вам нужно изменить разделы памяти с помощью Designer, можно удалить csc_registration.p а затем перегенерируйте его после завершения изменений. Поскольку P-кодированная версия файла имеет приоритет, в то время как оба файла существуют в пакете, разделы памяти защищены.

.

Ограничения

  • Генератор кода не применяет разделы памяти к данным, которые используют эти встроенные классы памяти:

    • ExportedGlobal

    • ImportedExtern

    • ImportedExternPointer

  • В Custom Storage Class Designer определитель типа хранилища, заданный для раздела памяти с помощью Qualifier текстового поля, влияет только на элементы данных, которые используют настройку класса памяти, отличную от этих встроенных классов памяти:

    • ExportedGlobal

    • ImportedExtern

    • ImportedExternPointer

    Генератор кода опускает квалификатор из других категорий данных.

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

Вставьте прагмы для функций и данных в сгенерированный код

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

Исследуйте модель примера

Откройте пример модели.

open_system('rtwdemo_memsec')

  1. Чтобы просмотреть разделы памяти в пакете ECoderDemos, нажмите кнопку Определений разделов памяти» в модели и выберите вкладку «Разделы памяти».

  2. Чтобы сконфигурировать разделы памяти для функций и данных, нажмите кнопку «Сконфигурировать разделы памяти для этой модели». В редакторе Отображения выберите соответствующую строку, а затем укажите разделы памяти в Property Inspector.

  3. Настройки уровня модели являются настройками по умолчанию для атомарных подсистем. Откройте раскрывающиеся списки параметров подсистемы, чтобы увидеть настройки раздела памяти для каждой из атомарных подсистем в модели. Можно переопределить настройку уровня модели по умолчанию, сконфигурировав параметры блоков подсистемы.

  4. Чтобы сгенерировать код, нажмите кнопку Generate Code Using Embedded Coder. Автоматически откроется отчет генерации кода. Смотрите определения данных и функций в .c Файлы и наблюдайте, как сгенерированные прагмы соответствуют заданным разделам памяти.

Похожие темы