SPI协议简介

.SPI 是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。是Motorola(摩托罗拉)首先在其MC68HCXX系列处理器上定义的。

.SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。

1.从器件只有在主控机发命令时才能接收或发送数据,其数据的传输格式是高位(MSB)在前,低位(LSB)在后。

.SPI主从模式

SPI分为主、从两种模式,一个SPI通讯系统需要包含一个(且只能是一个)主设备,一个或多个从设备。提供时钟的为主设备(Master),接收时钟的设备为从设备(Slave),SPI接口的读写操作,都是由主设备发起。当存在多个从设备时,通过各自的片选信号进行管理

2.SPI系统可直接与各个厂家生产的多种标准外围器件接口,它只需4条线:

MISO: 主设备输入/从设备输出引脚。该引脚在从模式下发送数据,在主模式下接收数据。

MOSI: 主设备输出/从设备输入引脚。该引脚在主模式下发送数据,在从模式下接收数据。

SCLK:串行时钟信号,由主设备产生。

CS/SS:从设备片选信号,由主设备控制。它的功能是用来作为“片选引脚”,也就是选择指定的从设备,让主设备可以单独地与特定从设备通讯,避免数据线上的冲突。

W25Q128(SPI flash)简介

W25Q128简介

1.W25Q128 是华邦公司推出的一款 SPI 接口的 NOR Flash 芯片,其存储空间为 128Mbit,相当于 16M 字节。 (换算成字节(Byte),也就是:128Mbits/8 = 16MB = 16*1024KB = 16384 KB = 16,777,216B,所以很容易计算出整个存储空间的地址范围:0x000000~0xFFFFFF)

W25Q128 可以支持 SPI 的模式 0 和模式 3,也就是 CPOL=0/CPHA=0 和CPOL=1/CPHA=1 这两种模式。

2.写入数据时,需要注意以下两个重要问题:

①、Flash 写入数据时和 EEPROM 类似,不能跨页写入,一次最多写入一页,W25Q128的一页是 256 字节。(整个存储空间被分成了256个块(Block),每个块包含16个扇区(Sector),每个扇区又包括16个页。每个块的大小是:16384KB/256 = 64KB ,每个扇区的大小是:64KB/16 = 4KB ,每个页的大小是:4KB/16 = 256B) 写入数据一旦跨页,必须在写满上一页的时候,等待 Flash 将数据从缓存搬移到非易失区,重新再次往里写。

②、Flash 有一个特点就是Flash的编程原理都是只能将1写为0,但是不能将 0 写成 1;要想将 0 写成 1,必 须进行擦除操作。因此通常要改写某部分空间的数据,必须首先进行一定物理存储空间擦除,

最小的擦除空间,通常称之为扇区,扇区擦除就是将这整个扇区每个字节全部变成 0xFF。

每款 Flash 的扇区大小不一定相同,W25Q128 的一个扇区是 4096 字节。为了提高擦除效率,

使用不同的擦除指令还可以一次性进行 32K(8 个扇区)、64K(16 个扇区)以及整片擦除。

3.地址范围

从存储容量来看,我们可以轻松的计算出W25Q128的整个存储空间的地址范围:0x000000~0xFFFFFF,也就是地址最大是24位。根据块的大小是64KB,扇区的大小是4KB,我们可以计算出每个块和扇区的地址范围:

块0的地址:`0x000000~0x00FFFF`

块1的地址:`0x010000~0x01FFFF`

.....

块255的地址:`0xFF0000~0xFFFFFF`

对于每个块,以块0为例:

块0扇区0的地址:`0x000000~0x000FFF`

块0扇区1的地址:`0x001000~0x001FFF`

...

块0扇区15的地址:`0x00F000~0x00FFF`

注:查看详细硬件手册可参考:https://blog.csdn.net/z123canghai/article/details/88700489

操作流程

1.可以用 读状态寄存器I 指令(0x05)然后查看返回的第1位,即 BUSY 位,等待标志位为 0 即说明 擦除/写入 成功完成,再读取则为写入值。

2.读取全部数据命令:03 0 0 0之后要读取多少个数据,则加上多少个0。

3.切记要读写要加上繁忙,空闲判断(或者直接加上延迟,不过最好还是判断比较稳定一点),否则容易出现读写失败。

4.基本流程如下:

配置spi---初始化spi---根据需求发送命令和地址---接收返回的数据

写操作:

使能---擦除---检验擦除---再使能---发送命令、地址、要写入的数据---发送读取数据命令、地址(检验是否正确写入)。

uboot下如何添加命令可参考:https://mp.csdn.net/mp_blog/creation/editor/109646415

代码如下:

#include <common.h>
#include <console.h>
#include <bootretry.h>
#include <cli.h>
#include <command.h>
#include <console.h>
#ifdef CONFIG_HAS_DATAFLASH
#include <dataflash.h>
#endif
#include <hash.h>
#include <inttypes.h>
#include <mapmem.h>
#include <watchdog.h>
#include <asm/io.h>
#include <linux/compiler.h>#include <stdlib.h>
#include <stdbool.h>#define read_spi_reg8(a)            (*(volatile uint8_t *)(a))
#define write_spi_reg8(a,v)         (*(volatile uint8_t *)(a) = (v))
#define read_spi_reg16(a)           (*(volatile uint16_t *)(a))
#define write_spi_reg16(a,v)        (*(volatile uint16_t *)(a) = (v))
#define read_spi_reg32(a)           (*(volatile uint32_t *)(a))
#define write_spi_reg32(a,v)        (*(volatile uint32_t *)(a) = (v))#define REG_SPI_CTRLR0(REG_BASE)     (REG_BASE + 0x00)   //CTRL0寄存器
#define REG_SPI_CTRLR1(REG_BASE)     (REG_BASE + 0x04)   //CTRL1寄存器
#define REG_SPI_SSIENR(REG_BASE)     (REG_BASE + 0x08)   //SPI使能寄存器
#define REG_SPI_MWCR(REG_BASE)       (REG_BASE + 0x0c)   //microwire控制寄存器
#define REG_SPI_SER(REG_BASE)        (REG_BASE + 0x10)   //从机使能寄存器
#define REG_SPI_BAUDR(REG_BASE)      (REG_BASE + 0x14)   //波特率选择寄存器
#define REG_SPI_TXFTLR(REG_BASE)     (REG_BASE + 0x18)   //发送FIFO阙值寄存器
#define REG_SPI_RXFTLR(REG_BASE)     (REG_BASE + 0x1c)   //接收FIFO阙值寄存器
#define REG_SPI_TXFLR(REG_BASE)      (REG_BASE + 0x20)   //发送FIFO等级寄存器
#define REG_SPI_RXFLR(REG_BASE)      (REG_BASE + 0x24)   //接收FIFO等级寄存器
#define REG_SPI_SR(REG_BASE)         (REG_BASE + 0x28)   //状态寄存器
#define REG_SPI_IMR(REG_BASE)        (REG_BASE + 0x2c)   //中断屏蔽寄存器
#define REG_SPI_RISR(REG_BASE)       (REG_BASE + 0x34)   //中断状态寄存器/*清理寄存器*/
#define REG_SPI_TXOICR(REG_BASE)      (REG_BASE + 0x38)   //清除发送FIFO溢出中断寄存器
#define REG_SPI_RXOICR(REG_BASE)      (REG_BASE + 0x3c)   //清除接收FIFO溢出中断寄存器
#define REG_SPI_RXUICR(REG_BASE)      (REG_BASE + 0x40)   //清除FIFO下溢中断寄存器
#define REG_SPI_MSTICR(REG_BASE)      (REG_BASE + 0x44)   //清除多主机争用中断寄存器
#define REG_SPI_ICR(REG_BASE)         (REG_BASE + 0x48)   //中断清除寄存器
#define REG_SPI_DR(REG_BASE)          (REG_BASE + 0x60)   //数据寄存器#define STATUS_TFE(bit)               ((bit) << 2)        //0:发送FIFO不为空 1:发送FIFO为空
#define STATUS_RFNE(bit)              ((bit) << 3)        //0:接收FIFO不为空 1:接收FIFO为空
#define STATUS_BUSY(bit)              ((bit) << 0)        //0:空闲            1:忙#define REG_SPI0_BASE                 (0X2800C000)        //spi0基地址
#define REG_SPI1_BASE                 (0X28013000)        //spi1基地址
#define FALSE                         0                   //bool
#define TRUE                          1
#define DISP_LINE_LEN   16typedef unsigned char               uint8_t;
typedef unsigned int                uint32_t;static ulong   base_address = 0;
static ulong    dp_last_addr, dp_last_size;
static ulong    dp_last_length = 0x40;
static ulong    mm_last_addr, mm_last_size;unsigned int base_addr = 0x2800c000;
const unsigned int g_spi[] = {0x2800c000,0x28013000};
unsigned int dex1 = 0;
unsigned int addr1=0,progress_bar=0,count=0,send_num=0;
unsigned int start_copy_addr1=0x600000; //6M(6291456=0x600000)往后的是新的bin
unsigned int block_addr = 0x0;/*模式*/
typedef enum spi_mode{SRDATA = 00,OSDATA = 10,ORDATA = 01,RRDATA = 11
}SPI_MODE;/*spi的基地址*/
typedef enum spi_baseaddr{base0 = REG_SPI0_BASE,base1 = REG_SPI1_BASE
}spi_BASEADDR;/*spi模块编号*/
typedef enum spi_idx{spi_idx_0 = 0,spi_idx_1 = 1
}spi_IDX;/*spi配置信息*/
typedef struct spi_cfg{spi_IDX spi_idx;spi_BASEADDR spi_baseaddr;SPI_MODE spi_mode;unsigned int rx_tl;unsigned int SCKDV;unsigned int interupt;bool init;
}SPI_CFG;SPI_CFG spiCfg0 = {.spi_idx = spi_idx_0,.spi_baseaddr = base0,.spi_mode = SRDATA,.SCKDV = 0x2,.rx_tl = 0xFF,.interupt = 0xFF,.init = FALSE
};SPI_CFG spiCfg1 = {.spi_idx = spi_idx_1,.spi_baseaddr = base1,.spi_mode = SRDATA,.SCKDV = 0x2,.rx_tl = 0xFF,.interupt = 0xFF,.init = FALSE
};void spi_writeword(unsigned int i2c_base_addr,unsigned int data)
{write_spi_reg32(REG_SPI_DR(i2c_base_addr),data);
}unsigned int spi_readword(unsigned int i2c_base_addr)
{return read_spi_reg32(REG_SPI_DR(i2c_base_addr));
}void spi_send(int sdx,unsigned int wd)
{unsigned int ret;int spi_index = sdx;unsigned int base_addr = g_spi[spi_index];spi_writeword(base_addr,wd);
}unsigned int spi_recive(int sdx)
{unsigned int ret;int spi_index = sdx;unsigned int base_addr = g_spi[spi_index];ret = spi_readword(base_addr);return ret;
}static void mmio_write_32(uintptr_t addr, uint32_t value)
{*(volatile uint32_t*)addr = value;
}static uint32_t mmio_read_32(uintptr_t addr)
{return *(volatile uint32_t*)addr;
}/*spi_exchange:通过串行接口交换数据*/
static void spi_exchange(int sdx,unsigned char *txbuffer,unsigned char *rxbuffer,int nwords)
{unsigned char *src  = (unsigned char *)txbuffer;unsigned char *dest = (unsigned char *)rxbuffer;unsigned char word;int spidx = sdx;int tnwords = nwords;int rnwords = nwords;unsigned int base_addr = g_spi[spidx];write_spi_reg32(REG_SPI_SSIENR(base_addr),0x0);//配置spiwrite_spi_reg32(REG_SPI_CTRLR0(base_addr),0xC7);write_spi_reg32(REG_SPI_SER(base_addr),0x1);write_spi_reg32(REG_SPI_SSIENR(base_addr),0x1);//使能spiwhile(tnwords-- > 0){if(src){word =*src++;}else{word = 0xff;}spi_send(spidx,(unsigned int)word);}while(!mmio_read_32(REG_SPI_SR(base_addr))&0x9);while(rnwords-- > 0){word = (unsigned char)spi_recive(spidx);if(dest){*dest++ = word;}}#if 0if(mmio_read_32(REG_SPI_SR(base_addr))&0x8)printf("rxfifo read not clean\n");mmio_write_32(REG_SPI_SER(base_addr),0x0);//控制器会自动拉高cs来完成操作printf("cs high!\n");
#endif}/*spi_setup:配置spi*/
int spi_setup(const SPI_CFG *cfg)
{int ret = 0;unsigned int spi_base_addr = cfg->spi_baseaddr;unsigned int rx_tl = cfg->rx_tl;unsigned int open = 0x1;unsigned int down = 0x0;write_spi_reg32(REG_SPI_SSIENR(spi_base_addr),down);write_spi_reg32(REG_SPI_IMR(spi_base_addr),cfg->interupt);write_spi_reg32(REG_SPI_BAUDR(spi_base_addr),cfg->SCKDV);write_spi_reg32(REG_SPI_TXFTLR(spi_base_addr),0xff);write_spi_reg32(REG_SPI_RXFTLR(spi_base_addr),0xff);write_spi_reg32(REG_SPI_SSIENR(spi_base_addr),open);/*      if(!rx_tl){unsigned int fifo;for(fifo = 1;fifo < 256;fifo++){write_spi_reg32(REG_SPI_TXFTLR(spi_base_addr),fifo);if(fifo != read_spi_reg32(REG_SPI_RXFTLR(spi_base_addr)))break;}rx_tl = (fifo == 1) ? 0:fifo;write_spi_reg32(REG_SPI_TXFTLR(spi_base_addr),0);}
*/          ret = 0;return ret;
}/*spi0初始化*/
void spi_init0(void)
{int stat;stat = spi_setup(&spiCfg0);if(0 == stat){printf("spi0 init ok!\n");}else{printf("spi0 init failed!\n");}return;
}/*spi1初始化*/
void spi_init1(void)
{int stat;stat = spi_setup(&spiCfg1);if(0 == stat){printf("spi1 init ok!\n");}else{printf("spi1 init faile!\n");}return;
}/*读取JEDEC ID*/
int read_jedec_id(int num)
{int i = 0;unsigned char datat[4] = {0x9F,0x0,0x0,0x0};unsigned char datar[4] = {0};for(i = 0;i < num;i++){spi_exchange(0,datat,datar,sizeof(datat));printf("jedec id :%02x,%02x,%02x,%02x\n",datar[0],datar[1],datar[2],datar[3]);printf("correct jedec id reference:00,ef,60,18;if no,please try again!\n");}
}/*读取device ID*/
void read_device_id(int num)
{int i = 0;int dex = 0;unsigned char datat[6] = {0x90,0x0,0x0,0x0,0x0,0x0};unsigned char datar[6] = {0};for(i = 0;i < num;i++){spi_exchange(0,datat,datar,sizeof(datat));for(dex=1;dex<=6;dex++){printf("rec device id:%8x\r\n",datar[dex]);}}
}/*1.1写使能(06h)*/
void write_enble(int num)
{int i = 0;int dex = 0;unsigned char datat[1] = {0x06};unsigned char datar[1] = {0};for(i=0;i<num;i++){spi_exchange(0,datat,datar,sizeof(datat));/*for(dex=1;dex<=1;dex++){printf("rec enble data:%8x\r\n",datar[dex]);}*/}
}/*1.2写失能(0x04)*/
void write_disable(void)
{unsigned char datat[1] = {0x04};unsigned char datar[1] = {0};spi_exchange(0,datat,datar,sizeof(datat));printf("%s disable data:%8x\r\n",__func__,datar[0]);
}/*2.1 64k块擦除(d8h)官方数据:擦除时间TYP=150ms,MAX=2000ms*/
void erase_block_64k(int num)
{int i = 0;int dex = 0;unsigned char datat[4] = {0xd8,0x0,0x0,0x0};unsigned char datar[4] = {0};for(i=0;i<num;i++){spi_exchange(0,datat,datar,sizeof(datat));for(dex=1;dex<=5;dex++){printf("rec erase 64k data:%8x\r\n",datar[dex]);}}
}
/*2.1 64k块擦除(d8h)官方数据:擦除时间TYP=150ms,MAX=2000ms*/
void erase_block_64k1()
{int dex = 0;unsigned char* datat =(unsigned char*)malloc(4);unsigned char* datar =(unsigned char*)malloc(4);datat[0]=0xd8;datat[1]=(block_addr >> 16);datat[2]=(block_addr >> 8);datat[3]=(block_addr & 0xff);spi_exchange(0,datat,datar,4);//mdelay(1000);block_addr+=0x10000;free(datat);   free(datar);    return 0;}/*2.2 4k块擦除(0x20 0 0 0)*/
void erase_block_4k(void)
{int dex = 0;unsigned char datat[4] = {0x20,0x00,0x00,0x00};unsigned char datar[4] = {0};spi_exchange(0,datat,datar,sizeof(datat));for(dex=0;dex<=3;dex++){printf("rec erase data:%8x\r\n",datar[dex]);}
}/*2.3 整片擦除(c7h/60h)官方数据:擦除时间TYP=40s,MAX=200s*/
void erase_chip(int num)
{
/*unsigned int val=0;unsigned int base_addr = g_spi[0];write_spi_reg32(REG_SPI_SSIENR(base_addr),0x0);write_spi_reg32(REG_SPI_CTRLR0(base_addr),0xC7);write_spi_reg32(REG_SPI_SER(base_addr),0x1);write_spi_reg32(REG_SPI_SSIENR(base_addr),0x1);spi_send(0,0x60);unsigned char word = (unsigned char)spi_recive(0);//printf("erasing chip ,rec data:%8x\r\n",word);
*/int i = 0;int dex = 0;unsigned char datat[1] = {0x60};unsigned char datar[1] = {0};for(i=0;i<num;i++){spi_exchange(0,datat,datar,sizeof(datat));/*for(dex=1;dex<=1;dex++){printf("rec enble data:%8x\r\n",datar[dex]);}*/} printf("erasing chip...\n");
}
/*3.检测是否擦除完成(05h 0 0)*/
void test_erase(int num)
{int i = 0;unsigned char datat[3] = {0x05,0x0,0x0};unsigned char datar[3] = {0};spi_exchange(0,datat,datar,sizeof(datat));while(datar[1]&0x3){printf("rec test_erase data:%02x,%02x,%02x\n",datar[0],datar[1],datar[2]);if(datar[1]&0x1){mdelay(1000);spi_exchange(0,datat,datar,sizeof(datat));}else{write_disable();mdelay(5000);break;}}printf("rec test_erase finish data:%02x,%02x,%02x\n",datar[0],datar[1],datar[2]);}/*读状态(0x05 0 0)*/
unsigned int read_status(void)
{unsigned char datat[3] = {0x05,0x0,0x0};unsigned char datar[3] = {0};spi_exchange(0,datat,datar,sizeof(datat));//printf("rec read_status0 data:%02x,%02x,%02x\n",datar[0],datar[1],datar[2]);unsigned int ret=(unsigned int)datar[2];datat[0] = 0x35;spi_exchange(0,datat,datar,sizeof(datat));//printf("rec read_status1 data:%02x,%02x,%02x\n",datar[0],datar[1],datar[2]);datat[0] = 0x15;spi_exchange(0,datat,datar,sizeof(datat));//printf("rec read_status2 data:%02x,%02x,%02x\n",datar[0],datar[1],datar[2]);return ret;}/*4.写入数据(02h 0 0 0)*/
void write_data(int num)
{int i = 0;int dex = 0;unsigned char datat[8] = {0x02,0x0,0x0,0x0,0x12,0x34,0x56,0x78};unsigned char datar[8] = {0};for(i=0;i<num;i++){spi_exchange(0,datat,datar,sizeof(datat));for(dex=1;dex<=8;dex++){printf("rec write_data data:%8x\r\n",datar[dex]);}}}/*5.读取数据*/
void read_all_data(int num)
{int i=0;int dex = 0;unsigned char datat[8] = {0x03,0x0,0x0,0x0,0x0,0x0,0x0,0x0};unsigned char datar[8] = {0};for(i=0;i<num;i++){spi_exchange(0,datat,datar,sizeof(datat));for(dex=0;dex<8;dex++){printf("rec read_all_data:%02x  ",datar[dex]);}}
}/*指定地址写入指定大小的数据*/
int spi_write_data1(unsigned long long length)
{unsigned long long x0 = length;//写入的数据unsigned long long size=0;unsigned char* datat =(unsigned char*)malloc(20);unsigned char* datar =(unsigned char*)malloc(20);while(1){    ++dex1;datat[0]=0x02;datat[1]=(addr1 >> 16);datat[2]=(addr1 >> 8);datat[3]=(addr1 & 0xff);size=16;memcpy( datat+4, (void*)start_copy_addr1,(size));spi_exchange(0,datat,datar,size+4);while(1){unsigned int ret = read_status();//printf("ret=%d\n",ret);if(ret == 3)continue;if(ret == 0)break;}send_num++;if((send_num%count) == 0){printf("\033[1Awriting .....................%d %%\n",progress_bar++);}x0-=size;start_copy_addr1+=size;addr1+=size;write_enble(1);read_status();if(x0<size || x0==size ){datat[0]=0x02;datat[1]=(addr1 >> 16);datat[2]=(addr1 >> 8);datat[3]=(addr1 & 0xff);size=x0;memcpy( datat+4, (void*)start_copy_addr1,(size));spi_exchange(0,datat,datar,size+4);start_copy_addr1+=size;addr1+=size;break;}}read_status();free(datat);    free(datar);    return 0;}   /*5.读取指定地址的数据*/
void read_all_data1(unsigned int read_addr)
{int dex = 0;unsigned char* datat =(unsigned char*)malloc(8);unsigned char* datar =(unsigned char*)malloc(8);datat[0]=0x03;datat[1]=(read_addr >> 16);datat[2]=(read_addr >> 8);datat[3]=(read_addr & 0xff);spi_exchange(0,datat,datar,8);for(dex=4;dex<=7;dex++){printf("%02x  ",datar[dex]);}printf("\n");free(datat);  free(datar);    return 0;}void send_for_first_addr(void)
{unsigned char* datat =(unsigned char*)malloc(20);unsigned char* datar =(unsigned char*)malloc(20);write_enble(1);    read_status();start_copy_addr1=0;addr1=0;datat[0]=0x02;datat[1]=(addr1 >> 16);datat[2]=(addr1 >> 8);datat[3]=(addr1 & 0xff);memcpy( datat+4, (void*)start_copy_addr1,16);#if 0for(int i=0;i<20;i++){printf("datat[%d]=%02x\n",i,datat[i]);}
#endif spi_exchange(0,datat,datar,20);free(datat);  free(datar);mdelay(1000);
}/*执行命令函数*/
static int do_bf(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{printf("Burn:copy xxx.bin from ddr memory to spi flash through SPI\n");unsigned int length;length = simple_strtoul(argv[1], NULL, 16);count=(length/16/100);spi_init0();spi_init1();read_jedec_id(1);read_status();write_enble(1);    //1.使能read_status();//mdelay(50);erase_chip(1);        //2.擦除整片read_status();mdelay(100000);   //延迟100秒,等待擦除完成for(int i=0;i<((length/0x10000)+1);i++)  //每次循环发送64k数据{      write_enble(1);    //4.再次使能read_status();spi_write_data1(0x10000);  //写入64k数据mdelay(1000);  //65536/256*5=1.28s}send_for_first_addr();read_all_data1(0x0);         //6.读出指定地址数据read_status();printf(" %d byte writen completion\n",length);return 0;}U_BOOT_CMD(bf,  2,  1,  do_bf,"copy fip-all.bin from ddr memory to spi flash through SPI",    "usage:[bf  count]-->example:[bf  100]");

U-boot下编写代码对SPI flash进行操作相关推荐

  1. 深入理解Arduino下的ESP8266_Non-OS_SDK API④ SPI Flash接口

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... 共同学习成长QQ群 622368884,不喜勿 ...

  2. 编写HTML提高编写代码的效率,优化innerHTML操作(提高代码执行效率)

    例子:我们要实现的效果是当用户点击鼠标的时候,就在旧数据上追加若干新数据. 如果使用标准DOM的话,完整代码如下: test data document.onmousedown = function( ...

  3. ADSP-BF531的SPI FLASH BOOT

    昨天写这篇文章写的差不多的时候,改了Windows Explorer的文件夹选项,气愤的是IE居然也跟着刷新了,我写的还没有保存--今天重新来. 到昨天为止,我毕设的几个关键技术的研究,包括超声测距. ...

  4. flash 嵌入html代码,flash嵌入html在html网页代码中嵌入Flash文件的解决方案(下).doc...

    flash嵌入html在html网页代码中嵌入Flash文件的解决方案(下).doc flash嵌入 在 网页代码中嵌入Flash文件的解决方案(下) 在 代码中嵌入Flash文件一直都是广大web爱 ...

  5. SPI Flash,NOR Flash,NAND Flash,eMMC对比

    快闪存储器(英语:Flash Memory),是一种电子式可清除程序化只读存储器的形式,允许在操作中被多次擦或写的存储器.这种科技主要用于一般性数据存储,以及在电脑与其他数字产品间交换传输数据,如储存 ...

  6. 如何给ESP32选择外接SPI Flash

    给ESP32选择外接SPI Flash [前言]:  许多用户在使用 ESP32 做开发的时候,都会碰到如何选择外接 Flash 的难题,因为不同厂商的 Flash 存在很多差异,Flash 支持的工 ...

  7. 如何理解站在CPU角度和站在NOR FLASH角度对NOR FLASH进行操作

    前言: 我觉得,用s3c2440对NOR FLASH进行操作,在代码编写上没什么特别的难度,主要是NOR FLASH说明书的理解,还有根据代码整理一下如何理解站在CPU角度和站在NOR FLASH角度 ...

  8. FPGA接口_N25Q128型号的spi flash驱动verilog代码编写

    # N25Q128型号的spi flash驱动verilog代码编写 提示:使用正点原子达芬奇pro做的小例子,由于教程中无flash的读写,因此撰写记录 文章目录 # N25Q128型号的spi f ...

  9. Keil(MDK)下用仿真器烧程序的同时烧写附加数据到SPI FLASH

    之前在i.MX rt板块经常看到i.MX RT最新支持XXX Flash的下载算法,于是冒出一个问题,下载算法是啥.故花时间研究了一下. 一.了解下载算法 研究过程中参考了这篇文章:更进一步的了解Ke ...

  10. SPI Flash芯片W25Q32英文版数据手册解读(三)---------程序编写,电路应用

    一.序言 序言对这篇文章进行一个总体的说明: 1.这部分是根据手册写程序,因此采用手册截图+程序截图的形式,对图片不进行标号,而且对重点部分进行颜色标注. 2.考虑到很多读者(包括我),使用手机看文章 ...

最新文章

  1. python mysql库对比_mysqlclient和PyMySQL对比
  2. 第五章:数据库交换开发篇
  3. PHP之星际设计模式下(转自lightsaber)
  4. Oracle 11g RAC features
  5. IOS之学习笔记五(合成存取方法)
  6. Windows PowerShell Cookbook
  7. python语音分割_用7行Python代码构建自己的有声读物
  8. threejs中坐标系转换和实现物体跟随鼠标移动
  9. jeecg下实现自动默认模糊查询
  10. mybatis学习笔记(1)-对原生jdbc程序中的问题总结
  11. 阅文推“单本可选新合同”:授权分级、免费或付费自选
  12. ad19电气规则检查_铁路机车操作规则(铁运2012281号)
  13. 粒子群算法(1)----粒子群算法简单介绍
  14. SAP ABAP开发实战——从入门到精通系列教程目录
  15. 威纶触摸屏485轮询通讯_威纶通触摸屏与PLC实现一机多屏通讯方法
  16. 乘幂法求矩阵的特征值及特征向量
  17. qq邮箱不能上传文件的修复
  18. 用Python挖掘网易云音乐的热门歌单
  19. linux media v4l2,Overview of the V4L2 driver framework (v4l2_subdev)
  20. 解决 java.lang.RuntimeException: Method i in android.util.Log not mocked. See http://g.co/androidstudi

热门文章

  1. 产品读书《简约至上 : 交互式设计四策略》
  2. 开放式激光振镜运动控制器:C++振镜矫正方法与实现
  3. 《英语阅读教学与思维发展》读书笔记(三)
  4. 经过负载均衡图片加载不出来_负载均衡基础知识
  5. 手机端App出现崩溃常见类型
  6. python转cython_10分钟带你入门Cython
  7. shell 中#!/bin/sh 的意思
  8. 第一次学游泳技巧_第一次学习游泳
  9. 层次、网状、关系模型
  10. 新职业教育的三节课,凭什么做到今天这样