汇编SPI-FLASH

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Mcu read and write flash
20180707tan
目录
一、SPI接口 (2)
二、25Q40的状态寄存器意义: (6)
三、Erase sector擦除扇区的试验: (12)
1.4KB擦除 (12)
2.擦除全片,指令C7H或者60H: (16)
3.32KB块擦除: (17)
4.64KB块擦除: (19)
5.擦除之前设定保护的块,2-127块: (21)
6.Page program试验 (24)
一、SPI接口
验证MCU使用科视连的KSL8M161单片机,和25Q64的FLASH芯片,使用KSLIDE编译选项,如图:
汇编指令如下:
#define P_SPI_CS PA4
#define P_SPI_CLK PA5
#define P_SPI_DIO PA0
#define P_SPI_DO PA2
;;return ACC=TMP1=从机输出的数据,MCU作为主机
F_SPI_WRITE_ACC:;;stack3
STR TMP1;;TMP1=ACC
;BCR P_SPI_CS
LDWI8;;ACC=8
STR TMP2
L_SPI_WRITE_BIT:
BCR P_SPI_CLK;;P_SPI_CLK=0;
RLR TMP1,REG;;TMP1<<=1;Carry=TMP1.BIT7,TMP1.BIT0=Carry
BTSSCarry
LJUMP L_SPI_WRITE_BIT_0
;LJUMP L_SPI_WRITE_BIT_1
;L_SPI_WRITE_BIT_1:
BSR P_SPI_DIO;;P_SPI_DIO=1;
LJUMP L_SPI_WRITE_BIT_END
L_SPI_WRITE_BIT_0:
BCR P_SPI_DIO;;P_SPI_DIO=0;
;LJUMP L_SPI_WRITE_BIT_END
L_SPI_WRITE_BIT_END:
;;read data
BCR TMP1,0;;TMP1.bit0=0;
BTSCP_SPI_DO
BSR TMP1,0;;TMP1.bit0=1;
BSR P_SPI_CLK;;P_SPI_CLK=1;
DECRSZ TMP2,REG;;--TMP;if TMP==0skip next LJUMP L_SPI_WRITE_BIT
;;SPI write a byte finish
;BSR P_SPI_CS
;BSR P_SPI_DIO
LDR TMP1,ACC;;ACC=TMP1;
RET
逻辑分析仪添加SPI模式3协议分析,如图:
如图,写0X03时序:
;;上升沿发送、下降沿接收、高位先发送
;;在CS跳变之前CLK为低则为模式0,常态CLK=0;为高则为模式3,,常态CLK=1;;;CS下降沿第一个字节作为指令
;;CLK上升沿写入数据到从机,下降沿读出从机数据
;;memory manage:32block*{16sector*4KB}=2^5*{2^4*2^2}=2^11KB=2MB
验证读flash芯片25Q64,连续读ACC个byte数据,并通过IO_PINT输出,汇编如下:;;read from24bit address SPI_ADD_BIT_23_16~SPI_ADD_BIT_7_0
;;read cnt ACC
F_SPI_READ_BLOCK:;;stack2
;LDWI50
STR SPI_ADD_READ_CNT
BCR P_SPI_CS
;;03h is read data,a byte
LDWI0X03;;flash read data command
LCALL F_SPI_WRITE_ACC
;;24bit address
LDR SPI_ADD_BIT_23_16,ACC
LCALL F_SPI_WRITE_ACC
LDR SPI_ADD_BIT_15_8,ACC
LCALL F_SPI_WRITE_ACC
LDR SPI_ADD_BIT_7_0,ACC
LCALL F_SPI_WRITE_ACC
;;read data
L_SPI_READ_CNT_LOOP:
;LDWI0X00
LCALL F_SPI_WRITE_ACC
LCALL F_PA1_PRINT_A
DECRSZ SPI_ADD_READ_CNT,REG;--SPI_ADD_READ_CNT;if SPI_ADD_READ_CNT==0 jump next
LJUMP L_SPI_READ_CNT_LOOP
BSR P_SPI_CS
RET
其中函数F_PA1_PRINT_A,从IO_PRINT口输出,汇编如下:
F_PA1_PRINT_A:
STR TMP2
LDWI0X08
STR TMP1
L_PRINT_A:
BCR GIE;;关总中断
BCR PA1
RLR TMP2,REG
BTSSCarry
LJUMP$+2
BSR PA1
BSR PA1
BSR PA1
BCR PA1
DECRSZ TMP1,REG
LJUMP L_PRINT_A
BSR GIE;;开总中断
RET
运行结果如图:
FLASH内容如图,验证了读取正确:
二、25Q40的状态寄存器意义:;;two status register,read status register1by command0x05
;;----------------
;;status register1:
;;read status register1by command0x05
;;bit7~0:SRP0,SEC,TB,BP2,BP1,BP0,WEL,BUSY
;;BIT0=BUSY:is1when writing or erasing
;;BIT1=WEL:write enable latch;read only,just a flag meanning status write able or not
;;BIT2,3,4=BP0,BP1,BP2:block protect bits;
;;BIT3=TB:top protect
;;BIT4=SEC:secttor/block protect;1,is sectors protect;0,is block protect;
;;----------------
;;status register2:
;;read status register2by command0x35
;;bit7~0:SUS,R,R,R,R,R,QE,SRP1
;;status2BIT0SRP1and status1BIT7SRP0comb next
;;is00meanning soft protect,write able after write enable command
;;is01meanning hardware protect,when/WP is low can't write,
;;/WP is high need write enable command
;;is10write able after poer down and power on
;;is11can't write able
;;BIT1=QE:quad enable,four speed read enable,use four PIN translate data;
;;BIT7=SUS:suspend status bit,read only;is1when erase suspend(75H),
;;is0after erase resume(7AH)
;;双倍速率读取:发送命令使用IO1一个脚传入,读出的时候先读IO2移位一bit再读IO1再移位1bit
;;然后下一个读bit周期重复
;;四倍速率读取也类似,IO1单脚输入命令,IO4,IO3,IO2,IO1一次读入数据并移位,再开始读下一周期
;;SEC,TB,BP2,BP1,BP0comb protect all memory
定义25Q40的命令:
;;command define
;;dummy signal is any data that virtual
#define WRITE_ENABLE0X06;;write a byte06h to enable writting
#define WRITE_DISABLE0X04;;write a byte04h to disable writting
#define READ_STATUS_REG10X05;;write a byte05h to ready read status register1and write a any byte to return register1
#define READ_STATUS_REG20X35;;write a byte35h to ready read status register2and write a any byte to return register2
#define WRITE_STATUS_REG0X01;;write0x01and two register value
#define PAGE_PROGRAM0X02;;write0x02and A23-A16,A15-A8,A7-A0,and D7-D0
#define QUAD_PAGE_PROGRAM0X32;;write0X32,A23-A16,A15-A8,A7-A0,and D7-D0 #define SECTOR_ERASE_4KB0X20;;write0X20and24bit address to erase
#define BLOCK_ERASE_32KB0X52;;write0X52and24bit address to erase
#define BLOCK_ERASE_64KB0XD8;;write0XD8and24bit address to erase
#define CHIP_ERASE0XC7;;write0xc7or0x60is chip erase,cover all memory by0XFF
#define ERASE_SUSPEND0X75;;write0x75
#define ERASE_RESUME0X7A;;write0x7A
#define POWER_DOWN0XB9;;write0xB9
#define READ_MODE_RESET0XFF;;write0xFF
#define READ_DATA0X03;;write0x03and follow24bit address,and write any data to return memory data
#define FAST_READ0X0B;;write0x03and follow24bit address,and a dummy byte and any data to return memory data
#define FAST_READ_DUAL_OUTPUT0X3B
#define FAST_READ_DUAL_IO0XBB
#define FAST_READ_QUAD_OUTPUT0X6B
#define FAST_READ_QUAD_IO0XEB
#define WORD_READ_QUAD_IO0XE7
#define OCTAL_WORD_READ_QUAD_IO0XE3
#define REL_POW_WODN_DEV_ID0XAB
#define MENUFACTURER_DEV_ID0X90
#define MENUFACTURER_DEV_ID_BY_DUAL_IO0X92
#define MENUFACTURER_DEV_ID_BY_QUAD_IO0X94
#define READ_JEDEC_ID0X9F;;write0x98and manufacturer,memory type,capacity
#define READ_UNIQUE_ID0X4B;;write0x4b,and4byte dummy,and any8byte data to return64bit ID
读取JEDEC ID试验:
F_READ_FLASH_ID:
BCR P_SPI_CS
LDWI READ_JEDEC_ID;;0X9F
LCALL F_SPI_WRITE_ACC
LCALL F_SPI_WRITE_ACC;;any data as dummy
LCALL F_SPI_WRITE_ACC;;any data as dummy
LCALL F_SPI_WRITE_ACC;;any data as dummy
BSR P_SPI_CS
RET
逻辑分析仪采样的SPI数据3byte,如图:
从图中获得JEDEC ID为:E04015
读取UNIQUE ID如图,8byte:
Page program测试,地址0连续写如数据0A,09,08,...01:
F_WRITE_FALSH_CONTINUE:
BCR P_SPI_CS;;P_SPI_CS=0
LDWI WRITE_ENABLE;;ACC=0X06
LCALL F_SPI_WRITE_ACC
BSR P_SPI_CS;;P_SPI_CS=1
NOP
NOP
BCR P_SPI_CS;;P_SPI_CS=0
LDWI PAGE_PROGRAM;;ACC=0X02
LCALL F_SPI_WRITE_ACC
;;write24bit address
LDR SPI_ADD_BIT_23_16,ACC;;ACC=RAM(SPI_ADD_BIT_23_16) LCALL F_SPI_WRITE_ACC
LDR SPI_ADD_BIT_15_8,ACC
LCALL F_SPI_WRITE_ACC
LDR SPI_ADD_BIT_7_0,ACC
LCALL F_SPI_WRITE_ACC
LDWI10;;ACC=10
STR SPI_ADD_READ_CNT;;RAM(SPI_ADD_READ_CNT)=ACC
;;write data continue
L_WRITE_FALSH_CONTINUE:
LDR SPI_ADD_READ_CNT,ACC
LCALL F_SPI_WRITE_ACC
DECRSZ SPI_ADD_READ_CNT,REG;--SPI_ADD_READ_CNT;if SPI_ADD_READ_CNT==0 jump next
LJUMP L_WRITE_FALSH_CONTINUE
BSR P_SPI_CS
RET
使用硕飞读取内容,如图:
正确的结果应该是0A0908070605....,前面5个字节意外的出现了0,为什么呢?先使用硕飞工具擦除全片,再使用这个MCU程序写,结果正确了,如图:
要写flash先执行擦除,因为如果flash只能把‘1’写成‘0’,要写‘1’必须擦除!
刚才已经写了“写使能”,重新上电读取状态寄存器,发现“写使能”清零了,并不保存,每次重新上电都要先写“写使能”:
F_READ_FLASH_STATUS:
BCR P_SPI_CS
LDWI READ_STATUS_REG1;;0X05
LCALL F_SPI_WRITE_ACC
LCALL F_SPI_WRITE_ACC;;get status register1
BSR P_SPI_CS
NOP
NOP
BCR P_SPI_CS
LDWI READ_STATUS_REG2;;0X35
LCALL F_SPI_WRITE_ACC
LCALL F_SPI_WRITE_ACC;;get status register2
BSR P_SPI_CS
RET
逻辑分析仪解析的数据:
使用硕飞工具读取状态寄存器,要注意工具有可能会改写状态寄存器;
三、Erase sector擦除扇区的试验:
1.4KB擦除
F_ERASE_FLASH_SECTOR:;;call at10ms
LDR SPI_FLASH_TEP,ACC;;ACC=RAM(SPI_FLASH_TEP)
ANDWI0X03
ADDWR PCL,REG;;PCL+=ACC;
LJUMP L_WRITE_ERASE_FLASH_CMD
LJUMP L_WAIT_ERASE_FLASH_FINISH
LJUMP L_ERASE_FLASH_END
;LJUMP L_ERASE_FLASH_END
L_ERASE_FLASH_END:
BSR PA1;;PA1=1;
RET
L_WAIT_ERASE_FLASH_FINISH:
LDWI BIT1
XORWR PORTA,REG;;PA1^=PA1;PA1TOG
BCR P_SPI_CS;;P_SPI_CS=0;
LDWI READ_STATUS_REG1;;0X05
LCALL F_SPI_WRITE_ACC
LCALL F_SPI_WRITE_ACC;;return status register1to ACC=TMP1
BSR P_SPI_CS;;P_SPI_CS=1;
BTSSTMP1,0;;if BUSY(bit0)not to next setp waitting continue
INCRSPI_FLASH_TEP,REG;;to next step
LJUMP L_ERASE_FLASH_FUNC_EXIT
L_WRITE_ERASE_FLASH_CMD:
BCR P_SPI_CS;;P_SPI_CS=0;
LDWI WRITE_ENABLE;;0X06
LCALL F_SPI_WRITE_ACC
BSR P_SPI_CS;;P_SPI_CS=1;
NOP
NOP
;;before erase must send write_enable command
BCR P_SPI_CS;;P_SPI_CS=0;
LDWI SECTOR_ERASE_4KB;;ACC=0X20
LCALL F_SPI_WRITE_ACC
;;write24bits address
LDWI0X00;;ACC=0
LCALL F_SPI_WRITE_ACC
CLRW;;ACC=0
LCALL F_SPI_WRITE_ACC
LDWI0X55;;test this byte is any value ok?
LCALL F_SPI_WRITE_ACC
BSR P_SPI_CS;;P_SPI_CS=1;
BCR PA1;;PA1=0;
INCRSPI_FLASH_TEP,REG;;RAM(SPI_FLASH_TEP)++,to next step ;LJUMP L_ERASE_FLASH_FUNC_EXIT
L_ERASE_FLASH_FUNC_EXIT:
RET
先使用工具写入flash内容为序号,然后保存为bin文件,如图:
运行结果,IO_PRINT引脚的跳变期间是正在擦除,为高后则擦除完成:
发送的擦除命令:
读状态寄存器BUSY bit检查是否擦除完成,如图,擦除未完成:
如图,擦除完成:
使用工具导出flash内容,保存为另一个bin文件,然后对比擦除之前的内容:写的sector擦除地址为00H,00H,55H,结果擦除了几块4KBytes内容:
擦除了从000H-FFFH=2^12=4KBytes的4KBytes内容:
擦除了从200000H-200FFFH的4KBytes内容:
也擦除了从400000H-400FFFH的4KBytes内容;
也擦除了从600000H-600FFFH的4KBytes内容;这是为什么呢?
25Q64内存64MBits=8MBytes,分127块block,一个block=16个sector,一个sector 分4KBytes;总容量=127*16*4KBytes=2^7*2^4*2^2=2^13KBytes=8MBytes;
地址总线使用2^3*2^20=2^23也就是23根地址总线;地址线的bit22-16决定block;bit15-12决定sector,bit111-0决定sector的内存;空间划分如图:
2.擦除全片,指令C7H或者60H:
#define CHIP_ERASE0XC7;;write0xc7or0x60is chip erase,
擦除时间4.8s左右;
通过工具读取数据后验证了擦除全片成功:
3.32KB块擦除:
#define BLOCK_ERASE_32KB0X52;;write0X52and24bit address to erase
大概需要160ms
指令如图:
发送5个字节,大概需要126ms;
使用工具读取擦除后的数据,使用beyong compare对比,设置beyong compare:
发现从地址00000H-7FFFH被擦除了,7FFFFH=2^15=32KBytes;
从地址200000H-207FFFH也被擦除了,7FFFFH=2^15=32KBytes;
从地址400000H-407FFFH也被擦除了,7FFFFH=2^15=32KBytes;
从地址600000H-607FFFH也被擦除了,7FFFFH=2^15=32KBytes;
每隔200000H重复擦除,和4KB擦除一样;
4.64KB块擦除:
#define BLOCK_ERASE_64KB0XD8;;write0XD8and24bit address to erase
同样先填充序列作为初始内存;
MCU执行擦除后使用工具读取内容对比,发现从地址0000H-FFFFH=2^16= 64KBytes倍擦除,同样没隔200000H都有64Kbytes倍擦除,同上;
可以认为200000H=2^21=2MBytes是一块,有4块,会执行同样的擦除动作;
关于擦除flash的疑问?能不能单独擦除指定一块的4KB或者32KB或者64KB?
有个保护内存的设置,能否有效避免被擦除不想擦除的部分?
从规格书找到说明:
大概意思是如果擦除或者program的指令指定的地址在保护的范围内,这些指令被忽略,也就是被保护了,不能被擦除或者program改写。

这里也有说明:如果要擦除的扇区被保护了,擦除指令不会执行;
Security register:
sector擦除的时候写入地址:000000H和写入地址600000H,同样都是每隔200000H 重复擦除了4KB,可见高位地址并无意义;
擦除扇区的时候传入地址:001000H,则擦除的是从001000H开始的4KB,同样每个200000H重复擦除4KB;
擦除的时候传入地址:FFFFFFH,擦除的是从1FF_000H开始的4KB,同样每隔200_000H重复擦除4KB;
由此可见对于4KB擦除有效的地址位是XXX1_1111__1111_XXXX__XXXX_XXXX B,X代表无效的BIT位,只有9bit地址有效(1的地址位),512个sertoc可选;
5.擦除之前设定保护的块,2-127块:
要设置状态寄存器的CMP=1;BP0=1;TB=1;WEL=1;其它为0;
状态寄存器1如图:
状态寄存器2如图:
捕捉到的逻辑分析仪的时序:
等待不用10ms时间flash状态就不BUSY了,因为指令被忽略了,块已经被保护?设置保护块的汇编如下:
BCR P_SPI_CS;;P_SPI_CS=0;
LDWI WRITE_STATUS_REG;;WRITE_STATUS_REG=0X01
LCALL F_SPI_WRITE_ACC
LDWI BIT5|BIT2|BIT1;;status register1;TB=1and BP0and WEL=1 LCALL F_SPI_WRITE_ACC
LDWI BIT6;;status register2=0;
LCALL F_SPI_WRITE_ACC
BSR P_SPI_CS;;P_SPI_CS=1;
NOP
NOP
使用工具读取flash的状态寄存器和配置:
导出bin文件后和原始数据的bin文件对比,数据是一致的,并没有擦除;
前面已经设了块保护位,清除块保护位后执行4KB擦除,结果也一样,未擦除;
更改现在擦除流程:写使能命令->写状态寄存器(设置块保护)->写使能->4KB 擦除->等待擦除完成
使用工具导出flash内容后和原始值内容对比,同样是每隔200000H就重复擦除了4KB,为什么呢?看起来保护并没有起作用。

?设置块保护后执行这样32KB擦除动作,也是每隔200000H就重复擦除了32KB;
6.Page program试验
从地址0开始写入200个数据,发现同样每隔200000H也写入了相同的数据,为什么?
最后找到原因是使用flash工具导出的时候选择的是大容量(8MB)芯片,实际是小容量的芯片25Q16(2MB),在导出的时候出现数据的回卷,25Q16只有2MByte=200000H Byte,所以读8MBytes个数据的时候每隔200000H就重复了!
对于25Q16芯片分512个4KB擦除块,512*4KB=2^9*2^2KB=2^11KB=2MB= 16Mbits。

20180708tan。

相关文档
最新文档