Embox di papan EFM32ZG_STK3200. Bagaimana cara memasukkan RTOS ke dalam RAM 4kB

gambar

Embox adalah RTOS yang sangat dapat dikonfigurasi. Ide utama Embox adalah menjalankan perangkat lunak Linux secara transparan di mana saja, termasuk di mikrokontroler. Di antara pencapaiannya, perlu disebutkan OpenCV , Qt , PJSIP , yang berjalan pada mikrokontroler STM32F7. Tentu saja, peluncuran tersebut menyiratkan bahwa tidak ada perubahan yang dilakukan pada proyek ini dan hanya opsi yang digunakan saat mengonfigurasi proyek asli dan parameter yang disetel dalam konfigurasi Embox itu sendiri. Tetapi pertanyaan alami muncul sejauh mana Embox memungkinkan Anda menghemat sumber daya dibandingkan dengan Linux yang sama? Bagaimanapun, yang terakhir ini juga dapat dikonfigurasi dengan cukup baik.



Untuk menjawab pertanyaan ini, Anda dapat memilih platform perangkat keras minimum untuk menjalankan Embox. Kami memilih EMF32ZG_STK3200 dari SiliconLabs sebagai platform seperti itu . Platform ini memiliki ROM 32kB dan memori RAM 4kB. Dan juga inti prosesor cortex-m0 +. UART, LED khusus, tombol, dan tampilan monokrom 128x128 tersedia dari periferal. Tujuan kami adalah meluncurkan aplikasi khusus apa pun untuk memastikan bahwa Embox berfungsi di papan ini.



Untuk bekerja dengan periferal dan papan itu sendiri, Anda memerlukan driver dan kode sistem lainnya. Kode ini dapat diambil dari contoh yang diberikan oleh produsen chip itu sendiri. Dalam kasus kami, pabrikan menyarankan untuk menggunakan SimplifyStudio. Ada juga buka repositori di GitHub ). Kami akan menggunakan kode ini.



Embox memiliki mekanisme untuk menggunakan BSP pabrikan saat membuat driver. Untuk melakukan ini, Anda perlu mengunduh BSP dan membuatnya sebagai pustaka di Embox. Dalam kasus ini, Anda dapat menentukan berbagai jalur dan tanda yang diperlukan untuk menggunakan pustaka ini di driver.



Contoh Makefile untuk mengunduh BSP:



PKG_NAME := Gecko_SDK
PKG_VER := v5.1.2
PKG_ARCHIVE_NAME := $(PKG_NAME)-$(PKG_VER).tar.gz

PKG_SOURCES := https://github.com/SiliconLabs/$(PKG_NAME)/archive/v5.1.2.tar.gz

PKG_MD5     := 0de78b48a8da80931af1a53d401e74f5

include $(EXTBLD_LIB)
      
      





Mybuild untuk membangun BSP:



package platform.efm32

...
@BuildArtifactPath(cppflags="-I$(EXTERNAL_BUILD_DIR)/platform/efm32/bsp_get/Gecko_SDK-5.1.2/hardware/kit/common/bsp/")
module bsp_get { }

@BuildDepends(bsp_get)
@BuildDepends(efm32_conf)
static module bsp extends embox.arch.arm.cmsis {


    source "platform/emlib/src/em_timer.c",
        "platform/emlib/src/em_adc.c",


    depends bsp_get
    depends efm32_conf
}

      
      





Mybuild untuk papan EFM32ZG_STK3200:



package platform.efm32.efm32zg_stk3200

@BuildArtifactPath(cppflags="-I$(EXTERNAL_BUILD_DIR)/platform/efm32/bsp_get/Gecko_SDK-5.1.2/platform/Device/SiliconLabs/EFM32ZG/Include")
@BuildArtifactPath(cppflags="-I$(EXTERNAL_BUILD_DIR)/platform/efm32/bsp_get/Gecko_SDK-5.1.2/hardware/kit/EFM32ZG_STK3200/config")
...
@BuildArtifactPath(cppflags="-D__CORTEX_SC=0")
@BuildArtifactPath(cppflags="-DUART_COUNT=0")
@BuildArtifactPath(cppflags="-DEFM32ZG222F32=1")
module efm32zg_stk3200_conf extends platform.efm32.efm32_conf {
    source "efm32_conf.h"
}

@BuildDepends(platform.efm32.bsp)
@BuildDepends(efm32zg_stk3200_conf)
static module bsp extends platform.efm32.efm32_bsp {

    @DefineMacro("DOXY_DOC_ONLY=0")
    @AddPrefix("^BUILD/extbld/platform/efm32/bsp_get/Gecko_SDK-5.1.2/")
    source
        "platform/Device/SiliconLabs/EFM32ZG/Source/system_efm32zg.c",
        "hardware/kit/common/drivers/displayls013b7dh03.c",

...

}
      
      





Setelah langkah-langkah yang cukup sederhana, Anda dapat menggunakan kode dari pabrikan. Sebelum Anda mulai bekerja dengan driver, Anda perlu memahami alat pengembangan dan bagian arsitektur. Embox menggunakan alat pengembangan biasa gcc, gdb, openocd. Saat memulai openocd, Anda perlu menunjukkan bahwa kami menggunakan platform efm32:



sudo openocd -f /usr/share/openocd/scripts/board/efm32.cfg
      
      





Tidak ada bagian arsitektur khusus untuk syal kami, hanya bagian khusus cortex-m0 +. Ini diatur oleh kompiler. Oleh karena itu, kita dapat mengatur kode umum untuk cotrex-m0 dengan menonaktifkan semua yang tidak perlu, misalnya, bekerja dengan floating point.



     @Runlevel(0) include embox.arch.generic.arch
    include embox.arch.arm.libarch
    @Runlevel(0) include embox.arch.arm.armmlib.locore
    @Runlevel(0) include embox.arch.system(core_freq=8000000)
    @Runlevel(0) include embox.arch.arm.armmlib.exception_entry(irq_stack_size=256)
    @Runlevel(0) include embox.kernel.stack(stack_size=1024,alignment=4)
    @Runlevel(0) include embox.arch.arm.fpu.fpu_stub
      
      





Setelah itu, Anda dapat mencoba mengompilasi Embox dan menjalankan langkah-langkahnya menggunakan debugger, dengan demikian memeriksa apakah kami telah menyetel parameter dengan benar di skrip linker



/* region (origin, length) */
ROM (0x00000000, 32K)
RAM (0x20000000, 4K)

/* section (region[, lma_region]) */
text   (ROM)
rodata (ROM)
data   (RAM, ROM)
bss    (RAM)
      
      





Driver pertama yang diterapkan untuk mendukung papan apa pun di Embox biasanya UART. Dewan kami memiliki LEUART. Cukup bagi pengemudi untuk mengimplementasikan beberapa fungsi. Dalam melakukannya, kita dapat menggunakan fungsi dari BSP.



static int efm32_uart_putc(struct uart *dev, int ch) {
    LEUART_Tx((void *) dev->base_addr, ch);
    return 0;
}

static int efm32_uart_hasrx(struct uart *dev) {
...
}

static int efm32_uart_getc(struct uart *dev) {
    return LEUART_Rx((void *) dev->base_addr);
}

static int efm32_uart_setup(struct uart *dev, const struct uart_params *params) {

    LEUART_TypeDef      *leuart = (void *) dev->base_addr;
    LEUART_Init_TypeDef init    = LEUART_INIT_DEFAULT;

    /* Enable CORE LE clock in order to access LE modules */
    CMU_ClockEnable(cmuClock_HFPER, true);

  ...

    /* Finally enable it */
    LEUART_Enable(leuart, leuartEnable);

    return 0;
}

...

DIAG_SERIAL_DEF(&efm32_uart0, &uart_defparams);
      
      





Agar fungsi BSP tersedia, Anda hanya perlu menunjukkan ini di deskripsi driver, file Mybuild:



package embox.driver.serial

@BuildDepends(platform.efm32.efm32_bsp)
module efm32_leuart extends embox.driver.diag.diag_api {
    option number baud_rate

    source "efm32_leuart.c"

    @NoRuntime depends platform.efm32.efm32_bsp
    depends core
    depends diag
}
      
      





Setelah mengimplementasikan driver UART, tidak hanya output yang tersedia untuk Anda, tetapi juga konsol tempat Anda dapat memanggil perintah khusus. Untuk melakukan ini, Anda hanya perlu menambahkan penerjemah perintah kecil ke file konfigurasi Embox:



    include embox.cmd.help
    include embox.cmd.sys.version

    include embox.lib.Tokenizer
    include embox.init.setup_tty_diag
    @Runlevel(2) include embox.cmd.shell
    @Runlevel(3) include embox.init.start_script(shell_name="diag_shell")
      
      





Dan juga menunjukkan bahwa Anda tidak perlu menggunakan tty lengkap yang tersedia melalui devfs, tetapi sebuah rintisan yang memungkinkan Anda mengakses perangkat yang ditentukan. Perangkat juga ditentukan dalam file konfigurasi mods.conf:



    @Runlevel(1) include embox.driver.serial.efm32_leuart
    @Runlevel(1) include embox.driver.diag(impl="embox__driver__serial__efm32_leuart")
    include embox.driver.serial.core_notty
      
      





Pengemudi lain yang sangat sederhana adalah GPIO. Untuk mengimplementasikannya, kita juga bisa menggunakan panggilan dari BSP. Untuk melakukan ini, dalam deskripsi driver, kami akan menunjukkan bahwa itu tergantung pada BSP:



package embox.driver.gpio

@BuildDepends(platform.efm32.efm32_bsp)
module efm32_gpio extends api {
    option number log_level = 0

    option number gpio_chip_id = 0
    option number gpio_ports_number = 2

    source "efm32_gpio.c"

    depends embox.driver.gpio.core
    @NoRuntime depends platform.efm32.efm32_bsp
}
      
      





Implementasinya sendiri:



static int efm32_gpio_setup_mode(unsigned char port, gpio_mask_t pins, int mode) {
...
}

static void efm32_gpio_set(unsigned char port, gpio_mask_t pins, char level) {
    if (level) {
        GPIO_PortOutSet(port, pins);
    } else {
        GPIO_PortOutClear(port, pins);
    }
}

static gpio_mask_t efm32_gpio_get(unsigned char port, gpio_mask_t pins) {

    return GPIO_PortOutGet(port) & pins;
}
...

static int efm32_gpio_init(void) {
#if (_SILICON_LABS_32B_SERIES < 2)
  CMU_ClockEnable(cmuClock_HFPER, true);
#endif

#if (_SILICON_LABS_32B_SERIES < 2) \
  || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2)
  CMU_ClockEnable(cmuClock_GPIO, true);
#endif
    return gpio_register_chip((struct gpio_chip *)&efm32_gpio_chip, EFM32_GPIO_CHIP_ID);

}
      
      





Ini cukup untuk menggunakan perintah 'pin' dari Embox. Perintah ini memungkinkan Anda untuk mengontrol GPIO. Dan khususnya, ini dapat digunakan untuk memeriksa kedipan LED.



Tambahkan perintah itu sendiri ke mods.conf:



include embox.cmd.hardware.pin
      
      





Dan mari kita jalankan saat startup. Untuk melakukannya, tambahkan salah satu baris di file konfigurasi start_sctpt.inc:



<source ">" pin GPIOC 10 blink ",

Atau



"pin GPIOC 11 blink",
      
      





Perintahnya sama, hanya nomor LED yang berbeda.



Mari coba mulai tampilan juga. Ini sederhana pada awalnya. Bagaimanapun, kita dapat menggunakan panggilan BSP lagi. Untuk melakukan ini, kita hanya perlu menambahkannya ke deskripsi driver framebuffer:



package embox.driver.video

@BuildDepends(platform.efm32.efm32_bsp)
module efm32_lcd {
...

    source "efm32_lcd.c"
    @NoRuntime depends platform.efm32.efm32_bsp
}
      
      





Tapi begitu kita melakukan panggilan apapun yang berhubungan dengan tampilan, misalnya DISPLAY_Init, bagian .bss kita bertambah lebih dari 2 kB, dengan ukuran RAM 4 kB, ini sangat signifikan. Setelah mempelajari masalah ini, ternyata di BSP itu sendiri sebuah framebuffer dialokasikan untuk tampilan. Artinya, 128x128x1 bit atau 2048 byte.



Pada titik ini, saya bahkan ingin berhenti di situ, karena ini merupakan pencapaian tersendiri untuk menyesuaikan panggilan perintah pengguna dengan beberapa penerjemah perintah sederhana dalam RAM 4kB. Tetapi saya memutuskan untuk mencobanya.



Pertama, saya menghapus shell dan hanya meninggalkan panggilan ke perintah pin yang sudah disebutkan. Untuk melakukan ini, saya memodifikasi file konfigurasi mods.conf sebagai berikut:



    //@Runlevel(2) include embox.cmd.shell
    //@Runlevel(3) include embox.init.start_script(shell_name="diag_shell")
    @Runlevel(3) include embox.init.system_start_service(cmd_max_len=32, cmd_max_argv=6)
      
      





Karena saya menggunakan modul yang berbeda untuk memulai kustom, saya memindahkan peluncuran perintah ke file konfigurasi yang berbeda. Saya menggunakan system_start.inc daripada start_script.inc.



Kemudian, karena saya tidak lagi perlu menggunakan inode di shell, serta pengatur waktu, saya menyingkirkannya menggunakan opsi di mods.config:



    include embox.driver.common(device_name_len=1, max_dev_module_count=0)
    include embox.compat.libc.stdio.file_pool(file_quantity=0)

    include embox.kernel.task.resource.idesc_table(idesc_table_size=3)
    include embox.kernel.task.task_no_table

    @Runlevel(1) include embox.kernel.timer.sys_timer(timer_quantity=1)
...
    @Runlevel(1) include embox.kernel.timer.itimer(itimer_quantity=0)
      
      





Karena saya memanggil perintah secara langsung dan tidak melalui shell, saya dapat mengurangi ukuran tumpukan:



    @Runlevel(0) include embox.arch.arm.armmlib.exception_entry(irq_stack_size=224)
    @Runlevel(0) include embox.kernel.stack(stack_size=448,alignment=4)
      
      





Akhirnya, saya menyalakan LED dan menyalakannya, dan di dalamnya ada panggilan untuk menginisialisasi tampilan.



Saya ingin menampilkan sesuatu di layar. Saya pikir logo Embox akan menjadi indikasi. Pada level yang baik, Anda perlu menggunakan driver framebuffer lengkap dan mengeluarkan gambar dari sebuah file, karena semua ini ada di Embox. Tapi tidak ada cukup ruang. Dan untuk demonstrasi, saya memutuskan untuk menampilkan logo secara langsung pada fungsi inisialisasi driver framebuffer. Selain itu, datanya langsung diubah menjadi bitmap. Jadi, saya membutuhkan tepat 2048 byte dalam ROM.



Kode itu sendiri, seperti sebelumnya, menggunakan BSP:



extern const uint8_t demo_image_mono_128x128[128][16];

static int efm_lcd_init(void) {
    DISPLAY_Device_t      displayDevice;
    EMSTATUS status;
    DISPLAY_PixelMatrix_t pixelMatrixBuffer;

    /* Initialize the DISPLAY module. */
    status = DISPLAY_Init();
    if (DISPLAY_EMSTATUS_OK != status) {
        return status;
    }

    /* Retrieve the properties of the DISPLAY. */
    status = DISPLAY_DeviceGet(DISPLAY_DEVICE_NO, &displayDevice);
    if (DISPLAY_EMSTATUS_OK != status) {
        return status;
    }
    /* Allocate a framebuffer from the DISPLAY device driver. */
    displayDevice.pPixelMatrixAllocate(&displayDevice,
            displayDevice.geometry.width,
            displayDevice.geometry.height,
            &pixelMatrixBuffer);
#if START_WITH_LOGO
    memcpy(pixelMatrixBuffer, demo_image_mono_128x128,
            displayDevice.geometry.width * displayDevice.geometry.height / 8 );

    status = displayDevice.pPixelMatrixDraw(&displayDevice,
            pixelMatrixBuffer,
            0,
            displayDevice.geometry.width,
            0,
            displayDevice.geometry.height);
#endif
    return 0;
}
      
      





Itu saja. Dalam video singkat Anda bisa melihat hasilnya.





Semua kode tersedia di GitHub . Jika ada papan, hal yang sama dapat direproduksi di atasnya menggunakan instruksi yang dijelaskan di wiki .



Hasilnya melebihi ekspektasi saya. Bagaimanapun, kami berhasil menjalankan Embox pada dasarnya pada RAM 2kB. Artinya, dengan opsi di Embox, overhead OS dapat diminimalkan. Apalagi sistemnya sudah multitasking. Bahkan jika itu kooperatif. Bagaimanapun, pengatur waktu tidak dipanggil secara langsung dalam konteks interupsi, tetapi dari konteksnya sendiri. Yang secara alami merupakan nilai tambah menggunakan OS. Tentu saja, contoh ini sebagian besar dibuat-buat. Memang, dengan sumber daya yang terbatas, fungsinya akan terbatas. Manfaat Embox mulai memengaruhi platform yang lebih canggih. Tetapi pada saat yang sama, ini dapat dianggap sebagai kasus pembatas Embox.



All Articles