在2024年全国大学生。嵌入式。芯片。与体系规划比赛中,各大高校学子纷繁展现出杰出的立异才能和厚实的技能功底。今日,特别为我们共享获奖作品——。USB。一线通监控副屏,它以其共同的规划和有用的功用赢得广泛好评与认可。 原文链接:https://club.。rt-thread。.。or。g/ask/ar。ti。cle/fd0a9bdab79b7c65.html。 环境树立。 环境变量装备。 为了进步一些编译的速度,挑选了在。Linux。体系下进行开发,在Linux上开发N947需求先装置 env 东西https://github.com/RT-Thread/env,依照阐明文档进行装置即可,然后装备一些环境变量: 其间 /opt/。arm。-gnu-toolchain-13.2.Rel1-x86_64-arm-none-eabi/bin 是自己的编译东西链的途径,/home/book/rt-thread 是rt-thread根目录的途径:。 source ~/.env/env.sh export RTT_CC=gcc export RTT_ROOT=/home/book/rt-thread export RTT_DIR=/home/book/rt-thread export RTT_EXEC_PATH=/opt/arm-gnu-toolchain-13.2.Rel1-x86_64-arm-none-eabi/binexportPATH=$PATH:$RTT_EXEC_PATH。 假如需求将N947的例程从rt-thread的根文件夹中独立出来的话,需求删去工程中Kconfig文件的这行代码: 代码高亮。 这儿运用VSCode中的Clang插件,代码高亮和补全能够经过运用编译时分生成的 com。pi。le_commands.json文件来完结,而RT-Thread的工程是选用的scons东西,所以能够运用scons_compi。led。b这个。python。包来生成compile_commands.json 完结代码高亮,修正正的SConstruct文件如下: import osimport sysimport rtconfigimport scons_compiledbif os.ge。te。nv('RTT_ROOT'): RTT_ROOT = os.getenv('RTT_ROOT')else: RTT_ROOT = os.path.normpath(os.getcwd() + '/../../../../..')sys.path = sys.path + [os.path.join(RTT_ROOT, 'tools')]try: from building import *except: print('。Can。not found RT-Thread root directory, please check RTT_ROOT') print(RTT_ROOT) exit(-1)TARGET = '。rtthread。.' + rtconfig.TARGET_EXTif rtconfig.PLATFORM == 'armcc': env = Environment(tools = ['mingw'], AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS, CC = rtconfig.CC, CFLAGS = rtconfig.CFLAGS, CXX = rtconfig.CXX, CXXFLAGS = rtconfig.CXXFLAGS, AR = rtconfig.AR, ARFLAGS = '-rc', LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS, # overwrite cflags, because cflags has '--C99' CXXCOM = '$CXX -o $TARGET --cpp -c $CXXFLAGS $_CCCOMCOM $SOURCES')else: env = Environment(tools = ['mingw'], AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS, CC = rtconfig.CC, CFLAGS = rtconfig.CFLAGS, CXX = rtconfig.CXX, CXXFLAGS = rtconfig.CXXFLAGS, AR = rtconfig.AR, ARFLAGS = '-rc', LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS, CXXCOM = '$CXX -o $TARGET -c $CXXFLAGS $_CCCOMCOM $SOURCES')env.PrependENVPath('PATH', rtconfig.EXEC_PATH)scons_compiledb.enable(env)env.CompileDb()if rtconfig.PLATFORM in ['。ic。carm']: env.Repl。ac。e(CCCOM = ['$CC $CFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -o $TARGET $SOURCES']) env.Replace(ARFLAGS = ['']) env.Replace(LINKCOM = env["LINKCOM"] + ' --map rtthread.map')Export('RTT_ROOT')Export('rtconfig')。SD。K_ROOT = os.path.abspath('./')if os.path.exists(SDK_ROOT + '/Libraries'): libraries_path_prefix = SDK_ROOT + '/Libraries'else: libraries_path_prefix = os.path.dirname(SDK_ROOT) + '/Libraries'SDK_LIB = libraries_path_prefixExport('SDK_LIB')# prepare building environmentobjs = PrepareBuilding(env, RTT_ROOT, has_lib。cpu。=False)objs.extend(SConscript(os.path.join(libraries_path_prefix, 'drivers', 'SConscript')))# include cmsisobjs.extend(SConscript(os.path.join(libraries_path_prefix, rtconfig.BSP_LIBRARY_TYPE, 'SConscript')))# make a buildingDoBuilding(TARGET,objs)。 终究树立完结的作用如下所示,代码高亮非常且便利检查代码: LVGL。适配。 屏幕拓展板。 FRDM-MCXN947这个开发板预留了一个FlexIO。接口。能够适配8080的并口屏,所以做了一个屏幕拓展板,把手里搁置的屏幕用起来: 什物如下,接触排线座子有点偏下,不过不影响功用: 屏幕手册阐明分辨率是240*320。驱动芯片。是ST7789V、接触芯片是FT6336G,而官方的SDK中是有ST7796和FT5406的驱动代码的,后续还需求稍作修正:。 驱动适配。 在官方的SDK中有ST7796和FT5406的驱动程序,直接移植过来即可,一起也把 E。DMA。和SMARTDMA的驱动仿制了过来,修正一下屏幕的初始化序列即可驱动屏幕: LVGL 适配。 将SDK中的 lvgl_support仿制到工程中,修正屏幕的宽高为240*320: 然后在board中新建一个lv_conf.h文件,填入关于LVGL的一些装备,由于许多装备在menuconfig中有所设置,所以这儿的装备项并不多:。 #ifndef LV_CONF_H#define LV_CONF_H#include。 #define LV_USE_SYSMON 1#define LV_USE_PE。RF。_MONITOR 0#define LV_COLOR_DEPTH 16#define LV_HOR_RES_MAX 240#define LV_VER_RES_MAX 320#define LV_COLOR_16_SWAP 0#define BSP_USING_LVGL_BENCHMARK_DEMO#define BSP_USING_LVGL_WIDGETS_DEMO#ifdef BSP_USING_LVGL_DAVE2D #define LV_USE_DRAW_DAVE2D 1#endif#ifdef BSP_USING_LVGL_WIDGETS_DEMO #define LV_USE_DEMO_WIDGETS 1 #define LV_DEMO_WIDGETS_SLIDESHOW 0#endif /* BSP_USING_LVGL_WIDGETS_DEMO *//*Benchmark your system*/#ifdef BSP_USING_LVGL_BENCHMARK_DEMO #define LV_USE_DEMO_BENCHMARK 1 /*Use RGB565A8 images with 16 bit color depth inste。ad。of ARGB8565*/ #define LV_DEMO_BENCHMARK_RGB565A8 1 #define LV_FONT_MONTSERRAT_14 1 #define LV_FONT_MONTSERRAT_24 1#endif /* BSP_USING_LVGL_BENCHMARK_DEMO *//*Stress test for LVGL*/#ifdef BSP_USING_LVGL_STRESS_DEMO #define LV_USE_DEMO_STRESS 1#endif /* BSP_USING_LVGL_STRESS_DEMO *//*Render test for LVGL*/#ifdef BSP_USING_LVGL_RENDER_DEMO #define LV_USE_DEMO_RENDER 1#endif /* BSP_USING_LVGL_RENDER_DEMO *//*Music player demo*/#ifdef BSP_USING_LVGL_MUSIC_DEMO #define LV_USE_DEMO_MUSIC 1 #define LV_DEMO_MUSIC_SQUARE 1 #define LV_DEMO_MUSIC_LANDSCAPE 0 #define LV_DEMO_MUSIC_ROUND 0 #define LV_DEMO_MUSIC_LARGE 0 #define LV_DEMO_MUSIC_AUTO_PLAY 0 #define LV_FONT_MONTSERRAT_12 1 #define LV_FONT_MONTSERRAT_16 1#endif /* BSP_USING_LVGL_MUSIC_DEMO */#endif。 仿制过来的lvgl_support中有对。FreeRTOS。的支撑,这儿将FreeRTOS的API修正为RTT的API,例如如下这段代码: 而且 N947 的驱动程序有EDMA + FlexIO和SMARTDMA + FlexIO两种驱动方法,详细差异不太了解,不过能够运转LVGL的Benchmark测验来看下成果,左面是SMARTDMA运转的成果,右边是EDMA的成果,能够看到前者的FPS更高。后续也就持续选用SMARTDMA + FlexIO的驱动方法:。 界面规划。 运用操作简洁的GUI Guider规划一个界面,生成制作界面的代码,然后添加到工程中:。 还需求修正工程文件夹中的 rtconfig.py,添加一个 LV_LVGL_H_INCLUDE_。SIM。PLE 的预界说,由于生成的代码默许包括lvgl.h是#include "lvgl/lvgl.h", CFLAGS = DEVICE + ' -Wall -D__FPU_PRESENT -DLV_LVGL_H_INCLUDE_SIMPLE'。 终究适配完结的LVGL代码和GUI Guider的代码目录如下,LVGL 的UI制作代码段如图右边所示,详细代码可见开源地址:。 USB通讯。 适配 C。DC。 完结了下位机的界面的初始化制作,后续的使命当然便是怎样把数据收集并发送给下位机来更新界面的数据了,下面先完结USB的通讯,这儿运用的是RTT官方。引荐。的CherryUSB这个开源USB协议栈:。 将如下链接中的适配代码仿制到工程中:。 https://github.com/CherryUSB/cherryusb_mcx。 由于传输的数据比较单一,这儿运用串口屏的思路,直接用CDC_ACM的通讯方法,也便是在。上位机。显现为一个USB转串口设备,直接运用串口API完结通讯。 将RTT根目录中 rt-thread/components/drivers/usb/cherryusb/demo文件夹中的CDC_ACM例程仿制到工程中,而且把根目录中的这两行代码屏蔽: 修正工程中的cherryusb_port.c文件,添加对CDC_ACM的支撑: /* * Copyright (c) 2006-2024, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2024/04/23 sakumisu fi。rs。t version */#include。 #include。 /* low level init here, this has implemented in cherryusb *//* low level deinit here, this has implemented in cherryusb */#ifdef RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACMint cherryusb_devinit(void){ // extern void cherryusb_devinit(uint8_t busid, uintptr_t reg_base); extern void cdc_acm_init(uint8_t busid, uintptr_t reg_base); cdc_acm_init(0, USBHS1__USBC_BASE); return 0;}INIT_COMPONENT_EXPORT(cherryusb_devinit);#endif#ifdef RT_CHERRYUSB_DEVICE_TEMPLATE_MSCint cherryusb_devinit(void){ extern void msc_。ram。_init(uint8_t busid, uintptr_t reg_base); msc_ram_init(0, USBHS1__USBC_BASE); return 0;}INIT_COMPONENT_EXPORT(cherryusb_devinit);#endif#ifdef RT_CHERRYUSB_HOST#include "usbh_core.h"int cherryusb_hostinit(void){ usbh_initialize(0, USBHS1__USBC_BASE); return 0;}INIT_COMPONENT_EXPORT(cherryusb_hostinit);#endif。 将方才仿制到工程中的CDC_ACM 的 demo程序中端点收发的程序做如下修正,添加关于输入。信息。的回显: oid usbd_cdc_acm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes){ USB_LOG_RAW("actual out len:%d", nbytes); /* setup next out ep read transfer */ usbd_ep_start_read(busid, CDC_OUT_EP, read_buffer, 2048); for (int i = 0; i。 < nbytes; i++) { printf("%02x ", read_buffer[i]); } printf("");} 验证。 然后插上开发板的USB HS那个USB接口,用串口东西发个数据包: 能够看到现已辨认成了USB串行设备,PID 和VID也是我自己设置的0xE6E9和0x1122,后续上位机与开发板树立通讯确定COM号便是依托PID VID来查询完结,运用串口东西给开发板发送的数据也能够正常接纳到。 上位机。时刻原因上位机做的比较简单,完结了如下几个功用: 读取。电脑。的CPU、。GPU。的占用率和温度信息、获取当时时刻。 依据VID、PID查询COM来与开发板通讯,下发收集数据与时刻。 添加帧头后发送到下位机,固定长度32+2个字节。 下位机数据更新。在开发板端添加一个thread来担任把USB接纳到的数据更新到屏幕上面,运用LVGL的API直接修正数据即可,代码如下: 数据结构体: typedef struct{ uint16_t cpu_usage; uint16_t mem_usage; uint16_t gpu_usage; uint16_t cpu_freq; uint16_t cpu_temperature; uint16_t gpu_temperature; uint16_t board_temperature;} monitor_info_u16_t;typedef struct { uint16_t wYear; uint16_t wMonth; uint16_t wDayOfWeek; uint16_t wDay; uint16_t wHour; uint16_t wMinute; uint16_t wSecond; uint16_t wMilliseconds;} mytime_t; 在USB端点输出的回调函数中添加音讯行列发送函数:void usbd_cdc_acm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes){ USB_LOG_RAW("actual out len:%d", nbytes); /* setup next out ep read transfer */ usbd_ep_start_read(busid, CDC_OUT_EP, read_buffer, 2048); for (int i = 0; i。 < nbytes; i++) { printf("%02x ", read_buffer[i]); } printf(""); if (34 == nbytes) { rt_mq_send(&usb_mq, read_buffer, 34); }} main函数中的接纳音讯行列:uint8_t read_buffer[128];while (1){ /* 从音讯行列中接纳音讯 */ if (rt_mq_recv(&usb_mq, read_buffer, 34, RT_W。AI。TING_FOREVER) >0) { mytime_t* p_time_u16 = (mytime_t*)(read_buffer + 2); monitor_info_u16_t* p_info_u16 = (monitor_info_u16_t *)(read_buffer + 2 + sizeof(mytime_t)); rt_kprintf("wYear %u", p_time_u16->wYear); rt_kprintf("wMonth %u", p_time_u16->wMonth); rt_kprintf("wDayOfWeek %u", p_time_u16->wDayOfWeek); rt_kprintf("wDay %u", p_time_u16->wDay); rt_kprintf("wHour %u", p_time_u16->wHour); rt_kprintf("wMinute %u", p_time_u16->wMinute); rt_kprintf("wSecond %u", p_time_u16->wSecond); rt_kprintf("wMilliseconds %u", p_time_u16->wMilliseconds); rt_kprintf("cpu_usage %u", p_info_u16->cpu_usage); rt_kprintf("mem_usage %u", p_info_u16->mem_usage); rt_kprintf("gpu_usage %u", p_info_u16->gpu_usage); rt_kprintf("cpu_freq %u", p_info_u16->cpu_freq); rt_kprintf("cpu_temperature %u", p_info_u16->cpu_temperature); rt_kprintf("gpu_temperature %u", p_info_u16->gpu_temperature); rt_kprintf("board_temperature %u", p_info_u16->board_temperature); lv_label_set_text_fmt(guider_ui.screen_label_cpu_temp, "%2d", p_info_u16->cpu_temperature); lv_label_set_text_fmt(guider_ui.screen_label_gpu_temp, "%2d", p_info_u16->gpu_temperature); lv_label_set_text_fmt(guider_ui.screen_label_cpu_load, "%2d", p_info_u16->cpu_usage); lv_label_set_text_fmt(guider_ui.screen_label_gpu_load, "%2d", p_info_u16->gpu_usage); lv_arc_set_value(guider_ui.screen_arc_gpu_load, p_info_u16->gpu_usage); lv_arc_set_value(guider_ui.screen_arc_gpu_temp, p_info_u16->gpu_temperature); lv_label_set_text_fmt(guider_ui.screen_time, "%02d:%02d", p_time_u16->wHour, p_time_u16->wMinute); lv_label_set_text_fmt(guider_ui.screen_date, "%02d.%02d.%02d", p_time_u16->wYear, p_time_u16->wMonth, p_time_u16->wDay); }}。 制品作用。 现在支撑了关于时刻、日期、CPU、GPU 的占用率和温度信息,其他的信息还在完善傍边。 内容来源:https://harmonyscentsg.com/app-1/ucw88 slot,https://chatbotjud-hml.saude.mg.gov.br/app-1/bh-bet.com.br
|