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

📄 samsung_nand.c

📁 新一代基于事件的嵌入式操作系统dyos在三星的s3c44b0的arm芯片上的完整移植代码
💻 C
📖 第 1 页 / 共 4 页
字号:
    }
    ce_inactive();                      //关闭片选
    return cn_all_right_verify;
}

//----读块(无ecc校验)----------------------------------------------------
//功能: 不带ecc校验从一块内读取数据,地址不能跨块边界
//参数: sector,扇区号
//      offset,块内偏移地址
//      data,保存读取数据的缓冲区
//      size,读取的尺寸
//返回: 正确读取
//-----------------------------------------------------------------------------
uint32_t read_block_ss_no_ecc(uint32_t block,uint32_t offset,
                         uint8_t *buf,uint32_t size)
{
    uint32_t start_sector;  //首扇区号
    uint32_t start_offset;  //首地址在首扇区的偏移量
    uint32_t end_sector;    //结束地址所在扇区
    uint32_t end_offset;    //结束地址在扇区中的偏移量
    uint32_t cur_sector;    //当前正在读的扇区
    uint32_t read_size;     //从当前扇区读取的数据量
    uint32_t completed = 0;

    if(block >= tg_samsung_nand.block_sum)
        return cn_limit_uint32;
    if((size + offset) > tg_samsung_nand.block_size)
        return cn_limit_uint32;
    if(size == 0)
        return 0;

    //起始扇区号
    start_sector = offset / cn_sector_size + u32g_sectors_per_block * block;
    //起始地址在起始扇区号中的偏移量
    start_offset = offset % cn_sector_size;
    //结束扇区号
    end_sector =(offset + size-1)/cn_sector_size+u32g_sectors_per_block*block;
    //结束地址在结束扇区中的偏移量
    end_offset = (offset + size -1) % cn_sector_size;
    for(cur_sector = start_sector; cur_sector <= end_sector; cur_sector++)
    {
        if(cur_sector != end_sector)    //当前扇区不是最后一个扇区
            read_size = cn_sector_size - start_offset;
        else    //当前扇区是最后一个扇区
            //+1是因为end_offset本身是需要写入的
            read_size = end_offset - start_offset +1;
        __read_sector_2808_no_ecc(cur_sector,start_offset,
                                  buf+completed,read_size);
        completed += read_size;
        start_offset = 0;   //从第二个扇区开始,肯定从0开始读
    }
    return completed;
}

//----ECC检查并改正-----------------------------------------------------------
//功能: ecc校验一个扇区
//参数: data,待校验数据的缓冲区
//      ecc,校验码
//返回:0=正确,1=被改正,2=错误且不能修正
//-----------------------------------------------------------------------------
//----------------------------------------------------------------------------
uint32_t __correct_sector(uint8_t *data,const uint8_t *ecc)
{
    uint32_t i,j,result = cn_all_right_verify;
    for(i = 0; i < cn_sector_size/256; i++)
    {
        j = ecc_corect_256(data + i*256, ecc + i*3);
        if(( j == -1) || (j == 2))
            return cn_ecc_error_verify;   //无法修正则直接返回
        if( j == 1)
            result = cn_ecc_right_verify;
    }
    return result;
}

//----读扇区(带ecc校验)----------------------------------------------------
//功能: 带ecc校验从一扇区内读取数据,地址不能跨扇区边界
//参数: sector,扇区号
//      offset,扇区内偏移地址
//      data,保存读取数据的缓冲区
//      size,读取的尺寸
//返回:0=正确,1=被改正,2=错误且不能修正
//-----------------------------------------------------------------------------
uint32_t __read_sector_2808_with_ecc(uint32_t sector,uint32_t offset,
                                     uint8_t *data,uint32_t size)
{
    uint32_t i;
    uint32_t address,result;
    uint8_t ecc[(cn_sector_size+255)/256*3];  //每256字节产生一个ECC码
    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 < cn_sector_size; i++)
    {
        pg_sector_buf[i] = *pg_nand_address;     //读取数据
    }
    if(cn_sector_size > 256)
    {
        for(i = 0; i < 5; i++)              //读取校验码,坏块标志前的5字节
            ecc[i] = *pg_nand_address;
        ecc[i] = *pg_nand_address;          //坏块标志,读取并丢弃
        for(; i < cn_sector_size/256*3; i++)//读取校验码,坏块标志后的部分
            ecc[i] = *pg_nand_address;
    }else
    {
        for(i = 0; i < 3; i++)              //读取校验码,只有3字节
            ecc[i] = *pg_nand_address;
    }
    ce_inactive();                      //关闭片选
    result = __correct_sector(pg_sector_buf,ecc);
    //无论校验结果如何,均执行数据copy,即使错误,也把错误数据告诉用户,让人知道
    //错在哪里。
    memcpy(data, pg_sector_buf + offset, size);
    return result;
}

//----读块(带ecc校验)----------------------------------------------------
//功能: 带ecc校验从一块内读取数据,地址不能跨块边界
//参数: sector,块号
//      offset,块内偏移地址
//      data,保存读取数据的缓冲区
//      size,读取的尺寸
//返回:实际读取的数据量
//-----------------------------------------------------------------------------
uint32_t read_block_ss_with_ecc(uint32_t block,uint32_t offset,
                         uint8_t *buf,uint32_t size)
{
    uint32_t start_sector;  //首扇区号
    uint32_t start_offset;  //首地址在首扇区的偏移量
    uint32_t end_sector;    //结束地址所在扇区
    uint32_t end_offset;    //结束地址在扇区中的偏移量
    uint32_t cur_sector;    //当前正在读的扇区
    uint32_t read_size;     //从当前扇区读取的数据量
    uint32_t completed = 0;
    uint32_t verify;

    if(block >= tg_samsung_nand.block_sum)
        return cn_limit_uint32;
    if((size + offset) > tg_samsung_nand.block_size)
        return cn_limit_uint32;
    if(size == 0)
        return 0;

    //起始扇区号
    start_sector = offset / cn_sector_size + u32g_sectors_per_block * block;
    //起始地址在起始扇区号中的偏移量
    start_offset = offset % cn_sector_size;
    //结束扇区号
    end_sector =(offset + size-1)/cn_sector_size+u32g_sectors_per_block*block;
    //结束地址在结束扇区中的偏移量
    end_offset = (offset + size -1) % cn_sector_size;
    for(cur_sector = start_sector; cur_sector <= end_sector; cur_sector++)
    {
        if(cur_sector != end_sector)    //当前扇区不是最后一个扇区
            read_size = cn_sector_size - start_offset;
        else    //当前扇区是最后一个扇区
            //+1是因为end_offset本身是需要写入的
            read_size = end_offset - start_offset +1;
        verify = __read_sector_2808_with_ecc(cur_sector,start_offset,
                                  buf+completed,read_size);
        if((verify == cn_all_right_verify) || (verify == cn_ecc_right_verify))
        {
            completed += read_size;
            start_offset = 0;   //从第二个扇区开始,肯定从0开始读
        }else
            break;
    }
    return completed;
}

//----读芯片状态-------------------------------------------------------------
//功能: 读芯片状态
//参数: 无
//返回:芯片状态
//-----------------------------------------------------------------------------
uint8_t __read_status_2808(void)
{
    uint8_t chip_status ;

    __write_command_2808(cn_2808_read_status);
    chip_status = *pg_nand_address;

    return chip_status;
}

//----写一个扇区(no ecc)-------------------------------------------------------------
//功能: 写一个扇区,不做ecc校验
//参数: sector,扇区号
//      offset,扇区内偏移地址
//      data,数据缓冲区
//      size,写入的尺寸
//返回:cn_all_right_verify=正确写入,cn_ecc_error_verify=写入错误
//-----------------------------------------------------------------------------
uint32_t __write_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);    //写入读模式命令
    __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( );  //等待芯片内部操作完成

    for(i=0; i < size; i++)
    {//逐个把待写入的数据写入到器件的扇区缓冲区
        *pg_nand_address = data[i];
       // printf("WriteFlash: data = 0x%x\n", data);
    }
    __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 cn_ecc_error_verify;
    }
    ce_inactive();
    return cn_all_right_verify;
}

//----写块(不带ecc校验)----------------------------------------------------
//功能: 不带ecc校验把缓冲区写入块内,地址不能跨块边界
//参数: sector,块号
//      offset,块内偏移地址
//      data,保存读取数据的缓冲区
//      size,读取的尺寸
//返回:实际写入的数据量,cn_limit_uint32表示出错
//-----------------------------------------------------------------------------
uint32_t write_block_ss_no_ecc(uint32_t block,uint32_t offset,
                               uint8_t *buf,uint32_t size)
{
    uint32_t start_sector;  //首扇区号
    uint32_t start_offset;  //首地址在首扇区的偏移量
    uint32_t end_sector;    //结束地址所在扇区
    uint32_t end_offset;    //结束地址在扇区中的偏移量
    uint32_t cur_sector;    //当前正在读的扇区
    uint32_t write_size;    //从当前扇区读取的数据量
    uint32_t completed = 0;
    uint32_t verify;

    if(block >= tg_samsung_nand.block_sum)
        return cn_limit_uint32;
    if((size + offset) > tg_samsung_nand.block_size)
        return cn_limit_uint32;

    //起始扇区号
    start_sector = offset / cn_sector_size + u32g_sectors_per_block * block;
    //起始地址在起始扇区号中的偏移量
    start_offset = offset % cn_sector_size;
    //结束扇区号
    end_sector =(offset + size-1)/cn_sector_size+u32g_sectors_per_block*block;
    //结束地址在结束扇区中的偏移量
    end_offset = (offset + size -1) % cn_sector_size;
    for(cur_sector = start_sector; cur_sector <= end_sector; cur_sector++)
    {
        if(cur_sector != end_sector)    //当前扇区不是最后一个扇区
            write_size = cn_sector_size - start_offset;
        else    //当前扇区是最后一个扇区
            //+1是因为end_offset本身是需要写入的
            write_size = end_offset - start_offset +1;
        verify = __write_sector_2808_no_ecc(cur_sector,start_offset,
                                  buf+completed,write_size);
        if((verify == cn_all_right_verify) || (verify == cn_ecc_right_verify))
        {
            completed += write_size;
            start_offset = 0;   //从第二个扇区开始,肯定从0开始读
        }else
            break;
    }
    return completed;

⌨️ 快捷键说明

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