spi-flash(GD25Q128C)

来源:互联网 发布:java并发是什么意思 编辑:程序博客网 时间:2024/06/06 20:27

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 = 600000000cpccr = 95752210U-Boot 2013.07-00004-g4861957 (Nov 26 2016 - 15:59:33)Board: burner_x1000 (Ingenic XBurst X1000 SoC)DRAM:  32 MiBTop of RAM usable for U-Boot at: 82000000Reserving 4642k for U-Boot at: 81b74000

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

Logo: width 240  height 60  colors 240  cmap 240fb:0x81febf60dump_lcdc_registersUSB_udc_probejz_dwc2_udc_v1.1Net:   =======>MacBase = 0xb34b0000, DmaBase = 0xb34b1000 PhyBase = 0x00000000GMAC-9162Hit any key to stop autoboot:  0 #sfc_init1#jz_sfc readdatasfcnor read Image from 0x40000 to  0x80800000 size is 0x300000 ...#jz_sfc readdatasfcnor 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 == 0b位offset 一次最大可写空间为c-bjz_sfc_set_address_modecmd[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                   512offset = 300  len = 500len -= 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;}
原创粉丝点击