Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
littlefs
NXP 微控制器
NXP-MCXN947
FRDM-MCXN947片上Flash实践
发布于 2024-03-21 21:32:49 浏览:545
订阅该版
[tocm] 感谢rt-thread 提供的FRDM-MCXN94 开发板,开发板做工很精良并且有丰富的外设资源,本次评测领取的任务是"FRDM-MCXN947上的Flash实践",本次实践开发环境使用IAR,划分片上的2Mflash 资源0~1M留给rt-thread使用,1~2M 的空间用于适配MTD设备管理,并在此基础上适配littlefs文件系统用于管理flash空间,本次评测主要基于上述的3点来展开。 # 1.基于IAR9.50 运行RT-thread 系统 ## 1.1创建 IAR 模板工程 我们从github 上拉取的最新的rt-thread 的nxp mcxn947的bsp 代码适配了gcc 和 keil5 的工程,暂时没有IAR的工程模板,我们添加IAR工程运行RT-thread 的标准版的最小系统。RT-thread 使用scons 来管理工程,如果要支持IAR 环境我们只要创建IAR 工程模板文件(template.ewp),模板文件只要设置mcu型号及使用的link文件的基本信息即可,使用scons 工具即可根据上述的模板文件生成IAR工程。 ![iar_temp1.jpg](https://oss-club.rt-thread.org/uploads/20240321/e5ea6f78bf2fcfdbd323538ec96c5e2e.jpg.webp) 在link 路径下选择如下link file ```c $PROJ_DIR$\board\linker_scripts\MCXN947_cm33_core0_flash.icf ``` ![iar_temp2.jpg](https://oss-club.rt-thread.org/uploads/20240321/cdf64c79486ebab348d4d3a93ebb6777.jpg.webp) 模板文件只要配置cpu信息及link路径即可。 ## 1.2生成IAR 工程 配置好上面的工程模板后,使用env工具在bsp 目录下执行menuconfig 命令更新config,之后使用scons --target=iar 就会自动生成IAR 工程。 执行完会在bsp目录下生成如下IAR工程配置文件。 ```c bsp/nxp/mcx/mcxn/frdm-mcxn947/project.ewp bsp/nxp/mcx/mcxn/frdm-mcxn947/project.eww bsp/nxp/mcx/mcxn/frdm-mcxn947/template.ewp ``` 使用IAR 打开上述生成的 project.eww workspace 文件,scons 生成的工程内已经包含了rt-thread 标准版的最小系统文件了。 ![iar_project.jpg](https://oss-club.rt-thread.org/uploads/20240321/b3d6b59d47659117cf3a1e7e75e560fa.jpg) IAR 工程生成完毕后,编译发现会有如下的编译错误。 ![iar_error.jpg](https://oss-club.rt-thread.org/uploads/20240321/5a65dedfd57d652b56af450f161fdf73.jpg) 错误的原因为RT-thread 设置了使用堆空间,修改board.h文件内IAR 堆地址配置即可,修改如下。 ```c --- a/bsp/nxp/mcx/mcxn/frdm-mcxn947/board/board.h +++ b/bsp/nxp/mcx/mcxn/frdm-mcxn947/board/board.h @@ -36,9 +36,8 @@ extern int Image$$ARM_LIB_STACK$$ZI$$Base; #define HEAP_END ((void*)&Image$$ARM_LIB_STACK$$ZI$$Base) #elif defined(__ICCARM__) #pragma section="HEAP" -#define HEAP_BEGIN (__segment_end("HEAP")) -extern void __RTT_HEAP_END; -#define HEAP_END (&__RTT_HEAP_END) +#define HEAP_BEGIN (__section_begin("HEAP")) +#define HEAP_END (__section_end("HEAP")) #elif defined(__GNUC__) extern int __HeapBase; extern int __HeapLimit; ``` 修改以上配置后将程序下载到板子内运行会输出RTT标志性的开机log,串口也可以正常响应输入命令,至此RT-thread 基于IAR 的最小系统已经运行起来。 ```c sram heap, begin: 0x0x04001868, end: 0x0x04003868 \ | / - RT - Thread Operating System / | \ 5.1.0 build Mar 21 2024 21:19:14 2006 - 2024 Copyright by RT-Thread team using iccarm, version: 9050001 MCXN947 HelloWorld msh > ``` # 2使用内部flash适配MTD NOR 设备驱动 RT-thread 将常用的存储设备抽象成MTD(Memory Technology Device)设备驱动,MCXN947 的片内有2M的NOR flash,大部分都是空闲未使用状态,本次试验将使用后1M进行验证将这部分flash 通过RT-thread 的MTD nor 设备进行管理。 ## 2.1添加flash驱动文件 默认的link 文件是将所有的flash 空间划分给用户使用的,我们更新link 文件保留后1M的空间用于MTD设备驱动管理,最终交给文件系统管理,按照如下修改方式释放后1M的空间不使用。 ```c --- a/bsp/nxp/mcx/mcxn/frdm-mcxn947/board/linker_scripts/MCXN947_cm33_core0_flash.icf +++ b/bsp/nxp/mcx/mcxn/frdm-mcxn947/board/linker_scripts/MCXN947_cm33_core0_flash.icf if (isdefinedsymbol(__qspi_xip__)) { @@ -84,8 +84,7 @@ if (isdefinedsymbol(__qspi_xip__)) { | mem:[from m_text_start to m_text_end]; } else { define region TEXT_region = mem:[from m_interrupts_start to m_interrupts_end] - | mem:[from m_text_start to m_text_end] - | mem:[from m_flash1_start to m_flash1_end]; + | mem:[from m_text_start to m_text_end];^M } define region DATA_region = mem:[from m_data_start to m_data_end-__size_cstack__] | mem:[from m_sramx_start to m_sramx_end]; ``` MTD NOR 设备通过结构体struct rt_mtd_nor_device 进行管理,包含了设备基类结构体,Flash 块大小,块起始地址,块结束地址,以及NOR 设备操作方法,定义如下: ```c struct rt_mtd_nor_device { struct rt_device parent; rt_uint32_t block_size; /* The Block size in the flash */ rt_uint32_t block_start; /* The start of available block*/ rt_uint32_t block_end; /* The end of available block */ /* operations interface */ const struct rt_mtd_nor_driver_ops* ops; }; struct rt_mtd_nor_driver_ops { rt_err_t (*read_id) (struct rt_mtd_nor_device* device); rt_ssize_t (*read) (struct rt_mtd_nor_device* device, rt_off_t offset, rt_uint8_t* data, rt_size_t length); rt_ssize_t (*write) (struct rt_mtd_nor_device* device, rt_off_t offset, const rt_uint8_t* data, rt_size_t length); rt_err_t (*erase_block)(struct rt_mtd_nor_device* device, rt_off_t offset, rt_size_t length); }; ``` 以上配置信息主要包括nor flash 的每个block 的大小及起始块和结束块已经nor flash 分读id,读/写及块擦除的ops 信息,rt-thread 系统内已经集成了nor flash 的驱动框架,我们只要填充好上述结构体注册到系统内部即完成了rt-thread 的nor flash驱动适配。 我们要实现内部flash 的读写擦除接口,需要使用nxp的flash 驱动文件fsl_flash.c,该文件现在的bsp是美有集成到工程内部的,我们需要修改/bsp/nxp/mcx/mcxn/Libraries/MCXN947/SConscript 脚本文件添加驱动文件即对应的文件include路径,对应修改如下: ```c diff --git a/bsp/nxp/mcx/mcxn/Libraries/MCXN947/SConscript b/bsp/nxp/mcx/mcxn/Libraries/MCXN947/SConscript index 9b806287b..021ffca28 100644 --- a/bsp/nxp/mcx/mcxn/Libraries/MCXN947/SConscript +++ b/bsp/nxp/mcx/mcxn/Libraries/MCXN947/SConscript @@ -2,7 +2,7 @@ Import('rtconfig') from building import * cwd = GetCurrentDir() -path = [cwd + '/../CMSIS/Core/Include',cwd + '/components/codec', cwd + '/MCXN947', cwd + '/MCXN947/drivers', cwd + '/middleware/sdmmc/inc', cwd + '/middleware/sdmmc/port'] +path = [cwd + '/../CMSIS/Core/Include',cwd + '/components/codec', cwd + '/MCXN947', cwd + '/MCXN947/drivers', cwd + '/middleware/sdmmc/inc', cwd + '/middleware/sdmmc/port', cwd + '/MCXN947/drivers/romapi/flash/'] src = Split(''' MCXN947/system_MCXN947_cm33_core0.c ''') @@ -58,6 +58,7 @@ src += ['MCXN947/drivers/fsl_mrt.c'] src += ['MCXN947/drivers/fsl_reset.c'] src += ['MCXN947/drivers/fsl_vref.c'] src += ['MCXN947/drivers/fsl_usdhc.c'] +src += ['MCXN947/drivers/romapi/flash/src/fsl_flash.c'] group = DefineGroup('Libraries', src, depend = [''], CPPPATH = path) ``` 更新配置脚本文件后,env下使用scons --target=iar命令更新IAR工程,重新生成的IAR工程里已经包含了flash 驱动文件了。 ## 2.2适配MTD设备驱动 添加完依赖的驱动文件后,我们基于sdk的flash驱动文件适配MTD NOR 设备驱动需要底层适配的接口及参数配置。 使用fsl_flash.c 驱动库适配mtd nor flash read函数: ```c rt_ssize_t mflash_read(struct rt_mtd_nor_device* device, rt_off_t offset, rt_uint8_t* data, rt_size_t length) { uint32_t dest; struct mflash_mtd * p_mflash_mtd = (struct mflash_mtd *)device; dest = p_mflash_mtd->mflash_start + offset; if((dest + length) > (device->block_end*device->block_size)) return 0; for(uint32_t i=0; i < length; i++) { data[i] = *((__IO rt_uint8_t*)dest); dest++; } return length; } ``` 使用fsl_flash.c 驱动库适配mtd nor flash write函数: ```c static flash_config_t g_flash_instance = {0}; static uint32_t g_pflashBlockBase = 0; static uint32_t g_pflashTotalSize = 0; static uint32_t g_pflashSectorSize = 0; static uint32_t g_pflashPageSize = 0; struct mflash_mtd { struct rt_mtd_nor_device mtd_device; struct rt_mutex lock; uint32_t mflash_start; uint8_t page_size; void * user_data; }; rt_ssize_t mlash_write(struct rt_mtd_nor_device* device, rt_off_t offset, const rt_uint8_t* data, rt_size_t length) { status_t ret; uint32_t dest; struct mflash_mtd * p_mflash_mtd = (struct mflash_mtd *)device; dest = p_mflash_mtd->mflash_start + offset; if((dest + length) > (device->block_end*device->block_size)) return 0; for(uint32_t i = 0;i < length; i += 128) { ret = FLASH_Program(&g_flash_instance, dest, (uint8_t *)data, 128); if(ret != kStatus_Success) break; } return ret == kStatus_Success ? length : 0; } ``` 使用fsl_flash.c 驱动库适配mtd nor flash erase函数: ```c rt_err_t mflash_erase_block(struct rt_mtd_nor_device* device, rt_off_t offset, rt_size_t length) { status_t ret; uint32_t addr; struct mflash_mtd * p_mflash_mtd = (struct mflash_mtd *)device; addr = p_mflash_mtd->mflash_start + offset; ret = FLASH_Erase(&g_flash_instance, addr, FSL_FEATURE_SYSCON_FLASH_SECTOR_SIZE_BYTES, kFLASH_ApiEraseKey); return ret == kStatus_Success ? RT_EOK : -1; } ``` 添加接口在driver 初始化阶段调用flash 初始化处理,配置flashblock信息,向系统注册mtd nor flash驱动 ```c int rt_hw_mflash_init(void) { static struct mflash_mtd mflash; mflash.mtd_device.ops = &mflash_ops; mflash.mtd_device.block_size = FSL_FEATURE_SYSCON_FLASH_SECTOR_SIZE_BYTES; mflash.mtd_device.block_start = 128; mflash.mtd_device.block_end = 255; mflash.mflash_start = 0x100000; mflash.page_size = 128; status_t result; result = FLASH_Init(&g_flash_instance); if (result != kStatus_Success) return result; result = FLASH_GetProperty(&g_flash_instance, kFLASH_PropertyPflashBlockBaseAddr, &g_pflashBlockBase); if (result != kStatus_Success) return result; result = FLASH_GetProperty(&g_flash_instance, kFLASH_PropertyPflashSectorSize, &g_pflashSectorSize); if (result != kStatus_Success) return result; result = FLASH_GetProperty(&g_flash_instance, kFLASH_PropertyPflashTotalSize, &g_pflashTotalSize); if (result != kStatus_Success) return result; result = FLASH_GetProperty(&g_flash_instance, kFLASH_PropertyPflashPageSize, &g_pflashPageSize); rt_mtd_nor_register_device("mflash",&mflash.mtd_device); return RT_EOK; } INIT_DEVICE_EXPORT(rt_hw_mflash_init); ``` flash 驱动依赖了mtd nor 驱动框架,在kconfig 文件内追加配置项目将mtd nor 驱动框架加入工程编译。 ```c diff --git a/bsp/nxp/mcx/mcxn/frdm-mcxn947/board/Kconfig b/bsp/nxp/mcx/mcxn/frdm-mcxn947/board/Kconfig index 673c8da05..dd170b531 100644 --- a/bsp/nxp/mcx/mcxn/frdm-mcxn947/board/Kconfig +++ b/bsp/nxp/mcx/mcxn/frdm-mcxn947/board/Kconfig @@ -19,6 +19,10 @@ menu "On-chip Peripheral Drivers" select RT_USING_PIN default y +config BSP_USING_MFLASH + select RT_USING_MTD_NOR + bool "Using mcxn947 mflash driver" + default n menuconfig BSP_USING_UART bool "Enable UART" default y ``` 然后在env 环境下使能BSP_USING_MFLASH 配置,并更新工程,此时mtd nor设备驱动就被加载到工程内部了。 ![mflash.jpg](https://oss-club.rt-thread.org/uploads/20240322/8cadf6b1d3d3ea9bf385fce20b66c525.jpg.webp) 烧写后输入list device 命令可以看到MTD 驱动已经被注册到系统内部了。 ```c msh >list device device type ref count -------- -------------------- ---------- mflash MTD Device 0 pin Pin Device 0 uart5 Character Device 0 uart4 Character Device 2 uart2 Character Device 0 ``` 我们继续添加mflash 测试代码验证mtd 驱动接口,open 用于打开设备获取driver handler,write/read 分别用于读写flash 验证。 ```c static void mflash(int argc,char *argv[]) { static rt_device_t mtd = RT_NULL; if(!strcmp(argv[1], "open")) { mtd = rt_device_find("mflash"); if(!mtd) rt_kprintf("rt find device failed.\n"); else rt_kprintf("rt find device ok.\n"); } else if(!strcmp(argv[1], "erase")) { rt_mtd_nor_erase_block((struct rt_mtd_nor_device*)mtd,0x00,8192); } else if(!strcmp(argv[1], "write")) { char * writetest = " hello world "; rt_mtd_nor_write((struct rt_mtd_nor_device*)mtd,0,writetest,16); } else if(!strcmp(argv[1], "read")) { char readbuff[16]; rt_mtd_nor_read((struct rt_mtd_nor_device*)mtd,0,readbuff,16); rt_kprintf("read test data is %s \n",readbuff); } } MSH_CMD_EXPORT(mflash, mflash mtd test); ``` 使用上面的测试命令输入mflash open、mflash write,mflash read 进行写入回读验证,测试命令写入的 " hello world "字符串已经被正常的读取回来了。至此mtd的精简驱动基本适配完成,上述的驱动程序没有适配多任务并发访问及输入参数的检查,只是作为基本验证驱动来使用。 ```c msh >mflash open rt find device ok. msh >mfl mflash msh >mflash write msh >mf mflash msh >mflash read read test data is hello world msh > ``` # 3对接flash驱动适配littlefs文件系统 适配好了MTD NOR 驱动程序后,我们可以对接文件系统,使用文件系统来管理flash设备,littlefs 我们可以使用rt-thread 的软件包开启,开启后配置flash参数即可,具体配置如下: ![littlefs.jpg](https://oss-club.rt-thread.org/uploads/20240322/8eee1322b5a984769b151f959614a278.jpg.webp) 使用littlefs 需要依赖DFS我们在menuconfig 内开启DFS配置。 ![dfs.jpg](https://oss-club.rt-thread.org/uploads/20240322/8d5920d3f58479542b8b84219e2005d0.jpg.webp) 保存配置后env下使用 pkgs --update 命令更新littlefs软件包,并使用scons重新生成iar 工程。 ```c $ pkgs --update [Use Gitee server] Cloning into 'D:\work\rt_thread_master\rt-thread\bsp\nxp\mcx\mcxn\frdm-mcxn947\packages\rt_vsnprintf_full-latest'... remote: Enumerating objects: 106, done. remote: Counting objects: 100% (21/21), done. remote: Compressing objects: 100% (21/21), done. remote: Total 106 (delta 11), reused 0 (delta 0), pack-reused 85 Receiving objects: 100% (106/106), 158.16 KiB | 834.00 KiB/s, done. Resolving deltas: 100% (41/41), done. ==============================> RT_VSNPRINTF_FULL latest is downloaded successfully. Cloning into 'D:\work\rt_thread_master\rt-thread\bsp\nxp\mcx\mcxn\frdm-mcxn947\packages\littlefs-latest'... remote: Enumerating objects: 3089, done. remote: Counting objects: 100% (3/3), done. remote: Compressing objects: 100% (3/3), done. remote: Total 3089 (delta 0), reused 0 (delta 0), pack-reused 3086Receiving objects: 99% (3059/3089), 1.11 MiB | 1.09 MiB/ Receiving objects: 100% (3089/3089), 1.36 MiB | 1.17 MiB/s, done. Resolving deltas: 100% (2148/2148), done. ==============================> LITTLEFS latest is downloaded successfully. ==============================> rt_vsnprintf_full update done ==============================> littlefs update done Operation completed successfully. ``` 编译工程后发现会有如下编译错误,错误原因是littlefs 的接口参数和dfs 定义的有差异,我们按照dfs 的参数修改即可。 ![littlefs_error.jpg](https://oss-club.rt-thread.org/uploads/20240322/5883a44c1f7939487c3d34785be741d2.jpg.webp) 修改如下: ![fix_error.jpg](https://oss-club.rt-thread.org/uploads/20240322/b8fbb3c46be855a58f4ba5f60916323a.jpg.webp) 修改后我们在启动过程中添加如下代码挂载文件系统。 ```c #if defined(BSP_USING_MFLASH) && defined(PKG_USING_LITTLEFS) #include
#include
#define DBG_TAG "app.filesystem" #define DBG_LVL DBG_INFO #include
static int littlefs_mount(void) { if(rt_device_find("mflash") == RT_NULL) { return -RT_EIO; } int ret = dfs_mount("mflash", "/", "lfs", 0, 0); if (ret != 0) { rt_kprintf("ret: %d\n",ret); LOG_E("mflash mount to '/' failed!"); ret = dfs_mkfs("lfs","mflash"); if(ret != 0) return ret; ret = dfs_mount("mflash", "/", "lfs", 0, 0); if(ret != 0) return ret; } return RT_EOK; } INIT_ENV_EXPORT(littlefs_mount); #endif ``` 启动运行系统内已经集成了文件系统相关的测试命令,简单测试了下文件创建写入,及文件夹创建都是ok的,df 命令也能看到当前文件系统的剩余空间,说明基于内部flash的littlefs 已经正常工作了。 ![littlefs.gif](https://oss-club.rt-thread.org/uploads/20240322/6214a67be9c5284678d6486ed1c09732.gif) # 4文件系统功能验证 ## 4.1使用ulog 功能组件 RTT 的ulog组件可以方便的把前端的log 和 后端的物理设备(uart/flash/fs)对接起来,官方的文档说明有详细的说明[ulog日志](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/ulog/ulog "ulog日志"),FRDM-MCXN947 默认ulog是开启的,只是对接的设备是console,我们基于本次适配的littlefs 将ulog 输出对接到littlefs 来验证文件系统的存储功能。 env 环境开启ulog 后端设备为文件。 ![ulog.png](https://oss-club.rt-thread.org/uploads/20240326/59c2ff89ebfa9399929ba962c4cb187d.png.webp) ## 4.2 测试验证ulog写入文件功能 env 下开启log 写入文件后,重新生成IAR工程后,我们就可以基于此基础上添加如下测试代码,王文件系统循环50次写入测试数据,对应测试代码如下: ```c /* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2018-08-02 armink the first version */ #include
#include
#ifndef ULOG_USING_SYSLOG #define LOG_TAG "example" #define LOG_LVL LOG_LVL_DBG #include
#else #include
#endif /* ULOG_USING_SYSLOG */ #include
/* * 后端注册表 */ struct _log_file { const char *name; //文件名 ulog_backend_t backend; struct ulog_file_be *file_be; const char *dir_path; //保存路径 rt_size_t max_num; //保存最大文件数量 rt_size_t max_size; //保存最大文件大小 rt_size_t buf_size; //文件保存缓存大小 }; /* * 文件后端标识 */ typedef enum { console_id, sys_id, motion_id, }ulog_file_be_name; #define ROOT_PATH "/" //设置保存路径 #define FILE_SIZE 5 * 1024 //设置单个文件大小 #define BUFF_SIZE 512 //设备缓存区大小 static struct ulog_backend sys_log_backend; static struct ulog_file_be sys_log_file; static struct _log_file table[] = { {"sys" ,&sys_log_backend,&sys_log_file,ROOT_PATH,10,FILE_SIZE,BUFF_SIZE}, }; /* Private function prototypes -----------------------------------------------*/ /** * @brief 系统日志文件后端初始化. * @param None. * @retval None. * @note None. */ void sys_log_file_backend_init(void) { struct ulog_file_be *file_be = &sys_log_file; uint8_t id = 0; file_be->parent = sys_log_backend; ulog_file_backend_init( file_be, table[id].name, table[id].dir_path, table[id].max_num, table[id].max_size, table[id].buf_size); ulog_file_backend_enable(file_be); //必须使能才能有效 } void ulog_example(void) { int count = 0; sys_log_file_backend_init(); #ifdef ULOG_USING_SYSLOG openlog("example1", 0, 0); #endif while (count++ < 50) { #ifndef ULOG_USING_SYSLOG /* output different level log by LOG_X API */ LOG_D("LOG_D(%d): RT-Thread is an open source IoT operating system from China.", count); LOG_I("LOG_I(%d): RT-Thread is an open source IoT operating system from China.", count); LOG_W("LOG_W(%d): RT-Thread is an open source IoT operating system from China.", count); LOG_E("LOG_E(%d): RT-Thread is an open source IoT operating system from China.", count); ulog_d("test", "ulog_d(%d): RT-Thread is an open source IoT operating system from China.", count); ulog_i("test", "ulog_i(%d): RT-Thread is an open source IoT operating system from China.", count); ulog_w("test", "ulog_w(%d): RT-Thread is an open source IoT operating system from China.", count); ulog_e("test", "ulog_e(%d): RT-Thread is an open source IoT operating system from China.", count); #ifdef ULOG_USING_FILTER if (count == 20) { /* Set the global filer level is INFO. All of DEBUG log will stop output */ ulog_global_filter_lvl_set(LOG_LVL_INFO); /* Set the test tag's level filter's level is ERROR. The DEBUG, INFO, WARNING log will stop output. */ ulog_tag_lvl_filter_set("test", LOG_LVL_ERROR); } else if (count == 30) { /* Set the example tag's level filter's level is LOG_FILTER_LVL_SILENT, the log enter silent mode. */ ulog_tag_lvl_filter_set("example", LOG_FILTER_LVL_SILENT); /* Set the test tag's level filter's level is WARNING. The DEBUG, INFO log will stop output. */ ulog_tag_lvl_filter_set("test", LOG_LVL_WARNING); } else if (count == 40) { /* Set the test tag's level filter's level is LOG_FILTER_LVL_ALL. All level log will resume output. */ ulog_tag_lvl_filter_set("test", LOG_FILTER_LVL_ALL); /* Set the global filer level is LOG_FILTER_LVL_ALL. All level log will resume output */ ulog_global_filter_lvl_set(LOG_FILTER_LVL_ALL); } #endif /* ULOG_USING_FILTER */ #else /* output different priority log by syslog API */ syslog(LOG_INFO, "syslog(%d) LOG_INFO: RT-Thread is an open source IoT operating system from China.", count); syslog(LOG_DEBUG, "syslog(%d) LOG_DEBUG: RT-Thread is an open source IoT operating system from China.", count); syslog(LOG_WARNING, "syslog(%d) LOG_WARNING: RT-Thread is an open source IoT operating system from China.", count); syslog(LOG_ERR, "syslog(%d) LOG_ERR: RT-Thread is an open source IoT operating system from China.", count); syslog(LOG_INFO | LOG_MAIL, "syslog(%d) LOG_INFO | LOG_MAIL: RT-Thread is an open source IoT operating system from China.", count); syslog(LOG_DEBUG | LOG_DAEMON, "syslog(%d) LOG_DEBUG | LOG_DAEMON: RT-Thread is an open source IoT operating system from China.", count); syslog(LOG_WARNING | LOG_AUTH, "syslog(%d) LOG_WARNING | LOG_AUTH: RT-Thread is an open source IoT operating system from China.", count); syslog(LOG_ERR | LOG_SYSLOG, "syslog(%d) LOG_ERR | LOG_SYSLOG: RT-Thread is an open source IoT operating system from China.", count); if (count == 20) { /* Set log priority mask. Only output ERR and WARNING log. */ setlogmask(LOG_MASK(LOG_ERR) | LOG_MASK(LOG_WARNING)); } else if (count == 40) { /* Set log priority mask. The log which level is less than ERROR will stop output. */ setlogmask(LOG_UPTO(LOG_ERR)); } #endif /* ULOG_USING_SYSLOG */ rt_thread_delay(rt_tick_from_millisecond(rand() % 1000)); } } MSH_CMD_EXPORT(ulog_example, run ulog example) ``` 使用上述测试代码集成的ulog_example 命令进行验证,发现运行后发现文件系统内会有对应的日志文件。 使用cat 命令读取的内容和输出的保持一致。 ![20240326-125332.gif](https://oss-club.rt-thread.org/uploads/20240326/9598fc4fa59d8d85d32ff55412b863b5.gif) ## 测试代码路径 [https://gitee.com/andeyqi/rt-thread/tree/NXP_BSP/bsp/nxp/mcx/mcxn](https://gitee.com/andeyqi/rt-thread/tree/NXP_BSP/bsp/nxp/mcx/mcxn "https://gitee.com/andeyqi/rt-thread/tree/NXP_BSP/bsp/nxp/mcx/mcxn")
3
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
andeyqi
这家伙很懒,什么也没写!
文章
7
回答
6
被采纳
0
关注TA
发私信
相关文章
1
试贴-消灭0主题
2
LPC M4的一些资料
3
LPC4088的临时分支
4
lpc1788 ad 不稳定
5
1788 LCD控制器缓冲区字节问题
6
一起来学习LPC4088吧
7
上传LPC4088的realtouch主工程
8
RealBoard 4088预定帖 [第一批板子不多,预定提前结束]
9
晒RealBoard LPC4088开箱照啦,速带小板凳前来围观
10
4088主程序需要的SD卡资源
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
rt_mq_消息队列_msg_queue
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
a1012112796
20
个答案
3
次被采纳
张世争
11
个答案
3
次被采纳
踩姑娘的小蘑菇
7
个答案
3
次被采纳
rv666
9
个答案
2
次被采纳
用户名由3_15位
13
个答案
1
次被采纳
本月文章贡献
程序员阿伟
9
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
RTT_逍遥
1
篇文章
6
次点赞
大龄码农
1
篇文章
5
次点赞
ThinkCode
1
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部