[Системное программирование, Программирование микроконтроллеров] Embox на плате EFM32ZG_STK3200
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Embox является сильно конфигурируемой RTOS. Основная идея Embox прозрачный запуск Linux программного обеспечения везде, в том числе и на микроконтроллерах. Из достижений стоит привести OpenCV, Qt, PJSIP запущенные на микроконтроллерах STM32F7. Конечно, запуск подразумевает, что в данные проекты не вносились изменения и использовались только опции при конфигурации оригинальных проектов и параметры задаваемые в самой конфигурации Embox. Но возникает естественный вопрос насколько Embox позволяет экономить ресурсы по сравнению с тем же Linux? Ведь последний также достаточно хорошо конфигурируется.
Для ответа на этот вопрос можно подобрать минимально возможную для запуска Embox аппаратную платформу. В качестве такой платформы мы выбрали EMF32ZG_STK3200 от компании SiliconLabs. Данная платформа имеет 32kB ROM и 4kB RAM память. А также процессорное ядро cortex-m0+. Из периферии доступны UART, пользовательские светодиоды, кнопки, а также 128x128 монохромный дисплей. Нашей целью является запуск любого пользовательского приложения, позволяющего убедиться в работоспособности Embox на данной плате.
Для работы с периферией и самой платой нужны драйвера и другой системный код. Данный код можно взять из примеров предоставляемых самим производителем чипа. В нашем случае производитель предлагает использовать SimplifyStudio. Есть также открытый репозиторий на GitHub). Этот код и будем использовать.
В Embox есть механизмы позволяющие использовать BSP производителя при создании драйверов. Для этого нужно скачать BSP и собрать его как библиотеку в Embox. При этом можно указать различные пути и флаги, необходимые для использования данной библиотеки в драйверах.
Пример Makefile для скачивания 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 для сборки 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 для платы 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",
...
}
После таких достаточно простых действий можно использовать код от производителя. Прежде чем приступить к работе с драйверами необходимо разобраться со средствами разработки и архитектурными частями. В Embox используются обычные средства разработки gcc, gdb, openocd. При запуске openocd нужно указать что мы используем платформу efm32:
sudo openocd -f /usr/share/openocd/scripts/board/efm32.cfg
Для нашей платки нет каких-то специальных архитектурных частей, только специфика cortex-m0+. Это задается компилятором. Поэтому мы можем задать общий код для cotrex-m0 отключив все лишнее, например, работу с плавающей точкой.
@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
После этого можно попробовать скомпилить Embox и походить с помощью отладчика по шагам, проверив тем самым правильно ли мы задали параметры в линкер скрипте
/* region (origin, length) */
ROM (0x00000000, 32K)
RAM (0x20000000, 4K)
/* section (region[, lma_region]) */
text (ROM)
rodata (ROM)
data (RAM, ROM)
bss (RAM)
Первым драйвером реализуемым для поддержки какой-нибудь платы в Embox обычно является UART. На нашей плате есть LEUART. Для драйвера достаточно реализовать несколько функций. При этом мы можем использовать функции из 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);
Для того чтобы функции BSP были доступны нужно просто указать это в описании драйвера, файл 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
}
После реализации драйвера UART вам доступны не только вывод, но и консоль где вы можете вызвать свои пользовательские команды. Для этого вам достаточно добавить в конфигурационный файл 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")
А также указать, что нужно использовать не полноценный tty доступный через devfs, а заглушку, которая позволяет обращаться к заданному устройству. Устройство задается также в конфигурационном файле 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
Еще один очень простой драйвер это GPIO. Для его реализации мы также можем воспользоваться вызовами из BSP. Для этого в описании драйвера укажем что он зависит от 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
}
Сама реализация
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);
}
Этого достаточно чтобы использовать команду ‘pin’ из Embox. Данная команда позволяет управлять GPIO. И в частности, может использоваться для проверки мигания светодиодом.
Добавляем саму команду в mods.conf
include embox.cmd.hardware.pin
И сделаем так, чтобы она запускалась при старте. Для этого в конфигурационном файле start_sctpt.inc добавим одну из строчек
<source">«pin GPIOC 10 blink»,
Или
"pin GPIOC 11 blink",
Команды одинаковые, просто номера светодиодов разные.
Попробуем запустить еще и дисплей. Сначала все просто. Ведь мы опять можем использовать вызовы BSP. Для этого нам нужно только добавить их в описание драйвера фреймбуфера
package embox.driver.video
@BuildDepends(platform.efm32.efm32_bsp)
module efm32_lcd {
...
source "efm32_lcd.c"
@NoRuntime depends platform.efm32.efm32_bsp
}
Но как только мы делаем любой вызов связанный с дисплеем например DISPLAY_Init у нас секция .bss увеличивается больше чем на 2 kB, при размерах RAM 4 kB, это очень существенно. После изучения данного вопроса, выяснилось, что в самом BSP выделен фреймбуфер размером под дисплей. То есть 128x128x1 бит или 2048 байт.
В этот момент я даже хотел остановиться на достигнутом, ведь уместить в 4kB RAM вызов пользовательских команд с каким-то простым командным интерпретатором само по себе достижение. Но все-таки решил попробовать.
Первым я убрал командный интерпретатор и оставил только вызов уже упомянутой команды pin. Для этого я изменил конфигурационный файл mods.conf следующим образом
//@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)
Поскольку я использовал другой модуль для пользовательского старта, я перенес запуск команд в другой конфигурационный файл. Вместо start_script.inc использовал system_start.inc.
Затем, поскольку уже не требовалось использовать индексные дескрипторы в командном интерпретаторе, а также таймеры, я с помощью опций в 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)
Поскольку я вызывал команды напрямую, а не через командный интерпретатор, я смог уменьшить размер стека
@Runlevel(0) include embox.arch.arm.armmlib.exception_entry(irq_stack_size=224)
@Runlevel(0) include embox.kernel.stack(stack_size=448,alignment=4)
Наконец, у меня собралось и запустилось мигание светодиодом, и при этом внутри был вызов инициализации дисплея.
Мне хотелось вывести что нибудь на дисплейю Я подумал, что логотип Embox будет показателен. По хорошему нужно использовать полноценный драйвер фреймбуфера и выводить изображение из файла, ведь все это есть в Embox. Но места совсем не хватало. И для демонстрации я решил вывести логотип прямо в функции инициализации драйвера фреймбуфера. Причем данные конвертировав напрямую в битовый массив. Таким образом мне потребовалось ровно 2048 байт в ROM.
Сам код, как и ранее, использует 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;
}
Собственно все. На коротком видео можно увидеть результат.
Извините, данный ресурс не поддреживается. :(
Весь код доступен на GitHub. Если есть плата, то же самое можно воспроизвести на ней с помощью инструкции описанной на wiki.
Результат превзошел мои ожидания. Ведь удалось запустить Embox по сути на 2kB RAM. Это означает, что с помощью опций в Embox накладные расходы на использование ОС можно свести к минимуму. При этом в системе присутствует многозадачность. Пусть даже она и кооперативная. Ведь обработчики таймеров вызываются не напрямую в контексте прерывания, а из собственного контекста. Что естественно является плюсом использования ОС. Конечно, данный пример во многом искусственный. Ведь при столь ограниченных ресурсах и функциональность будет ограниченной. Преимущества Embox начинают сказываться на более мощных платформах. Но в то же время это можно считать предельным случаем работы Embox.
===========
Источник:
habr.com
===========
Похожие новости:
- [Программирование, Системное программирование, Отладка, Реверс-инжиниринг] Особенности структурной обработки исключений в Win64
- [Системное администрирование, Системное программирование, DevOps] Как управлять многоступенчатым окружением с помощью Ansible (перевод)
- [Программирование микроконтроллеров, Разработка под Arduino, DIY или Сделай сам] Запускаем код для Arduino в браузере
- [FPGA, Программирование микроконтроллеров, Учебный процесс в IT, Компьютерное железо, Робототехника] Passcode Data Protection by Using FPGA and Verilog
- [Системное администрирование, Системное программирование, DevOps] Проверка ролей Ansible через делегированный драйвер Molecule (перевод)
- [Проектирование и рефакторинг, C, Программирование микроконтроллеров] Свободный мини AUTOSAR редактор для микроконтроллеров
- [Информационная безопасность, Системное администрирование, Системное программирование, DevOps] Безопасное использование секретов: шаблон для использования HashiCorp Vault (перевод)
- [Программирование, Системное программирование, Реверс-инжиниринг] Планировщик Windows? Это очень просто
- [Программирование микроконтроллеров] STM32 Assembler Editor: Гора так и не сдвинулась с места, Магомед идет к ней
- [Промышленное программирование, Программирование микроконтроллеров] Программирование Modbus RTU Master на примере Simatic S7-1200 и ПЧ Sinamics V20
Теги для поиска: #_sistemnoe_programmirovanie (Системное программирование), #_programmirovanie_mikrokontrollerov (Программирование микроконтроллеров), #_efm32, #_embox, #_mcu, #_rtos, #_blog_kompanii_embox (
Блог компании Embox
), #_sistemnoe_programmirovanie (
Системное программирование
), #_programmirovanie_mikrokontrollerov (
Программирование микроконтроллеров
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 19:21
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Embox является сильно конфигурируемой RTOS. Основная идея Embox прозрачный запуск Linux программного обеспечения везде, в том числе и на микроконтроллерах. Из достижений стоит привести OpenCV, Qt, PJSIP запущенные на микроконтроллерах STM32F7. Конечно, запуск подразумевает, что в данные проекты не вносились изменения и использовались только опции при конфигурации оригинальных проектов и параметры задаваемые в самой конфигурации Embox. Но возникает естественный вопрос насколько Embox позволяет экономить ресурсы по сравнению с тем же Linux? Ведь последний также достаточно хорошо конфигурируется. Для ответа на этот вопрос можно подобрать минимально возможную для запуска Embox аппаратную платформу. В качестве такой платформы мы выбрали EMF32ZG_STK3200 от компании SiliconLabs. Данная платформа имеет 32kB ROM и 4kB RAM память. А также процессорное ядро cortex-m0+. Из периферии доступны UART, пользовательские светодиоды, кнопки, а также 128x128 монохромный дисплей. Нашей целью является запуск любого пользовательского приложения, позволяющего убедиться в работоспособности Embox на данной плате. Для работы с периферией и самой платой нужны драйвера и другой системный код. Данный код можно взять из примеров предоставляемых самим производителем чипа. В нашем случае производитель предлагает использовать SimplifyStudio. Есть также открытый репозиторий на GitHub). Этот код и будем использовать. В Embox есть механизмы позволяющие использовать BSP производителя при создании драйверов. Для этого нужно скачать BSP и собрать его как библиотеку в Embox. При этом можно указать различные пути и флаги, необходимые для использования данной библиотеки в драйверах. Пример Makefile для скачивания 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 для сборки 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 для платы 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", ... } После таких достаточно простых действий можно использовать код от производителя. Прежде чем приступить к работе с драйверами необходимо разобраться со средствами разработки и архитектурными частями. В Embox используются обычные средства разработки gcc, gdb, openocd. При запуске openocd нужно указать что мы используем платформу efm32: sudo openocd -f /usr/share/openocd/scripts/board/efm32.cfg
Для нашей платки нет каких-то специальных архитектурных частей, только специфика cortex-m0+. Это задается компилятором. Поэтому мы можем задать общий код для cotrex-m0 отключив все лишнее, например, работу с плавающей точкой. @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 После этого можно попробовать скомпилить Embox и походить с помощью отладчика по шагам, проверив тем самым правильно ли мы задали параметры в линкер скрипте /* region (origin, length) */
ROM (0x00000000, 32K) RAM (0x20000000, 4K) /* section (region[, lma_region]) */ text (ROM) rodata (ROM) data (RAM, ROM) bss (RAM) Первым драйвером реализуемым для поддержки какой-нибудь платы в Embox обычно является UART. На нашей плате есть LEUART. Для драйвера достаточно реализовать несколько функций. При этом мы можем использовать функции из 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); Для того чтобы функции BSP были доступны нужно просто указать это в описании драйвера, файл 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 } После реализации драйвера UART вам доступны не только вывод, но и консоль где вы можете вызвать свои пользовательские команды. Для этого вам достаточно добавить в конфигурационный файл 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") А также указать, что нужно использовать не полноценный tty доступный через devfs, а заглушку, которая позволяет обращаться к заданному устройству. Устройство задается также в конфигурационном файле 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 Еще один очень простой драйвер это GPIO. Для его реализации мы также можем воспользоваться вызовами из BSP. Для этого в описании драйвера укажем что он зависит от 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 } Сама реализация 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); } Этого достаточно чтобы использовать команду ‘pin’ из Embox. Данная команда позволяет управлять GPIO. И в частности, может использоваться для проверки мигания светодиодом. Добавляем саму команду в mods.conf include embox.cmd.hardware.pin
И сделаем так, чтобы она запускалась при старте. Для этого в конфигурационном файле start_sctpt.inc добавим одну из строчек <source">«pin GPIOC 10 blink», Или "pin GPIOC 11 blink",
Команды одинаковые, просто номера светодиодов разные. Попробуем запустить еще и дисплей. Сначала все просто. Ведь мы опять можем использовать вызовы BSP. Для этого нам нужно только добавить их в описание драйвера фреймбуфера package embox.driver.video
@BuildDepends(platform.efm32.efm32_bsp) module efm32_lcd { ... source "efm32_lcd.c" @NoRuntime depends platform.efm32.efm32_bsp } Но как только мы делаем любой вызов связанный с дисплеем например DISPLAY_Init у нас секция .bss увеличивается больше чем на 2 kB, при размерах RAM 4 kB, это очень существенно. После изучения данного вопроса, выяснилось, что в самом BSP выделен фреймбуфер размером под дисплей. То есть 128x128x1 бит или 2048 байт. В этот момент я даже хотел остановиться на достигнутом, ведь уместить в 4kB RAM вызов пользовательских команд с каким-то простым командным интерпретатором само по себе достижение. Но все-таки решил попробовать. Первым я убрал командный интерпретатор и оставил только вызов уже упомянутой команды pin. Для этого я изменил конфигурационный файл mods.conf следующим образом //@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) Поскольку я использовал другой модуль для пользовательского старта, я перенес запуск команд в другой конфигурационный файл. Вместо start_script.inc использовал system_start.inc. Затем, поскольку уже не требовалось использовать индексные дескрипторы в командном интерпретаторе, а также таймеры, я с помощью опций в 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) Поскольку я вызывал команды напрямую, а не через командный интерпретатор, я смог уменьшить размер стека @Runlevel(0) include embox.arch.arm.armmlib.exception_entry(irq_stack_size=224)
@Runlevel(0) include embox.kernel.stack(stack_size=448,alignment=4) Наконец, у меня собралось и запустилось мигание светодиодом, и при этом внутри был вызов инициализации дисплея. Мне хотелось вывести что нибудь на дисплейю Я подумал, что логотип Embox будет показателен. По хорошему нужно использовать полноценный драйвер фреймбуфера и выводить изображение из файла, ведь все это есть в Embox. Но места совсем не хватало. И для демонстрации я решил вывести логотип прямо в функции инициализации драйвера фреймбуфера. Причем данные конвертировав напрямую в битовый массив. Таким образом мне потребовалось ровно 2048 байт в ROM. Сам код, как и ранее, использует 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; } Собственно все. На коротком видео можно увидеть результат. Извините, данный ресурс не поддреживается. :( Весь код доступен на GitHub. Если есть плата, то же самое можно воспроизвести на ней с помощью инструкции описанной на wiki. Результат превзошел мои ожидания. Ведь удалось запустить Embox по сути на 2kB RAM. Это означает, что с помощью опций в Embox накладные расходы на использование ОС можно свести к минимуму. При этом в системе присутствует многозадачность. Пусть даже она и кооперативная. Ведь обработчики таймеров вызываются не напрямую в контексте прерывания, а из собственного контекста. Что естественно является плюсом использования ОС. Конечно, данный пример во многом искусственный. Ведь при столь ограниченных ресурсах и функциональность будет ограниченной. Преимущества Embox начинают сказываться на более мощных платформах. Но в то же время это можно считать предельным случаем работы Embox. =========== Источник: habr.com =========== Похожие новости:
Блог компании Embox ), #_sistemnoe_programmirovanie ( Системное программирование ), #_programmirovanie_mikrokontrollerov ( Программирование микроконтроллеров ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 19:21
Часовой пояс: UTC + 5