Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 0.0% 0 / 0 / 8
Functions: -% 0 / 0 / 0
Branches: -% 0 / 0 / 0

OMCompiler/Compiler/Template/CodegenESP32.tpl
Line Branch Exec Source
1 /*
2 * This file is part of OpenModelica.
3 *
4 * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC),
5 * c/o Linköpings universitet, Department of Computer and Information Science,
6 * SE-58183 Linköping, Sweden.
7 *
8 * All rights reserved.
9 *
10 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR
11 * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8.
12 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
13 * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL
14 * VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
15 *
16 * The OpenModelica software and the OSMC (Open Source Modelica Consortium)
17 * Public License (OSMC-PL) are obtained from OSMC, either from the above
18 * address, from the URLs:
19 * http://www.openmodelica.org or
20 * https://github.com/OpenModelica/ or
21 * http://www.ida.liu.se/projects/OpenModelica,
22 * and in the OpenModelica distribution.
23 *
24 * GNU AGPL version 3 is obtained from:
25 * https://www.gnu.org/licenses/licenses.html#GPL
26 *
27 * This program is distributed WITHOUT ANY WARRANTY; without
28 * even the implied warranty of MERCHANTABILITY or FITNESS
29 * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
30 * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
31 *
32 * See the full OSMC Public License conditions for more details.
33 *
34 */
35
36 // This file defines templates for transforming Modelica models into an
37 // ESP-IDF project that can be built and flashed onto an ESP32 board
38 // (developed for and tested on the ESP32-C6).
39 //
40 // The generated project is self contained: it has no dependency on the
41 // OpenModelica simulation runtime and no dependency on the FMI headers. The
42 // equations, functions and expressions are the same ones the experimental
43 // embedded C target generates, which is why most of the low level templates
44 // are imported from CodegenEmbeddedC instead of being duplicated here.
45 //
46 // Four templates are called by the code generator, one per generated file:
47 //
48 // projectCMakeFile <prefix>_esp32/CMakeLists.txt
49 // componentCMakeFile <prefix>_esp32/main/CMakeLists.txt
50 // sdkconfigFile <prefix>_esp32/sdkconfig.defaults
51 // modelHeaderFile <prefix>_esp32/main/<prefix>_model.h
52 // modelSourceFile <prefix>_esp32/main/<prefix>_model.c
53 // appMainFile <prefix>_esp32/main/main.c
54 // readmeFile <prefix>_esp32/README.md
55
56 package CodegenESP32
57
58 import interface SimCodeTV;
59 import interface SimCodeBackendTV;
60
61 import CodegenUtil.*;
62 import CodegenUtilSimulation.*;
63 import CodegenEmbeddedC.*;
64
65 ✗ template projectCMakeFile(SimCode simCode)
66 "Top level CMakeLists.txt of the generated ESP-IDF project."
67 ::=
68 let modelNamePrefixStr = modelNamePrefix(simCode)
69 match simCode
70 case simCode as SIMCODE(modelInfo=MODELINFO(__)) then
71 <<
72 # Generated by OpenModelica from <%dotPath(modelInfo.name)%>
73 cmake_minimum_required(VERSION 3.16)
74
75 include($ENV{IDF_PATH}/tools/cmake/project.cmake)
76 project(<%modelNamePrefixStr%>_esp32 C)
77 >>
78 end projectCMakeFile;
79
80 ✗ template componentCMakeFile(SimCode simCode)
81 "CMakeLists.txt of the main component of the generated ESP-IDF project."
82 ::=
83 let modelNamePrefixStr = modelNamePrefix(simCode)
84 <<
85 # Generated by OpenModelica
86 idf_component_register(SRCS "main.c" "<%modelNamePrefixStr%>_model.c"
87 INCLUDE_DIRS ".")
88 >>
89 end componentCMakeFile;
90
91 ✗ template sdkconfigFile(SimCode simCode)
92 "sdkconfig.defaults of the generated ESP-IDF project."
93 ::=
94 <<
95 # Generated by OpenModelica
96 # The chip the model is built for. Override with `idf.py set-target <chip>`.
97 CONFIG_IDF_TARGET="esp32c6"
98 # Print the results on UART0, which is the port the USB-serial bridge of the
99 # devkit is wired to, and therefore the same port the board is flashed over.
100 # Replace this with CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y to print them on the
101 # built in USB-Serial-JTAG port instead, which enumerates as a port of its own.
102 CONFIG_ESP_CONSOLE_UART_DEFAULT=y
103 # The reduced formatting of newlib-nano does not print doubles, and the whole
104 # output of the simulation is doubles.
105 CONFIG_NEWLIB_NANO_FORMAT=n
106 # The model is solved in floating point, so keep the FPU related optimizations
107 # and compile for speed rather than for size.
108 CONFIG_COMPILER_OPTIMIZATION_PERF=y
109 >>
110 end sdkconfigFile;
111
112 ✗ template modelHeaderFile(SimCode simCode)
113 "Public interface of the generated model, used by main.c."
114 ::=
115 let modelNamePrefixStr = modelNamePrefix(simCode)
116 match simCode
117 case simCode as SIMCODE(simulationSettingsOpt=NONE()) then
118 error(sourceInfo(), "Missing simulation settings")
119 case simCode as SIMCODE(modelInfo=MODELINFO(varInfo=varInfo as VARINFO(__)),
120 simulationSettingsOpt=SOME(settings as SIMULATION_SETTINGS(__))) then
121 <<
122 /* Generated by OpenModelica from <%dotPath(modelInfo.name)%> */
123 #ifndef OM_<%modelNamePrefixStr%>_MODEL_H
124 #define OM_<%modelNamePrefixStr%>_MODEL_H
125
126 #define OM_MODEL_NAME "<%dotPath(modelInfo.name)%>"
127 #define OM_START_TIME (<%settings.startTime%>)
128 #define OM_STOP_TIME (<%settings.stopTime%>)
129 #define OM_STEP_SIZE (<%settings.stepSize%>)
130 #define OM_NUM_REAL (<%nVariablesReal(varInfo)%>)
131
132 /* The same scalar types the embedded C target uses, so that the equations and
133 the functions below are generated by the very same templates. They are
134 spelled out here instead of being included from fmi2TypesPlatform.h to keep
135 the generated project free of any OpenModelica include path. */
136 typedef double fmi2Real;
137 typedef int fmi2Integer;
138 typedef int fmi2Boolean;
139 typedef char fmi2Char;
140 typedef const fmi2Char* fmi2String;
141
142 #define fmi2True 1
143 #define fmi2False 0
144
145 typedef enum {
146 fmi2OK = 0,
147 fmi2Warning,
148 fmi2Discard,
149 fmi2Error,
150 fmi2Fatal,
151 fmi2Pending
152 } fmi2Status;
153
154 typedef struct <%symbolName(modelNamePrefixStr,"fmi2Component_s")%>* fmi2Component;
155
156 /* Names of the real variables, in the order <%symbolName(modelNamePrefixStr,"getReal")%>
157 indexes them: the states first, then the state derivatives, then the
158 algebraic and the discrete real variables. */
159 extern const char * const <%symbolName(modelNamePrefixStr,"realNames")%>[OM_NUM_REAL];
160
161 /* The single statically allocated instance of the model. There is no heap
162 allocation anywhere in the generated code. */
163 fmi2Component <%symbolName(modelNamePrefixStr,"instantiate")%>(void);
164 /* Sets the time and evaluates the equations once, so that the variables are
165 consistent before the first step is taken. */
166 fmi2Status <%symbolName(modelNamePrefixStr,"initialize")%>(fmi2Component comp, fmi2Real startTime);
167 /* One explicit Euler step of size stepSize, taken from currentTime. */
168 fmi2Status <%symbolName(modelNamePrefixStr,"step")%>(fmi2Component comp, fmi2Real currentTime, fmi2Real stepSize);
169 fmi2Real <%symbolName(modelNamePrefixStr,"getTime")%>(fmi2Component comp);
170 fmi2Real <%symbolName(modelNamePrefixStr,"getReal")%>(fmi2Component comp, int index);
171
172 #endif /* OM_<%modelNamePrefixStr%>_MODEL_H */
173 >>
174 end modelHeaderFile;
175
176 ✗ template modelSourceFile(SimCode simCode)
177 "The model itself: state, equations and the fixed step solver."
178 ::=
179 let modelNamePrefixStr = modelNamePrefix(simCode)
180 match simCode
181 case simCode as SIMCODE(simulationSettingsOpt=NONE()) then
182 error(sourceInfo(), "Missing simulation settings")
183 case simCode as SIMCODE(modelInfo=MODELINFO(functions=functions, varInfo=varInfo as VARINFO(__), vars=vars as SIMVARS(__)),
184 extObjInfo=extObjInfo as EXTOBJINFO(vars=extObjVars),
185 simulationSettingsOpt=SOME(settings as SIMULATION_SETTINGS(__))) then
186 <<
187 /* Generated by OpenModelica from <%dotPath(modelInfo.name)%> */
188 #include "<%modelNamePrefixStr%>_model.h"
189
190 #include <math.h>
191 #include <stdarg.h>
192 #include <stdio.h>
193
194 void ModelicaFormatMessage(const char *fmt, ...)
195 {
196 va_list args;
197 va_start(args, fmt);
198 vprintf(fmt, args);
199 va_end(args);
200 }
201
202 struct <%symbolName(modelNamePrefixStr,"fmi2Component_s")%> {
203 fmi2Real currentTime;
204 <% match nVariablesReal(varInfo)
205 case 0 then ""
206 case n then 'fmi2Real fmi2RealVars[<%n%>];<%\n%>'
207 %><% match varInfo.numIntAlgVars
208 case 0 then ""
209 case n then 'fmi2Integer fmi2IntegerVars[<%n%>];<%\n%>'
210 %><% match varInfo.numBoolAlgVars
211 case 0 then ""
212 case n then 'fmi2Boolean fmi2BooleanVars[<%n%>];<%\n%>'
213 %><% match varInfo.numStringAlgVars
214 case 0 then ""
215 else error(sourceInfo(), "String variables not supported yet")
216 %><% match varInfo.numParams
217 case 0 then ""
218 case n then 'fmi2Real fmi2RealParameter[<%n%>];<%\n%>'
219 %><% match varInfo.numIntParams
220 case 0 then ""
221 case n then 'fmi2Integer fmi2IntegerParameter[<%n%>];<%\n%>'
222 %><% match varInfo.numBoolParams
223 case 0 then ""
224 case n then 'fmi2Boolean fmi2BooleanParameter[<%n%>];<%\n%>'
225 %><% match listLength(extObjVars)
226 case 0 then ""
227 case n then 'void* extObjs[<%n%>];<%\n%>'
228 %>
229 };
230
231 static struct <%symbolName(modelNamePrefixStr,"fmi2Component_s")%> <%symbolName(modelNamePrefixStr,"component")%> = {
232 .currentTime = <%settings.startTime%>,
233 <% match nVariablesReal(varInfo)
234 case 0 then ""
235 else
236 <<
237 .fmi2RealVars = {
238 <%vars.stateVars |> var => startValue(var) %>
239 <%vars.derivativeVars |> var => startValue(var) %>
240 <%vars.algVars |> var => startValue(var) %>
241 <%vars.discreteAlgVars |> var => startValue(var) %>
242 <%vars.realOptimizeConstraintsVars |> var => startValue(var) %>
243 <%vars.realOptimizeFinalConstraintsVars |> var => startValue(var) %>
244 },<%\n%>
245 >>
246 %><% match varInfo.numIntAlgVars
247 case 0 then ""
248 else
249 <<
250 .fmi2IntegerVars = {
251 <%vars.intAlgVars |> var => startValue(var) %>
252 },<%\n%>
253 >>
254 %><% match varInfo.numBoolAlgVars
255 case 0 then ""
256 else
257 <<
258 .fmi2BooleanVars = {
259 <%vars.boolAlgVars |> var => startValue(var) %>
260 },<%\n%>
261 >>
262 %><% match varInfo.numParams
263 case 0 then ""
264 else
265 <<
266 .fmi2RealParameter = {
267 <%vars.paramVars |> var => startValue(var) %>
268 },<%\n%>
269 >>
270 %><% match varInfo.numIntParams
271 case 0 then ""
272 else
273 <<
274 .fmi2IntegerParameter = {
275 <%vars.intParamVars |> var => startValue(var) %>
276 },<%\n%>
277 >>
278 %><% match varInfo.numBoolParams
279 case 0 then ""
280 else
281 <<
282 .fmi2BooleanParameter = {
283 <%vars.boolParamVars |> var => startValue(var) %>
284 },<%\n%>
285 >>
286 %>
287 };
288
289 const char * const <%symbolName(modelNamePrefixStr,"realNames")%>[OM_NUM_REAL] = {
290 <%vars.stateVars |> var => realVarName(var) %>
291 <%vars.derivativeVars |> var => realVarName(var) %>
292 <%vars.algVars |> var => realVarName(var) %>
293 <%vars.discreteAlgVars |> var => realVarName(var) %>
294 <%vars.realOptimizeConstraintsVars |> var => realVarName(var) %>
295 <%vars.realOptimizeFinalConstraintsVars |> var => realVarName(var) %>
296 };
297
298 /* TODO: Generate used builtin functions before SimCode */
299 static inline double om_mod(double x, double y)
300 {
301 return x-floor(x/y)*y;
302 }
303
304 <%functionsFile(functions, literals, externalFunctionIncludes)%>
305
306 /* Evaluates every equation of the model for the current time and the current
307 state, which leaves both the state derivatives and the algebraic variables
308 up to date. */
309 static fmi2Status <%symbolName(modelNamePrefixStr,"functionEquations")%>(fmi2Component comp)
310 {
311 <% match allEquations
312 case {} then ""
313 case {eqs} then (eqs |> eq => equation_(eq); separator="\n")
314 else (allEquations |> eqs => (eqs |> eq => equation_(eq); separator="\n"); separator="\n")
315 %>
316 return fmi2OK;
317 }
318
319 fmi2Component <%symbolName(modelNamePrefixStr,"instantiate")%>(void)
320 {
321 return &<%symbolName(modelNamePrefixStr,"component")%>;
322 }
323
324 fmi2Status <%symbolName(modelNamePrefixStr,"initialize")%>(fmi2Component comp, fmi2Real startTime)
325 {
326 comp->currentTime = startTime;
327 <%callExternalObjectConstructors(extObjInfo)%>
328 return <%symbolName(modelNamePrefixStr,"functionEquations")%>(comp);
329 }
330
331 fmi2Status <%symbolName(modelNamePrefixStr,"step")%>(fmi2Component comp, fmi2Real currentTime, fmi2Real stepSize)
332 {
333 fmi2Status status;
334 comp->currentTime = currentTime;
335 /* The derivatives are evaluated before the states are advanced, which makes
336 the step below a plain explicit Euler step. */
337 status = <%symbolName(modelNamePrefixStr,"functionEquations")%>(comp);
338 if (status != fmi2OK) {
339 return status;
340 }
341 <%match varInfo.numStateVars
342 case 0 then ""
343 else
344 <<
345 {
346 int i;
347 for (i=0; i<<%varInfo.numStateVars%>; i++) {
348 comp->fmi2RealVars[i] += comp->fmi2RealVars[i+<%varInfo.numStateVars%>]*stepSize;
349 }
350 }
351 >>
352 %>
353 comp->currentTime = currentTime + stepSize;
354 /* Report the algebraic variables at the time the states were advanced to. */
355 return <%symbolName(modelNamePrefixStr,"functionEquations")%>(comp);
356 }
357
358 fmi2Real <%symbolName(modelNamePrefixStr,"getTime")%>(fmi2Component comp)
359 {
360 return comp->currentTime;
361 }
362
363 fmi2Real <%symbolName(modelNamePrefixStr,"getReal")%>(fmi2Component comp, int index)
364 {
365 <% match nVariablesReal(varInfo)
366 case 0 then
367 <<
368 (void)comp;
369 (void)index;
370 return 0.0;
371 >>
372 else
373 <<
374 if (index < 0 || index >= OM_NUM_REAL) {
375 return 0.0;
376 }
377 return comp->fmi2RealVars[index];
378 >>
379 %>
380 }
381 >>
382 end modelSourceFile;
383
384 ✗ template realVarName(SimVar var)
385 "One entry of the name table of the real variables."
386 ::=
387 match var
388 case SIMVAR(__) then '"<%Util.escapeModelicaStringToCString(CodegenUtil.crefStr(name))%>",<%\n%>'
389 end realVarName;
390
391 ✗ template appMainFile(SimCode simCode)
392 "The ESP-IDF application: runs the model in a task and prints the results."
393 ::=
394 let modelNamePrefixStr = modelNamePrefix(simCode)
395 match simCode
396 case simCode as SIMCODE(modelInfo=MODELINFO(__)) then
397 <<
398 /* Generated by OpenModelica from <%dotPath(modelInfo.name)%> */
399 #include <stdio.h>
400 #include <stdint.h>
401 #include <unistd.h>
402
403 #include "freertos/FreeRTOS.h"
404 #include "freertos/task.h"
405 #include "esp_timer.h"
406
407 #include "<%modelNamePrefixStr%>_model.h"
408
409 /* Print one line every OM_PRINT_EVERY steps. Printing every step of a model
410 solved with a small step size floods the console and slows the solver down
411 more than the solver itself costs. */
412 #ifndef OM_PRINT_EVERY
413 #define OM_PRINT_EVERY 1
414 #endif
415
416 /* Run the simulation in real time, that is, spend OM_STEP_SIZE seconds of
417 wall clock time on every step. Set it to 0 to solve as fast as the chip
418 can, which is what you want when the results are only printed. */
419 #ifndef OM_REALTIME
420 #define OM_REALTIME 0
421 #endif
422
423 /* Solve forever instead of stopping at OM_STOP_TIME. */
424 #ifndef OM_RUN_FOREVER
425 #define OM_RUN_FOREVER 0
426 #endif
427
428 /* The stack of the task the model is solved in. Every variable of the model
429 is statically allocated, so this only has to hold the function calls. */
430 #ifndef OM_TASK_STACK_SIZE
431 #define OM_TASK_STACK_SIZE 8192
432 #endif
433
434 /* Hand the CPU back at least this often, in microseconds, so that the idle
435 task gets to run and feed the task watchdog. How many steps that is depends
436 on the model and on how fast the results are printed, which is why it is a
437 time and not a number of steps. */
438 #ifndef OM_YIELD_INTERVAL_US
439 #define OM_YIELD_INTERVAL_US 200000
440 #endif
441
442 static void om_print_header(void)
443 {
444 int i;
445 printf("time");
446 for (i=0; i<OM_NUM_REAL; i++) {
447 printf(",%s", <%symbolName(modelNamePrefixStr,"realNames")%>[i]);
448 }
449 printf("\n");
450 }
451
452 static void om_print_values(fmi2Component comp)
453 {
454 int i;
455 printf("%g", (double)<%symbolName(modelNamePrefixStr,"getTime")%>(comp));
456 for (i=0; i<OM_NUM_REAL; i++) {
457 printf(",%g", (double)<%symbolName(modelNamePrefixStr,"getReal")%>(comp, i));
458 }
459 printf("\n");
460 }
461
462 static void om_simulation_task(void *arg)
463 {
464 fmi2Component comp;
465 fmi2Status status = fmi2OK;
466 double time = OM_START_TIME;
467 const double h = OM_STEP_SIZE;
468 uint32_t step = 0;
469 int64_t wallClockStart;
470 int64_t lastYield;
471
472 (void)arg;
473
474 comp = <%symbolName(modelNamePrefixStr,"instantiate")%>();
475 if (comp == NULL) {
476 printf("Failed to instantiate " OM_MODEL_NAME "\n");
477 vTaskDelete(NULL);
478 return;
479 }
480
481 printf("# OpenModelica " OM_MODEL_NAME " on %s\n", CONFIG_IDF_TARGET);
482 <%symbolName(modelNamePrefixStr,"initialize")%>(comp, OM_START_TIME);
483 om_print_header();
484 om_print_values(comp);
485
486 wallClockStart = esp_timer_get_time();
487 lastYield = wallClockStart;
488
489 while (OM_RUN_FOREVER || time < OM_STOP_TIME) {
490 status = <%symbolName(modelNamePrefixStr,"step")%>(comp, time, h);
491 if (status != fmi2OK) {
492 printf("# step failed at time %g\n", time);
493 break;
494 }
495 step++;
496 time = OM_START_TIME + h*(double)step;
497
498 if ((step % OM_PRINT_EVERY) == 0) {
499 om_print_values(comp);
500 }
501
502 if (OM_REALTIME) {
503 /* Sleep until the wall clock has caught up with the simulated time. */
504 int64_t due = wallClockStart + (int64_t)((time - OM_START_TIME)*1e6);
505 int64_t now = esp_timer_get_time();
506 if (due > now) {
507 usleep((useconds_t)(due - now));
508 lastYield = esp_timer_get_time();
509 }
510 }
511 /* A step shorter than a tick does not sleep above, and solving as fast as
512 possible never does, so give the idle task a tick of its own whenever it
513 has been waiting for too long. */
514 if (esp_timer_get_time() - lastYield >= OM_YIELD_INTERVAL_US) {
515 vTaskDelay(1);
516 lastYield = esp_timer_get_time();
517 }
518 }
519
520 printf("# done at time %g after %u steps\n", time, (unsigned)step);
521 vTaskDelete(NULL);
522 }
523
524 void app_main(void)
525 {
526 xTaskCreate(om_simulation_task, "om_sim", OM_TASK_STACK_SIZE, NULL, 5, NULL);
527 }
528 >>
529 end appMainFile;
530
531 ✗ template readmeFile(SimCode simCode)
532 "How to build the generated project and flash it onto the board."
533 ::=
534 let modelNamePrefixStr = modelNamePrefix(simCode)
535 match simCode
536 case simCode as SIMCODE(modelInfo=MODELINFO(__)) then
537 <<
538 # <%dotPath(modelInfo.name)%> on an ESP32
539
540 This is an [ESP-IDF](https://docs.espressif.com/projects/esp-idf) project
541 generated by OpenModelica with `--simCodeTarget=ESP32`. It solves the model
542 with a fixed step explicit Euler solver and prints the results as CSV on the
543 console of the board. It needs neither the OpenModelica simulation runtime nor
544 the FMI headers, only ESP-IDF itself.
545
546 ## Build and flash
547
548 The default chip is the ESP32-C6, with the results printed on UART0, which is
549 the port the USB-serial bridge of the devkit is wired to. It is the same port
550 the board is flashed over: a `COMx` on Windows, a `/dev/ttyUSBx` on Linux.
551 Boards with a built in USB-Serial-JTAG port enumerate a second port; set
552 `CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y` in `sdkconfig.defaults` to print the
553 results there instead.
554
555 ```
556 . $IDF_PATH/export.sh
557 idf.py set-target esp32c6
558 idf.py build
559 idf.py -p COM6 flash monitor
560 ```
561
562 Use `idf.py set-target esp32` (or `esp32s3`, `esp32c3`, ...) for another chip.
563
564 ## What is generated
565
566 | File | Contents |
567 | ---- | -------- |
568 | `main/<%modelNamePrefixStr%>_model.h` | Model interface: the number of variables, the simulation settings and the functions below |
569 | `main/<%modelNamePrefixStr%>_model.c` | The statically allocated model state, the equations, the model functions and the solver step |
570 | `main/main.c` | `app_main`, which solves the model in a FreeRTOS task and prints the results |
571
572 ## Tuning the application
573
574 `main/main.c` starts with a handful of defines that you can change, or
575 override from `main/CMakeLists.txt` with `target_compile_definitions`:
576
577 | Define | Default | Meaning |
578 | ------ | ------- | ------- |
579 | `OM_PRINT_EVERY` | 1 | Print one line of results every N steps |
580 | `OM_REALTIME` | 0 | Spend `OM_STEP_SIZE` seconds of wall clock time on every step |
581 | `OM_RUN_FOREVER` | 0 | Keep solving instead of stopping at `OM_STOP_TIME` |
582 | `OM_TASK_STACK_SIZE` | 8192 | Stack of the task the model is solved in |
583 | `OM_YIELD_INTERVAL_US` | 200000 | Hand the CPU back at least this often, so the task watchdog stays fed |
584
585 To drive the hardware from the model, read the variables with
586 `<%symbolName(modelNamePrefixStr,"getReal")%>` and write them to a peripheral
587 instead of printing them. `<%symbolName(modelNamePrefixStr,"realNames")%>`
588 holds the name of every variable, in the same order.
589
590 ## Limitations
591
592 The target inherits the limitations of the experimental embedded C target it
593 shares its equation generation with: no algebraic loops, no events, no arrays,
594 no records and no strings. Models that use them fail to generate.
595 >>
596 end readmeFile;
597
598 annotation(__OpenModelica_Interface="codegen");
599 end CodegenESP32;
600
601 // vim: filetype=susan sw=2 sts=2
602