Генерация кода для Миландр 1986ВЕ91Т (Бегущие огни)¶
Введение¶
В этом примере рассмотрена генерация кода из модели Engee для микроконтроллера 1986ВЕ91Т от АО "ПКК Миландр". Модель воспроизводит работу "бегущих огней" на отладочной плате микроконтроллера, сборка проекта осуществляется в среде Keil μVision, а загрузка исполняемого кода - через отладчик J-Link.
Аппаратная часть¶
Целевое устройство - микроконтроллер от АО "ПКК Миландр" 1986ВЕ91Т (MDR32F9Q1). В примере используется отладочный модуль для микросхем 1986ВЕ91Т, 1986ВЕ94Т (версия 5):
В примере тестируется работа цифровых выходов PORT_Pin_10
- PORT_Pin_14
порта PORTD
микроконтроллера, которые на отладочной плате соединены со светодиодами VD5 - VD9. Для тестирования работы воспроизведём "бегущий огонь" - последовательное включение и выключение светодиодов. Время включения каждого из светодиодов зададим равным 100 мс.
Описание модели¶
Модель примера - mdr32f9q1_running_lights.engee
. Длительность выдачи высокого уровня сигнала на цифровые выходы устанавливается в модели блоком period_msec
.
Блок Chart
воcпроизводит алгоритм изменения с заданным периодом номера выходного светодиода по порядку. Блок Demultiplexer
по номеру выходного светодиода выдаёт на соответствующий выходной порт единицу. Конечный автомат, реализуемый блоком Chart
, включает в себя пять состояний, циклически поочередно активируемых.
Для перехода между состояниями конечного автомата используется темпоральная логика.
Блоки периферии¶
Блоки PORTD_CONFIG
и PORT1
- PORT5
добавляют в модель код Си для работы с периферией контроллера. Для того чтобы добавить в сгенерированный код строки с подключением необходимых заголовочных файлов, во вкладке Build options
блока PORTD_CONFIG
прописаны имена и путь к подключаемых файлов заголовков. Сами файлы не содержат код и не используются при моделировании. При сборке же проекта подключаемые файлы будут добавлены из пакета поддержки для микроконтроллера.
Блок PORTD_CONFIG
добавляет в сгенерированный из модели код с функциями для инициализации используемых в проекте портов, а блоки PORT1
- PORT5
- код с функциями для установки и сброса активного состояния соответствующих цифровых пинов.
Содержимое кодовых ячеек периферийных блоков "обёрнуто" в условные директивы препроцессора:
#if defined ( USE_MDR1986VE9x )
// пользовательский код
#endif
Это позволяет выполнять код из блоков только на определенных целевых устройствах, игнорируя его, например, при моделировании в Engee.
Результаты моделирования¶
Загрузим и выполним модель примера:
# @markdown **Программное управление моделированием:**
# @markdown Требуется ввести только имя модели
имя_модели = "mdr32f9q1_running_lights" # @param {type:"string"}
if имя_модели in [m.name for m in engee.get_all_models()]
модель = engee.open( имя_модели );
else
модель = engee.load( "$(@__DIR__)/"*имя_модели*".engee" );
end
данные = engee.run(модель);
Построим графики выходных переменных. Сигналы единичных импульсов по каналам отмасштабируем для наглядности:
gr(size = (900,400))
plot(данные["channel"].time, [данные["channel"].value, 1.05.*данные["vd5"].value,
1.1.*данные["vd6"].value, 1.15.*данные["vd7"].value, 1.2.*данные["vd8"].value, 1.25.*данные["vd9"].value,];
label=[:none "vd5" "vd6" "vd7" "vd8" "vd9"], title="Бегущие огни", st = :step)
Как видно из графиков, конечный автомат и демультиплексор отрабатывают заданный алгоритм, формируя последовательно импульсы на пять каналов с заданной длительностью.
Генерация кода¶
Сгенерируем код из разработанной модели.
# @markdown **Генерация кода:**
# @markdown Папка для результатов генерации кода будет создана в папке скрипта:
папка = "code" # @param {type:"string"}
# @markdown Генерация кода для подсистемы:
включить = false # @param {type:"boolean"}
if(включить)
подсистема = "" # @param {type:"string"}
engee.generate_code( "$(@__DIR__)/"*имя_модели*".engee", "$(@__DIR__)/"*папка;
subsystem_name = подсистема)
else
engee.generate_code( "$(@__DIR__)/"*имя_модели*".engee", "$(@__DIR__)/"*папка)
end
# @markdown Генерировать `main.c`?
использовать = false # @param {type:"boolean"}
if (!использовать)
cd("$(@__DIR__)/"*папка)
rm("main.c")
end
Так как в проекте будет использоваться готовый main.c
, для устранения путаницы кодовая ячейка выше удаляет сгенерированный из модели шаблон main.c
. Готовый main.c
и сгенерированные из модели файлы теперь необходимо добавить в проект среды разработки Keil μVision.
Состав проекта¶
Для работы с микроконтроллером в среде разработке необходимо установить пакет поддержки. Для этого примера мы использовали неофициальный пакет поддержки.
Далее следуют стандартные шаги при работе в Keil μVision. - создание проекта, добавление файлов источников для необходимой периферии и файлов заголовков для конфигурации устройства, а также настройка сборщика и дебаггера. После этого скачаем файлы примера из папки \code
, а также main.c
и добавим их в проект Keil.
Далее можно перейти к сборке проекта и загрузке/отладке кода.
Сборка проекта и загрузка кода¶
Соберём проект Keil, после чего в терминале среды должно быть выведено аналогичное сообщение:
Build started: Project: new_project_1
*** Using Compiler 'V6.22', folder: 'C:\Users\engeeuser\AppData\Local\Keil_v5\ARM\ARMCLANG\Bin'
Build target 'Target_1'
compiling main.c...
mdr32f9q1_running_lights.c(49): warning: variable 'seq' is uninitialized when used here [-Wuninitialized]
49 | cfunc_symbols->seq = seq;
| ^~~
mdr32f9q1_running_lights.c(44): note: initialize the variable 'seq' to silence this warning
44 | int8_t seq;
| ^
| = '\0'
mdr32f9q1_running_lights.c(291): warning: comparison of integers of different signs: 'int64_t' (aka 'long long') and 'uint64_t' (aka 'unsigned long long') [-Wsign-compare]
291 | return counter * numerator >= (uint64_t)ceil(condition * denominator);
| ~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
mdr32f9q1_running_lights.c(338): warning: unused variable 'seq' [-Wunused-variable]
338 | double seq = PORTD_CONFIG_cfunc_symbols.seq;
| ^~~
mdr32f9q1_running_lights.c(351): warning: variable 'Chart_selector' set but not used [-Wunused-but-set-variable]
351 | int Chart_selector;
| ^
4 warnings generated.
compiling mdr32f9q1_running_lights.c...
linking...
Program Size: Code=5264 RO-data=224 RW-data=16 ZI-data=1672
".\Objects\new_project_1.axf" - 0 Error(s), 4 Warning(s).
Build Time Elapsed: 00:00:00
Сборка прошла без ошибок, перейдём к загрузке кода в микроконтроллер. Подключим питание платы и JTAG-отладчик. В данном примере - это SEGGER J-link.
В случае успешной загрузки исполняемого кода в микроконтроллер в командной строке среды будет выведено аналогичное сообщение:
Load "D:\\HARDWARE\\Milandr\\new_project_1\\Objects\\new_project_1.axf"
* JLink Info: Device "CORTEX-M3" selected.
Set JLink Project File to "D:\HARDWARE\Milandr\new_project_1\JLinkSettings.ini"
* JLink Info: Device "CORTEX-M3" selected.
JLink info:
------------
DLL: V8.12a, compiled Jan 9 2025 14:34:24
Firmware: J-Link ARM V8 compiled Nov 28 2014 13:44:46
Hardware: V8.00
Feature(s) : RDI,FlashDL,FlashBP,JFlash,GDB
* JLink Info: Found SW-DP with ID 0x2BA01477
* JLink Info: DPv0 detected
* JLink Info: CoreSight SoC-400 or earlier
* JLink Info: Scanning AP map to find all available APs
* JLink Info: AP[1]: Stopped AP scan as end of AP map has been reached
* JLink Info: AP[0]: AHB-AP (IDR: 0x24770011, ADDR: 0x00000000)
* JLink Info: Iterating through AP map to find AHB-AP to use
* JLink Info: AP[0]: Core found
* JLink Info: AP[0]: AHB-AP ROM base: 0xE00FF000
* JLink Info: CPUID register: 0x412FC230. Implementer code: 0x41 (ARM)
* JLink Info: Found Cortex-M3 r2p0, Little endian.
* JLink Info: FPUnit: 6 code (BP) slots and 2 literal slots
* JLink Info: CoreSight components:
* JLink Info: ROMTbl[0] @ E00FF000
* JLink Info: [0][0]: E000E000 CID B105E00D PID 002BB000 SCS
* JLink Info: [0][1]: E0001000 CID B105E00D PID 002BB002 DWT
* JLink Info: [0][2]: E0002000 CID B105E00D PID 002BB003 FPB
* JLink Info: [0][3]: E0000000 CID B105E00D PID 002BB001 ITM
* JLink Info: [0][4]: E0040000 CID B105900D PID 002BB923 TPIU-Lite
ROMTableAddr = 0xE00FF000
* JLink Info: Reset type: NORMAL (https://wiki.segger.com/J-Link_Reset_Strategies)
* JLink Info: Reset: Halt core after reset via DEMCR.VC_CORERESET.
* JLink Info: Reset: Reset device via AIRCR.SYSRESETREQ.
Target info:
------------
Device: MDR1986BE91
VTarget = 3.319V
State of Pins:
TCK: 1, TDI: 1, TDO: 0, TMS: 1, TRES: 1, TRST: 1
Hardware-Breakpoints: 6
Software-Breakpoints: 8192
Watchpoints: 4
JTAG speed: 2000 kHz
* JLink Info: Memory map 'after startup completion point' is active
Full Chip Erase Done.
Programming Done.
Verify OK.
* JLink Info: Memory map 'before startup completion point' is active
* JLink Info: Reset type: NORMAL (https://wiki.segger.com/J-Link_Reset_Strategies)
* JLink Info: Reset: Halt core after reset via DEMCR.VC_CORERESET.
* JLink Info: Reset: Reset device via AIRCR.SYSRESETREQ.
* JLink Info: Memory map 'after startup completion point' is active
Application running ...
Flash Load finished at 10:40:49
Выполнение кода на микроконтроллере¶
После загрузки код автоматически запускается на контроллере, в чём можно убедиться по бегущим огням на плате:
Загруженный код выполняет заданный моделью Engee алгоритм.
Вывод¶
В этом примере мы разработали модель Engee, воспроизводящую алгоритм "бегущих огней" с использованием библиотеки конечных автоматов Engee и темпоральных операторов, сгенерировали код из модели и проверили его работу на микроконтроллере Миландр 1986ВЕ91Т, собрав проект и загрузив его в устройство из среды Keil μVision.