前言
- 本篇主要的内容就是根据上篇博客内容的基础上增加levelx组件
- 调整对应的文件命令来进行适配w25q128和sd之间的一个切换
代码调整
宏定义的调整
- 说明sd卡的扇区大小一般是512字节,w25q128的扇区大小是4096,所以在分配的缓冲区的时候按最大的来分配
#define SD_CACHE_BUFFER_SIZE (512)
#define W25Q128_CACHE_BUFFER_SIZE (4096) /*4KB*/
#define FX_MEDIA_CACHE_BUF_SIZE (W25Q128_CACHE_BUFFER_SIZE) /*media 缓冲区分配大小*/
#define FX_FAULT_TOLERANT_BUF_SIZE (2048) /*容错区*/
levelx组件的调整
增加filex的格式化适配
/*
* 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 APP_COMPONENT_LX_ENABLE
#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 设备初始化(用于验证flash内部是否正常使用)
* @return
*/
int app_nor_flash_init() {
UINT status = lx_nor_flash_open(&nor_w25q128,
"nor w25q128",
lx_stm32_nor_w25q128bv_driver_initialize);
/* Erase the simulated NOR flash. */
/*打开失败(将失败的空间进行格式化)*/
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;
} else {
#if 1 /*此部分是为了适配fx 建立文件系统*/
#include "fx_stm32_nor_w25q128_driver.h"
status = fx_media_format(&g_fx_media,
fx_nor_flash_w25q128_driver,
FX_NULL, // Unused
g_fx_media_cache_buffer, // Media buffer pointer
SD_CACHE_BUFFER_SIZE, // Media buffer size
"MY_NOR_DISK", // Volume Name
1, // Number of FATs
32, // Directory Entries
0, // Hidden sectors
LX_NOR_W25Q128_BLOCKS_NUM - 2, // Total sectors(保留最后的两个扇区不用于文件系统)
W25Q128_PHY_PER_SECTOR_SIZE, // Sector size
1, // Sectors per cluster
1, // Heads
1); // Sectors per track
#endif
}
}
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
filex组件的调整(调整变量名称)
/*
* Copyright (c) 2024-2024,shchl
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-4-16 shchl fx 组件入口函数
*/
#include "includes.h"
#if 1
#include "fx_api.h"
/*
*******************************************************************************************************
* 外部引入变量
*******************************************************************************************************
*/
/*
*******************************************************************************************************
* 变量
*******************************************************************************************************
*/
void *g_fx_media_cache_buffer; /*缓冲区指针*/
FX_MEDIA g_fx_media; /*全局sd 文件硬盘结构体*/
#ifdef FX_ENABLE_FAULT_TOLERANT
void *g_fault_tolerant_buffer = NULL;
#endif
/*
*********************************************************************************************************
* 静态全局变量
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* 函数声明
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* 外部函数
*********************************************************************************************************
*/
int fx_application_define(void) {
/* 分配内存空间. */
g_fx_media_cache_buffer = app_malloc(FX_MEDIA_CACHE_BUF_SIZE);
#ifdef FX_ENABLE_FAULT_TOLERANT
g_fault_tolerant_buffer = app_malloc(FX_FAULT_TOLERANT_BUF_SIZE);
#endif
/*fx 初始化*/
fx_system_initialize();
return FX_SUCCESS;
}
TX_APP_DEFINE_EXPORT(fx_application_define); /*首先创建模块应用*/
/*
*********************************************************************************************************
* 内部函数
*********************************************************************************************************
*/
#endif
文件封装后的api文件调整
UINT app_fx_open_sd();
UINT app_fx_close_sd();
- 增加挂载和卸载,移除打开和关闭的逻辑,用于适配sd卡和w25q128之间的切换
头文件
/*
* Copyright (c) 2024-2024,shchl
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-4-16 shchl first version
*/
#ifndef STM32_PROJECT_APP_FILE_API_H
#define STM32_PROJECT_APP_FILE_API_H
#include "includes.h"
#define NOR_MEDIA_NAME "nor_media"
#define SD_MEDIA_NAME "sd_media"
UINT app_media_mount(char *name);
UINT app_media_unmount(char *name);
UINT app_fx_file_create(const CHAR *file_name);
UINT app_fx_dir_create(const CHAR *dir_name);
UINT app_fx_file_open(FX_FILE *fp, CHAR *file_name, UINT open_type);
UINT app_fx_file_close(FX_FILE *fp);
UINT app_fx_file_delete(char *file_name);
UINT app_fx_file_fprintf(FX_FILE *fp, const char *fmt, ...);
UINT app_fx_dir_attr_read(char *dir_name,UINT *attr);
UINT app_fx_dir_delete(char *dir_name);
#endif //STM32_PROJECT_APP_FILE_API_H
源文件
/*
* Copyright (c) 2024-2024,shchl
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-4-16 shchl first version
*/
#include "app_file_api.h"
#include "fx_stm32_sd_driver.h"
#include "fx_stm32_nor_w25q128_driver.h"
#include "levelx/lx_stm32_nor_w25q128_driver.h"
#define driver_media_ptr (&g_fx_media)
#define FX_DATA_BUF_SIZE 256
static char fx_data_buf[FX_DATA_BUF_SIZE] = {0};
static UINT media_init_stat = 0;
/**
* @brief 挂载 media
* @param name
* @return
*/
UINT app_media_mount(char *name) {
TX_INTERRUPT_SAVE_AREA
UINT status = FX_NOT_FOUND;
UINT cache_buf_size;/*缓存内存大小*/
VOID (*drv_ptr)(FX_MEDIA *media_ptr);
if (strcmp(name, NOR_MEDIA_NAME) == 0) {
drv_ptr = fx_nor_flash_w25q128_driver;
cache_buf_size = W25Q128_CACHE_BUFFER_SIZE;
} else if (strcmp(name, SD_MEDIA_NAME) == 0) {
drv_ptr = fx_stm32_sd_driver;
cache_buf_size = SD_CACHE_BUFFER_SIZE;
} else {
return FX_NOT_FOUND;
}
if (media_init_stat) return FX_ALREADY_CREATED;
status = fx_media_open(driver_media_ptr,
SD_MEDIA_NAME,
drv_ptr,
0,
g_fx_media_cache_buffer,
cache_buf_size);
TX_DISABLE
if (status == FX_SUCCESS) {
media_init_stat = 1;
}
TX_RESTORE
#ifdef FX_ENABLE_FAULT_TOLERANT
/* Enable the Fault-tolerant feature. */
status = fx_fault_tolerant_enable(driver_media_ptr,
g_fault_tolerant_buffer,
FX_FAULT_TOLERANT_BUF_SIZE);
#endif
return status;
}
UINT app_media_unmount(char *name) {
TX_INTERRUPT_SAVE_AREA
UINT status = FX_SUCCESS;
if (media_init_stat) {
status = fx_media_close(driver_media_ptr);
TX_DISABLE
if (status == FX_SUCCESS) {
media_init_stat = 0;
}
TX_RESTORE
}
return status;
}
/**
* @brief 创建文件
* @param file_name 文件名
* @return
*/
UINT app_fx_file_create(const CHAR *file_name) {
UINT status;
status = fx_file_create(driver_media_ptr, (CHAR *) file_name);
fx_media_flush(driver_media_ptr);/*将缓存数据刷新到sd卡中*/
return status;
}
UINT app_fx_dir_create(const CHAR *dir_name) {
UINT status;
status = fx_directory_create(driver_media_ptr, (CHAR *) dir_name);
fx_media_flush(driver_media_ptr); /*将缓存数据刷新到sd卡中*/
return status;
}
/**
* @brief 打开文件,
* @param fp 文件指针
* @param file_name 文件名称
* @param open_type 打开类型
* @note 如果是 FX_OPEN_FOR_WRITE,文件如果不存在,则会创建新文件
* @return
*/
UINT app_fx_file_open(FX_FILE *fp, CHAR *file_name, UINT open_type) {
UINT status;
status = fx_file_open(driver_media_ptr, fp, file_name, open_type);
// 如果文件不存在,并且访问类型为写,则先创建文件,然后再打开一次
if (status == FX_NOT_FOUND && open_type == FX_OPEN_FOR_WRITE) {
status = fx_file_create(driver_media_ptr, file_name);
if (status == FX_SUCCESS) {
status = fx_file_open(driver_media_ptr, fp, file_name, open_type);
}
}
return status;
}
UINT app_fx_file_close(FX_FILE *fp) {
return fx_file_close(fp);
}
UINT app_fx_file_delete(char *file_name) {
return fx_file_delete(driver_media_ptr, file_name);
}
UINT app_fx_dir_delete(char *dir_name) {
return fx_directory_delete(driver_media_ptr, dir_name);
}
/**
* @brief 目录属性读取
* @param dir_name [in] 目录名
* @param attr [out] 返回
* @return
*/
UINT app_fx_dir_attr_read(char *dir_name, UINT *attr) {
return fx_directory_attributes_read(driver_media_ptr, dir_name, attr);
}
/**
* @brief 格式化文件写入数据
* @param fp
* @param fmt
* @param ...
* @return
*/
UINT app_fx_file_fprintf(FX_FILE *fp, const char *fmt, ...) {
if (!fp) return FX_PTR_ERROR;
va_list v_args;
va_start(v_args, fmt);
int len = vsnprintf((char *) fx_data_buf,
(size_t) sizeof(fx_data_buf),
(char const *) fmt,
v_args);
va_end(v_args);
if (len > FX_DATA_BUF_SIZE) return FX_NOT_ENOUGH_MEMORY;/*没有足够的内存*/
return fx_file_write(fp, fx_data_buf, len);
}
文件操作的命令
- 移除
UINT app_fx_open_sd();UINT app_fx_close_sd();函数的调用集合
增加挂载和卸载命令
/*
* Copyright (c) 2024-2024,shchl
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-4-18 shchl first version
*/
#include "includes.h"
#if 1
#include "fx_api.h"
#include "filex/app_file_api.h"
/**
* @brief 文件驱动挂载
* @param argc
* @param argv
* @see 用法 mount 驱动名
* @return
*/
int fx_mount_cmd(int argc, char *argv[]) {
char *driver_name;
UINT status;
if (argc != 2) {
logWarning("mount <driver_name>");
return -1;
} else {
driver_name = argv[1];
status = app_media_mount(driver_name);
if (status) {
logError("app_media_mount error:%#x", status);
}
}
return 0;
}
SHELL_EXPORT_CMD(
SHELL_CMD_PERMISSION(0) |
SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), mount, fx_mount_cmd, "mount fx driver");
/**
* @brief 文件驱动挂载
* @param argc
* @param argv
* @see 用法 mount 驱动名
* @return
*/
int fx_unmount_cmd(int argc, char *argv[]) {
char *driver_name;
UINT status;
if (argc != 2) {
logWarning("unmount <driver_name>");
return -1;
} else {
driver_name = argv[1];
status = app_media_unmount(driver_name);
if (status) {
logError("app_media_mount error:%#x", status);
}
}
return 0;
}
SHELL_EXPORT_CMD(
SHELL_CMD_PERMISSION(0) |
SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), unmount, fx_unmount_cmd, "unmount fx driver");
#endif
增加levelx适配fx的驱动代码(参考fx提供的ram模拟驱动代码)
/*
* Copyright (c) 2024-2024,shchl
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-4-17 shchl first version
*/
#include "fx_stm32_nor_w25q128_driver.h"
#include "levelx/lx_stm32_nor_w25q128_driver.h"
/**
* @brief fx lx
* @param media_ptr
*/
/* Create a NOR flash control block. */
extern LX_NOR_FLASH nor_w25q128;
/* Define prototypes. */
VOID fx_nor_flash_w25q128_driver(FX_MEDIA *media_ptr) {
UCHAR *source_buffer;
UCHAR *destination_buffer;
ULONG logical_sector;
ULONG i;
UINT status;
/* 此值由驱动程序返回。如果操作成功,则此字段应设置为 FX_SUCCESS for before returning。否则,如果发生错误,则此字段应设置为 FX_IO_ERROR。
FX_MEDIA Member Meaning
fx_media_driver_request FileX 请求类型。来自 FileX 的有效请求如下:
FX_DRIVER_READ
FX_DRIVER_WRITE
FX_DRIVER_FLUSH
FX_DRIVER_ABORT
FX_DRIVER_INIT
FX_DRIVER_BOOT_READ
FX_DRIVER_RELEASE_SECTORS
FX_DRIVER_BOOT_WRITE
FX_DRIVER_UNINIT
fx_media_driver_status 此值由驱动程序返回。如果操作成功,则此字段应设置为 FX_SUCCESS for before returning。
否则,如果发生错误,则此字段应设置为 FX_IO_ERROR。
fx_media_driver_buffer 指向缓冲区的指针,用于读取或写入扇区数据。这是由 FileX 提供的。
fx_media_driver_logical_sector FileX 正在请求的逻辑扇区。
fx_media_driver_sectors FileX 请求的扇区数。
以下是可选 FX_MEDIA 结构成员的摘要:
FX_MEDIA Member Meaning
fx_media_driver_info 指向任何其他信息或内存的指针。
这对于驱动程序使用是可选的,并且是设置的
从fx_media_open呼叫。RAM 磁盘使用
此指针用于 RAM 磁盘内存本身。
fx_media_driver_write_protect DRIVER 将其设置为写入介质时FX_TRUE 保护。这通常是在初始化中完成的, 但可以随时完成。
fx_media_driver_free_sector_update DRIVER 在需要时将其设置为 FX_TRUE
了解集群何时发布。这很重要 用于 FLASH 磨损均衡驱动器。
fx_media_driver_system_write FileX 将此标志设置为 FX_TRUE 如果扇区是 written 是一个系统扇区,例如,boot、fat 或
目录扇区。驱动程序可以选择使用它 启动错误恢复逻辑以处理更大的故障 宽容。
fx_media_driver_data_sector_read FileX 将此标志设置为 FX_TRUE 如果扇区为 read 是文件数据扇区,即 NOT 系统扇区。
fx_media_driver_sector_type FileX 将此变量设置为特定类型的正在读取或写入的扇区。以下部门确定类型:
FX_UNKNOWN_SECTOR
FX_BOOT_SECTOR
FX_FAT_SECTOR
FX_DIRECTORY_SECTOR
FX_DATA_SECTOR
*/
/*处理媒体控制块中指定的驱动程序请求。 */
switch (media_ptr->fx_media_driver_request) {
case FX_DRIVER_READ: {
/* 设置目标缓冲区和逻辑扇区。 */
logical_sector = media_ptr->fx_media_driver_logical_sector;
destination_buffer = (UCHAR *) media_ptr->fx_media_driver_buffer;
/* 循环从闪存读取扇区。 */
for (i = 0; i < media_ptr->fx_media_driver_sectors; i++) {
/* 从 NOR 闪存读取扇区。 */
status = lx_nor_flash_sector_read(&nor_w25q128, logical_sector, destination_buffer);
/* 确定读取是否成功。 */
if (status != LX_SUCCESS) {
/* Return an I/O error to FileX. */
media_ptr->fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Move to the next entries. */
logical_sector++;
destination_buffer = destination_buffer + media_ptr->fx_media_bytes_per_sector;
}
/* Successful driver request. */
media_ptr->fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_WRITE: {
/* Setup the source buffer and logical sector. */
logical_sector = media_ptr->fx_media_driver_logical_sector;
source_buffer = (UCHAR *) media_ptr->fx_media_driver_buffer;
/* Loop to write sectors to flash. */
for (i = 0; i < media_ptr->fx_media_driver_sectors; i++) {
/* Write a sector to NOR flash. */
status = lx_nor_flash_sector_write(&nor_w25q128, logical_sector, source_buffer);
/* Determine if the write was successful. */
if (status != LX_SUCCESS) {
/* Return an I/O error to FileX. */
media_ptr->fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Move to the next entries. */
logical_sector++;
source_buffer = source_buffer + media_ptr->fx_media_bytes_per_sector;
}
/* Successful driver request. */
media_ptr->fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_RELEASE_SECTORS: {
/* Setup the logical sector. */
logical_sector = media_ptr->fx_media_driver_logical_sector;
/* Release sectors. */
for (i = 0; i < media_ptr->fx_media_driver_sectors; i++) {
/* Release NOR flash sector. */
status = lx_nor_flash_sector_release(&nor_w25q128, logical_sector);
/* Determine if the sector release was successful. */
if (status != LX_SUCCESS) {
/* Return an I/O error to FileX. */
media_ptr->fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Move to the next entries. */
logical_sector++;
}
/* Successful driver request. */
media_ptr->fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_FLUSH: {
/* Return driver success. */
media_ptr->fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_ABORT: {
/* Return driver success. */
media_ptr->fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_INIT: {
/* FLASH 驱动程序负责在介质结构中设置多个字段,如下所示:
media_ptr -> fx_media_driver_free_sector_update
media_ptr -> fx_media_driver_write_protect
fx_media_driver_free_sector_update 标志用于指示 FileX 在未使用扇区时通知驱动程序。
这对于 FLASH 管理器特别有用,因此他们不必对不再使用的扇区进行维护映射。
驱动程序可以随时设置fx_media_driver_write_protect标志,以指示媒体不可写。
设置此标志时进行的写入尝试将作为错误返回。*/
/* 在此处执行基本初始化...因为随后将再次读取卷名请求的引导记录。 */
/* 通过闪边磨损均衡,FileX 应在扇区时告诉磨损均衡 不再使用。 */
media_ptr->fx_media_driver_free_sector_update = FX_TRUE;
/* Open the NOR flash simulation. */
status = lx_nor_flash_open(&nor_w25q128,
"w25q128 nor flash",
lx_stm32_nor_w25q128bv_driver_initialize);
/* Determine if the flash open was successful. */
if (status != LX_SUCCESS) {
/* Return an I/O error to FileX. */
media_ptr->fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Successful driver request. */
media_ptr->fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_UNINIT: {
/* There is nothing to do in this case for the RAM driver. For actual
devices some shutdown processing may be necessary. */
/* 关闭 NOR 闪存模拟。 */
status = lx_nor_flash_close(&nor_w25q128);
/* Determine if the flash close was successful. */
if (status != LX_SUCCESS) {
/* Return an I/O error to FileX. */
media_ptr->fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Successful driver request. */
media_ptr->fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_BOOT_READ: {
/* 读取引导记录并返回给调用方。 */
/* Setup the destination buffer. */
destination_buffer = (UCHAR *) media_ptr->fx_media_driver_buffer;
/* Read boot sector from NOR flash. */
status = lx_nor_flash_sector_read(&nor_w25q128, 0, destination_buffer);
/* For NOR driver, determine if the boot record is valid. */
if ((destination_buffer[0] != (UCHAR) 0xEB) ||
(destination_buffer[1] != (UCHAR) 0x34) ||
(destination_buffer[2] != (UCHAR) 0x90)) {
/* Invalid boot record, return an error! */
media_ptr->fx_media_driver_status = FX_MEDIA_INVALID;
return;
}
/* Determine if the boot read was successful. */
if (status != LX_SUCCESS) {
/* Return an I/O error to FileX. */
media_ptr->fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Successful driver request. */
media_ptr->fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_BOOT_WRITE: {
/* Setup the source buffer. */
source_buffer = (UCHAR *) media_ptr->fx_media_driver_buffer;
/* Write boot sector to NOR flash. */
status = lx_nor_flash_sector_write(&nor_w25q128, 0, source_buffer);
/* Determine if the boot write was successful. */
if (status != LX_SUCCESS) {
/* Return an I/O error to FileX. */
media_ptr->fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Successful driver request. */
media_ptr->fx_media_driver_status = FX_SUCCESS;
break;
}
default: {
/* Invalid driver request. */
media_ptr->fx_media_driver_status = FX_IO_ERROR;
break;
}
}
}
测试验证
- 逻辑为 必须先挂载,然后才能操作,否则是无效的,然后切换到另外一个设备时,要先卸载之前的,重新挂载,没有做多个的适配。
- 在没有卸载以前的挂载,代码是直接限制返回错误