This article describes the usage of a script interpreter in EFM32 environment. The chosen language is the Lua language, the used board is the Silicon Labs Pearl Gecko (SLSTK3402A) starter kit board and the development environment is the standard IDE of Silicon Labs: Simplicity Studio. In the next section a brief description of the script language is provided followed by the goals, requirements and architecture descriptions. You can also find an attached source code and an explanation how to use this example project.
For the impatient:
- 1. Brief description of Lua
- 2. Why do I need a script interpreter?
- 3. Goals
- 4. Requirements
- 5. Architecture
- 6. Implementation
- 7. Uploading scripts
- 8. How to use
- 9. Future improvements
- Additional notes:
- Fazit (conclusion)
According to the Lua website:
"Lua is a powerful and fast programming language that is easy to learn and use and to embed into your application."
The emphasis is here on "embeddable". Lua is a software package designed from start to embed into a so-called "host", which is (in most cases) a foreign, compiled language. Most often it is C, but it can be also any other language. Lua is used in a wide variety of application, aerospace, photography, research and mostly: in games (due to its speed). It is easy to learn, the hello-world example is a one-liner and the language elements have a low learning threshold.
An example of Lua code:
local function run() print("--Run--") while counter < threshold do if IsBtnPushed() then if (counter % 8) == 0 then print("down") end Delay(10) counter = counter + 1 else counter = 0 end end end
C is a powerful language, why do I need then an other language?
What Lua does offer is what C is not good for: dynamic structures, no redundancies, ease of usage, safe environment, automatic memory management and handling strings and other kinds of data with dynamic size.
Other aspects are that the language is easier to learn by non-programmer thus it gets an environment for a broader user attendance.
An embeddable script language has the advantage that it can be used as part of the application that is frequently changed without the need of recompilation, for example in handling configuration parameters, automatic test cases, measurements, tryout/oneshot programs, user provided code, customize layout and/or behavior, etc.
You can give the user the possibility to change something in the application. It is easy to develop and platform independent. But bear in mind that if you provide the possibility to modify something in your application then it must be a safe environment. Fortunately Lua can be configured to have this kind of 'sandbox'.
The goal of the project to use a working interpreter embedded in C code. It is not intended to be a complete, full-featured development environment for some kind of application but to provide a firm base to develop one.
The Lua interpreter requires a processor and some amount of random access memory (RAM), it can be satisfied with few resources but - because it is not a stripped down package - it needs some. At startup the Lua interpreter consumes about 17kB of RAM but memory usage depends on the allocation of variables. The interpreter itself needs some memory too and a larger amount of flash for the code itself. Therefore a starter kit with 256kB with RAM and 1MB of flash is used: a Pearl Gecko.
The starter kit has some hardware, LEDs, buttons, temperature-sensor, LCD display. It provides the possibility to show how a hardware element can be controlled by Lua.
Also there must be a possibility to upload programs to the starter kit to change its behavior, therefore we need a mechanism to deliver script code (from outside to the kit) that can be executed on the board.
The structure of the project can be seen on the next picture.
To the main application a Lua interpreter module is linked but it (the main) does not call into it directly. Instead an interface is created where the application can request some services.
In this project it can require only two things:
Lua can do a little bit more:
Because Simplicity Studio creates makefiles on the fly, it is not difficult to add a Lua interpreter to the project. You have to create a simple example project that fits your needs and add a new folder inside the project directory. Download the Lua source files from the website and copy all the source files into the newly created directory, except `lua.c` and `luac.c` (or exclude both files from the compilation). Both are in the Lua distribution to demonstrate the use of the Lua package. `lua.c` passes the overgiven parameters from the command line to the interpreter; `luac.c` is a Lua 'compiler' (Lua converts the scripts into tokens before executing it). Both has a `main()` function therefore they cannot be added to the project. Don't forget to add the folder to the include directories that other files can include the Lua header files.
The next step is to create an interface to Lua. This has a predefined protocol. Because Lua is a dynamically typed language, data exchange to the host language occurs over a so-called 'virtual stack'. Lua (or the C code) places values onto that stack and the other language can use it.
The other thing is to have an interface from Lua to the Gecko SDK (thus to the hardware). This can be done by simply calling functions of the SDK, all the examples and applications do that.
To have access to the Gecko SDK, Lua has to be extended with C code. C code that is called from Lua must be registered in the interpreter, that means that if the script executes an appropriate statement (e.g. a function call) then the corresponding C code is executed. It communicates (overgives parameters and returns results) over the previously mentioned virtual stack.
In the example application interface to controlling the LEDs, the LCD display, reading the temperature sensor is implemented. Read and write to the standard input/output files is also implemented (only partly). The Gecko does not have console therefore these read/write operation are redirected to the already present VCOM interface and by connecting a computer to the serial line (with a terminal program) this can be used as a text based interface (for humans and applications).
Functions that can be called from Lua are as follows:
print(...) -- print to console LED(0, true) -- switch LED on/off temp, rh = TempRh() -- measure temperature Delay(400) -- sleep for x miliseconds ToggleLED(1) -- invert LED state ClrScr() -- clear the LCD display Line(1,2,3,4) -- draw a line (on LCD) Circle(64,64,40) -- draw a circle LCDrefresh(bool) -- switch LCD refresh on/off bool = IsBtnPushed() -- read button state (BTN1) str = ReadCon() -- read a line from terminal DrawPixel(x, y) -- draw a dot on LCD
To have a console-like user interface the project redirects standard I/O files to a serial line. The SDK has already predefined files for that. Add
to the project files. These pass `printf/getch` type function outputs to the already on the board present VCOM serial line and reads the input from that line. The data will be sent through the USB port to the connected computer. You can use a terminal emulator program (Tera Term, minicom, PuTTY) on your computer to communicate with the board.
The provided project export (the .sls file) has to be imported (into Simplicity Studio), compiled and flashed onto the Gecko board. The user can use a terminal program to communicate with the application. I use Teraterm because it has the ability to upload files with the XMODEM protocol already implemented. The computer side can be of course a custom application. In that case other type of serial protocol can be used but it have to be implemented on both sides. In that case the file `lfg_xmodem.c` has to be changed/replaced. Baud rate has to be set to the value of 115200.
lfg_xmodem has a very simple interface, it provides only one function:
int lfg_XmodemReceive(char *recvBuffer, int recvBufSize, int *actSize);
It starts the communication and places the received data into the provided text buffer and reports the number of received data into the variable that points `actSize` to. Return value can be LFG_OK or an error code.
There is not much of use of an application when the scripts has to be inserted/compiled into the C code. It loses the flexibility provided by the script language. Therefore the example project uses the XMODEM protocol to copy scripts from a computer to the Gecko board over the serial line. Fortunately there is already a serial line present called VCOM. If you plug in your board via the USB connector it does three things. Implements a JTAG interface, creates an USB mass storage device, realizes a serial communication interface. The latter is used to upload scripts to the board. COM port number can be determined by the Device manager or by the /dev/ttyUSBx file (in Linux).
XMODEM is a simple file transfer protocol, it allows users to transmit files between computers when both sides use the same protocol. The next picture shows the program structure to receive data:
By pressing the reset button on the Gecko board the following lines are displayed on the terminal:
Lua for Gecko - example application memory used : 11.18164 kB Enter command (or help). >
Enter 'help' to display the available commands.
led 0 on switch led 0 on led 0 off switch led 0 off led 1 on switch led 1 on led 1 off switch led 1 off temp measure temperature clrscr clear the LCD display cls clear the console --------- --------------------- load load script (from PC) with xmodem protocol cat display loaded script dump display loaded script as hex forget clear loaded script run run loaded script help display help
Most of them are fairly straightforward, one thing has to be explained: the script upload.
The XMODEM protocol requires that the receiver (the Gecko board) starts the communication, but the sender (the terminal program) has to be already in 'send' mode and waiting (for the start signal) to start sending. Therefore the first thing is to put the Gecko board into send mode by entering the `load` command. This does not start the communication but waits for an event to start. The Tera Term program must be instructed to send a file (File -> Transfer -> xmodem -> Send... menu item). It will wait for a start signal from the receiver. The start signal can be issued by pressing the `BTN0` button on the Gecko board. Press BTN0.
That loads a script onto the board. There are already some example scripts that the user can upload (e.g. example1.lua ...). This uploads but does not start the script automatically. To run the script the `run` command has to be entered. Type 'run'.
a.) enter 'load' on the terminal (Tera Term)
b.) use send-file in Tera Term
c.) press 'BTN0' on the Gecko board
d.) type 'run' into the terminal
If all went well you have a working environment where you can evaluate Lua running on a Gecko board. But there is a lot of space for improvement.
There are already some examples in the `src` folder:
"Lua is becoming the language of choice for anyone who needs a scripting language that is simple, efficient, extensible, portable, and free. Currently, Lua is being used in areas ranging from embedded systems to Web development and is widely spread in the game industry, where knowledge of Lua is an indisputable asset." (Google.books)
Lua has a lot of sophisticated additional things under the hood (tables, metatables, threads, user defined types ...), this article scratches only the surface of the possibilities that can be reached by using a powerful script language.