Retain Variables: RETAIN is a reserved keyword in IEC61131-3. In TwinCAT 3 RETAIN is reserved. If RETAIN is used a compile error will be generated automatically. Use PERSISTENT instead.
Синоним NOVRAM
Интересным нововведением в TwinCAT 3.1.4020 стало автоматическое сохранение переменных, объявленных как VAR RETAIN, в области NOVRAM. Если в TwinCAT 2 необходимо вручную линковать ПЛК переменную с аналогичной в NOVRAM ветке, либо вызывать специализирванный ФБ, то теперь достаточно указать системе на наличие таких переменных вообще, а все остальное TwinCAT сделает сам: отследит изменения, сохранит и восстановит данные в случае провала электропитания.
NOVRAM состоит из двух областей памяти, одна — оперативная и энергоЗАвисимая, другая область — длительного хранения и энергоНЕзависимая. Оперативная часть питается от источника питания ПЛК. Когда электричество пропадает, энергия, накопленная в ионисторе, дает дополнительные несколько секунд работоспособности для сброса данных из оперативной части NOVRAM в ее энергонезависимую флэш часть. Таким образом экономится ресурс флэш памяти NOVRAM (постоянное обновление и перезапись данных происходит только в оперативной части). При восстановлении электропитания, данные переписываются из постоянной половины в оперативную.
Минимальный размер NOVRAM составляет 128 килобайт, но для энергонезависимого хранения будет доступно только 64Кб (65504 байта): вторая половина оперативная и мы имеем доступ только к ней (половине всего объема NOVRAM). В то же время NOVRAM может быть опционально расширен до 512 килобайт (будет доступно для хранения 256Кб), но обойдется это в чуть меньше, чем 499 евро, поэтому для таких объемов можно использовать PERSISTENT. Подробнее об этом можно прочитать в статье с кратким названием NOVRAM.
Retain Handler
Для проверки я использовал следующую конфигурацию:
- ПЛК: CX2030 XAR TwinCAT 3.1.4020.32
- Среда разработки: XAE TwinCAT 3.1.4020.32
В общем случае последовательность действий такая:
- При сканировании конфигурации оставьте "галку" для включения устройства NOV-DP-RAM в конфигурацию.
- После сканирования добавьте к этому устройству — Beckhoff Automation GmbH → Retain Handler.
- Необходимые для автоматического сохранения переменные объявляейте как VAR RETAIN.
- Соберите проект (Build Solution).
- Предположим, что проект называется Untitled1. Ткните мышой в Untitled1 Instance (смотрите на картинку с деревом проекта выше).
- В закладке Data Area в столбце Retain Hdl для PlcTask Retains выберите из выпадающего списка созданный на шаге (2) соответствующий Retain Handler.
Все переменные ПЛК-проекта, обозначенные как RETAIN, теперь будут контролироваться TwinCAT. Причем не важно сколько у вас программ и подпрограмм — все переменные будут сохраняться и восстанавливаться с помощью одной области NOVRAM.
При удалении RETAIN переменных из программы, необходимо очистить и пересобрать проект, а затем вручную обновить NOVRAM. Для этого кликните правой кнопкой мыши по Retain Handler в разделе конфигурации NOV-DP-RAM, затем пункт Optimize Retain Variables. Это официальная рекомендация справочной системы. Неофициальная — удалите Retain Handler, очистите и пересоберите проект, а затем повторите все шаги начиная со второго (2).
Многозадачность
Как будет вести себя область памяти NOVRAM, если в проекте несколько "рантаймов", то есть несколько, параллельно работающих задач? Начнем с того, что для каждой задачи необходимо персонально назначить область памяти Retain Hdl. Этот шаг ничем не отличается от описанного выше.
В общем случае, TwinCAT различает задачи по номеру их ADS-порта: 851, 852, ... И даже если в разных задачах будут совпадать имена переменных, функциональных блоков или программ, номер порта задачи по прежнему будет отличать переменную от ее тезки в другой задаче.Несмотря на то, что область памяти NOVRAM одна на все задачи, XAE спокойно и равномерно распределяет все переменные RETAIN всех задач по единственной области памяти NOVRAM. При условии, что этой памяти достаточно.
Посмотрите на адресацию (Address) и номер порта в [квадратных скобках] поля Name:
Быстродействие
На копирование данных все-равно будет затрачиваться какое-то время. В статье Note the write speed of the Retain Handler утверждается, что на 512Кб (a это максимум для NOVRAM, на данный момент) потребуется около 3,6 миллисекунды (3600 мкс). На 8Кб около 0,4 миллисекунды (400 мкс). При стандартном цикле ПЛК задачи в 10 миллисекунд — это очень даже неплохие показатели, но я все-равно проверил.
Для начала, у меня под рукой был только "толстый" ПЛК CX2030 с быстрым процессором и "широкой" шиной. Это плохо, так как он всегда быстрый, но пока только так. На контроллере установлен минимальный NOVRAM объемом 128Кб, поэтому XAE при сборке ограничила меня 65504 байтами.
Первое замечание: очень долгая сборка проекта для массива из 64000 ячеек BYTE и быстрая сборка для 8000 ячеек LREAL. Возможно, на продолжительность сборки влияет количество переменных, так как объем данных у меня не менялся. Вероятно XAE пытается вставить в дерево проекта каждую ячейку массива по отдельности, что дает неслабую нагрузку на процессор-память.
В итоге, как и ожидалось, получилось очень быстро и практически никакой нагрузки на процессор:
- Ожидание — 213,7 микросекунд на цикл. Заполнение массива varPack и ожидание команды start (читайте Приложение ниже).
- Сохранение — 245,2 микросекунд на 64Кб данных. Заполнение массива retPack и сохранения в NOVRAM.
Какая-то нагрузка видна, но она практически не заметна — нужен ПЛК помедленнее. Пока же буду считать, что RETAIN вполне себе полезная вещь, хотя бы для критических настроек.
Приложение
Для черновых испытаний использовались два массива: один (varPack) я изменял постоянно, но не сохранял в NOVRAM, другой же (retPack) изменялся по требованию (start) и, следовательно, в этом же цикле сохранялся системой в NOVRAM. Попеременное использование двух массивов позволяет исключить из тестирования производительности затраты на заполнение массива данными (занимает порядка 180 микросекунд).
PROGRAM MAIN VAR counter : UINT; i : UINT; start : BOOL; Max100ns : UDINT; varPack : ARRAY [1..HOWMANYRETS] OF LREAL; END_VAR VAR RETAIN retPack : ARRAY [1..HOWMANYRETS] OF LREAL; END_VAR VAR CONSTANT HOWMANYRETS : UINT := 8000; END_VAR [...] counter := counter + 1; Max100ns := MAX(_TaskInfo[1].LastExecTime, Max100ns); IF start THEN start := FALSE; FOR i := 1 TO HOWMANYRETS DO retPack[i] := counter + i; END_FOR ELSE FOR i := 1 TO HOWMANYRETS DO varPack[i] := counter + i; END_FOR END_IF
Длительность работы цикла берется из глобальной системной структуры _TaskInfo[1].LastExecTime в 100 наносекундных интервалах.