这一篇是读SPIFLASH程序。
/*
* SPI read chip (using spidev driver)
*
* Copyright (c) 2007 MontaVista Software, Inc.
* Copyright (c) 2007 Anton Vorontsov <avorontsov@ru.mvista.com>
* Copyright (c) 2012 fengchen <fengchen_rs@qq.com>
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* Cross-compile with cross-gcc -I/path/to/cross-kernel/include
*/
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
/*********spi conf******************/
#define SPI_BITS_PER_WORD 8
#define SPI_SPEED 25000000
#define SPI_MODE 0
#define SPI_DEVICE "/dev/spidev0.0"
#define ONCE_READ_MAX_BYTES 3*1024*1024
/*********device******************/
#define MX25L32
//#define MX25L64
//#define W25Q80
/*******************pagesize*******************/
#define SIZE_1M_PAGE_NUM 256*16 //(256sectors)*(16pages/sector)
#ifdef W25Q80
//#define CHIP_ID 0x13
#define SPI_FLASH_25_X_XX
#define PAGE_NUM SIZE_1M_PAGE_NUM
#define TIME_ERASECHIP 2*1000*1000
#define TIME_PAGEPROGRAM 700
#endif
#ifdef MX25L32
//#define CHIP_ID 0x15
#define SPI_FLASH_25_X_XX
#define PAGE_NUM SIZE_1M_PAGE_NUM*4
#define TIME_ERASECHIP 25*1000*1000
#define TIME_PAGEPROGRAM 1400
#endif
#ifdef MX25L64
//#define CHIP_ID 0x16
#define SPI_FLASH_25_X_XX
#define PAGE_NUM SIZE_1M_PAGE_NUM*8
#define TIME_ERASECHIP 50*1000*1000
#define TIME_PAGEPROGRAM 1400
#endif
/*************** cmd type ************/
struct cmd_type {
char* cmd_name;
uint8_t cmd;
uint8_t num_addr;
uint8_t *p_cmd_addr;
uint8_t num_dummy;
uint8_t mode_data_rw; //r:0,w:1
uint32_t num_data;
uint8_t *p_rw_data;
uint32_t delay_usecs;
};
#ifdef SPI_FLASH_25_X_XX
#define PAGE_SIZE 256 //256bytes/page
#define CHIP_SIZE PAGE_SIZE*PAGE_NUM
#define NUM_ADDR 3
struct cmd_type cmd_readdeviceid = {
.cmd_name = "cmd_readdeviceid",
.cmd = 0xAB,
.num_addr = 0,
.p_cmd_addr = NULL,
.num_dummy = 3,
.mode_data_rw = 0,
.num_data = 1,
.delay_usecs = 0,
};
struct cmd_type cmd_chiperase = {
.cmd_name = "cmd_chiperase",
.cmd = 0x60,
.num_addr = 0,
.p_cmd_addr = NULL,
.num_dummy = 0,
.mode_data_rw = 0,
.num_data = 0,
.p_rw_data = NULL,
.delay_usecs = TIME_ERASECHIP,
};
struct cmd_type cmd_writeenable = {
.cmd_name = "cmd_writeenable",
.cmd = 0x06,
.num_addr = 0,
.p_cmd_addr = NULL,
.num_dummy = 0,
.mode_data_rw = 0,
.num_data = 0,
.p_rw_data = NULL,
.delay_usecs = 0,
};
struct cmd_type cmd_readstatus = {
.cmd_name = "cmd_readstatus",
.cmd = 0x05,
.num_addr = 0,
.p_cmd_addr = NULL,
.num_dummy = 0,
.mode_data_rw = 0,
.num_data = 1,
.p_rw_data = NULL,
.delay_usecs = 0,
};
struct cmd_type cmd_fastread = {
.cmd_name = "cmd_fastread",
.cmd = 0x0B,
.num_addr = NUM_ADDR,
.p_cmd_addr = NULL,
.num_dummy = 1,
.mode_data_rw = 0,
.num_data = CHIP_SIZE,
.p_rw_data = NULL,
.delay_usecs = 0,
};
struct cmd_type cmd_pageprogram = {
.cmd_name = "cmd_pageprogram",
.cmd = 0x02,
.num_addr = NUM_ADDR,
.p_cmd_addr = NULL,
.num_dummy = 0,
.mode_data_rw = 1,
.num_data = PAGE_SIZE,
.p_rw_data = NULL,
.delay_usecs = 0/4,//transmit need too long time
};
#endif
int Fd_dev;//spi device
struct spi_ioc_transfer Spi_tr[2]={
{
.cs_change = 0, //not change(??)
.bits_per_word = SPI_BITS_PER_WORD,
.delay_usecs = 0,
.rx_buf = (unsigned long)NULL,
},
{
.cs_change = 0, //change(??)
.bits_per_word = SPI_BITS_PER_WORD,
},
};
uint8_t transmit(struct cmd_type *p_cmd)
{
int ret;
uint32_t i;
uint8_t *a_tr_buf;
struct spi_ioc_transfer *p_spi_tr;
//send cmd+addr+dummy
p_spi_tr = Spi_tr;
p_spi_tr->len = 1+(p_cmd->num_addr)+(p_cmd->num_dummy);
a_tr_buf = (uint8_t *)malloc(p_spi_tr->len);
p_spi_tr->tx_buf = (unsigned long)a_tr_buf;
p_spi_tr->rx_buf = (unsigned long)NULL;
a_tr_buf[0] = p_cmd->cmd;
for(i=0;i<(p_cmd->num_addr);i++){
a_tr_buf[1+i] = (p_cmd->p_cmd_addr)[(p_cmd->num_addr-1)-i];//large addr first
}
for(i=0;i<(p_cmd->num_dummy);i++){
a_tr_buf[1+(p_cmd->num_addr)+i] = 0xFF;
}
//send/receive data
p_spi_tr ++;
p_spi_tr->len = p_cmd->num_data;
p_spi_tr->delay_usecs = p_cmd->delay_usecs;
if(p_cmd->num_data){
if(p_cmd->mode_data_rw){ //write
p_spi_tr->tx_buf = (unsigned long)(p_cmd->p_rw_data);
p_spi_tr->rx_buf = (unsigned long)NULL;
}
else{//read
p_spi_tr->tx_buf = (unsigned long)NULL;
p_spi_tr->rx_buf = (unsigned long)(p_cmd->p_rw_data);
}
}
//spi operation
ret = ioctl(Fd_dev, SPI_IOC_MESSAGE(2), Spi_tr);
if (ret < 1){
printf("\n[Return = %d. Can't read/write chip !]\n",ret);
goto ERROR;
}
free(a_tr_buf);
return 0;
ERROR:
free(a_tr_buf);
return 1;
}
uint8_t spi_conf(char *device)
{
int ret = 0;
uint8_t mode = SPI_MODE,bits_per_word = SPI_BITS_PER_WORD;
uint32_t max_speed_hz = SPI_SPEED;
ret += ioctl(Fd_dev, SPI_IOC_WR_MODE, &mode);
ret += ioctl(Fd_dev, SPI_IOC_RD_MODE, &mode);
ret += ioctl(Fd_dev, SPI_IOC_WR_BITS_PER_WORD, &bits_per_word);
ret += ioctl(Fd_dev, SPI_IOC_RD_BITS_PER_WORD, &bits_per_word);
ret += ioctl(Fd_dev, SPI_IOC_WR_MAX_SPEED_HZ, &max_speed_hz);
ret += ioctl(Fd_dev, SPI_IOC_RD_MAX_SPEED_HZ, &max_speed_hz);
if(ret||(mode!=SPI_MODE)||(bits_per_word!=SPI_BITS_PER_WORD)||(max_speed_hz!=SPI_SPEED)){
printf("SPI mode configure ERROR : mode=%d!\n",mode);
return 1;
}
return 0;
}
uint8_t read_status()
{
uint8_t status=0x88;
int ret;
cmd_readstatus.p_rw_data = &status;
ret = transmit(&cmd_readstatus);
if(ret){
puts("Read status ERROR!");
}
return status;
}
uint8_t verity_id(char * filename)
{
uint8_t id=0x1d;
int ret;
if((read_status())&0x01){
puts("Device is busy!");
return 1;
}
cmd_readdeviceid.p_rw_data = &id;
ret = transmit(&cmd_readdeviceid);
if(ret){
puts("Get ID Failure!");
return 1;
}
printf("\nThe chip ID is 0x%x.\nContinue ? (y/n)",id);
if(getchar()=='y'){
puts("Wait several minute...");
}
else{
puts("Exit.\n");
return 1;
}
return 0;
}
uint8_t read_chip(uint8_t *p_buf_r,uint32_t size_r)
{
uint8_t p_addr[NUM_ADDR];
int ret;
uint32_t i,j;
int n;
uint32_t addr;
addr = 0;
for(n = size_r,i = 0;n > 0;n -= ONCE_READ_MAX_BYTES,i++){
addr += ONCE_READ_MAX_BYTES*i;
for(j=0;j<NUM_ADDR;j++){
p_addr[j] = (uint8_t)(addr>>j*8);
}
cmd_fastread.p_cmd_addr = p_addr;
p_buf_r += ONCE_READ_MAX_BYTES*i;
cmd_fastread.p_rw_data = p_buf_r;
if(n<ONCE_READ_MAX_BYTES){
cmd_fastread.num_data = n;
}
else{
cmd_fastread.num_data = ONCE_READ_MAX_BYTES;
}
ret = transmit(&cmd_fastread);
if(ret){
puts("\nRead CHIP Failure!");
goto ERROR;
}
}
return 0;
ERROR:
return 1;
}
uint8_t chip_to_file(char * filename)
{
uint8_t *p_buf_r;
int ret;
uint32_t i;
int fd_file;
fd_file = open(filename,O_WRONLY | O_CREAT,S_IRUSR | S_IWUSR);
if (fd_file < 0){
printf("Can't open/creat file : %s\n",filename);
return 1;
}
p_buf_r = (uint8_t *)malloc(CHIP_SIZE);
ret = read_chip(p_buf_r,CHIP_SIZE);
if(ret){
goto ERROR;
}
ret = write(fd_file,p_buf_r,CHIP_SIZE);
if(ret < 0){
puts("Write file ERROR!");
goto ERROR;
}
printf("Read %dBytes(%.2fMBytes).\nRead Done.\n",CHIP_SIZE,(float)CHIP_SIZE/1024/1024);
close(fd_file);
free(p_buf_r);
return 0;
ERROR:
close(fd_file);
free(p_buf_r);
return 1;
}
void check_exit(int ret)
{
if(ret){
close(Fd_dev);
exit(0);
}
}
int main(int argc, char *argv[])
{
int ret;
char *filename = argv[1];//"/home/fengchen/nfs.dir/spi_flash/MX25L80_firmware";
Fd_dev = open(SPI_DEVICE, O_RDWR);
if (Fd_dev < 0){
puts("Can't open device.");
return 1;
}
ret = spi_conf(SPI_DEVICE);
check_exit(ret);
ret = verity_id(filename);
check_exit(ret);
ret = chip_to_file(filename);
check_exit(ret);
close(Fd_dev);
puts("Succeed !"); //ok
return 0;
}