Lua di STM32

Halo!

Terkadang Anda ingin mencoba sesuatu dengan cepat di mikrokontroler, memprogram prototipe yang berfungsi untuk sebuah ide. Untuk tujuan ini, seperti yang Anda tahu, bahasa scripting sangat cocok. Pada artikel ini saya ingin memberi tahu cara menggunakan Embox untuk menjalankan Lua interpreter (standar, bukan eLua) pada STM32. Untuk menunjukkan, kami mengedipkan LED melalui jaringan menggunakan pustaka luasocket, dan juga bekerja sedikit dengan http.



Lua adalah bahasa pemrograman scripting yang interpreternya cukup ringan sehingga mudah diintegrasikan ke dalam proyek lain, ditambah lisensi MIT gratis. Kami telah lama tertarik dengan bahasa ini, oleh karena itu, di bawah Embox, ada dukungan Lua di qemu i386. Dan karena interpreternya ringan dan kompatibel dengan POSIX, muncul ide untuk meluncurkan Lua dengan cara yang sama seperti yang kami lakukan dengan perpustakaan lain seperti Pjsip , OpenCV , Qt .

Saya akan segera mencatat bahwa karena kita akan mulai dengan dukungan luasocket, kami akan memilih tidak stm32f4-discovery (1 MB flash, RAM 192 KB), tetapi sedikit lebih banyak - stm32f7-discovery(1 MB flash, 320 KB RAM, dan SDRAM tambahan). Pada saat yang sama, tidak ada keraguan bahwa versi dasar Lua tanpa dukungan jaringan dapat dengan mudah dimulai pada stm32f4 (lihat di bawah).

Untuk memulai, mari kita siapkan contoh sederhana - menghitung angka Fibonacci n:

function fib(n)
    if n < 3 then
        return 1
    else
        return fib(n - 1) + fib(n - 2)
    end
end

print("fib(7) = " .. fib(7))

Mari kita mulai dengan Linux terlebih dahulu dan lihat berapa banyak memori yang dibutuhkan. Dan kemudian kami akan mentransfernya ke Embox tanpa perubahan. Pertama, unduh lua segar. Saya mengunduh 5.3.5, dan mengkompilasinya sebagai "make linux". Tetapi pada kenyataannya, untuk tujuan kami, Anda dapat memasukkannya dari repositori. Selanjutnya, jalankan fib.lua kami:

$ valgrind --tool=massif --massif-out-file=fib.massif lua fib.lua
$ ms_print fib.massif > fib.out

Sekarang Anda dapat melihat di fib.out dan mengetahui bahwa jumlah maksimum memori yang dialokasikan di heap adalah sekitar 30 Kb. Di sini, tentu saja, saya tidak akan mengatakan bahwa ini adalah ukuran minimum. Sebagai contoh, dalam artikel di bagian “Persyaratan untuk RAM”, secara substansial lebih sedikit persyaratan yang diberikan, tetapi hanya pada saat menyalakan mesin Lua. Tapi bagaimanapun, 30 Kb terlihat menggembirakan - kami memiliki 320 Kb.

Sekarang bangun templat arm / stm32f746g-discovery-lua untuk Embox:

$ make confload-arm/stm32f746g-discovery-lua
$ make -j $(nproc)

Build / base / bin / embox firmware di papan tulis seperti yang ditunjukkan pada wiki kami dan jalankan:

embox> lua fib.lua 
fib(7) = 13

Hebat, semuanya persis seperti di Linux (tidak mengherankan :)).

Mari menyulitkan tugas, namun sekarang jaringan adalah kebutuhan hampir di mana-mana. Kirim permintaan HTTP / GET di suatu tempat di Internet. Untuk melakukan ini, Anda memerlukan perpustakaan luasocket . Kemudian saya tidak mulai mengumpulkan dari kode sumber, tetapi saya menggunakan paket yang sudah jadi ("sudo apt-get install lua-socket").

Untuk mengirim permintaan HTTP, gunakan contoh sederhana ini:

local http = require("socket.http")

if not arg or not arg[1] then
    print("lua http_request.lua <url>")
    os.exit(0)
end

local body, code = http.request(arg[1])
print(code)
print(body)

os.exit(code == 200)

Sekali lagi, semuanya dapat diperiksa di Linux:

lua http_request.lua http://example.com

Akan mengembalikan kode 200 dan konten halaman. Mari kita lihat dari ingatan. Jika Anda menjalankan valgrind lagi, Anda dapat melihat bahwa konsumsi memori puncak pada heap telah meningkat menjadi 242 Kb. Jadi di sini saya akhirnya menemukan bahwa stm32f4 tidak akan cocok tanpa optimasi tambahan. Tampaknya mungkin untuk mendapatkan stm32f7 - ada 320 Kb, tetapi dengan mempertimbangkan bahwa masih ada OS dengan sistem file dan jaringan, saya memutuskan sedikit untuk mengotak-atik menggunakan sekelompok SDRAM eksternal.

Kami menghidupkan (dalam konfigurasi ini sudah termasuk) tumpukan biasa di RAM, dan yang tambahan di SDRAM.

    include embox.mem.static_heap(heap_size=0x10000)
    include embox.mem.fixed_heap(heap_size=0x40000, heap_start=0x60000000)

Kami memeriksa stm32f7-discovery, ini berfungsi seperti di Linux.

Akhirnya mari kita berkedip LED "jarak jauh".

local socket = require("socket")

port = arg[1] or 1027
udp = assert(socket.udp())
assert(udp:setsockname('*', port))
print("Lua UDP server started on port " .. port .. "...")
while 1 do
    cmd, ip, port = assert(udp:receivefrom())
    print("Execute '" .. cmd .. "' from " .. ip .. ":" .. port)
    os.execute(cmd)
end

Di sini kita hanya mendapatkan data UDP dari port yang ditentukan dan meneruskannya ke os.execute (). Sebagai perintah yang akan dieksekusi, kami akan mengirimkan perintah pin dari klien. Ini adalah perintah sederhana di Embox yang mengontrol GPIO - misalnya, untuk stm32f7-disco Anda perlu menjalankan "pin gpioi 1 toggle", yang berarti mengubah baris pertama menjadi GPIOI.

Contoh standar dari luasocket akan diambil sebagai klien:

echoclnt.lua
-----------------------------------------------------------------------------
-- UDP sample: echo protocol client
-- LuaSocket sample files
-- Author: Diego Nehab
-----------------------------------------------------------------------------
local socket = require("socket")

host = "localhost"
port = 1027
if arg then
    host = arg[1] or host
    port = arg[2] or port
end

udp = assert(socket.udp())
assert(udp:setpeername(host, port))
print("Using remote host '" ..host.. "' and port " .. port .. "...")
while 1 do
    line = io.read()
    if not line or line == "" then os.exit() end
    assert(udp:send(line))
end


Seperti biasa, periksa dulu di Linux. Valgrind menunjukkan bahwa konsumsi memori puncak pada heap adalah sekitar 70 Kb, yang lebih dari 2 kali lipat dari kasus dengan Fibonacci (30 Kb), tetapi secara signifikan lebih sedikit daripada dalam contoh dengan HTTP (242 Kb).

Segera tunjukkan contoh peluncuran di Embox.

Di Linux:

$ lua echoclnt.lua 192.168.0.128 1027
Using remote host '192.168.0.128' and port 1027...
pin gpioi 1 toggle
pin gpioi 1 toggle

Di Embox:

embox>                                                   
embox>lua udp_server.lua                                                        
Lua UDP server started on port 1027...
Execute 'pin gpioi 1 toggle' from 192.168.0.102:34300
Execute 'pin gpioi 1 toggle' from 192.168.0.102:34300

Kesimpulan


Kami berhasil menjalankan Lua + luasocket pada stm32f7-discovery. Dan dengan bantuan mereka, kedipkan LED dari jarak jauh melalui jaringan. Dan ternyata cukup sederhana, karena seperti yang disebutkan di awal, bahasa skrip dapat menghemat waktu pada prototipe.

Saya juga ingin mencatat bahwa ada proyek eLua yang berjalan pada bare metal tanpa OS. Tapi dia punya beberapa nuansa. Pertama, dukungan jaringan terbatas: UDP tidak ada di sana, dan dokumentasi mengatakan bahwa jaringan tersebut “sedang dalam proses” untuk saat ini. Kedua, saya tidak dapat menemukan dukungan untuk stm'ku jenis F3, F4 (hanya F1). Dan secara umum, Anda harus setuju, jauh lebih berguna untuk menggunakan proyek yang didukung secara luas, dan dalam hal ini, elua tentu saja lebih rendah daripada proyek utama.

Semua contoh yang dijelaskan dalam artikel ada di repositori kami.

Embox juga memiliki bahasa skrip lain - python (tinipy), Ruby (mruby), Tcl. Tapi ini di luar cakupan artikel ini :)

Kontak kami:
Newsletter: embox-ru@googlegroups.com
Obrolan Telegram: t.me/embox_chat

All Articles