#芯片# SM25QH128M

国产芯片

FLASH芯片 学习笔记

国微的SM25QH128M

百度上搜索的资料太少了。目前为止,百度只能搜到2条相关的文章。
该国产芯片与进口芯片W25Q128JV 很相似。可以参考W25Q128JV。

1. 简述

  • SM25QH128M是一种Nor FLash芯片。
  • 存储空间大小为128Mbit。
  • 工作环境满足国军标N1级要求。
  • 工作电压为2.7V到3.6V。
  • 支持SPI,Dual SPI,Quad SPI。SPI可以工作在mode0或者mode3模式下
  • 正常读取时钟为83MHz,快读频率最大支持104MHz。
  • 支持扇区擦除,块擦除,芯片擦除。支持页page编程写入数据。

2. 地址空间划分

  • 128Mbit空间,也就是16MByte。空间大小可以满足绝大多数应用场景。
  • 一个扇区有4KByte(4096字节)。共有4096个扇区。
  • 可以将8个扇区分为一个块,或者将16个扇区分成一个块。这点在进行块擦除时,值得注意。
    #芯片# SM25QH128M_第1张图片

3. 状态寄存器

与进口芯片不同,SM25QH128M官方手册表明,只有一个状态寄存器。如下图所示:

  • SRP位 为 状态寄存器保护位。
  • EBL位 为 使能锁定位。
    #芯片# SM25QH128M_第2张图片

4. 指令列表

#芯片# SM25QH128M_第3张图片
根据上表,进行宏定义:

/*
2021年11月19日
根据官方手册,进行的用户宏定义。By Kshine。
*/
//配置,状态,信息
#define SM25QH128M_RESET_ENABLE 0x66 //复位使能    (第一字节写入)
#define SM25QH128M_RESET_DEVICE 0x99 //复位器件    (第一字节写入)
#define SM25QH128M_QPI_ENTER    0x38 //进入QPI模式 (第一字节写入)
#define SM25QH128M_QPI_EXIT     0xFF //退出QPI模式 (第一字节写入)
#define SM25QH128M_WRITE_ENABLE 0x06 //写入使能    (第一字节写入)
#define SM25QH128M_WRITE_DISABLE 0x04 //写入禁止   (第一字节写入)
#define SM25QH128M_STATUS_READ  0x05 //读状态寄存器 (第一字节写入)(第二字节读出状态)
#define SM25QH128M_STATUS_WRITE 0x01 //写状态寄存器 (第一字节写入)(第二字节写入状态)
#define SM25QH128M_MANUFACTURER 0x90 //读取制造商ID,设备ID (第一字节写入)(第2字节冗余)(第3字节冗余)(第4字节写入0x00或者0x01)(第5字节读出前数据)(第6字节读出后数据)
#define SM25QH128M_ID           0x9F //读取ID (第一字节写入)(第二字节制造商号)(第3字节ID高8位)(第4字节ID低8位)

//读取指令
#define SM25QH128M_NORMAL_READ 0x03 //正常读取 (第一字节写入指令)(再写入3个字节的地址)(读出数据)
#define SM25QH128M_FAST_READ   0x0B //快速读取 
#define SM25QH128M_DUAL_OUTPUT_FAST_READ 0x3B
#define SM25QH128M_DUAL_IO_FAST_READ     0xBB
#define SM25QH128M_QUAD_IO_FAST_READ     0xEB
#define SM25QH128M_QUAD_OUTPUT_FAST_READ 0x6B

//写指令
#define SM25QH128M_PAGE_PROGRAM 0x02 //页编程 (第一字节写入指令)(再写入3个字节的地址)(写入数据)
#define SM25QH128M_QUAD_PAGE_PROGRAM  0x32 //Quad 输入页编程

//擦除
#define SM25QH128M_SECTOR_ERASE 0x20 //扇区擦除
#define SM25QH128M_BLOCK32KB_ERASE 0x52 //块擦除 32KB
#define SM25QH128M_BLOCK64KB_ERASE 0xD8 //块擦除 64KB
#define SM25QH128M_CHIP_ERASE  0xC7 //或者 0x60  //芯片擦除

5. SPI常用操作

(1)写入使能

在执行任何写入操作之前,需要先将WEL位置1。当操作完成之后,WEL自动复位到0状态
#芯片# SM25QH128M_第4张图片

void SM25QH128_WriteEnable(void)
{
    _CS = 0;
	WriteByte(SM25QH128M_WRITE_ENABLE);//0x06
	_CS = 1;
}

void SM25QH128_WriteDisable(void)
{
    _CS = 0;
	WriteByte(SM25QH128M_WRITE_DISABLE );//0x04
	_CS = 1;
}


(2)读取制造商MID,设备ID

  • FLASH存储器有两个标准,CFI和JEDEC。本存储芯片很明显支持的是JEDEC。Joint Electron Device Engineering Council 即电子元件工业联合会。JEDEC是由生产厂商们制定的国际性协议,主要为计算机内存制定。工业标准的内存通常指的是符合JEDEC标准的一组内存。
  • jedec_id 信息,包括制造商ID,存储类型ID,容量ID。
    #芯片# SM25QH128M_第5张图片
    这里我们使用的指令0x9F。
    #芯片# SM25QH128M_第6张图片
#define MANUFACTURER_ID 0x20
#define MEMMORY_TYPE_ID 0x7018
#define CAPACITY_ID     0x17
#define FLASH9FID       0x00207017
uint32_t  SM25QH128_ReadID(void)
{
    uint32_t ID = 0;

    _CS = 0;
	WriteByte(SM25QH128M_ID);//0x9F
	ID |= readWriteByte(0xFF) << 16;
	ID |= readWriteByte(0xFF) << 8;
	ID |= readWriteByte(0xFF);
	_CS = 1;
	return ID;
}

(3)对芯片进行复位

芯片的复位操作需要 复位使能0x66复位操作0x99 一起执行,才能实现复位操作。
#芯片# SM25QH128M_第7张图片

void SM25QH128_ResetEnable(void)
{
    _CS = 0;
	WriteByte(SM25QH128M_RESET_ENABLE );//0x66
	_CS = 1;
}
void SM25QH128_Reset(void)
{
    _CS = 0;
	WriteByte(SM25QH128M_RESET_DEVICE);//0x99
	_CS = 1;
}

void SM25QH128_init(void)
{
    uint8_t i=0;
    SM25QH128_WriteEnable();   //写使能
    SM25QH128_ResetEnable();   //复位使能
    SM25QH128_Reset();         //复位
    //SM25QH128_WriteDisable();//写禁止 (自动关闭)
    
    rt_thread_delay(50);
    //读取ID信息
    for(i = 0;i < 100;i++)	// 等待访问Flash OK
	{
		if(FLASH9FID == SM25QH128_ReadID())
		{
		    i=0;
			break;
		}
		rt_thread_delay(50);	
	}
	if(i != 0) return 0; //失败
	return 1; //成功
}

(3)读状态寄存器

在执行编程,擦除,写入状态位时,通过读取状态寄存器0x05 ,WIP位,检测芯片的状态。WIP位可以看成 busy 指示位。
由下面的时序图,可以看到 有2个字节的状态寄存器值。(与上述定义的1字节 状态寄存器 不太相符,官方文档还需要更严谨才行)实际使用按照一个字节去读。
#芯片# SM25QH128M_第8张图片

uint8_t SM25QH128_ReadStatus(void)
{
    uint8_t status = 0;
    _CS = 0;
	WriteByte(SM25QH128M_STATUS_READ);
	status = readWriteByte(0xFF);
	_CS = 1;
	return status;
}

(4)正常读取操作

正常读取操作频率为83MHz。
#芯片# SM25QH128M_第9张图片

uint32_t SM25QH128_Read(uint32_t addr, uint8_t *buff, uint32_t len)
{
    int i=0;
    uint8_t status = 0;
    uint8_t cmd[4] = {0};
    cmd[0] = SM25QH128M_NORMAL_READ;
	cmd[1] = (addr >> 16 ) & 0xFF;
	cmd[2] = (addr >> 8  ) & 0xFF;
	cmd[3] = (addr >> 0  ) & 0xFF;
    while(1)
    {
        state = SM25QH128_ReadStatus(); 
        if(state&0x01) continue;
        else           break; 
    }
    _CS = 0;
	for(i = 0; i < 4; i++)    WriteByte(cmd[i]);
	for(i = 0; i < len; i++)  buff[i] = readWriteByte(0xff);
    _CS = 1;
    return len;
}

(5)快速读取数据

最高频率为104MHz。由时序图可以看到,发送完地址后,有一字节的无效数据。
#芯片# SM25QH128M_第10张图片

uint32_t SM25QH128_FastRead(uint32_t addr, uint8_t *buff, uint32_t len)
{
    int i=0;
    uint8_t status = 0;
    uint8_t cmd[5] = {0};
    cmd[0] = SM25QH128M_FAST_READ ;
	cmd[1] = (addr >> 16 ) & 0xFF;
	cmd[2] = (addr >> 8  ) & 0xFF;
	cmd[3] = (addr >> 0  ) & 0xFF;
	cmd[4] = 0xFF;
    while(1)
    {
        state = SM25QH128_ReadStatus(); 
        if(state&0x01) continue;
        else           break; 
    }
    _CS = 0;
	for(i = 0; i < 5; i++)    WriteByte(cmd[i]);
	for(i = 0; i < len; i++)  buff[i] = readWriteByte(0xff);
    _CS = 1;
    return len;
}

(6)写入数据,页编程

  • Page页编程 0x02 操作,一次可以向芯片写入256字节的数据。
  • 在页编写之前,需要发送**写使能指令0x06 **,使得状态寄存器的WEL位z置1。完成操作以后,WEL 自动复位0。
  • 如果超过 256 bytes 数据被写入到芯片内,则芯片只会接收后面的 256 bytes 数据写入 Page 内部。
  • 如果小于 256 bytes 数据被写入到芯片内,则芯片会将对应地址的数据写入,而其他未涉及到的数据则保持不变。
    页编程
//一次可以向芯片写入256字节的数据
void SM25QH128_WirtePage(uint32_t addr, uint8_t *data, uint16_t len)
{
	uint8_t state = 0;
	uint16_t    i = 0;
	uint8_t cmd [4] = {0};
	cmd[0] = SM25QH128M_PAGE_PROGRAM;
	cmd[1] = (addr >> 16 ) & 0xFF;
	cmd[2] = (addr >> 8  ) & 0xFF;
	cmd[3] = (addr >> 0  ) & 0xFF;
	while(1)
    {
        state = SM25QH128_ReadStatus(); 
        if(state&0x01) continue;
        else           break; 
    }
	SM25QH128_WriteEnable();
	_CS = 0;
	for(i = 0; i < 4; i++)   WriteByte(cmd[i]);
    for(i = 0; i < len; i++) WriteByte(data[i]);
	_CS = 1;
	//SM25QH128_WriteDisable();//写禁止 (自动关闭)
}

int SM25QH128_Wirte(uint32_t addr, uint8_t *data, int len)
{
	int i = 0;
	int page_num = len / PAGE_SIZE;
	int last_len = len % PAGE_SIZE;
	for(i = 0; i < page_num; i++)
	{
		SM25QH128_WirtePage((addr + (i * PAGE_SIZE)), data + (i * PAGE_SIZE), PAGE_SIZE);
	}
	
	if(last_len)
	{
		SM25QH128_WirtePage((addr + (i * PAGE_SIZE)), data + (i * PAGE_SIZE), last_len);
	}
	
	return len;
}

(7)扇区擦除

  • 在执行扇区擦除操作之前,WEL 必须通过 **写使能指令0x06 **设置为 1,完成扇区擦除操作以后,WEL 自动复位。
  • 扇区擦除指令 0x20。
    #芯片# SM25QH128M_第11张图片
int SM25QH128_EraseSector(uint32_t addr)
{
	uint8_t state = 0;
	uint16_t    i = 0;
	uint8_t cmd [4] = {0};
	cmd[0] = SM25QH128M_SECTOR_ERASE;
	cmd[1] = (addr >> 16 ) & 0xFF;
	cmd[2] = (addr >> 8  ) & 0xFF;
	cmd[3] = (addr >> 0  ) & 0xFF;
    while(1)
    {
        state = SM25QH128_ReadStatus(); 
        if(state&0x01) continue;
        else           break; 
    }
    SM25QH128_WriteEnable();
    _CS = 0;
	for(i = 0; i < 4; i++)   WriteByte(cmd[i]);
	_CS = 1;
	//SM25QH128_WriteDisable();//写禁止 (自动关闭)
}
#define PAGE_SIZE	0x100     //一页 256字节
#define SECTOR_SIZE	0x1000   //一个扇区有4KByte(4096字节)。共有4096个扇区
#define SECTOR_TO_ADDR(n) ((n)*0x1000)
void Flash_erase(uint32_t addr, uint32_t len)
{
	uint32_t i = 0;
	uint32_t start_sector = addr / SECTOR_SIZE;
	uint32_t sector_num = len / SECTOR_SIZE;
	if( addr % SECTOR_SIZE)
	{
		start_sector = start_sector -1;
		sector_num++;
	}
	
	if(len % SECTOR_SIZE)
	{
		sector_num++;
	}
	
	for(i = 0; i <= sector_num; i++)
	{
		SM25QH128_EraseSector(SECTOR_TO_ADDR(start_sector+i));
	}
}

(8)块擦除

  • 在执行扇区擦除操作之前,WEL 必须通过 **写使能指令0x06 **设置为 1,完成扇区擦除操作以后,WEL 自动复位。
  • 块擦除指令 32KB的0x52 、64KB的0xD8。
    #芯片# SM25QH128M_第12张图片

(9)芯片擦除

  • 在执行扇区擦除操作之前,WEL 必须通过 **写使能指令0x06 **设置为 1,完成扇区擦除操作以后,WEL 自动复位。
  • 芯片擦除指令0xC7 、0x60。
    #芯片# SM25QH128M_第13张图片

6. 软件初始化与应用

7. 应用电路

#芯片# SM25QH128M_第14张图片

你可能感兴趣的:(芯片与传感器的使用,flash)