linu spi子系统驱动开发笔记之实例(1)

转自:http://blog.chinaunix.net/uid-25445243-id-4026974.html

一、W25Q32BV芯片简介

        W25X是一系列SPI接口Flash芯片的简称,它采用SPI接口和CPU通信,本文使用的W25Q32BV容量为32M,具体特性如下:

1.1、基本特性

        该芯片最大支持104MHz的时钟,供电电压范围在2.7~3.6V,SPI的片选信号CS低有效,在操作芯片的时候,

需要将/WP和/HOLD管脚接电源。

        发送地址或数据到设备时,MOSI管脚数据采样在CLK的上升沿,从芯片读数据或者状态时,MISO管脚数据采样在CLK

的下降沿,所以在设置SPI的工作模式时,必须设置为MODE0或者MODE3,本文设置为MODE3。

1.2、存储空间简介

        W25Q32BV总共有16384页(page),每页有256bytes,每次最大可以编程一页。在擦除上,可以一次擦除

4KB、32KB、64KB,或者擦除整个芯片。整个芯片的存储空间如下图:


        W25Q32BV存储空间分为sector和block。一个sector共有4KB,一个block共有32KB。一个sector存储空间如下图:

    

        本文共支持四种擦除方式,分别如下:

        1) cmd = 0x20,sector擦除,一次可以擦除4KB。芯片共有1024个sector。

        2) cmd = 0x52,半个block擦除,一次可以擦除32KB。芯片共有128个半block。

        3) cmd = 0xd8,block擦除,一次可以擦除64KB。芯片共有64个block。

        4) cmd = 0xC7,芯片擦除,擦除整个芯片。

1.3、状态寄存器

        W25Q32BV共有两个字节的状态寄存器,我们需要关心的就是BIT0和BIT1。

        BIT0:busy flag,1:busy,0:free。

        BIT1:write enable latch,1:write enable,0:write disable。

1.4、操作要求

        在操作W25Q32BV时,如果是写数据到芯片,则每写一个字节,都需要读取一个数据。

        在从芯片接收数据时,首先往芯片写一个字节的0xff,然后就是需要读取的数据。

二、设备驱动

2.1、设备注册

        在系统启动的时候,首先会对设备信息进行注册,见《Linux spi驱动分析(一)----总线驱动》中的3.1。

所以编写w25q的设备驱动程序时,首先需要对设备信息进行注册

#if defined(CONFIG_SPI_FLASH_W25Q)
 static struct gsc3280_spi_info w25q_spi1_dev_platdata = {
     .cs_type            = 1,
    .pin_cs            = 87,
    .num_cs            = 1,
    .cs_value            = 0,
    .lsb_flg            = 0,
    .bits_per_word    = 8,
};
#endif
static struct spi_board_info gsc3280_spi_devices[]={
#if defined(CONFIG_SPI_FLASH_W25Q)
    {
        .modalias        ="spi-w25q",
        .bus_num        = 1,
        .chip_select        = 2,
        .mode            = SPI_MODE_3,
        .max_speed_hz    = 5* 1000* 1000,
        .controller_data    =&w25q_spi1_dev_platdata,
    },
#endif

};
static int __init gsc3280_spi_devices_init(void)
{
    spi_register_board_info(gsc3280_spi_devices, ARRAY_SIZE(gsc3280_spi_devices));
    return 0;
}
device_initcall(gsc3280_spi_devices_init);


2.2、初始化函数

        首先从设备注册开始,程序如下:

static struct spi_driver w25q_driver ={
    .driver    ={
        .name    ="spi-w25q",
        .owner    = THIS_MODULE,
    },
    //.id_table    = w25q_ids,
    .probe    = w25q_probe,
    .remove    = __devexit_p(w25q_remove),
};


static int __init w25q_init(void)
{
    return spi_register_driver(&w25q_driver);
}
static void __exit w25q_exit(void)
{
    spi_unregister_driver(&w25q_driver);
}
module_init(w25q_init);
module_exit(w25q_exit);


        由于W25Q32BV使用SPI接口,所以将其注册为SPI驱动,接下来看下探测函数w25q_probe,程序如下:

static int __devinit w25q_probe(struct spi_device*spi)
{
    int ret = 0;
    struct w25q_dev *w25q;

    DBG("############\n");
    DBG("w25q spi flash probe start.\n");
    w25q = kzalloc(sizeof(struct w25q_dev), GFP_KERNEL);
    if (!w25q){
        DBG("!!!!kzalloc error!\n");
        return -ENOMEM;
    }
    ret = spi_setup(spi);
    if (ret != 0){
        DBG("!!!!setup error!\n");
        return ret;
    }
    w25q->spi= spi;
    mutex_init(&w25q->mlock);
    strlcpy(w25q->name, W25Q_SPI_FLASH_NAME, sizeof(w25q->name));
    ret = alloc_chrdev_region(&w25q->devt, 0, W25Q_MAX_MINOR,"w25q");
    if (ret < 0){
        DBG("!!!!%s: failed to allocate char dev region!\n", __FILE__);
        goto err_kzall;
    }
    w25q->dev.devt= MKDEV(MAJOR(w25q->devt), 1);
    cdev_init(&w25q->cdev,&w25q_fops);
    w25q->cdev.owner= THIS_MODULE;
    ret = cdev_add(&w25q->cdev, w25q->devt, 1);
    if (ret) {
        DBG("!!!!cdev add error!\n");
        goto err_alloc;
    }
    w25q->class= class_create(THIS_MODULE,"w25q-spi");
    if (IS_ERR(w25q->class)){
        DBG("!!!!failed in create w25q spi flash class!\n");
        goto err_alloc;;
    }
    device_create(w25q->class,NULL, w25q->devt,NULL,"w25q");
    dev_set_drvdata(&spi->dev, w25q);
    DBG("w25q spi flash probe success.\n");
    DBG("############\n");
    return 0;

err_alloc:
    unregister_chrdev_region(w25q->devt, W25Q_MAX_MINOR);
err_kzall:
    kfree(w25q);
    printk(KERN_ERR "!!!!!!w25q spi flash probe error.!!!!!!\n");
    return ret;
}


        说明:
        1) 首先申请设备驱动结构体。
        2) 调用spi_setup(spi)函数对设备信息初始化。
        3) 初始化设备驱动结构体成员变量。
        4) 创建/dev目录下操作文件,操作函数集为w25q_fops。
        5) 将设备驱动结构体中的链表插入本文件全局链表w25q_device_list中,以便在函数操作集的open函数中找到设备驱动结构体。
        remove函数是探测函数的相反过程,具体程序如下:

static int __devexit w25q_remove(struct spi_device*spi)
{
    struct w25q_dev *w25q = dev_get_drvdata(&spi->dev);

    cdev_del(&w25q->cdev);
    unregister_chrdev_region(w25q->devt, W25Q_MAX_MINOR);
    device_destroy(w25q->class, w25q->devt);
    class_destroy(w25q->class);
    kfree(w25q);
    return 0;
}


2.3、操作函数集w25q_fops

        操作函数集结构体具体内容如下:

static const struct file_operations w25q_fops={
    .owner = THIS_MODULE,
    .open = w25q_open,
    .write = w25q_write,
    .unlocked_ioctl = w25q_ioctl,
    .read = w25q_read,
    .llseek = w25q_llseek,
    .release = w25q_release,
};


        接下来我们一一讲述。
        首先看下open函数w25q_open,具体程序如下:

static int w25q_open(struct inode*inode, struct file*file)
{
    struct w25q_dev *w25q = container_of(inode->i_cdev, struct w25q_dev, char_cdev);

    if (test_and_set_bit(W25Q_BIT_LOCK_OPEN,&w25q->bit_lock)){
        DBG("!!!!w25q open err, busy!\n");
        return -EBUSY;
    }
    file->private_data= w25q;
    return 0;
}

        说明:
        1) 通过container_of找到在探测函数w25q_probe中定义的设备驱动结构体。
        2) 测试并且设置忙标志,如果测试忙,直接忙退出。
        3) 将找到的设备驱动结构体指针指向file->private_data,在函数操作集的其他函数中就可以使用设备驱动结构体了。
        接下来看下写函数w25q_write(),程序如下:

#define W25Q_BUF_LEN                4096
#define W25Q_PAGE_NUM                256
static ssize_t w25q_write(struct file*file,const char __user*user_buf, size_t count, loff_t*ppos)
{
    int ret = 0;
    u8 *buf_start,*buf_tmp,*w25q_buf;
    struct w25q_dev *w25q= file->private_data;
    u32 buf_size = 0, page_num= W25Q_PAGE_NUM,len= 0;
    
    DBG("@@@@w25q write start\n");
    buf_start = buf_tmp = kzalloc(W25Q_BUF_LEN, GFP_KERNEL);
    w25q_buf = w25q->buf= kzalloc(page_num+ 4, GFP_KERNEL);
    if (!buf_start || !w25q_buf) {
        DBG("!!!!kzalloc error!\n");
        return -ENOMEM;
    }
    ret = mutex_lock_interruptible(&w25q->mlock);
    if (ret) {
        DBG("!!!!mutex lock error!");
        goto exit_kfree;
    }
    len = W25Q_BUF_LEN;
    buf_size = min(count,len);
    if (copy_from_user(buf_tmp, user_buf, buf_size)){
        DBG("!!!!copy_from_user() error!\n");
        ret = -EFAULT;
        goto exit_lock;
    }
    DBG("w25q->const_addr = 0x%x\n", w25q->const_addr);
    buf_tmp = buf_start;
    w25q->cmd= W25X_PAGE_PROG;
    w25q->addr= w25q->const_addr;
    while(buf_size){
        w25q->buf= w25q_buf;
        w25q->len= min(buf_size, page_num);
        memcpy(w25q->buf+ 4, buf_tmp, w25q->len);
        ret = w25q_write_date(w25q);
        if (ret != 0){
            break;
        }
        buf_tmp += w25q->len;
        w25q->addr+= w25q->len;
        buf_size -= w25q->len;
    }

exit_lock:
    mutex_unlock(&w25q->mlock);
exit_kfree:
    kfree(buf_start);
    kfree(w25q_buf);
    if (ret != 0)
        DBG("!!!!w25q write error!\n");
    else
        DBG("w25q write success\n");
    return ret;
}

        说明:
        1) 写函数首先申请两段内存,第一段内存用于存储从应用层复制来的待写数据,最大为4KB。第二段内存用于存储每次
            往W25Q32BV写的数据。由于W25Q32BV每次最大能写256bytes,所以page_num= 256,加上4是由于每次
            传输时,需要在最前面加上一个字节的命令和三个字节的地址。
        2) 获取本次可以传输的最大数据长度。
        3) 设置好传输的cmd和起始地址,然后进入while循环。
        4) 在while循环中,获取本次可以传输的最大长度,最长为256bytes,然后将其拷贝到buf中,加上4的目的是因为buf
            的前四个字节需要放置命令和地址。
        5) 调用w25q_write_date(w25q)函数实现数据传输。
        6) 更新变量,为下一次传输做好准备。
        w25q_write_date(w25q)函数具体内容如下:

static void w25q_write_enable(struct w25q_dev*w25q)
{
    u8 cmd = W25X_WRITE_ENABLE;

    spi_w8r8(w25q->spi, cmd);
}
static int w25q_wait_null(struct w25q_dev*w25q)
{
    uint8_t limit = 5;

    /* wait BUSY bit clear*/
    while(((w25q_read_stat_reg(w25q)& 0x01)== 0x01)&&(limit!= 0)){
        limit--;
        mdelay(50);
    }
    if (limit == 0){
        DBG("!!!!w25q_wait_null:time out!\n");
        return -EBUSY;
    }
    else
        return 0;
}
/*
 * when you call this function,
 * the w25q->cmd, w25q->len(txdatelen),
 * w25q->addrand w25q->buf(date) are OK
 *
 */
static int w25q_write_date(struct w25q_dev*w25q)
{
    int ret = 0;
    u8 i = 0, rx= 0;
    struct spi_message message;
    struct spi_transfer    x[(w25q->len+ 4)* 2];

    w25q_write_enable(w25q);    //SET WEL
    ret = w25q_wait_null(w25q);
    if (ret != 0){
        DBG("!!!!w25q_write_date: wait null err!\n");
        return ret;
    }
    if((w25q_read_stat_reg(w25q)& 0x02)!= 0x02){
        DBG("!!!!state register write able is 0\n");
        return -EBUSY;    //disable write
    }

    DBG("cmd = 0x%x, addr = 0x%x\n", w25q->cmd, w25q->addr);
    w25q->buf[0]= w25q->cmd;
    w25q->buf[1]=((u8)(w25q->addr>> 16));
    w25q->buf[2]=((u8)(w25q->addr>> 8));
    w25q->buf[3]=((u8)w25q->addr);
    
    spi_message_init(&message);
    memset(x, 0, sizeof x);
    for (i = 0; i<(w25q->len+ 4)* 2; i++){
        x[i].len= 1;
        spi_message_add_tail(&x[i],&message);
        if ((i % 2) == 0){
            x[i].tx_buf= w25q->buf++;
        } else {
            x[i].rx_buf=℞
        }
    }
    /*do the i/o*/
    ret = spi_sync(w25q->spi,&message);
    if (ret != 0){
        DBG("!!!!w25q_write_date: spi_sync() error!");
        return ret;
    }
    ret = w25q_wait_null(w25q);
    if (ret != 0)
        DBG("!!!!w25q_write_date: w25q_wait_null() error!");
    return ret;
}


        说明:
        1) 在调用w25q_write_date(w25q)函数之前,需要首先设置好w25q->cmd, w25q->len(txdatelen)
            w25q->addr和w25q->buf(date)变量。
        2) 设置芯片状态寄存器,使其可写。
        3) 等待芯片不忙。
        4) 读取芯片状态寄存器,查看其是否可写。
        5) 配置发送buf,调用spi_sync(w25q->spi,&message);函数实现写数据。
        6) 等待芯片不忙,退出。
        接下来看下函数操作集中的ioctl函数,程序如下:

static long w25q_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    int ret = 0;
    u32 get_value = 0;
    struct w25q_dev *w25q= file->private_data;
    void __user *argp = (void __user *)arg;
    int __user *p = argp;

    DBG("@@@@w25q ioctl start.\n");
    ret = mutex_lock_interruptible(&w25q->mlock);
    if (ret) {
        DBG("!!!!mutex lock error!\n");
        return ret;
    }
    if ((_IOC_TYPE(cmd)!= W25Q_IOC_MAGIC)||(_IOC_NR(cmd)> W25Q_IOC_MAXNR)){
        DBG("!!!!ioc type or ioc nr error!\n");
        ret = -ENOTTY;
        goto exit;
    }
    switch(cmd){
    case W25Q_SECTOR_ERASE:
    case W25Q_HALF_BLOCK_ERASE:
    case W25Q_BLOCK_ERASE:
        if (get_user(get_value, p)){
            DBG("!!!!get value error!\n");
            ret = -EFAULT;
            goto exit;
        }
        ret = w25q_erase(w25q, get_value, cmd);
        break;
    case W25Q_CHIP_ERASE:
        ret = w25q_chip_erase(w25q);
        break;
    case W25Q_READ_DEVICE_ID:
        ret = w25q_read_id(w25q);
        if (ret == 0)
            put_user(w25q->result, p);
        break;
    default:
        DBG("!!!!cmd error!\n");
        ret = -ENOTTY;
        break;
    }

exit:
    mutex_unlock(&w25q->mlock);
    if (ret != 0)
        DBG("!!!!w25q ioctl error!\n");
    else
        DBG("w25q ioctl success.\n");
    return ret;
}


        说明:
        1) 目前共支持5个命令,包括sector擦除,half block擦除,block擦除,芯片擦除和读取芯片ID。
        2) 前三种擦除方式共用一个函数w25q_erase(w25q, get_value, cmd);,程序如下:

static int w25q_erase(struct w25q_dev*w25q, u32 num, unsignedint cmd)
{
    int ret = 0;
    u8 *buf_start;

    switch(cmd){
    case W25Q_SECTOR_ERASE:
        DBG("sector erase cmd\n");
        if (num > W25Q_SECTOR_MAX){
            DBG("!!!!sector max is over\n");
            return -EFAULT;
        }
        w25q->const_addr= num* W25Q_ONE_SECTOR_ADDR;
        w25q->cmd= W25X_SECTOR_ERASE_CMD;
        break;
    case W25Q_HALF_BLOCK_ERASE:
        DBG("half block erase cmd\n");
        if (num > W25Q_HALF_BLOCK_MAX){
            DBG("!!!!half block max is over\n");
            return -EFAULT;
        }
        w25q->const_addr= num* W25Q_HALF_BLOCK_ADDR;
        w25q->cmd= W25X_HALF_BLOCK_ERASE_CMD;
        break;
    case W25Q_BLOCK_ERASE:
        DBG("block erase cmd\n");
        if (num > W25Q_BLOCK_MAX){
            DBG("!!!!block max is over\n");
            return -EFAULT;
        }
        w25q->const_addr= num* W25Q_ONE_BLOCK_ADDR;
        w25q->cmd= W25X_BLOCK_ERASE_CMD;
        break;
    }
    DBG("w25q->const_addr = 0x%x\n", w25q->const_addr);
    w25q->len= 0;
    buf_start = w25q->buf= kzalloc(w25q->len+ 4, GFP_KERNEL);
    if (!buf_start){
        DBG("!!!!kzalloc is error\n");
        return -ENOMEM;
    }
    w25q->addr= w25q->const_addr;
    ret = w25q_write_date(w25q);
    kfree(buf_start);
    if (ret != 0){
        DBG("!!!!w25q_erase: spi write err!\n");
        return ret;
    }
    DBG("w25q_erase: erase OK\n");
    return ret;
}


        说明:
        1) 首先根据不同的擦除方式,设置命令和地址两个变量。
        2) 调用w25q_write_date(w25q);函数实现数据传输。
        芯片擦除函数w25q_chip_erase()如下:

static int w25q_chip_erase(struct w25q_dev*w25q)
{
    int ret = 0;
    u8 cmd = W25X_CHIP_ERASE;

    DBG("w25q_chip_erase\n");
    w25q_write_enable(w25q);    //SET WEL
    ret = w25q_wait_null(w25q);
    if (ret != 0){
        DBG("!!!!chip_erase: wait null err!\n");
        return ret;
    }
    if((w25q_read_stat_reg(w25q)& 0x02)!= 0x02){
        DBG("!!!!state register write able is 0\n");
        return -EBUSY;    //disable write
    }
    spi_w8r8(w25q->spi, cmd);
    return w25q_wait_null(w25q);
}


        读取设备ID函数w25q_read_id()如下:

static int w25q_read_id(struct w25q_dev*w25q)
{
    int ret = 0;
    u8 *buf_start;

    DBG("w25q_read_id\n");
    w25q->len= 2;
    w25q->addr= 0;
    w25q->cmd= W25X_READ_ID_CMD;
    buf_start = w25q->buf= kzalloc(w25q->len, GFP_KERNEL);
    if (!buf_start){
        DBG("!!!!kzalloc is error\n");
        return -ENOMEM;
    }
    ret = w25q_read_data(w25q);
    w25q->buf= buf_start;
    w25q->result=*w25q->buf<< 8;
    w25q->buf++;
    w25q->result|=*w25q->buf;
    kfree(buf_start);
    if (ret != 0){
        DBG("!!!!w25q_read_id: w25q_read_data error!\n");
        return ret;
    }
    DBG("w25q_read_id: read id OK\n");
    return ret;
}


        说明:
        1) 首先设置好变量,申请内存
        2) 调用w25q_read_data()函数实现读取数据。
        w25q_read_data函数如下:

/*
 * when you call this function,
 * the w25q->cmd, w25q->len(receivelen)
 * w25q->buf(kzalloc receive)and w25q->addr are OK
 *
 */
static int w25q_read_data(struct w25q_dev*w25q)
{
    int ret = 0;
    struct spi_message message;
    struct spi_transfer    x[(w25q->len+ 4)* 2];
    u8 i = 0, rx= 0, dumy_value= 0xff, tx_buff[4]={0};

    w25q_write_enable(w25q);    //SET WEL
    ret = w25q_wait_null(w25q);
    if (ret != 0){
        DBG("!!!!chip_erase: wait null err!\n");
        return ret;
    }
    if((w25q_read_stat_reg(w25q)& 0x02)!= 0x02){
        DBG("!!!!state register write able is 0\n");
        return -EBUSY;    //disable write
    }

    DBG("cmd = 0x%x, addr = 0x%x\n", w25q->cmd, w25q->addr);
    tx_buff[0]= w25q->cmd;
    tx_buff[1]=((uint8_t)(w25q->addr>> 16));
    tx_buff[2]=((uint8_t)(w25q->addr>> 8));
    tx_buff[3]=((uint8_t)(w25q->addr));
    
    spi_message_init(&message);
    memset(x, 0, sizeof x);
    for (i = 0; i< 8; i++){    //cmd
        x[i].len= 1;
        spi_message_add_tail(&x[i],&message);
        if ((i % 2) == 0){
            x[i].tx_buf=&tx_buff[i/ 2];
        } else {
            x[i].rx_buf=℞
        }
    }
    for (i = 8; i<(w25q->len+ 4)* 2; i++){
        x[i].len= 1;
        spi_message_add_tail(&x[i],&message);
        if ((i % 2) == 0){
            x[i].tx_buf=&dumy_value;
        } else {
            x[i].rx_buf= w25q->buf++;
        }
    }
    /*do the i/o*/
    return spi_sync(w25q->spi,&message);
}


        说明:
        1) 在从芯片读取数据时的格式为:首先发送一个字节命令+三个字节读取地址,然后就可以接收数据了。
        2) 第一个for循环发送的是命令和地址,第二个for循环是接收数据。
        3) 调用此函数之前,需要设置好w25q->cmd, w25q->len(receivelen),w25q->buf(kzalloc receive)和w25q->addr。
        接下来看下函数操作集中的读数据函数w25q_read(),程序如下:

static ssize_t w25q_read(struct file *file, char __user *user_buf, size_t count, loff_t*ppos)
{
    int ret = 0;
    u8 *buf_start,*buf_tmp,*w25q_buf;
    struct w25q_dev *w25q = file->private_data;
    u32 buf_size = 0, read_len= 0, page_num= W25Q_PAGE_NUM;

    DBG("@@@@w25q read start\n");
    buf_start = buf_tmp = kzalloc(W25Q_BUF_LEN, GFP_KERNEL);
    w25q_buf = w25q->buf= kzalloc(page_num, GFP_KERNEL);
    if (!buf_start || !w25q_buf ) {
        DBG("!!!!kzalloc error!\n");
        return -ENOMEM;
    }
    ret = mutex_lock_interruptible(&w25q->mlock);
    if (ret) {
        DBG("!!!!mutex lock error!\n");
        goto exit_kfree;
    }
    read_len = W25Q_BUF_LEN;
    buf_size = min(count, read_len);
    read_len = buf_size;
    
    w25q->cmd= W25X_READ_DATA;
    w25q->addr= w25q->const_addr;
    DBG("w25q->addr = 0x%x\n", w25q->addr);
    while (buf_size) {
        w25q->buf= w25q_buf;
        w25q->len= min(buf_size, page_num);
        ret = w25q_read_data(w25q);
        if (ret != 0){
            goto exit_lock;
        }
        memcpy(buf_tmp, w25q_buf, w25q->len);
        buf_tmp += w25q->len;
        buf_size -= w25q->len;
        w25q->addr+= w25q->len;
    }
    ret = copy_to_user(user_buf, buf_start, read_len);
    ret = read_len -ret;

exit_lock:
    mutex_unlock(&w25q->mlock);
exit_kfree:
    kfree(buf_start);
    kfree(w25q_buf);
    DBG("w25q read stop, ret = %d\n", ret);
    return ret;
}


        说明:
        1) 此函数需要申请两段内存空间,第一段用于存放从W25Q32BV接收到的数据,第二段用于存放每次接收的数据。
        2) 设置好变量后,调用w25q_read_data(w25q)读取数据。
        3) 读取完成后,将读取到的数据拷贝到应用层。

三、应用层测试

        应用层测试程序如下:

/*
* first you must erase,
* then write,then read
* or you can read only
*
*/
#include "w25q.h"


int main(int argc, char**argv)
{
    char str[10]={0};
    int fd = 0, ret = 0;
    unsigned char buffer[BUFSIZE]={0};
    unsigned int i = 0, idCmd = 0, num = 0;
    
    fd = open("/dev/w25q", O_RDWR);
    if (fd < 0){
        printf("Open ADC Device Faild!\n");
        exit(1);
    }
    while(1){
        idCmd = 0;
        printf("please enter the cmd and num :\n");
        scanf("%s%x", str,&num);
        //printf("cmd = %s, idFreq = %d\n", str, idFreq);
        if (num >= 0){
            if (strcmp(str,"SECTOR")== 0){
                idCmd = W25Q_SECTOR_ERASE;
                ret = ioctl(fd, idCmd,&num);
                if (ret != 0){
                    printf("sector erase Faild!\n");
                }
            } else if(strcmp(str,"HALF")== 0){
                idCmd = W25Q_HALF_BLOCK_ERASE;
                ret = ioctl(fd, idCmd,&num);
                if (ret != 0){
                    printf("half block erase Faild!\n");
                }
            } else if(strcmp(str,"BLOCK")== 0){
                idCmd = W25Q_BLOCK_ERASE;
                ret = ioctl(fd, idCmd,&num);
                if (ret != 0){
                    printf("block erase Faild!\n");
                }
            } else if(strcmp(str,"CHIP")== 0){
                idCmd = W25Q_CHIP_ERASE;
                ret = ioctl(fd, idCmd,&num);
                if (ret != 0){
                    printf("chip erase Faild!\n");
                }
            } else if(strcmp(str,"ID")== 0){
                idCmd = W25Q_READ_DEVICE_ID;
                ret = ioctl(fd, idCmd,&num);
                if (ret != 0){
                    printf("read ID Faild!\n");
                } else {
                    printf("ID = 0x%x\n", num);
                }
            } else if(strcmp(str,"READ")== 0){
                memset(buffer, 0, BUFSIZE);
                printf("------------\n");
                for (i = 0; i< WRITE_NUM; i++){
                    if((i!= 0)&&((i% 8)== 0)){
                        printf("\n");
                    }
                    printf("0x%x ", buffer[i]);
                }
                printf("\n------------\n");
                ret = read(fd, buffer, WRITE_NUM);
                printf("\n------------\n");
                for (i = 0; i< WRITE_NUM; i++){
                    if((i!= 0)&&((i% 8)== 0)){
                        printf("\n");
                    }
                    printf("0x%x ", buffer[i]);
                }
                printf("\n------------\n");
            } else if(strcmp(str,"WRITE")== 0){
                for (i = 0; i< WRITE_NUM; i++){
                    buffer[i]= i;
                }
                ret = write(fd, buffer, WRITE_NUM);
                if (ret != 0){
                    printf("w25q write oper Faild!\n");
                }
            } else if(strcmp(str,"QUIT")== 0){
                break;
            } else {
                printf("wrong string\n");
            }
        } else {
            printf("wrong input num(< 0)\n");
        }
    }/*endwhile(1)*/
    close(fd);
    return 0;
}


        说明:
        1) 首先从终端接收命令内容。
        2) 比较命令,然后进入不同的处理流程。

四、测试演示

4.1、读取芯片ID



4.2、读写芯片






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值