ThreadX Levelx的移植和使用(nor flash)

LevelX

Azure RTOS也就是ThreadX。

Azure RTOS LevelX 向嵌入式应用程序提供 NAND 和 NOR 闪存提供实现磨损均衡的手段。由于NAND和NOR闪存都只能进行有限次数的擦除,均衡分配闪存的使用至关重要,这通常被称为磨损均衡,通过LevelX实现。

这段话来自 Azure RTOS LevelX 用户手册。可以知道 Azure RTOS通过LevelX组件实现对NANDNOR两种flash实现磨损平衡,LevelX组件只是一个组件,与任何硬件、文件系统以及操作系统都没有关系,那便可以移植出来使用。

它的github地址:https://github.com/azure-rtos/levelx

LevelX源码目录结构

在这里插入图片描述
源码都在common目录下
在这里插入图片描述

  • inc,头文件目录
  • src,源文件目录

LevelX 使用ANSI C编写,其中每个函数包含在其自己单独的 C 文件中。
在这里插入图片描述

没看手册前第一次看到这个源码真的有点蒙,咋这么多C文件,很独特,每个函数单独一个文件实现。。。
从文件名前缀可以看出文件对应的是nand还是nor flash。

inc目录下有一个头文件lx_user_sample.h,这个是用户配置头文件,里面已经定义了很多宏,通过这些就可以配置LevelX。

LevelX NAND 和 NOR 实例的模拟器和 FileX 驱动程序示例:
在这里插入图片描述

LevelX移植

移植主要是就是对接自己的flash的硬件驱动程序。

LevelX divides each NOR flash block into 512-byte logical sectors.
LevelX 将nor flash物理块划分为512字节大小的逻辑扇区。

0、驱动程序移植方法

通过调用_lx_nor_flash_open,给函数指针nor_driver_initialize指定函数,通过nor_driver_initialize调用将驱动程序注册进LevelX。

UINT  _lx_nor_flash_open(LX_NOR_FLASH  *nor_flash, CHAR *name, UINT (*nor_driver_initialize)(LX_NOR_FLASH *))

怎么在指定驱动程序呢?可以nor_driver_initialize看到有一个参数类型为LX_NOR_FLASH

typedef struct LX_NOR_FLASH_STRUCT
{
    ULONG                           lx_nor_flash_state;
    ULONG                           lx_nor_flash_total_blocks;     /* 总块数 */
    ULONG                           lx_nor_flash_words_per_block;  /* 每块有多少字,也就是多少4字节 */
    ULONG                           lx_nor_flash_total_physical_sectors;    /* 总的物理扇区数 */
    ULONG                           lx_nor_flash_physical_sectors_per_block;  /* 每个块有多少个物理扇区 */

    ULONG                           *lx_nor_flash_base_address;       /* flash基地址 */
    ULONG                           lx_nor_flash_block_free_bit_map_offset;
    ULONG                           lx_nor_flash_block_bit_map_words;
    ULONG                           lx_nor_flash_block_bit_map_mask;
    ULONG                           lx_nor_flash_block_physical_sector_mapping_offset;
    ULONG                           lx_nor_flash_block_physical_sector_offset;

    ULONG                           lx_nor_flash_free_physical_sectors;
    ULONG                           lx_nor_flash_mapped_physical_sectors;
    ULONG                           lx_nor_flash_obsolete_physical_sectors;
    ULONG                           lx_nor_flash_minimum_erase_count;
    ULONG                           lx_nor_flash_maximum_erase_count;

    ULONG                           lx_nor_flash_free_block_search;
    ULONG                           lx_nor_flash_found_block_search;
    ULONG                           lx_nor_flash_found_sector_search;   

    ULONG                           lx_nor_flash_write_requests;
    ULONG                           lx_nor_flash_read_requests;
    ULONG                           lx_nor_flash_sector_mapping_cache_hits;
    ULONG                           lx_nor_flash_sector_mapping_cache_misses;
    ULONG                           lx_nor_flash_physical_block_allocates;
    ULONG                           lx_nor_flash_physical_block_allocate_errors;
    ULONG                           lx_nor_flash_diagnostic_system_errors;
    ULONG                           lx_nor_flash_diagnostic_system_error;
    ULONG                           lx_nor_flash_diagnostic_initial_format;
    ULONG                           lx_nor_flash_diagnostic_erased_block;
    ULONG                           lx_nor_flash_diagnostic_re_erase_block;
    ULONG                           lx_nor_flash_diagnostic_sector_being_obsoleted;
    ULONG                           lx_nor_flash_diagnostic_sector_obsoleted;
    ULONG                           lx_nor_flash_diagnostic_mapping_invalidated;
    ULONG                           lx_nor_flash_diagnostic_mapping_write_interrupted;
    ULONG                           lx_nor_flash_diagnostic_sector_not_free;
    ULONG                           lx_nor_flash_diagnostic_sector_data_not_free;

    UINT                            (*lx_nor_flash_driver_read)(ULONG *flash_address, ULONG *destination, ULONG words);
    UINT                            (*lx_nor_flash_driver_write)(ULONG *flash_address, ULONG *source, ULONG words);
    UINT                            (*lx_nor_flash_driver_block_erase)(ULONG block, ULONG erase_count);
    UINT                            (*lx_nor_flash_driver_block_erased_verify)(ULONG block);
    UINT                            (*lx_nor_flash_driver_system_error)(UINT error_code);

    ULONG                           *lx_nor_flash_sector_buffer;
    UINT                            lx_nor_flash_sector_mapping_cache_enabled;
    LX_NOR_SECTOR_MAPPING_CACHE_ENTRY   
                                    lx_nor_flash_sector_mapping_cache[LX_NOR_SECTOR_MAPPING_CACHE_SIZE];

#ifndef LX_NOR_DISABLE_EXTENDED_CACHE

    UINT                            lx_nor_flash_extended_cache_entries;
    LX_NOR_FLASH_EXTENDED_CACHE_ENTRY
                                    lx_nor_flash_extended_cache[LX_NOR_EXTENDED_CACHE_SIZE];
    ULONG                           lx_nor_flash_extended_cache_hits;
    ULONG                           lx_nor_flash_extended_cache_misses;
#endif

#ifdef LX_THREAD_SAFE_ENABLE

    /* When this conditional is used, the LevelX code utilizes a ThreadX mutex for thread
       safe operation. Generally, this is not required since FileX ensures thread safe operation at
       a higher layer.  */
    TX_MUTEX                        lx_nor_flash_mutex;
#endif
    
    /* Define the NOR flash control block open next/previous pointers.  */
    struct LX_NOR_FLASH_STRUCT      *lx_nor_flash_open_next,
                                    *lx_nor_flash_open_previous;
    
} LX_NOR_FLASH;
  • 跟驱动程序相关的几个成员函数:
UINT                            (*lx_nor_flash_driver_read)(ULONG *flash_address, ULONG *destination, ULONG words);
UINT                            (*lx_nor_flash_driver_write)(ULONG *flash_address, ULONG *source, ULONG words);
UINT                            (*lx_nor_flash_driver_block_erase)(ULONG block, ULONG erase_count);
UINT                            (*lx_nor_flash_driver_block_erased_verify)(ULONG block);
UINT                            (*lx_nor_flash_driver_system_error)(UINT error_code);

1、添加源码

在这里插入图片描述
由于flash是nor flash,所以只添加nor flash相关源码。nor 和 nand的实现是分开的,如果使用的nand flash,添加前缀带nand的源码即可。

编译,会提示如下错误:

..\Components\levelx-6.1.10_rel\common\inc\lx_api.h(102): error:  #5: cannot open source input file "tx_api.h": No such file or directory

搜索源码目录可以发现没有tx_api.h头文件。

查看lx_api.h头文件内容:

/* Determine if the optional LevelX user define file should be used.  */
#ifdef LX_INCLUDE_USER_DEFINE_FILE

/* Yes, include the user defines in lx_user.h. The defines in this file may 
   alternately be defined on the command line.  */
#include "lx_user.h"
#endif

/* Include the ThreadX api file.  */
#ifndef LX_STANDALONE_ENABLE
#include "tx_api.h"
#endif

#ifdef LX_STANDALONE_ENABLE

/* Define compiler library include files.  */
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
...
...

#endif 

从注释Include the ThreadX api file,可以看出tx_api.h是ThreadX 的头文件。
以及从LX_STANDALONE_ENABLE宏定义名字STANDALONE可以知道,单定义该宏时表示独立使用而不依赖于其他东西。

直接在lx_api.h定义LX_STANDALONE_ENABLE

lx_api.h头文件开头可以看到还包含了#include "lx_user.h",inc目录下有一个头文件lx_user_sample.h,文件内容都是一些宏定义,LX_STANDALONE_ENABLE也就是宏定义,很容易就可以猜到需要把lx_user_sample.h重命名为lx_user.h

包含lx_user.hlx_api.h头文件定义LX_INCLUDE_USER_DEFINE_FILE

#define LX_INCLUDE_USER_DEFINE_FILE

修改lx_user.h文件:取消LX_STANDALONE_ENABLE宏的注释

#define LX_STANDALONE_ENABLE

再次编译发现已经没有错误。

2、驱动程序移植

实现这几个函数:

UINT (*nor_driver_initialize)(LX_NOR_FLASH *)
UINT                            (*lx_nor_flash_driver_read)(ULONG *flash_address, ULONG *destination, ULONG words);
UINT                            (*lx_nor_flash_driver_write)(ULONG *flash_address, ULONG *source, ULONG words);
UINT                            (*lx_nor_flash_driver_block_erase)(ULONG block, ULONG erase_count);
UINT                            (*lx_nor_flash_driver_block_erased_verify)(ULONG block);
UINT                            (*lx_nor_flash_driver_system_error)(UINT error_code);

从LevelX手册可以知道,实现nor_driver_initialize的时候除了实现跟硬件操作的几个函数,还要初始化指定:

  • nor flash的基地址
  • 块总数和每个块有多少个字
  • 开辟RAM缓冲区,以 ULONG对齐进行读取512字节扇区。
#include "lx_api.h"
#include "bsp_w25qxx.h"
#include "rtthread.h"
#include "slog.h"

#define FLASH_SIZE_PER_BLOCK         32        /* Kbyte */
#define FLASH_SECTORS_PER_BLOCK      (32/4)    /* 每个块包含的扇区数 */

#define FLASH_TOTAL_SECTORS          128

#define FLASH_NAME                  "XM25Q128A"
#define FLASH_BASE_ADDR              0x00        /* Flash base address */
#define FLASH_TOTAL_BLOCKS           FLASH_TOTAL_SECTORS       /* 总块数 */

#define FLASH_SIZE_KB_PER_SECTOR     4   /* 扇区Kbyte大小 */
#define FLASH_SIZE_BYTE_PER_SECTOR   (FLASH_SIZE_KB_PER_SECTOR * 1024)   /* 扇区字节大小 */

#define FLASH_WORDS_PER_SECTOR       (FLASH_SIZE_BYTE_PER_SECTOR/sizeof(ULONG))  /* word = 4 byte */

static ULONG sector_buffer[FLASH_WORDS_PER_SECTOR];   /* 开辟的RAM缓冲区 */

/* 读flash */
static UINT lx_nor_flash_driver_read(ULONG *flash_address, ULONG *destination, ULONG words)
{
    W25QXX_Read((uint8_t *)destination, (uint32_t)flash_address, (uint16_t)(words*4));
    return (LX_SUCCESS);
}

/* 写flash */
static UINT lx_nor_flash_driver_write(ULONG *flash_address, ULONG *source, ULONG words)
{
    W25QXX_Write_NoCheck((uint8_t *)source, (uint32_t)flash_address, (uint16_t)(words*4));
    return (LX_SUCCESS);
}

/* 擦除 */
static UINT lx_nor_flash_driver_block_erase(ULONG block, ULONG erase_count)
{
    LX_PARAMETER_NOT_USED(erase_count);

    W25QXX_EraseSector(block * FLASH_SIZE_BYTE_PER_SECTOR);
    return (LX_SUCCESS);
}

/* 用于校验指定的块是否擦除成功 */
static UINT lx_nor_flash_driver_block_erased_verify(ULONG block)
{
    LX_PARAMETER_NOT_USED(block);
    
    return (LX_SUCCESS);
}

/* 用于检测系统错误,依赖于驱动程序 */
static UINT lx_nor_flash_driver_system_error(UINT error_code)
{
    LX_PARAMETER_NOT_USED(error_code);
    
    return (LX_ERROR);
}   

static UINT nor_driver_initialize(LX_NOR_FLASH *nf)
{
    /* Setup the base address of the flash memory.  */
    nf->lx_nor_flash_base_address = (ULONG *)FLASH_BASE_ADDR;

  /* Setup geometry of the flash.  */
	nf->lx_nor_flash_total_blocks = FLASH_TOTAL_BLOCKS;
    nf->lx_nor_flash_words_per_block = FLASH_WORDS_PER_SECTOR;
    
    /* Setup  driver’s initialization function */
    nf->lx_nor_flash_driver_read                = lx_nor_flash_driver_read;
    nf->lx_nor_flash_driver_write               = lx_nor_flash_driver_write;
    nf->lx_nor_flash_driver_block_erase         = lx_nor_flash_driver_block_erase;
    nf->lx_nor_flash_driver_block_erased_verify = lx_nor_flash_driver_block_erased_verify;
    nf->lx_nor_flash_driver_system_error        = lx_nor_flash_driver_system_error;

    /* Setup local buffer for NOR flash operation. This buffer must be the sector size of the NOR flash memory.  */
    nf->lx_nor_flash_sector_buffer = sector_buffer;

    return(LX_SUCCESS);
}
nf->lx_nor_flash_total_blocks = FLASH_TOTAL_BLOCKS; 设置总的块数大小,
这里的blocks是LevelX定义的块跟nor flash的块不一样,
在这里将norflash的扇区当作LevelX的块来处理。

测试代码:

LX_NOR_FLASH XM25Q128A;

void LX_NOR_FLASH_Init(void)
{
    _lx_nor_flash_initialize();

    _lx_nor_flash_open(&XM25Q128A, FLASH_NAME, nor_driver_initialize);
}

void LX_NOR_FLASH_ReadWrite_Test(void)
{
    uint8_t wbuf[512] = "http://www.optomedic.com";
    uint8_t rbuf[512] = {0};
    
    uint8_t wbuf_other[512] = "Who am I?";

    _lx_nor_flash_sector_write(&XM25Q128A, 1, wbuf);
    
    _lx_nor_flash_sector_write(&XM25Q128A, 1, wbuf_other);

    _lx_nor_flash_sector_read(&XM25Q128A, 1, rbuf);

    printf("lx read %s\r\n", rbuf);
}

uint8_t wbuf[50] = "http://www.optomedic.com";
uint8_t rbuf[50] = {0};
刚开始一直定义 50大小的缓冲区进行读写测试,必定进入hardfault。
问题找了很久,用了stlink调试也找不出导致hardfault的代码。

偶然看到了其接口参数注释:

/*    nor_flash                             NOR flash instance            */ 
/*    logical_sector                        Logical sector number         */ 
/*    buffer                                Pointer to buffer to read into*/ 
/*                                            (the size is 512 bytes)     */ 

注意!!!:

读写接口的buffer的大小一定要设置为512字节(128),否则hardfault。
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

欲盖弥彰1314

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

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

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

打赏作者

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

抵扣说明:

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

余额充值