spi-flash(GD25Q128C)

GD25Q128Datasheets


由图可知GD25Q128C 16MB这里写图片描述

  • block 64/32K 共(256/512)个块
  • sector 4K 共4096个扇区
  • page 256B 共64个页

一般擦除最小单位为扇区,也就是4K

GD25Q128 4个信号线

  • SCLK:Serial Clock
  • CS#:Chip Select
  • SI: Serial Data Input
  • SO: Serial Data Output

X1000-uboot spi-flash

定义drivers/spi/jz_spi.h

{
        .id_manufactory = 0x1860c8,
        .name = "GD25LQ128C",
        .page_size = 256,
        .sector_size = 4 * 1024,
        .addr_size = 3,
        .size = 16 * 1024 * 1024,
        .quad_mode = {
            .dummy_byte = 8,
            .RDSR_CMD = CMD_RDSR_1,
            .WRSR_CMD = CMD_WRSR,
            .RDSR_DATE = 0x2,// the data is write the spi status register for QE bit
            .RD_DATE_SIZE = 1,
            .WRSR_DATE = 0x0200,// this bit should be the flash QUAD mode enable
            .WD_DATE_SIZE = 2,
            .cmd_read = CMD_QUAD_READ,
#ifdef CONFIG_JZ_SFC
            .sfc_mode = TRAN_SPI_QUAD,
#endif
        },

common/env_sfc.c

uboot中保存环境变量的实现方法

int saveenv(void)
{
    sfc_get_env_addr(copy, &offset);
    env_new.crc = crc32(0, env_new.data, ENV_SIZE);

    sfc_nor_write(offset, CONFIG_ENV_SIZE , (char *)&env_new, 1);

    sfc_nor_read(offset, CONFIG_ENV_SIZE, (char *)buf);
}

uboot加载时发现

uboot第一阶段启动时,加载的是common/spl/spl_sfc_nor.c

#spl_sfc_nor read
#spl_sfc_nor read
#spl_sfc_nor read
#spl_sfc_nor read
#spl?
U-Boot SPL 2013.07-00004-g4861957 (Nov 26 2016 - 15:59:33)
apll = 576000000
 mpll = 600000000
cpccr = 95752210


U-Boot 2013.07-00004-g4861957 (Nov 26 2016 - 15:59:33)

Board: burner_x1000 (Ingenic XBurst X1000 SoC)
DRAM:  32 MiB
Top of RAM usable for U-Boot at: 82000000
Reserving 4642k for U-Boot at: 81b74000

加载内核时使用的是driver/spi/jz_sfc readdata函数

Logo: width 240  height 60  colors 240  cmap 240
fb:0x81febf60
dump_lcdc_registers
USB_udc_probe
jz_dwc2_udc_v1.1
Net:   =======>MacBase = 0xb34b0000, DmaBase = 0xb34b1000 PhyBase = 0x00000000
GMAC-9162
Hit any key to stop autoboot:  0 
#sfc_init1
#jz_sfc readdata
sfcnor read Image from 0x40000 to  0x80800000 size is 0x300000 ...
#jz_sfc readdata
sfcnor read ok!
## Starting application at 0x80800000 ...
compare suc

drivers/mtd/spi/sfc.c
->sfc_init();

spi_flash参数初始化

sfc_nor_init

for (i = 0; i < ARRAY_SIZE(jz_spi_support_table); i++) {
    gparams = jz_spi_support_table[i];
    if (gparams.id_manufactory == idcode){
            printf("the id code = %x, the flash name is %s\n",idcode,gparams.name);
        if(sfc_quad_mode == 1){
            quad_mode = &jz_spi_support_table[i].quad_mode;
        }
        break;
    }
}

jz_spi_support_table[i] 在jz_spi中定义
{
        .id_manufactory = 0x1840c8,
        .name = "GD25Q128C",
        .page_size = 256,
        .sector_size = 4 * 1024,
        .addr_size = 3,
        .size = 16 * 1024 * 1024,
        .quad_mode = {
            .dummy_byte = 8,
            .RDSR_CMD = CMD_RDSR_1,
            .WRSR_CMD = CMD_WRSR_1,
            .RDSR_DATE = 0x2,// the data is write the spi status register for QE bit
            .RD_DATE_SIZE = 1,
            .WRSR_DATE = 0x2,// this bit should be the flash QUAD mode enable
            .WD_DATE_SIZE = 1,
            .cmd_read = CMD_QUAD_READ,
#ifdef CONFIG_JZ_SFC
            .sfc_mode = TRAN_SPI_QUAD,
#endif
        },
    },

定义了nor共享参数 static struct nor_sharing_params pada;
具体赋值在

sfc_nor_init
  ->sfc_nor_read_params
    ->jz_sfc_read_norflash_params

sfc_nor_write示例

U_BOOT_CMD(
    sfcnor, 6,  0,  do_sfcnor,
    "sfc nor",
    "sfcnor read   [src:nor flash addr] [bytes:0x..] [dst:ddr address]\n"
    "sfcnor write  [src:nor flash addr] [bytes:0x..] [dst:der address] [force erase:1, nor erase:0]\n"
    "sfcnor erase  [src:nor flash addr] [bytes:0x..]\n "
);


static int do_sfcnor(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
    ......
    sfc_nor_read(src_addr,count,dst_addr);
    ......
    sfc_nor_write(src_addr,count,dst_addr,erase_en);
    ......
    sfc_nor_erase(src_addr,count);
}

jz_sfc_write分析

有程序可知一次写入空间为一页PageSize
数据写入开始地址需要PageSize对齐,不可跨页写,例如

`|----|------------------|`
a    b                  c
例a%page_size == 0
b位offset 

一次最大可写空间为c-b

jz_sfc_set_address_mode
cmd[0] = CMD_WREN;      //设置可写

if(sfc_quad_mode == 1){
    cmd[1]  = CMD_QPP;  //写入
    mode = TRAN_SPI_QUAD;
}else{
    cmd[1]  = CMD_PP;
    mode = TRAN_SPI_STANDARD;
}

cmd[flash->addr_size + 2] = CMD_RDSR;//读状态寄存器

while(length)
{
    if (length >= flash->page_size)//参数错误 设置待写入长度为0
        pagelen = 0;
    else
        pagelen = length % flash->page_size;//设置一次写入大小
    sfc_send_cmd(&cmd[0],0,0,0,0,0,1);//Write enable

    if (offset % flash->page_size + len > flash->page_size)//若偏移地址+待写入长度 >1PageSize
        len -= offset % flash->page_size + len - flash->page_size;//保证offset对page_size对齐后+len < Page_size
    cmd[2] [3] [4] = offset

    sfc_send_cmd(&cmd[1], len,offset,flash->addr_size,0,1,1);//发送写入命令

    sfc_write_data(send_buf ,len);

    sfc_send_cmd(&cmd[flash->addr_size + 2],1,0,0,0,1,0);
    sfc_read_data(&tmp, 1);
    while(tmp & CMD_SR_WIP) {
        sfc_send_cmd(&cmd[flash->addr_size + 2],1,0,0,0,1,0);
        sfc_read_data(&tmp, 1);
    }//读状态寄存器  等待处理完成

    offset += retlen;//自动后移
    send_buf += retlen;
    length -= retlen;
}

addr1 addr2               addr3
`|--|---------------------|`
256 300                   512
offset = 300  len = 500
len -= 300 % 256 + 500 - 256
     = 46 + 246
     = 292

jz_sfc_reader分析

if(sfc_quad_mode == 1){
    cmd[0]  = quad_mode->cmd_read;
    mode = quad_mode->sfc_mode;
}else{
    cmd[0]  = CMD_READ;
    mode = TRAN_SPI_STANDARD;
}

for(i = 0; i < flash->addr_size; i++){
    cmd[i + 1] = offset >> (flash->addr_size - i - 1) * 8;
}//cmd[0]  reader cmd[1] [2] [3]读地址

sfc_send_cmd(&cmd[0],read_len,offset,flash->addr_size,0,1,0);

sfc_read_data(data, len);

jz_sfc_erase分析

if((len >= 0x10000)&&((offset % 0x10000) == 0)){
    erase_size = 0x10000;//offset为64K整数倍 且擦除大小>=64K erase_size = 64K;
}else if((len >= 0x8000)&&((offset % 0x8000) == 0)){
    erase_size = 0x8000;//offset为32K整数倍 且擦除大小>=64K erase_size = 32;
}else{
    erase_size = 0x1000;//4K
}

if(len % erase_size != 0){
    len = len - (len % erase_size) + erase_size;//向上取整
}

cmd[0] = CMD_WREN;
cmd[1] = CMD_ERASE_64K/32K/4K;

cmd[flash->addr_size + 2] = CMD_RDSR;

while(len)
{
    for(i = 0; i < flash->addr_size; i++){
        cmd[i+2] = offset >> (flash->addr_size - i - 1) * 8;
    }//设置擦除开始地址
    sfc_send_cmd(&cmd[0],0,0,0,0,0,1);
    sfc_send_cmd(&cmd[1],0,offset,flash->addr_size,0,0,1);

    sfc_send_cmd(&cmd[flash->addr_size + 2], 1,0,0,0,1,0);
    sfc_read_data(&buf, 1);
    while(buf & CMD_SR_WIP) {//wait spi_flash not busy
        sfc_send_cmd(&cmd[flash->addr_size + 2], 1,0,0,0,1,0);
        sfc_read_data(&buf, 1);
    }

    offset += erase_size;
    len -= erase_size;
}
  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值