threadx之levelx组件的使用记录(结合w25q128)

官方概述

在这里插入图片描述

整体代码框架

在这里插入图片描述

代码

核心逻辑部分(tx os对接)

/*
 * Copyright (c) 2024-2024,shchl
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-4-4     shchl   first version
 *
 *
 * tx_kernel_enter() 执行逻辑(关键)
 *   TX_PORT_SPECIFIC_PRE_INITIALIZATION----可扩展
 *    _tx_initialize_low_level() --- 设备层(寄存器)初始化
 *    _tx_initialize_high_level() --- tx os 内部相关初始化
 *   TX_INITIALIZE_KERNEL_ENTER_EXTENSION----可扩展
 *     tx_application_define(_tx_initialize_unused_memory);
 *   TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION ---可扩展
 *
 */

#include "includes.h"

#define APP_MAIN_STACK_SIZE 2048
#define APP_MEM_ALLOC_STATIC_ENABLE (0) /*静态内存分配使能*/


/*
*******************************************************************************************************
*                               外部引入变量
*******************************************************************************************************
*/
extern void app_component_init(void);
extern void app_define_component_init(void);
/*
*******************************************************************************************************
*                               变量
*******************************************************************************************************
*/


/*
*********************************************************************************************************
*                                       静态全局变量
*********************************************************************************************************
*/
static TX_THREAD app_start_thread; /*应用启动线程*/
/*
*********************************************************************************************************
*                                      函数声明
*********************************************************************************************************
*/
static void app_start_entry(ULONG input);
/*
*********************************************************************************************************
*                                      内部函数
*********************************************************************************************************
*/

static void app_start_entry(ULONG input) {
    /*应用组件初始化*/
    app_component_init();
    while (1) {
        /* 需要周期性处理的程序,对应裸机工程调用的SysTick_ISR */
        bsp_ProPer1ms();
        tx_thread_sleep(1);
    }
}



/**
  * @brief  应用组件定义初始化
  * @param  first_unused_memory : 指向第一个未使用的内存的指针
  * @retval None
  */
VOID tx_application_define(VOID *first_unused_memory) {
    UINT stat;
#if APP_MEM_ALLOC_STATIC_ENABLE
#define TX_STATIC_MEM_SIZE (60*1024) /*静态内存字节数*/
    /*内存池初始化*/
    static uint8_t mem_pool_area[TX_STATIC_MEM_SIZE];
    tx_mem_pool_static_init(mem_pool_area, TX_STATIC_MEM_SIZE);
#else
    if (first_unused_memory) {
        tx_mem_pool_init(first_unused_memory);
    } else {
        // todo 未使用动态内存,后面禁止使用 app_malloc 函数
        /*错误处理: 线程创建失败*/
        Error_Handler();
    }
#endif
    stat = tx_thread_create(&app_start_thread, "app start thread",
                            app_start_entry, 0,
                            app_malloc(APP_MAIN_STACK_SIZE), APP_MAIN_STACK_SIZE,
                            2, 2,
                            TX_NO_TIME_SLICE, TX_AUTO_START);
    if (stat != TX_SUCCESS) {

        /*错误处理: 线程创建失败*/
        Error_Handler();
    }
    /*组件初始化---不需要主线程中进行初始化的部分,使用TX_APP_DEFINE_EXPORT此进行初始化*/
    app_define_component_init();
}

自动初始化组件

使用到的宏定义

#define TX_APP_DEFINE_EXPORT(fn) INIT_EXPORT(fn, "6.5")
#define TX_THREAD_EXPORT_LV1(fn) INIT_EXPORT(fn, "7.0")
#define TX_THREAD_EXPORT(fn) INIT_EXPORT(fn, "7.5")
/*
 * Copyright (c) 2024-2024,shchl
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-4-13     shchl   first version
 */
#include "includes.h"


/*
*******************************************************************************************************
*                               外部引入变量
*******************************************************************************************************
*/

/*
*******************************************************************************************************
*                               变量
*******************************************************************************************************
*/
TX_MUTEX AppPrintfSemp;    /* 用于printf互斥 */

/*
*********************************************************************************************************
*                                       静态全局变量
*********************************************************************************************************
*/
/*
*********************************************************************************************************
*                                      函数声明
*********************************************************************************************************
*/
/**
 * @brief 组件初始化开始
 * @return
 */
static int tx_app_define_init_start() {

    return TX_SUCCESS;
}

INIT_EXPORT(tx_app_define_init_start, "6");

/**
 * @brief 组件初始化开始
 * @return
 */
static int tx_component_init_start() {


    /* 创建互斥信号量 */
    tx_mutex_create(&AppPrintfSemp, "AppPrintfSemp", TX_NO_INHERIT);

    return TX_SUCCESS;
}

INIT_EXPORT(tx_component_init_start, "7");


static int tx_component_init_end() {

    return TX_SUCCESS;
}
INIT_EXPORT(tx_component_init_end, "8");

void app_component_init(void) {
    tx_log("--------------app component init[start]---------------\r\n");
    bsp_components_app_init(&__os_init_tx_component_init_start,
                            &__os_init_tx_component_init_end);
    tx_log("--------------app component init[end]---------------\r\n");

}

void app_define_component_init(void) {
    bsp_components_app_init(&__os_init_tx_app_define_init_start,
                            &__os_init_tx_component_init_start);

}

levelx组件的初始化(这里使用的是自动初始化方式)

/*
 * Copyright (c) 2024-2024,shchl
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-4-15     shchl   first version
 */
#include "includes.h"


#if 1

#include "lx_api.h"
#include "levelx/lx_stm32_nor_w25q128_driver.h"

LX_NOR_FLASH nor_w25q128;


int lx_application_define(void) {

    lx_nor_flash_initialize();

    return LX_SUCCESS;
}

TX_APP_DEFINE_EXPORT(lx_application_define); /*首先创建模块应用*/


/**
 * @brief nor flash 设备初始化
 * @return 
 */
int app_nor_flash_init() {
    UINT status = lx_nor_flash_open(&nor_w25q128,
                                    "nor w25q128",
                                    lx_stm32_nor_w25q128bv_driver_initialize);
    /*打开失败(将失败的空间进行格式化)*/
    if (status) { /*这个一般只会执行一次,后面基本上不会再执行*/
        tx_log("need format space\r\n");
        lx_stm32_nor_w25q128bv_flash_format(&nor_w25q128); /*格式化*/
        /*再尝试一次*/
        status = lx_nor_flash_open(&nor_w25q128,
                                   "nor w25q128",
                                   lx_stm32_nor_w25q128bv_driver_initialize);
        if (status) {

            tx_log("nor flash init error\r\n");
            // todo

            return (int) status;
        }


    }

    tx_log("nor flash device init ok\r\n");

    // 是否需要关?
    //lx_nor_flash_close(&nor_w25q128);/*这里直接关闭,后面如果需要,再打开*/
    return (int) LX_SUCCESS; /*返回状态*/
}

TX_THREAD_EXPORT(app_nor_flash_init); 


#endif

levelx驱动实现(w25q128)

头文件

/**************************************************************************/
/*                                                                        */
/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
/*                                                                        */
/*       This software is licensed under the Microsoft Software License   */
/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
/*       and in the root directory of this software.                      */
/*                                                                        */
/**************************************************************************/

#ifndef LX_STM32_NOR_DRIVER_H
#define LX_STM32_NOR_DRIVER_H

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "lx_api.h"

#define W25Q128_PHY_TOTAL_SIZE (16*1024*1024)   /*16M*/
#define W25Q128_PHY_PER_BLOCK_SIZE (64*1024)   /*64KB*/
#define W25Q128_PHY_PER_SECTOR_SIZE (4*1024)    /*4KB*/



#define LX_NOR_W25Q128_BASE_ADDR        (0x0U)       /*相对于硬件的基地址*/
#define LX_NOR_W25Q128_ALLOC_TOTAL_SIZE (2*1024*1024) /*分配给LX管理 2M*/
#define LX_NOR_W25Q128_PER_BLOCK_SIZE   W25Q128_PHY_PER_SECTOR_SIZE  /*LX每个块的大小(字节)*/
#define LX_NOR_W25Q128_BLOCKS_NUM     ((LX_NOR_W25Q128_ALLOC_TOTAL_SIZE)/(LX_NOR_W25Q128_PER_BLOCK_SIZE)) /*LX 总块数*/


UINT lx_stm32_nor_w25q128bv_driver_initialize(LX_NOR_FLASH *nor_flash);

UINT lx_stm32_nor_w25q128bv_flash_format(LX_NOR_FLASH *nor_flash);
#ifdef __cplusplus
}
#endif
#endif /* LX_STM32_NOR_DRIVER_H */


源文件

/**************************************************************************/
/*                                                                        */
/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
/*                                                                        */
/*       This software is licensed under the Microsoft Software License   */
/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
/*       and in the root directory of this software.                      */
/*                                                                        */
/**************************************************************************/
#include "includes.h"
#include "levelx/lx_stm32_nor_w25q128_driver.h"

/* Private includes ----------------------------------------------------------*/

/* USER CODE BEGIN Includes */





/* Private typedef -----------------------------------------------------------*/

static UINT lx_nor_driver_read(ULONG *flash_address, ULONG *destination, ULONG words);

static UINT lx_nor_driver_write(ULONG *flash_address, ULONG *source, ULONG words);

static UINT lx_nor_driver_block_erase(ULONG block, ULONG erase_count);

static UINT lx_nor_driver_block_erased_verify(ULONG block);

/* USER CODE BEGIN USER_CODE_SECTION_1 */

/* USER CODE END USER_CODE_SECTION_1 */

#ifndef LX_DIRECT_READ

#ifndef LX_NOR_W25Q128_PER_BLOCK_SIZE
#define LX_NOR_W25Q128_PER_BLOCK_SIZE 512
#endif

static ULONG nor_sector_memory[LX_NOR_W25Q128_PER_BLOCK_SIZE / sizeof(ULONG)];
#endif

UINT lx_stm32_nor_w25q128bv_driver_initialize(LX_NOR_FLASH *nor_flash) {
    UINT ret = LX_SUCCESS;
    nor_flash->lx_nor_flash_total_blocks = LX_NOR_W25Q128_BLOCKS_NUM;
    nor_flash->lx_nor_flash_words_per_block = LX_NOR_W25Q128_PER_BLOCK_SIZE / sizeof(ULONG);
    nor_flash->lx_nor_flash_driver_read = lx_nor_driver_read;
    nor_flash->lx_nor_flash_driver_write = lx_nor_driver_write;

    nor_flash->lx_nor_flash_driver_block_erase = lx_nor_driver_block_erase;
    nor_flash->lx_nor_flash_driver_block_erased_verify = lx_nor_driver_block_erased_verify;

#ifndef LX_DIRECT_READ
    nor_flash->lx_nor_flash_sector_buffer = nor_sector_memory; /*直接赋值底层数据缓冲区,避免多次开辟数据*/
#endif
    return ret;
}

/**
 * @brief
 * @param flash_address 读取地址
 * @param destination 保存数据的位置
 * @param words 读取的数据量
 * @return
 */

static UINT lx_nor_driver_read(ULONG *flash_address, ULONG *destination, ULONG words) {

    uint32_t real_addr = (uint32_t) flash_address + LX_NOR_W25Q128_BASE_ADDR;
    sf_ReadBuffer((uint8_t *) destination,
                  real_addr,
                  words * sizeof(ULONG));

    return LX_SUCCESS;
}

/**
 * @brief
 * @param flash_address 写入地址
 * @param source 要写入的数据
 * @param words 写入的数据大小(字)
 * @return
 */
static UINT lx_nor_driver_write(ULONG *flash_address, ULONG *source, ULONG words) {
    uint32_t real_addr = (uint32_t) flash_address + LX_NOR_W25Q128_BASE_ADDR;
    sf_WriteBuffer((uint8_t *) source,
                   real_addr,
                   words * sizeof(ULONG));
    return LX_SUCCESS;
}

/**
 * @brief
 * @param block 擦除块的下标
 * @param erase_count 擦除的大小(字)
 *  @note 这里已在驱动写入的时候就会覆盖,这里就不做任何处理了
 * @return
 */
static UINT lx_nor_driver_block_erase(ULONG block, ULONG erase_count) {

//    sf_EraseSector(block * FLASH_SIZE_BYTE_PER_SECTOR);
    return LX_SUCCESS;
}

/**
 * @brief 块擦除验证
 * @param block 块的索引下标
 * @return
 */
static UINT lx_nor_driver_block_erased_verify(ULONG block) {


    return LX_SUCCESS;
}

/**
 * @brief 格式化分配的内存空间
 * @param nor_flash
 * @return
 */
UINT lx_stm32_nor_w25q128bv_flash_format(LX_NOR_FLASH *nor_flash) {
    uint32_t erase_addr = 0;
    for (int i = 0; i < nor_flash->lx_nor_flash_total_blocks; ++i) {
        erase_addr = i * LX_NOR_W25Q128_PER_BLOCK_SIZE + LX_NOR_W25Q128_BASE_ADDR;
        sf_EraseSector(erase_addr);
    }
    return LX_SUCCESS;
}

w25q128驱动(这里使用的是:论坛里面驱动代码)

测试线程(使用串口线程)

/*
 * Copyright (c) 2024-2024,shchl
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-4-4     shchl   first version
 */
#include "includes.h"

#if 1
#define APP_TASK_SERIAL_MONI_STK_SIZE 2048
#define APP_TASK_SERIAL_MONI_PRIO 10
/*
*******************************************************************************************************
*                               外部引入变量
*******************************************************************************************************
*/
/*
*******************************************************************************************************
*                               变量
*******************************************************************************************************
*/

/*
*********************************************************************************************************
*                                       静态全局变量
*********************************************************************************************************
*/
static TX_THREAD serial_moni_thread;

/*
*********************************************************************************************************
*                                      函数声明
*********************************************************************************************************
*/
static void serial_moni_entry(ULONG input);
/*
*********************************************************************************************************
*                                      外部函数
*********************************************************************************************************
*/
/**
 * @brief cpu 状态任务
 */
int tx_task_serial_monitor_create() {
    tx_thread_create(&serial_moni_thread,              /* 任务控制块地址 */
                     "serial_moni",               /* 任务名 */
                     serial_moni_entry,                  /* 启动任务函数地址 */
                     0,                             /* 传递给任务的参数 */
                     app_malloc(APP_TASK_SERIAL_MONI_STK_SIZE),            /* 堆栈基地址 */
                     APP_TASK_SERIAL_MONI_STK_SIZE,    /* 堆栈空间大小 */
                     APP_TASK_SERIAL_MONI_PRIO,        /* 任务优先级*/
                     APP_TASK_SERIAL_MONI_PRIO,        /* 任务抢占阀值 */
                     TX_NO_TIME_SLICE,               /* 不开启时间片 */
                     TX_AUTO_START);                 /* 创建后立即启动 */

    return TX_SUCCESS;
}

TX_THREAD_EXPORT(tx_task_serial_monitor_create);

/*
*********************************************************************************************************
*                                      内部函数
*********************************************************************************************************
*/
extern void lx_write_data_test();

static void serial_moni_entry(ULONG input) {
    uint8_t cmd;
    while (1) {
        comGetChar(COM1, &cmd);
        switch (cmd) {
      
            case '1': {

                lx_write_data_test();
            }
                break;

            case '2':
                break;

            case '5':
                app_task_info_out();
                break;

            default:
                break;
        }
        cmd = 0;
        tx_thread_sleep(10);
    }

}

#endif

测试代码

/*
 * Copyright (c) 2024-2024,shchl
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-4-15     shchl   first version
 */
#include "includes.h"

#if 1

#include "lx_api.h"

extern LX_NOR_FLASH nor_w25q128;
static ULONG wr_data_buf[LX_NOR_SECTOR_SIZE];
static ULONG rd_data_buf[LX_NOR_SECTOR_SIZE];

void lx_write_data_test() {
    static ULONG dat = 0;
    for (int i = 0; i < LX_NOR_SECTOR_SIZE; ++i) {
        wr_data_buf[i] = dat;
        dat++;
    }
    lx_nor_flash_sector_write(&nor_w25q128, 1, wr_data_buf);

    lx_nor_flash_sector_read(&nor_w25q128, 1, rd_data_buf);

    for (int i = 0; i < LX_NOR_SECTOR_SIZE; ++i) {
        if (wr_data_buf[i] != rd_data_buf[i]) {
            tx_log("lx_write_data_test error\r\n");
            return;
        }
    }
    tx_log("lx_write_data_test ok\r\n");

}


#endif

测试结果

在这里插入图片描述

总结

  1. 这里使用lx_nor_flash_open打开设备的时候会出现状态不正确的情况,原因可能是flash中的数据格式问题,需要格式化一次。
<think>嗯,用户想了解如何在RT-Thread中使用FAL组件与W25Q128闪存芯片进行交互。首先,我需要回忆一下FAL组件的基本概念。FAL(Flash Abstraction Layer)是RT-Thread中的一个抽象层,用于统一管理不同类型的Flash设备,包括片内Flash和片外SPI Flash。这样开发者可以通过统一的API进行读写操作,而不需要关心底层硬件的差异。 接下来,用户提到W25Q128,这是一款SPI接口的NOR Flash芯片,容量为16MB。使用它需要先通过SPI总线将其注册到RT-Thread的设备框架中。根据引用3的内容,用户需要编写初始化代码,使用SPI设备框架将W25Q128挂载到SPI总线上。这部分代码通常包括启用GPIO时钟、注册SPI设备,并通过rt_sfud_flash_probe函数探测设备。INIT_COMPONENT_EXPORT宏确保初始化函数在系统启动时自动执行。 然后,配置FAL组件。根据引用2,用户需要在工程中添加porting文件夹,并修改fal_cfg.h文件来定义Flash分区。对于STM32F407,可能需要同时配置片内Flash和W25Q128。每个分区需要指定名称、起始地址、大小以及所属的Flash设备。例如,片内Flash可能命名为"stm32_onchip",而W25Q128的分区可能命名为"filesystem"。 接下来,用户需要初始化FAL组件并调用fal_init()。之后,就可以使用FAL提供的API,如fal_partition_find()获取分区句柄,fal_partition_read()和fal_partition_write()进行读写操作。如果用户需要使用文件系统,还需要将分区挂载到elm或LittleFS,这通常通过DFS和MTD层来实现。 可能遇到的问题包括SPI设备初始化失败,需要检查硬件连接是否正确,SPI配置参数是否匹配W25Q128的规格。另外,分区配置错误可能导致读写异常,需要仔细检查fal_cfg.h中的地址和大小设置。用户可能还需要参考RT-Thread的文档和示例代码,确保所有步骤正确无误。 总结步骤:硬件连接、SPI设备注册、FAL配置、API使用。需要确保每个环节都正确配置,特别是SPI的引脚和时钟初始化,以及FAL分区的正确划分。此外,提供示例代码和参考链接能帮助用户更好地理解和实践。</think>### RT-Thread FAL组件与W25Q128交互教程 #### 一、硬件准备与驱动配置 1. **SPI设备挂载** 需通过RT-Thread SPI框架注册W25Q128设备,参考代码片段如下: ```c static int rt_hw_spi_flash_init(void) { __HAL_RCC_GPIOC_CLK_ENABLE(); // 启用SPI片选引脚时钟 rt_hw_spi_device_attach("spi1", "spi10", GPIOC, GPIO_PIN_0); // 挂载SPI设备 if (RT_NULL == rt_sfud_flash_probe("W25Q128", "spi10")) { // 探测Flash设备 return -RT_ERROR; } return RT_EOK; } INIT_COMPONENT_EXPORT(rt_hw_spi_flash_init); // 自动初始化 ``` 此代码将W25Q128注册为名为`W25Q128`的块设备[^3]。 2. **FAL组件移植** - 在工程中添加`porting`文件夹,包含`fal_cfg.h`配置文件 - 定义Flash设备表与分区表(示例): ```c /* fal_cfg.h */ static const fal_partition_t _fal_partitions[] = { /* 片内Flash */ {FAL_PART_MAGIC_WORD, "boot", "stm32_onchip", 0x08000000, 64*1024, 0}, {FAL_PART_MAGIC_WORD, "app", "stm32_onchip", 0x08010000, 512*1024, 0}, /* W25Q128分区 */ {FAL_PART_MAGIC_WORD, "param", "W25Q128", 0x00000000, 256*1024, 0}, {FAL_PART_MAGIC_WORD, "filesystem", "W25Q128", 0x00040000, 14*1024*1024, 0} }; ``` 此处`W25Q128`对应驱动注册的设备名[^2]。 #### 二、FAL组件初始化与API使用 1. **初始化流程** ```c #include <fal.h> int main(void) { fal_init(); // 初始化FAL组件 /* 后续操作... */ } ``` 2. **读写操作示例** ```c #define BUFFER_SIZE 256 void flash_ops_demo(void) { const struct fal_partition *fs_part = fal_partition_find("filesystem"); uint8_t write_buf[BUFFER_SIZE] = {0xA5}; uint8_t read_buf[BUFFER_SIZE]; /* 擦除->写入->读取验证 */ fal_partition_erase(fs_part, 0, BUFFER_SIZE); fal_partition_write(fs_part, 0, write_buf, BUFFER_SIZE); fal_partition_read(fs_part, 0, read_buf, BUFFER_SIZE); } ``` #### 三、文件系统集成(可选) 若需挂载文件系统到W25Q128: ```c #include <dfs_fs.h> int mnt_init(void) { if (dfs_mount("filesystem", "/", "elm", 0, 0) == 0) { rt_kprintf("Flash文件系统挂载成功\n"); } return RT_EOK; } INIT_ENV_EXPORT(mnt_init); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

詩不诉卿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值