⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 samsung_nand.c

📁 新一代基于事件的嵌入式操作系统dyos在三星的s3c44b0的arm芯片上的完整移植代码
💻 C
📖 第 1 页 / 共 4 页
字号:
//----------------------------------------------------
//Copyright (C), 2004-2009,  lst.
//版权所有 (C), 2004-2009,   lst.
//所属模块: 文件系统芯片驱动
//作者:lst
//版本:V1.1.0
//文件描述: 用于三星nand flash的文件系统驱动模块
//其他说明:
//修订历史:
//    2. 日期:20090131
//       作者:lst
//       新版本号:v1.1.0
//       修改说明: 添加用定时器中断来等待操作完成的代码。
//    1. 日期:20090104
//       作者:lst
//       新版本号:v1.0.0
//       修改说明:原始版本
//------------------------------------------------------
//特注: 用int_sync函数修改flash操作函数,使之不死等。
#include "inc_os.h"
#include "samsung_nand.h"
#include "flashfile.h"
#include "gpio.h"
#include <string.h>

static  struct flash_chip tg_samsung_nand;    //芯片
static  volatile uint8_t *pg_nand_address = (uint8_t *)nand_rw_address;
//扇区缓冲区指针,扇区读写函数内部专用,djyffs中,扇区不是所有flash的共性,故不
//出现在struct flash_chip 结构中。动态分配内存而不定义成静态数组,是因为chip作
//为一个资源,是可以删除的,删除时可以回收资源。
static uint8_t *pg_sector_buf;      //扇区缓冲区指针
static uint32_t u32g_sectors_per_block; //每块包含的扇区数

//----读扇区(含oob)-------------------------------------------------------------
//功能: 读一个扇区,含oob中的内容一起读
//参数: sector,被读的扇区号
//      data,读出数据的缓冲区
//返回: 无
//-----------------------------------------------------------------------------
void __read_sector_and_oob(uint32_t sector,uint8_t *data)
{
    uint32_t i;
    uint32_t address;
    address =cn_sector_size*sector;     //计算实际地址
    ce_active();                        //激活片选
    __write_command_2808(cn_2808_select_page0);    //写入读模式命令
    address_start();                    //开始写入地址
    *pg_nand_address = (uint8_t)address;         // A0 ~ A7
    *pg_nand_address = (uint8_t)(address >> 9);  // A9 ~ A16
    *pg_nand_address = (uint8_t)(address >> 17); // A17 ~ A22
    address_end();                      //完成写入地址

    __wait_ready_2808( );  //等待芯片内部操作完成

    for(i=0; i < 528; i++)
    {
        data[i] = *pg_nand_address;     //读取数据
    }
    ce_inactive();                      //关闭片选
    return ;
}

//----写掉电恢复块-------------------------------------------------------------
//功能: 当芯片正在写入数据时掉电或者复位,将使正在写入的块数据丢失,为在这种情况
//      下保护数据,采用的策略是:
//      1.如果写入的是新块,则直接写入,因为写入新块失败和写入掉电恢复块失败的
//        后果是一样的。
//      2.如果是修改一块或者从一块后面添加数据,则把数据先写入到掉电恢复块,并
//        在掉电恢复块的适当位置标明掉电恢复块保护的是哪一块数据。
//      3.写入掉电恢复块后,接着把数据写入到目标块中,完成后,擦除掉电恢复块。
//      4.重新启动后,如果检测到掉电恢复块有有效数据,则恢复到目标块
//      本函数的职责:第三种条件下,调用本函数把数据写入掉电恢复块。
//参数: PCRB_block,用于保存掉电恢复数据的块号,芯片的绝对块号
//      protected_block,被保护的目标块号,芯片的绝对块号。
//返回: true = 成功写入,false = 写入失败,可能第PCRB_block块是坏块。
//-----------------------------------------------------------------------------
bool_t write_PCRB_2808(uint32_t PCRB_block,
                       uint32_t protected_block,uint8_t *buf)
{
    uint32_t cur_sector;    //当前正在写的扇区
    uint32_t completed = 0;
    uint32_t verify;
    uint32_t address;
    uint32_t loop;
    uint8_t obuf[528];

    if(PCRB_block >= tg_samsung_nand.block_sum)
        return false;
    cur_sector = PCRB_block * u32g_sectors_per_block;
    for(loop = 0; loop < u32g_sectors_per_block; loop++)
    {
        verify = __write_sector_2808_with_ecc(cur_sector,0,
                                  buf+completed,cn_sector_size);
        if((verify == cn_all_right_verify) || (verify == cn_ecc_right_verify))
        {
            completed += cn_sector_size;
        }else
            return false;
        cur_sector++;
    }
    //第一页的最后4字节保存受保护的目标块号。
    address =cn_block_size*PCRB_block + 12;
    ce_active();                        //激活片选
    __write_command_2808(cn_2808_select_oob);    //操作oob页
    __write_command_2808(cn_2808_page_program); //启动编程命令
    address_start();    //启动写入地址时序
    *pg_nand_address = (uint8_t)address;         // A0 ~ A7
    *pg_nand_address = (uint8_t)(address >> 9);  // A9 ~ A16
    *pg_nand_address = (uint8_t)(address >> 17); // A17 ~ A22
    address_end();      //结束写入地址时序
    __wait_ready_2808( );  //等待芯片内部操作完成

    //受保护的目标块号写入flash,注意:没有做ECC校验,以后补上---db
    *pg_nand_address = (uint8_t)protected_block;
    *pg_nand_address = (uint8_t)(protected_block>>8);
    *pg_nand_address = (uint8_t)(protected_block>>16);
    *pg_nand_address = (uint8_t)(protected_block>>24);
    __write_command_2808(cn_2808_startup_write);  //启动芯片内部写入过程
    __wait_ready_2808_slow(cn_wait_page_write);        //等待芯片内部操作完成

    if(__read_status_2808() & cn_2808_failure)
    {
        ce_inactive();
        return false;
    }
    ce_inactive();

    return true;
}

//----从掉电恢复块恢复数据-----------------------------------------------------
//功能: 从掉电恢复块恢复数据,如果掉电恢复块里有有效数据,比较其与目标块的数据是
//      否一致,如果不一致则用掉电恢复块的数据覆盖目标块。无论是否需要恢复,最后
//      均擦除掉电恢复块。
//参数: PCRB_block,掉电恢复块块号,芯片的绝对块号
//      restored,本指针返回被恢复的目标块
//返回: true = 无需恢复或者正确恢复,false = 发生错误,一般是因为目标块是坏块。
//-----------------------------------------------------------------------------
bool_t restore_PCRB_2808(uint32_t PCRB_block,uint32_t *restored)
{
    uint32_t verify;
    uint32_t address;
    uint32_t loop;
    uint32_t protected_block;
    uint32_t sector_from,sector_to;
    uint8_t *sector_buf;   //扇区缓冲区,动态分配,不在栈中分配
    bool_t result = true;

    if(PCRB_block >= tg_samsung_nand.block_sum)
        return false;
    //第一页的最后4字节保存受保护的目标块号。
    address =cn_block_size*PCRB_block + 12;
    ce_active();                        //激活片选
    __write_command_2808(cn_2808_select_oob);    //操作oob页
    address_start();    //启动写入地址时序
    *pg_nand_address = (uint8_t)address;         // A0 ~ A7
    *pg_nand_address = (uint8_t)(address >> 9);  // A9 ~ A16
    *pg_nand_address = (uint8_t)(address >> 17); // A17 ~ A22
    address_end();      //结束写入地址时序
    __wait_ready_2808( );  //等待芯片内部操作完成

    //受保护的目标块号写入flash,注意:没有做ECC校验,以后补上---db
    protected_block = *pg_nand_address;
    protected_block += (uint32_t)(*pg_nand_address)<<8;
    protected_block += (uint32_t)(*pg_nand_address)<<16;
    protected_block += (uint32_t)(*pg_nand_address)<<24;
    *restored = protected_block;

    ce_inactive();
    if(protected_block > tg_samsung_nand.block_sum)
    {
        erase_block_2808(PCRB_block);
        return true;
    }
    sector_buf = m_malloc(cn_sector_size,0);
    if(sector_buf == NULL)
        return false;
    erase_block_2808(protected_block);
    sector_from = PCRB_block * u32g_sectors_per_block;
    sector_to = protected_block * u32g_sectors_per_block;
    for(loop = 0; loop < u32g_sectors_per_block; loop++)
    {
        verify = __read_sector_2808_with_ecc(
                        sector_from,0,sector_buf,cn_sector_size);
        if((verify != cn_all_right_verify) && (verify != cn_ecc_right_verify))
        {
            result = false;
            break;
        }
        verify = __write_sector_2808_with_ecc(
                                    sector_to,0,sector_buf,cn_sector_size);
        if((verify != cn_all_right_verify) && (verify != cn_ecc_right_verify))
        {
            result = false;
            break;
        }
        sector_from++;
        sector_to++;
    }
    m_free(sector_buf);
    erase_block_2808(PCRB_block);
    return result;
}

//----等待芯片内部完成操作----------------------------------------------------
//功能: 对芯片执行写操作后,要效用本函数等待操作完成才能进一步操作。
//参数: 无
//返回: true = 正确完成操作,false = 发生错误
//-----------------------------------------------------------------------------
bool_t __wait_ready_2808(void)
{
    volatile uint32_t val;
    do
    {
        val=nand_busy_port;
        val &= nand_busy_bit;
    } while(val == 0);
    return true;
}

//----等待芯片内部慢速操作完成-------------------------------------------------
//功能: 对芯片执行写操作后,要调用本函数等待操作完成才能进一步操作。由于一连串的
//      同步操作将浪费很多时间,对于一些很快就绪的操作,宜使用__wait_ready_2808
//      函数。
//参数: wait_time,估计等待时间,微秒数
//返回: true = 正确完成操作,false = 发生错误
//-----------------------------------------------------------------------------
bool_t __wait_ready_2808_slow(uint16_t wait_time)
{
    volatile uint32_t val;

    timer_set_counter(4,wait_time);     //计数值设为wait_time
    timer_reload(4);                    //重载定时值
    timer_start(4);                     //启动定时器
    int_asyn_signal_sync(cn_irq_line_timer4);
    timer_stop(4);

    do
    {
        val=nand_busy_port;
        val &= nand_busy_bit;
    } while(val == 0);
    return true;
}

//----写入命令----------------------------------------------------
//功能: 写入芯片写命令字
//参数: val,写命令字,
//返回: 无
//-----------------------------------------------------------------------------
void __write_command_2808(uint8_t val)
{
    command_start();
    *pg_nand_address = val;
    command_end();
}

//----读扇区(无ecc校验)----------------------------------------------------
//功能: 不带ecc校验从一扇区内读取数据,地址不能跨扇区边界
//参数: sector,扇区号
//      offset,扇区内偏移地址
//      data,保存读取数据的缓冲区
//      size,读取的尺寸
//返回: 正确读取
//-----------------------------------------------------------------------------
uint32_t __read_sector_2808_no_ecc(uint32_t sector,uint32_t offset,
                                 uint8_t *data,uint32_t size)
{
    uint32_t i;
    uint32_t address;
    address =cn_sector_size*sector + offset;     //计算实际地址
    ce_active();                        //激活片选
    if(address & 0x100)
        __write_command_2808(cn_2808_select_page1);    //写入读模式命令
    else
        __write_command_2808(cn_2808_select_page0);    //写入读模式命令
    address_start();                    //开始写入地址
    *pg_nand_address = (uint8_t)address;         // A0 ~ A7
    *pg_nand_address = (uint8_t)(address >> 9);  // A9 ~ A16
    *pg_nand_address = (uint8_t)(address >> 17); // A17 ~ A22
    address_end();                      //完成写入地址

    __wait_ready_2808( );  //等待芯片内部操作完成

    for(i=0; i < size; i++)
    {
        data[i] = *pg_nand_address;     //读取数据

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -