Running Embedded Lua On Microcontrollers
Very often while developing complex systems, engineers have to greatly simplify the task of writing final user space applications. In this case it is desirable to move as far as possible from the architectural features of the systems used and focus on the algorithms and program logic of the programs. One possible solution in such cases is the use of simple scripting languages such as Lua.
Scripting languages spare you much thinking about specific types of data, byte order, and other internal platform features. Usually, this code is less bulky and easier to understand. Also, a simplified syntax helps master the language in the shortest possible time.
Lua is freely distributable (under MIT license) open-source codes in C. It is an interpretable language, which means that programs written in it are translated into byte code directly at runtime, without pre-compilation. This byte code is executed on a virtual machine (it is basically an abstract virtual processor with a set of registers), which provides an excellent cross-platform performance. Analogous to Net and Java, a Lua virtual machine includes a garbage collector.
The price of this approach is lower operational speed and compact stored code. However, Lua helps minimize both of these drawbacks. Even though this language is procedure-oriented and does not support object-oriented programming principles (OOP), some of the OOP features (such as inheritance) are fully implemented using.
From the outset, Lua was not intended to be used independently but applied together with lower-level languages such as C. A small interpreter, a relatively high speed of execution, and easy expandability enabled it to be used in the development of computer games. (In 2003, Lua was voted the most popular scripting language for developing games, according to the GameDev.net community.)
Lua also is widely used for writing extensions and plug-ins for software products, as well as for creating user interfaces and configuration files. It currently is the basis of Codea, which is the only development environment for iPad that makes it possible to create applications on the device itself.
Through the Embedded Lua (eLua) project, Lua has found its application as an intermediary between a programmer and a platform for microcontroller-based embedded systems.
Very often, developers can provide their customers with all the source codes of the project, but it is extremely important to allow for the possibility of changing the behavior algorithms of any system. In this case, the basic operational logic can be shifted to an open interpreted code and the remaining part can be implemented in a low-level language without having to open the source code.
The ]]>eLua project]]> makes it possible to use full Lua support in embedded systems. It was jointly developed by Bogdan Marinescu, a programmer from Romania, and Dado Sutter, head of the Led Lab at PUC-Rio University, Brazil. Like the language itself, the eLua project is free, open, and distributed under MIT license.
This product works as a standalone application, without the need to use operating systems. If necessary, multithreading is achieved through standard scripting language tools. However, eLua is not only an interpreter. Its modular structure also provides a lot of useful components that continue to greatly expand the interpreter functionality. Today, eLua v0.8 supports useful components such as:
- Console via UART or Ethernet with the possibility of transmitting source code files via Xmodem
- Support for file systems (virtual ROMFS, FAT on SD/MMC cards, or NFS remote file system)
- DHCP client and DNS resolver, as well as multiplexing of serial ports
- The set of used components is specified when the project is compiled and can be adjusted to reduce the amount of the code.
The very core of the interpreter and the language used is not at all reduced compared to the full-functional version of Lua for PC. Moreover, eLua developers focus their efforts not on cutting but on expanding Lua, which will make it more “friendly” for embedded systems, reducing memory usage and increasing productivity. All this means that through eLua programmers can use an absolutely full-featured language complete with specific capabilities for embedded use.
For a better understanding of the principles of interaction between eLua and the “outer world,” we should discuss the concept of a module. From the perspective of a Lua programmer, a module is a table in a global environment whose fields are defined functions and variables combined semantically. In some way, the concept of a module is analogous to that of namespace in C++.
User-defined modules can be used to partition a large program into logical sections for the “emulation” of some OOP principles and to reference outside isolated parts of the code responsible for certain functions. This referencing is widely used in eLua. All features connecting the interpreter to the periphery are represented as modules. In eLua version 0.8, you can find the following modules:
- pio: access to input-output ports
- tmr: access to physical and virtual timers
- pwm: PWM access
- uart: access to serial ports
- spi: SPI access
- net: TCP/IP support
- adc: ADC access
- cpu: low-level access to processor registers
- pd: receiving platform data
- term: terminal access
- bit: bit operations
- pack: packing/unpacking of binary data into lines
- i2c: I2C access
- can: CAN access
- rpc: remote procedure call
- elua: system behavior control
The implementation of the modules includes variables, constants, and functions in C available in the Lua global environment. The modules themselves are implemented in a specific format that’s described on the project Web site. For example, all it takes to send data via UART using the respective module is to call in any part of Lua script the following function:
uart.write(ID, Data1, [Data2], ..., [DataN])
where ID is the identifier of the required serial port and Data1-DataN are the data to be transmitted, which can be a string or an 8-bit number.
The syntax and general rules are similar to object method access in object-oriented languages , with the only difference that the UART table is always present in the global environment without creating any variable objects, etc. It makes it easier to work with modules and generally simplifies the use of Lua.
eLua Application Options
The eLua project is oriented toward the use of many hardware platforms and architectures, both those based on microcontrollers and microprocessors and those performed as x86 PC applications. The table lists platforms supported by eLua.
The platform requires, at a recommended minimum, a 32-bit CPU, at least 256 kbytes of flash memory, and at least 64 kbytes of RAM. The exact requirements depend on the instruction set of a specific processor and the employed set of extensions. Low-level work with the platform is also based on the modular principle that allows the developer to easily add support for new platforms and boards.
We can single out three eLua application options: use of finished images, building images using Web Builder, and building images out of source codes. The eLua project provides ready-to-use images of the latest stable eLua version for the most common development kits. This greatly simplifies the process of initial familiarization with the system.
If you need to change the settings of the final image, you can use eLua Web Builder, which is available on the official Web site of the project upon registration. This service helps compile eLua with the specified settings on the side of the Web service, receiving a finished image and its source code with the specified settings.
But our primary focus, of course, is independent eLua building from source codes. The eLua code is available at the ]]>GitHub Web site]]> as a project ready for cross-compilation. The project is written in C, and part of the initialization code for a particular platform is written in assembly language. Also, project compilation involves Python scripts. Many useful manuals and user guides to assist you in setting up, using, and writing eLua extensions can be found on the project Web site.
Example Of eLua Use
Let us consider the example of using eLua with the EK-LM3S9B92 software development kit, based on the Stellaris microcontroller by Texas Instruments. The Lm3s9b92 microcontroller has on-board 256-Gbyte flash memory and 96-Gbyte RAM, which would be enough to use all eLua features available for this platform. To repeat this example, we will need the following components:
- A PC running any operating system of the Linux family (the example features Ubuntu 12.04)
- An installed ARM toolchain (the example uses a free package, Sourcery CodeBench Lite Edition)
- A board itself with a target 32-bit microcontroller ]]>(Fig. 1)]]> (the example features the EK-LM3S9B92 by TI) and an in-circuit debugger for the controller firmware ]]>(Fig. 2)]]>
- Installed packages SCons and Python
First, we download the source code of the latest stable eLua version (currently it is v0.8). You can do it using Git:
git clone git://github.com/elua/elua.git
In addition, the source code can be downloaded in a zip or gzip archive through the Web interface of a branch of the eLua project at GitHub .
Either way, we will get a folder with the eLua project. Let’s take a look at its contents. Most of the code is located in the folder src. The src/platform contents are of greatest interest for us. They are platform-specific modules for various microcontrollers (initialization code in assembly language functions for peripherals, etc.).
The romfs folder includes Lua scripts to be included in the generated binary image of the project and will be available for running through a built-in read-only file system. If the autorun.lua script is found in this folder, it will run automatically after the system boot.
The root of the project folder includes the Sconstruct file, which includes all eLua build parameters (the language used for configuration is Python), including links to the installed set of tools, the ARM toolchain (toolchain_list array), and a list of platform-controller-board relations for supported platforms (platform_list and board_list). Since the microcontroller (lm3s9b92 from TI) and toolchain (Sourcery CodeBench Lite) used are originally supported by eLua, no changes should be made to the file.
Now let’s configure the eLua platform lm3s. To do this, open the file / src/platform/lm3s/platform_conf.h. This file describes the list of components and modules to be included in the project. The components used are defined by the # define directives. This example involves network support (uIP stack), a telnet console, and ROMFS. Comment out the directives # define BUILD_*, except:
#define BUILD_SHELL #define BUILD_ROMFS #define BUILD_UIP #define BUILD_CON_TCP
The list of plug-in modules (i.e., Lua extensions) is defined by the # define section LUA_PLATFORM_LIBS_ROM. By default, all supported modules are included and will be added to the project. You can turn off the ones that we do not plan to use, which will help reduce the space occupied by flash memory. Since the problem we are facing now is not about saving, we will leave this directive unchanged.
We will not use the option of obtaining an IP address via DHCP (which we enabled by default, but turned off earlier), so we need to specify network settings manually. To do this, we will enter the IP address 192.168.1.100 in the Static TCP/IP configuration section of the platform_conf.h file. We can leave the subnet mask, the default gateway, and the DNS server unchanged.
Let’s make a test script. We create in the romfs folder the hello.lua file with the following contents:
Now everything is ready for the final stage of building an eLua binary image. The build process involves the use of Scons as a build utility, with the following parameters:
scons [target=lua | lualong | lualonglong] [cpu=] [board=] [cpumode=arm | thumb] [allocator = newlib | multiple | simple] [toolchain = ] [optram = 0 | 1] [romfs = verbatim | compress | compile] [prog]
We will not dwell in detail on the description of each option, as the information is available in the corresponding ]]>eLua documentation]]>. In our case, the build command would look like this:
scons cpu=lm3s9b92 board=ek-lm3s9b92 toolchain=codesourcery prog
The build process will take some time, after which, unless errors are detected, we will get a file of the type elua_lua_lm3s9b92.bin in the project root folder. This binary image is ready for recording it to the flash memory of the used board, which we are now doing.
After building firmware, we will connect the board to an Ethernet network and try to gain access to the embedded console through telnet:
In case we use DNS resolving, there is no need to know the board IP address, and it is enough to execute:
If we have done everything correctly at the previous stages, we will see the console (Fig. 3).
Figure 3. The eLua command line console provides an interactive interface to the system.
user@hostname:~$ telnet 192.168.1.100 Trying 192.168.1.100... Connected to 192.168.1.100. Escape character is '^]'. eLua dev-fbebb29 Copyright (C) 2007-2011 ]]>www.eluaproject.net]]> eLua#
The list of shell commands is not long, but it helps perform all the necessary operations:
- help: print the list of all shell commands on the console
- ver: print the eLua version installed
- recv: receive a file through Xmodem (only for UART)
- lua or lua -e 'command' i: run a script to be executed
- ls or dir: display the list of files in eLua file systems
- cat or type : print the file content on the console
- cp : copy files within eLua
- exit: close the telnet session and exit the console
If you use a console through UART, it works in the same way, with port parameters 115200 (38400 for STR7), 8N1. It is possible to create an eLua build with only one of the possible ways of accessing the console (through UART or via Ethernet). Finished images on the project Web site are built using the console over UART.
It is now time to check the operation of the interpreter by executing the test script hello.lua. To do this, we enter the following command into eLua the console:
Executing the script will result in outputting the interpreter hello message and the much-awaited line “Hello world!” This can also be achieved by executing:
lua -e 'print("Hello world!")'
There are many ]]>examples of Lua scripts]]> for eLua using a variety of modules, from blinking LEDs to a Web server. These examples will help designers learn to work with the Lua syntax and the periphery in the shortest possible time.
In general, eLua is a pretty good environment for executing scripts in embedded systems, but it’s not the only one. As an alternative, you can consider the PyMite interpreter using Python. If you need a very lightweight solution, we can recommend a C-like language, Pawn, with a minimum interpreter size. And, of course, we should mention a far more popular solution for similar problems, Java, which has extensive capabilities, but also the most stringent demands for resources.
The eLua environment-interpreter, in its turn, boasts an unusually low entry threshold (even a beginner in programming will be able to learn to write simple Lua scripts), easy extensibility, and portability without seriously compromising the functionality of the system.
Anyway, the use of scripting languages in embedded systems helps perform a wide range of tasks. As hardware components develop, these solutions increase in popularity.
Source URL: ]]>http://electronicdesign.com]]>