在 ALIENTEK 阿波罗STM32F429开发板上使用 openvela 点亮 LED(二)

一、概述

本指南(参考在STM32F411 上使用 openvela 点亮 LED)将引导您基于 ALIENTEK 阿波罗STM32F429开发板上,在 openvelapackages/demos 目录下添加、配置并运行一个自定义的 LED 控制应用。区别于在 ALIENTEK 阿波罗STM32F429开发板上使用 openvela 点亮 LED(一),本文创建了一个独立的 APP_DEMOS_LED 选项,而不是复用 EXAMPLES_LEDS,这使得新增的 Demo 逻辑清晰,配置简单,避免了不必要的依赖和混淆。

二、准备工作

在开始之前,请确保您已完成以下准备工作:

  1. 获取源码:参考文档快速入门下载最新代码。
  2. 了解 openvela 架构:建议您预先阅读 openvela 架构以理解其分层设计。
  3. 查阅系统启动流程文档,获取更详细的启动时序和函数调用关系图。
  4. 准备好硬件及配套软件
  5. 已完成前期的移植验证操作。

三、新增 Demo

本章将指导您如何在 openvelapackages/demos 目录下添加、配置并运行一个自定义的 LED 控制应用。

1、核心步骤概述

openvela 中集成一个新应用,主要遵循以下流程:

  1. 创建应用文件:在 packages/demos/ 下创建新目录,并编写应用的 C 源码、KconfigMakefile
  2. 注册应用到编译系统:创建并编辑 packages/demos/Make.defs 文件,让构建系统能够发现您的新应用。
  3. 配置与编译:创建apollo-stm32f429i/configs/leds_demo/deconfig,启用新应用的配置,并编译生成包含新应用的固件。
  4. 运行与验证:烧录固件,并通过终端命令运行您的 Demo。

2、创建 Demo 源码及配置文件

  1. 创建 leds 目录:

    # 确保当前位于 openvela 源码根目录
    mkdir -p packages/demos/leds
    
  2. 创建 C 语言源文件 (packages/demos/led/leds_main.c): 此文件是 Demo 的核心逻辑,它通过 ioctl 系统调用与底层 LED 驱动进行交互。

    /****************************************************************************
     * packages/demos/leds/leds_main.c
     ****************************************************************************/
    
    /****************************************************************************
     * Included Files
     ****************************************************************************/
    
    #include <nuttx/config.h>
    
    #include <sys/ioctl.h>
    #include <stdbool.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <fcntl.h>
    #include <sched.h>
    #include <errno.h>
    #include <signal.h>
    #include <unistd.h>
    
    #include <nuttx/leds/userled.h>
    
    /****************************************************************************
     * Private Data
     ****************************************************************************/
    
    static bool g_led_daemon_started;
    
    /****************************************************************************
     * Private Functions
     ****************************************************************************/
    
    /****************************************************************************
     * Name: sigterm_action
     ****************************************************************************/
    
    static void sigterm_action(int signo, siginfo_t *siginfo, void *arg)
    {
      if (signo == SIGTERM)
        {
          printf("SIGTERM received\n");
    
          g_led_daemon_started = false;
          printf("led_daemon: Terminated.\n");
        }
      else
        {
          printf("\nsigterm_action: Received signo=%d siginfo=%p arg=%p\n",
                 signo, siginfo, arg);
        }
    }
    
    /****************************************************************************
     * Name: led_daemon
     ****************************************************************************/
    
    static int led_daemon(int argc, char *argv[])
    {
      userled_set_t supported;
      userled_set_t ledset;
      int ret;
      int fd;
      int loop_num;
      pid_t mypid;
      struct sigaction act;
    
      /* SIGTERM handler */
    
      memset(&act, 0, sizeof(struct sigaction));
      act.sa_sigaction = sigterm_action;
      act.sa_flags     = SA_SIGINFO;
    
      sigemptyset(&act.sa_mask);
      sigaddset(&act.sa_mask, SIGTERM);
    
      ret = sigaction(SIGTERM, &act, NULL);
      if (ret != 0)
        {
          fprintf(stderr, "Failed to install SIGTERM handler, errno=%d\n",
                  errno);
          return (EXIT_FAILURE + 1);
        }
    
      /* Indicate that we are running */
    
      mypid = getpid();
    
      g_led_daemon_started = true;
      printf("\nled_daemon (pid# %d): Running\n", mypid);
    
      /* Open the LED driver */
    
      printf("led_daemon: Opening %s\n", CONFIG_APP_DEMOS_LEDS_DEVPATH);
      fd = open(CONFIG_APP_DEMOS_LEDS_DEVPATH, O_WRONLY);
      if (fd < 0)
        {
          int errcode = errno;
          printf("led_daemon: ERROR: Failed to open %s: %d\n",
                 CONFIG_APP_DEMOS_LEDS_DEVPATH, errcode);
          goto errout;
        }
    
      /* Get the set of LEDs supported */
    
      ret = ioctl(fd, ULEDIOC_SUPPORTED,
                  (unsigned long)((uintptr_t)&supported));
      if (ret < 0)
        {
          int errcode = errno;
          printf("led_daemon: ERROR: ioctl(ULEDIOC_SUPPORTED) failed: %d\n",
                 errcode);
          goto errout_with_fd;
        }
    
      /* Excluded any LEDs that not supported AND not in the set of LEDs the
       * user asked us to use.
       */
    
      printf("led_daemon: Supported LEDs 0x%02x\n", (unsigned int)supported);
      supported &= CONFIG_APP_DEMOS_LEDS_LEDSET;
    
      /* Now loop for a while, changing the LED set */
    
      loop_num = 5;
    
      while (g_led_daemon_started == true)
        {
            ledset = (1 << (loop_num % 2) ) & supported;
            printf("led_daemon: LED set 0x%02x\n", (unsigned int)ledset);
            
            ret = ioctl(fd, ULEDIOC_SETALL, (unsigned long)ledset);
            if (ret < 0)
            {
                printf("ioctl(ULEDIOC_SETALL) failed: %d\n", ret);
                close(fd);
                return -1;
            }
            sleep(1); 
    
          if (loop_num-- == 0)
            {
                goto sigtermout;
            }
    
         
        }
    
      /* treats signal termination of the task
       * task terminated by a SIGTERM
       */
    sigtermout: 
      g_led_daemon_started = false;
      close(fd);
      printf("led_daemon: Terminating\n");
      printf("LED Demo finished.\n");
      exit(EXIT_SUCCESS);
    
    errout_with_fd:
      close(fd);
    
    errout:
      g_led_daemon_started = false;
      printf("led_daemon: Terminating\n");
    
      return EXIT_FAILURE;
    }
    
    /****************************************************************************
     * Public Functions
     ****************************************************************************/
    
    /****************************************************************************
     * leds_main
     ****************************************************************************/
    
    int main(int argc, FAR char *argv[])
    {
      int ret;
    
      printf("leds_main: Starting the led_daemon\n");
      if (g_led_daemon_started)
        {
          printf("leds_main: led_daemon already running\n");
          return EXIT_SUCCESS;
        }
    
      ret = task_create("led_daemon", CONFIG_APP_DEMOS_LEDS_PRIORITY,
                        CONFIG_APP_DEMOS_LEDS_STACKSIZE, led_daemon,
                        NULL);
      if (ret < 0)
        {
          int errcode = errno;
          printf("leds_main: ERROR: Failed to start led_daemon: %d\n",
                 errcode);
          return EXIT_FAILURE;
        }
    
      printf("leds_main: led_daemon started\n");
      return EXIT_SUCCESS;
    }
    
    
  3. 创建 Kconfig 文件。此文件用于在 menuconfig 中生成一个独立的配置选项来控制是否编译此 Demo。

    packages/demos/leds/Kconfig:

    # Defines the configuration option for the custom LED Demo.
    # This will appear under "Application Configuration -> Demos".
    config APP_DEMOS_LEDS
        bool "Custom LED control demo"
        default n
        depends on USERLED  # This demo requires the base USERLED driver
        ---help---
            Enable this to build the custom LED control demo, which
            demonstrates how to turn an LED on and off via ioctl.
    
    if APP_DEMOS_LEDS
    
    config APP_DEMOS_LEDS_PROGNAME
    	string "Program name"
    	default "leds_demo"
    	---help---
    		This is the name of the program that will be used when the NSH ELF
    		program is installed.
    
    config APP_DEMOS_LEDS_PRIORITY
    	int "LED task priority"
    	default 100
    
    config APP_DEMOS_LEDS_STACKSIZE
    	int "LED stack size"
    	default DEFAULT_TASK_STACKSIZE
    
    config APP_DEMOS_LEDS_DEVPATH
    	string "LED device path"
    	default "/dev/userleds"
    
    config APP_DEMOS_LEDS_LEDSET
    	hex "Subset of LEDs to use"
    	default 0x0f
    
    endif # APP_DEMOS_LEDS
    

说明:我们创建了一个独立的 APP_DEMOS_LED 选项,而不是复用 EXAMPLES_LEDS,这使得新增的 Demo 逻辑清晰,配置简单,避免了不必要的依赖和混淆。

  1. 创建 Makefile 文件: 此文件定义了本应用的编译规则,如程序名、优先级和堆栈大小。
    packages/demos/leds/Makefile:

    include $(APPDIR)/Make.defs
    ifeq ($(CONFIG_APP_DEMOS_LEDS), y)
    # Application details, linked to the Kconfig option
    PROGNAME  = $(CONFIG_APP_DEMOS_LEDS_PROGNAME)
    PRIORITY  = $(CONFIG_APP_DEMOS_LEDS_PRIORITY)
    STACKSIZE = $(CONFIG_APP_DEMOS_LEDS_STACKSIZE)
    MODULE = $(CONFIG_APP_DEMOS_LEDS)
    # Source file for the application
    MAINSRC = leds_main.c
    endif
    
    include $(APPDIR)/Application.mk
    

3、注册新 Demo 到编译系统

编辑 packages/demos/ 目录下的 Make.defs 文件,将我们的 led Demo 加入编译列表。

  1. 打开 packages/demos/leds/Make.defs 文件。

  2. 在文件末尾添加以下代码:

    ifneq ($(CONFIG_APP_DEMOS_LEDS),)
    CONFIGURED_APPS += $(APPDIR)/packages/demos/leds
    endif
    

4、创建新的配置

为ALIENTEK 阿波罗STM32F429开发板移植openvela :: 二、代码实现步骤 :: 1.创建代码目录结构 为基础,在nuttx/boards/arm/stm32/apollo-stm32f429i/configs目录下,创建一个名为 leds_demo的新目录,并在此目录中创建LED示例的默认配置文件deconfig

nuttx/boards/arm/stm32/apollo-stm32f429i/configs/leds_demo/deconfig

#
# This file is autogenerated: PLEASE DO NOT EDIT IT.
#
# You can use "make menuconfig" to make any modifications to the installed .config file.
# You can then do "make savedefconfig" to generate a new defconfig file that includes your
# modifications.
#
# CONFIG_ARCH_FPU is not set
# CONFIG_ARCH_LEDS is not set
# CONFIG_NSH_ARGCAT is not set
# CONFIG_NSH_CMDOPT_HEXDUMP is not set
CONFIG_APP_DEMOS_LEDS=y
CONFIG_ARCH="arm"
CONFIG_ARCH_BOARD="apollo-stm32f429i"
CONFIG_ARCH_BOARD_APOLLO_STM32F429I=y
CONFIG_ARCH_BUTTONS=y
CONFIG_ARCH_CHIP="stm32"
CONFIG_ARCH_CHIP_STM32=y
CONFIG_ARCH_CHIP_STM32F429I=y
CONFIG_ARCH_STACKDUMP=y
CONFIG_BOARD_LATE_INITIALIZE=y
CONFIG_BOARD_LOOPSPERMSEC=13984
CONFIG_BUILTIN=y
CONFIG_DEBUG_SYMBOLS=y
CONFIG_EXAMPLES_LEDS=y
CONFIG_FS_PROCFS=y
CONFIG_HAVE_CXX=y
CONFIG_HAVE_CXXINITIALIZE=y
CONFIG_INIT_ENTRYPOINT="nsh_main"
CONFIG_INTELHEX_BINARY=y
CONFIG_MM_REGIONS=2
CONFIG_NSH_BUILTIN_APPS=y
CONFIG_NSH_FILEIOSIZE=512
CONFIG_NSH_READLINE=y
CONFIG_PREALLOC_TIMERS=4
CONFIG_RAM_SIZE=114688
CONFIG_RAM_START=0x20000000
CONFIG_RAW_BINARY=y
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_WAITPID=y
CONFIG_START_DAY=6
CONFIG_START_MONTH=12
CONFIG_START_YEAR=2011
CONFIG_STM32_DISABLE_IDLE_SLEEP_DURING_DEBUG=y
CONFIG_STM32_JTAG_SW_ENABLE=y
CONFIG_STM32_PWR=y
CONFIG_STM32_USART1=y
CONFIG_SYSTEM_NSH=y
CONFIG_TASK_NAME_SIZE=0
CONFIG_USART1_SERIAL_CONSOLE=y
CONFIG_USERLED=y
CONFIG_USERLED_LOWER=y

四、运行Demo

1、编译代码

切换到 openvela 的根目录,distclean 之后 build:

# (Optional but recommended) Clean previous build artifacts
./build.sh nuttx/boards/arm/stm32/apollo-stm32f429i/configs/leds_demo distclean
# Build the project with the new configuration
./build.sh apollo-stm32f429i:leds_demo -j8

编译完成后,生成的文件位于 nuttx 目录下,包括:

  • nuttx.bin
  • nuttx.hex

2、烧录固件

参考在 STM32F411 上使用 openvela 点亮 LED: : 四、运行Demo::5、烧录固件

3、连接串口

参考在 STM32F411 上使用 openvela 点亮 LED: : 四、运行Demo::6、连接串口

4、运行 LED 示例

  1. 重新打开 minicom,连接成功后,在 Minicom 终端中按回车,您会看到 nsh> 提示符。

  2. 运行 LED 示例,请输入以下命令:

    leds_demo
    
  3. 您将看到开发板上的用户 LED 开始交替闪烁,同时串口终端会输出运行日志。

leds_demo_new

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐