s5pv210开发系列八_yaffs的移植

ljbguanli ljbguanli     2022-08-30     542

关键词:

S5PV210开发系列八

Yaffs的移植

象棋小子    1048272975

Nand作为市面上最基本的非易失性闪存技术之中的一个,应用在各种固态大容量存储解决方式中。因为Nand flash自身的特点,Nand存储器往往须要一款专用的Nand文件系统进行管理。开源的Yaffs文件系统因为其优异的性能,在Nand flash中受到广泛的应用,笔者此处就Yaffs的移植作一个简单的介绍。

1. Yaffs概述

Yaffs是由Aleph One公司所发展出来的Nand flash文件系统,专门为Nand flash存储器设计,适用于大容量的存储设备。在GPL协议下公布,可在其官网上免费获得源代码。

Yaffs是基于日志的文件系统,提供了坏块管理、磨损平衡和掉电恢复的健壮性,保证数据在系统对文件系统改动的过程中发生意外也不被破坏。特别针对Nand flash,在启动时间、内存空间占用、读写速度等方面做了优化,已经在Linux、Android、WinCE等商业产品中使用。

2. Yaffs移植

Yaffs文件系统分为文件系统管理层接口、Yaffs内部实现层和Nand接口层。这简化了与系统的接口设计。便于集成到系统中去。移植即为实现Nand接口层。

因为Yaffs一直在维护更新。其内部数据结构、函数实现流程等有细微的更新。

因此对于时间跨度比較大的版本号,再者之间的移植将会有较大的差异。

对于可移植的开源项目,一般应在源代码包对应的makefile、readme等文档中获知项目的文件夹架构,提取对应的源代码。接口的移植也应參考源代码包中的Demo接口移植。了解对应接口应实现的功能需求,便于针对特定设备又一次实现类似的接口功能。应用编程也能够參考源代码中的应用測试代码。笔者此处以2015/06版本号的源代码为例说明Yaffs的移植。

2.1. 编译器相关

对于可移植开源项目。不会使用编译器的数据类型、扩展语法等,由于不同体系的cpu、不同编译器这部分是不同的,是不可移植的,开源项目有自定义的数据类型。这是须要依据详细的cpu、详细的编译器重定义的。

Yaffs提供posix文件操作接口,使用了posix文件操作数据类型。而posix为unix下可移植操作系统应用编程接口。并非c标准,c编译器不必实现posix。因此需自定义Yaffs中使用到的posix数据类型。Yaffs应用编程跟posix文件操作应用编程是全然一致的。

即基于posix的应用程序在基于unix类、windows、支持posix的rtos等都是源代码级可移植的。

#ifndef __YAFFS_CONFIG_H__

#define __YAFFS_CONFIG_H__

 

#define     CONFIG_YAFFS_DIRECT

#define     CONFIG_YAFFS_YAFFS2

#define     CONFIG_YAFFS_PROVIDE_DEFS

#define     CONFIG_YAFFSFS_PROVIDE_VALUES

#define         CONFIG_YAFFS_DEFINES_TYPES

 

typedef unsigned short      dev_t;

typedef unsigned short      mode_t;

typedef long                off_t;

typedef long long           loff_t;

 

#endif

2.2. 操作系统相关

Yaffs须要訪问操作系统资源,如提供锁、时间戳、系统错误等。对于单线程訪问、无操作系统并不须要操作系统的锁等相关功能。在Yaffs中yaffs_osglue.h列出了所需实现的操作系统相关接口函数。

#include"stdio.h"

#include"stdlib.h"

#include"time.h"

 

static intyaffs_errno;

 

/*

 * yaffs_bug_fn()

 * Function to report a bug.

 */

voidyaffs_bug_fn(const char *fn, int n)

{

    printf("yaffs bug at %s:%d ", fn,n);

}

 

/*

 * yaffsfs_CurrentTime() retrns a 32-bittimestamp.

 *

 * Can return 0 if your system does not careabout time.

 */

unsigned intyaffsfs_CurrentTime(void)

{

    return time(NULL);

}

 

/*

 * yaffsfs_SetError() andyaffsfs_GetLastError()

 * Do whatever to set the system error.

 * yaffsfs_GetLastError() just fetches the lasterror.

 */

voidyaffsfs_SetError(int err)

{

    yaffs_errno = err;

}

 

intyaffsfs_GetLastError(void)

{

    return yaffs_errno;

}

 

/*

 * yaffsfs_CheckMemRegion()

 * Check that access to an address is valid.

 * This can check memory is in bounds and iswritable etc.

 *

 * Returns 0 if ok, negative if not.

 */

intyaffsfs_CheckMemRegion(const void *addr, size_t size, int write_request)

{

    if(!addr) {

        return -1;

    }

    return 0;

}

 

/*

 * yaffsfs_malloc()

 * yaffsfs_free()

 *

 * Functions to allocate and free memory.

 */

void*yaffsfs_malloc(size_t size)

{

    return malloc(size);

}

 

voidyaffsfs_free(void *ptr)

{

    free(ptr);

}

 

/*

 * yaffsfs_Lock()

 * yaffsfs_Unlock()

 * A single mechanism to lock and unlock yaffs.Hook up to a mutex or whatever.

 */

voidyaffsfs_Lock(void)

{

   

}

 

voidyaffsfs_Unlock(void)

{

   

}

 

voidyaffsfs_OSInitialisation(void)

{

    /* No locking used */

}

2.3. Nand接口相关

Nand驱动在前面章节有具体的描写叙述,一般针对Nand flash的特性,Nand底层驱动应实现Nand初始化、Nand页读、Nand页编程、Nand块擦除、Nand坏块标记、Nand坏块检查。Yaffs通过函数指针的方式实现訪问以上的Nand底层驱动接口,需实现的Nand接口函数指针例如以下:

int(*drv_write_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,

            const u8 *data, int data_len,

            constu8 *oob, int oob_len);

int(*drv_read_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,

            u8 *data, int data_len,

            u8 *oob, int oob_len,

            enum yaffs_ecc_result *ecc_result);

int(*drv_erase_fn) (struct yaffs_dev *dev, int block_no);

int(*drv_mark_bad_fn) (struct yaffs_dev *dev, int block_no);

int(*drv_check_bad_fn) (struct yaffs_dev *dev, int block_no);

int(*drv_initialise_fn) (struct yaffs_dev *dev);

int(*drv_deinitialise_fn) (struct yaffs_dev *dev);

2.3.1. drv_initialise_fn函数指针

drv_initialise_fn主要实现Nand的初始化,在文件系统挂载时,会最先调用该函数指针对Nand进行初始化。

static int yaffs_nand_drv_Initialise(struct yaffs_dev*dev)

{

    Nand_Init();

    returnYAFFS_OK;

}

2.3.2. drv_erase_fn函数指针

drv_erase_fn主要对某一个块进行擦除。

static int yaffs_nand_drv_EraseBlock(struct yaffs_dev*dev, int block_no)

{

    if(Nand_EraseBlock(block_no) != 0) {

        returnYAFFS_FAIL;

    }

    returnYAFFS_OK;

}

2.3.3. drv_mark_bad_fn函数指针

drv_mark_bad_fn需实现对某一块进行坏块标记。

static int yaffs_nand_drv_MarkBad(struct yaffs_dev*dev, int block_no)

{

    if (Nand_MarkBadBlock(block_no)!= 0) {

        returnYAFFS_FAIL;

    }

    returnYAFFS_OK;

}

2.3.4. drv_check_bad_fn函数指针

drv_check_bad_fn需实现对某一块进行检查,是否坏块。

static int yaffs_nand_drv_CheckBad(struct yaffs_dev*dev, int block_no)

{

    if(Nand_IsBadBlock(block_no) != 0) {      

        // badblock

        returnYAFFS_FAIL;

    }

    returnYAFFS_OK;

}

2.3.5. drv_write_chunk_fn函数指针

drv_write_chunk_fn需实现对某chunk(page)在Nand data area写入特定长度的数据。通常为1 chunk(page),在Nand spare area写入特定长度的oob数据(tags)。

static int yaffs_nand_drv_WriteChunk(struct yaffs_dev*dev, int nand_chunk,

        const u8*data, int data_len, const u8 *oob, int oob_len)

{

    if (!data ||!oob) {

        returnYAFFS_FAIL;

    }

    if(Nand_WriteWithOob(nand_chunk, data, data_len, oob, oob_len) != 0) {

        returnYAFFS_FAIL;

    }

    returnYAFFS_OK;

}

2.3.6.drv_read_chunk_fn函数指针

drv_read_chunk_fn需实现对某chunk(page)在Nand data area读取特定长度的数据,通常为1 chunk(page),在Nand spare area读取特定长度的oob数据(tags)。此处採用Nand驱动硬件ecc。而未使用Yaffs自带的软件ecc,需处理数据是否无错或可纠错。

static int yaffs_nand_drv_ReadChunk(struct yaffs_dev*dev, int nand_chunk,

            u8*data, int data_len, u8 *oob, int oob_len,

            enumyaffs_ecc_result *ecc_result_out)

{

    int ret;

    if (data ==NULL) {

        data_len= 0;

    }

    ret =Nand_ReadWithOob(nand_chunk, data, data_len, oob, oob_len);

    if (ret != 0){

        if(ecc_result_out) {

            *ecc_result_out= YAFFS_ECC_RESULT_UNKNOWN;

        }

        returnYAFFS_FAIL;

    } else {

        if(ecc_result_out) {

            *ecc_result_out= YAFFS_ECC_RESULT_NO_ERROR;

        }

    }

    returnYAFFS_OK;

}

2.3.7.drv_deinitialise_fn函数指针

drv_deinitialise_fn为取消选中Nand flash,do nothing。

static int yaffs_nand_drv_Deinitialise(structyaffs_dev *dev)

{

    returnYAFFS_OK;

}

2.3.8.yaffs_start_up函数

Yaffs在挂载使用前,必须先安装Nand驱动。通过yaffs_start_up函数把对应的Nand底层訪问接口载入进Yaffs的接口层。

struct yaffs_dev *yaffs_nand_install_drv(const char*dev_name)

{

    struct yaffs_driver*drv;  

    structyaffs_dev *dev;

    structyaffs_param *param;

   

    dev =malloc(sizeof(struct yaffs_dev));

    if (!dev) {

        returnNULL;

    }

    memset(dev,0, sizeof(*dev));  

    param =&dev->param;

    param->name= strdup(dev_name);

    if(!param->name){

        free(dev);

        returnNULL;       

    }

 

    param->total_bytes_per_chunk= 2048;

    param->chunks_per_block= 64;

    param->n_reserved_blocks= 5;

    param->start_block= 32; // First block, reserve 4M for boot

    param->end_block= 4096 - 1;

    param->is_yaffs2= 1;

    param->use_nand_ecc= 1; // use driver‘s ecc

    param->n_caches= 10;  

   

    drv =&dev->drv;

    drv->drv_write_chunk_fn= yaffs_nand_drv_WriteChunk;

    drv->drv_read_chunk_fn= yaffs_nand_drv_ReadChunk;

    drv->drv_erase_fn= yaffs_nand_drv_EraseBlock;

    drv->drv_mark_bad_fn= yaffs_nand_drv_MarkBad;

    drv->drv_check_bad_fn= yaffs_nand_drv_CheckBad;

    drv->drv_initialise_fn= yaffs_nand_drv_Initialise;

    drv->drv_deinitialise_fn= yaffs_nand_drv_Deinitialise;

   

    /* The yaffsdevice has been configured, install it into yaffs */

    yaffs_add_device(dev);

 

    return dev;

}

 

int yaffs_start_up(void)

{

    static u8start_up_called = 0;

 

    if(start_up_called){

        return 0;

    }

    start_up_called= 1;

    // Stuff toinitialise anything special (eg lock semaphore).

    yaffsfs_OSInitialisation();

    yaffs_nand_install_drv("/");

    return 0;

}

3. 应用測试

Yaffs提供了posix文件操作应用接口,因此Yaffs应用编程实际与posix文件操作应用编程全然一致。此处測试在”/”文件夹下可通过选择创建test.txt測试文件,每次可对该文件累计写入測试字符串,通过对应选项读出该文件的内容。可选择列举全部”/”文件夹下的全部文件,在第一次使用Yaffs时,必须先对Nand flash进行格式化。不然不同的Nand驱动标记的脏数据会造成Nand信息的出错。

static const char test[] = "This is yaffs testfile ";

 

static const char *yaffs_file_type_str(structyaffs_stat *stat)

{

    switch(stat->st_mode & S_IFMT) {

    case S_IFREG:return "regular file";

    case S_IFDIR:return "directory";

    case S_IFLNK:return "symlink";

    default:return "unknown";

    }

}

 

int yaffs_ls(const char *mountpt, int longlist)

{

    int i;

    yaffs_DIR *d;

    structyaffs_dirent *de;

    structyaffs_stat stat;

    chartempstr[255];

 

    d =yaffs_opendir(mountpt);

 

    if (!d) {

        printf("opendirfailed, %s ", yaffs_error_to_str(yaffsfs_GetLastError()));

        return-1;

    }

 

    for (i = 0;(de = yaffs_readdir(d)) != NULL; i++) {

    if (longlist){

        sprintf(tempstr,"%s/%s", mountpt, de->d_name);

        yaffs_lstat(tempstr,&stat);

        printf("%-25s %7ld",

                de->d_name,

                (long)stat.st_size);

        printf("%5d %s ",

                stat.st_ino,

                yaffs_file_type_str(&stat));

    } else {

        printf("%s ",de->d_name);

    }

    }

 

    yaffs_closedir(d);

 

    return 0;

}

 

// 又一次依据新的驱动规则扫描标注坏块

void nand_scan_bad_block(void)

{

    int i;

    for (i = 8; i<= (2048-1); i++) {

        if(Nand_IsBadBlock(i)) {

        if(Nand_EraseBlock(i)) {

            Nand_MarkBadBlock(i);// 确实为坏块

        }

        }

    }

}

 

void main(void)

{  

char Text[1024];

int handle;

int BytesRead;

uint8_t Command;   

RTC_Time Time = {

    2015, 7, 1,22, 00, 0, 3

}; 

 

Uart_Init();

RTC_Init(&Time);

   

yaffs_start_up();

yaffs_mount("/");

 

while (1) {

printf("1: Write test.txt ");

printf("2: View test.txt ");

printf("3: List files in nand ");

printf("4: Format nand flash ");

Command = Uart_WaitChar();

switch (Command) {

case ‘1‘:

    handle =yaffs_open("/test.txt", O_CREAT|O_WRONLY|O_APPEND, S_IREAD|S_IWRITE);

    if (handle ==-1) {

        printf("Createtest.txt failed ");

        break;

    }

    yaffs_write(handle,test, strlen(test));

    yaffs_close(handle);

    break;

case ‘2‘:

    handle =yaffs_open("/test.txt", O_RDONLY, S_IREAD|S_IWRITE);

    if (handle ==-1) {

        printf("Opentest.txt failed ");

        break;

    }

    while (1) {

    BytesRead =yaffs_read(handle, Text, sizeof(Text)-1);

    if (BytesRead== -1) {

        printf("Read test.txt error ");

        yaffs_close(handle);

        break;

    }

    Text[BytesRead]= 0;

    printf("%s",Text);

    if (BytesRead< (sizeof(Text)-1)) {

        yaffs_close(handle);

        break;

    }

    }

    break;

case ‘3‘:

    yaffs_ls("/",1);

    break;

case ‘4‘:

    yaffs_unmount("/");

    nand_scan_bad_block();

    yaffs_format("/",0, 0, 0);

    yaffs_mount("/");

    break;

default:

    break;

}

printf(" ");

}

}

 

4. 附录

S5PV210_Yaffs.rar,Yaffs在IAR下的移植project,包含S5PV210 Bootloader、Yaffs源代码、以及对应的Nand flash驱动。

http://pan.baidu.com/s/1gdxYmqB

 

s5pv210移植minigui3.0.12

移植平台:ubuntu:14.04 开发板:s5pv210(A8) Minigui版本:3.0.12-----------------------------------------------------以下软件是开发板正常运行的必须安装包,在MiniGui官网可以下载http://www.minigui.org/zhcn/【已放在嵌入式软件组资料共享文件夹】--... 查看详情

移植tslib和qt5.6到三星s5pv210开发板

tslib1.4移植下载tslib1.4后1.cptslib-1.4.tar.bz2/home/gec2.tarjxvftslib-1.4.tar.bz23.sudo-s4.cdtslib-1.4/5../configure--host=arm-linux--prefix=/usr/local/armac_cv_func_malloc_0_nonnull=yes6.make7.makeinstal 查看详情

qt开发之移植qt5.6.2到s5pv210(代码片段)

1、移植前的准备工作 (1)确认已经烧录uboot,并设置环境变量bootcmd和bootargs从tftp、nfs启动; (2)zImage事先编译好的,文件夹形式的rootfs准备好,成功启动内核进入命令行; (3)ts驱动源码确认添加、设备文件确认OK(dev/input/event2... 查看详情

s5pv210移植无线wifi网卡mt7601

一、准备工作1、MT7601驱动下载点击下载2、插入usbWiFi启动开发板linux,lsusb查看usb驱动Bus001Device003:ID148f:7601看到的是该驱动的厂家设备信息3、解压源码到linux下,确认USB的VID和PID,在rtusb_dev_id.c中USB_DEVICE_IDrtusb_dev_id[]=#ifdefRT6570USB_D... 查看详情

s5pv210-kernel-从三星官方的内核开始移植

...ARCH的架构对不对5、在arch/arm/configs这个目录下找到和我们开发板最接近的一个配置,用这个配置文件,我们在kernel根目录下,makex 查看详情

嵌入式开发(s5pv210)——u-boot的顶层mkconfig文件分析(代码片段)

mkconfig文件的调用#第一步:SRCTREE是源码的路径,也就是顶层的目录MKCONFIG :=$(SRCTREE)/mkconfigexportMKCONFIG#第二步:配置#$(@:_config=):作用是将x210_sd_config的_config去掉,得到x210_sdx210_sd_c 查看详情

s5pv210——中断

1:s5pv210的中断步骤(1):建立异常向量表;(2):写入中断处理函数;(3):中断初始化;(4):建立中断号与中断处理函数的联系,使能中断;当中断发生时,中断处理函数会自动处理中断;流程如下: 2:建立异常向量表:s5pv21... 查看详情

嵌入式开发(s5pv210)——u-boot的不同来源和目录结构

...来源大致有三个途径:uboot官网下载、Soc厂商提供、开发板厂商提供。假设某个厂商推出新的Soc,Soc厂商的工程师会去uboot的官网下载uboot,然后把此款Soc的开发板的uboot移植上去并开源,让买这款Soc的公司去参考... 查看详情

嵌入式开发(s5pv210)——u-boot的头文件包含问题(代码片段)

...移植的,不同的配置和编译指令可以编译出不同Soc和开发板的程序,其中源码是没有改动的。不同的编译配置指令就是将链接指向不同的目录,将适配的同名头文件或者同功能的配置文件包含进去, 查看详情

cortexa8系列s5pv210的启动概述

1、硬件特性:(1)内存:内存有两种类型,SRAM(StaticRAM)和DRAM(DynamicRAM),分别称为静态内存和动态内存。SRAM:静态内存,特点是容量小、价格高。优点是不需要软件初始化就可以直接上电使用,读取执行内部存储的信息。DR... 查看详情

第一章之s5pv210启动顺序

我所使用的开发板是:友善之臂smart210,cpu为s5pv210.u-boot版本是:u-boot-2012-101,首先在u-boot中配置相对应的开发板的配置文件#makes5p_goni_config2,设事先编译好的交叉编译器放在Makefile中添加上去,打开Makefile在67行补充CROSS_COMPILE?=arm-linux-... 查看详情

tiny210(s5pv210)移植u-boot(基于2014.4版本号)——移植u-boot.bin(打印串口控制台)

   在之前我们移植的代码中,都没看到明显的效果,这节我们实现控制台的信息打印。在上节。我们看到调用relocate_code重定位。在u-boot的帮助文档doc/README.arm-relocation中对重定位有说明。u-boot为了生成位置无关码,在... 查看详情

s5pv210开发板常用易忘操作记录

一、调试串口2、SD卡槽  查看详情

嵌入式开发(s5pv210)——u-boot的链接脚本分析(代码片段)

1、脚本内容OUTPUT_FORMAT("elf32-littlearm","elf32-littlearm","elf32-littlearm")/*OUTPUT_FORMAT("elf32-arm","elf32-arm","elf32-arm")*/OUTPUT_ARCH(arm)ENTRY(_s 查看详情

gpio中断

主要功能:通过两个GPIO(S5PV210_GPJ2(7)和S5PV210_GPJ3(0))作为输出,来控制两个作为中断的GPIO(S5PV210_GPH1(4)和S5PV210_GPH1(2)),从而触发两个LED灯( S5PV210_GPH0(6... 查看详情

gpio中断

主要功能:通过两个GPIO(S5PV210_GPJ2(7)和S5PV210_GPJ3(0))作为输出,来控制两个作为中断的GPIO(S5PV210_GPH1(4)和S5PV210_GPH1(2)) 查看详情

s5pv210开发--i2c你知道多少?

如需转载请注明出处:https://blog.csdn.net/qq_29350001/article/details/78835639I2C部分已经接近尾声了,接下来我们回过头来看一下剩下的一些小知识点。如I2C仲裁、LinuxI2C工具查看配置I2C设备、什么是漏极开路等等。一、动手画出I2... 查看详情

s5pv210中断体系结构分析

我们按照Tiny210官方的裸板程序来梳理S5PV210的中断体系。关于S5PV210的中断体系结构S5PV210的中断控制器是由4个向量中断控制器(VIC)、ARMPrimeCellPL192和4个TrustZoneInterruptController(TZIC)共同组成。S5PV210共支持93个中断源(具体见官方手册)... 查看详情