STM32F103驱动M24256 256k存储芯片进行读写

0
12

0 摘要

M24256 是一个256k的存储芯片,本文将主要讲解如何采用模拟IIC实现对M24256的读写驱动操作。并且使用Proteus进行仿真验证。处理器采用STM32F103,使用STM32CubeMX和Keil5进行联合开发。

1 所使用的软件

  • Proteus 8.9 SP2

    链接:https://pan.baidu.com/s/1Mnc5M0A5rOIQ2xrPT96ugw

    提取码:dfct

  • Keil5

    链接:https://pan.baidu.com/s/1Aavx3TkvBSLrLxlFOZ7xPw

    提取码:uagc

  • STM32CubeMX

    https://www.st.com/en/development-tools/stm32cubemx.html

2 M24256介绍

M24256是ST公司的一款256k EEPROM存储芯片,其具有以下特点。

  • M24256具有256kbit EEPROM内容,每页可写入的内容为64bytes(Page Size = 64 bytes)
  • Single supply voltage and high speed
  • Write:
    • – Byte Write within 5 ms
    • – Page Write within 5 ms
  • Random and sequential Read modes
  • Write protect of the whole memory array 所有内存整列均可以进行写保护
  • Enhanced ESD/Latch-Up protection
  • More than 4 million Write cycles
  • More than 200-years data retention

     
     

M24256引脚接口如表2-1所示:

表2-1 芯片引脚定义

Signal name

Function

Direction

E2、E1、E0

Chip Enable

Input

SDA

Serial Data

I/O

SCL

Serial Clock

Input

WC(低电平有效)

Write Control

Input

VCC

Supply voltage

  

VSS

Ground

  

 
 

通过控制E2、E1、E0的电平关系来修改芯片的地址,也就是说每一个IIC总线上最多可以挂接8个M24256存储芯片。

Write Control引脚用于保护写操作,可以用来保护存储器的整个内容免受意外写操作。将写控制(WC)驱动为高电平时,将禁止对整个存储器阵列进行写操作。 当写控制(WC)被驱动为低电平或悬空时,使能写操作。 将写控制(WC)驱动为高电平时,确认器件选择和地址字节,不确认数据字节。

3 M24256设备地址

 
 

表3-1 芯片地址(设备选择代码)

通过硬件电路定义E2、E1、E0的电平来定义设备的地址,其中最低位为读写标志位,当bit0=1时处于Read模式,反之处于Write模式。而高八位为固定地址,通常使用的是Memory array情况,所以高八位为A

如果在设备选择代码上发生匹配,则相应的设备会在第9位时间内给出串行数据(SDA)的确认。 如果设备与设备选择代码不匹配,则会从总线上取消选择自身,并进入待机模式。

 
 

4 M24256写操作

当芯片处于非写保护状态,即WC为0时对应的时序图如图4-1所示。

表4-1 M24256写时序(WC为低电平)

由图可以看出,M24256支持两种形式的写操作,分别是按字节写入和按页写入。接下来将针对其时序图逐一进行分析。

4.1 Byte Write Mode

按字节写入的时序图如图4-2所示。

图4-2 Byte Write Mode 时序图

由图可知,该模式下,设备仅向指定地址中写入一个字节的数据。其包含的时序过程如下:

Start

发送设备地址

1010 E2E1E0 0

ACK

待写入的设备地址高8位

Byte addr

ACK

待写入的设备地址低8位

Byte addr

ACK

待写入的八位数据

Data in

ACK

Stop

对应的写入代码如下:

uint8_t W24256_Byte_Write(uint8_t WriteData,uint16_t address)

{

    uint16_t usAddr;

    usAddr = address;  

    /* 第1步:发起I2C总线启动信号 */

    IIC_Start();

    /* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */

    IIC_Send_Byte(EEPROM_DEV_ADDR | I2C_WR);    /* 此处是写指令 */

    /*第3步:等待ACK信号*/

    if (IIC_Wait_Ack() != 0)

    {

        goto cmd_fail;  /* EEPROM器件无应答 */

    }

    /* 第4步:发送字节地址,发送地址直接高八位*/

    IIC_Send_Byte((uint8_t)(usAddr>> 8));

    /*第5步:等待ACK信号*/

    if (IIC_Wait_Ack() != 0)

    {

        goto cmd_fail;  /* EEPROM器件无应答 */

    }

    /* 第6步:发送字节地址,发送地址直接低八位*/

    IIC_Send_Byte((uint8_t)(usAddr&0x00ff));

    /*第7步:等待ACK信号*/

    if (IIC_Wait_Ack() != 0)

    {

        goto cmd_fail;  /* EEPROM器件无应答 */

    }

    /* 第8步:开始写入数据 */

    IIC_Send_Byte(WriteData);

    /*第7步:等待ACK信号*/

    if (IIC_Wait_Ack() != 0)

    {

        goto cmd_fail;  /* EEPROM器件无应答 */

    }

    IIC_Stop();

    return 1;

cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */

    /* 发送I2C总线停止信号 */

    IIC_Stop();

    return 0;

}

4.2 Page Write Mode

按页写入的时序图如图4-3所示。

图4-3 Page Write Mode

由图可知,该模式下,设备可以向指定页中写入指定字节的数据,可写入的字节数小于等于64byte。其包含的时序过程如下:

Start

发送设备地址

1010 E2E1E0 0

ACK

待写入的设备地址高8位

Byte addr

ACK

待写入的设备地址低8位

Byte addr

ACK

待写入的八位数据

Data in

如果继续写入,则ACK

停止写入,则NACK

STOP

对应的按页写入代码如下:

uint8_t W24256_Page_Write(uint8_t *WriteBuf, uint16_t Page, uint16_t Size)

{

    uint16_t i,m;

    uint16_t usAddr;

    
 

    /*

     * 写串行EEPROM不像读操作可以连续读取很多字节,每次写操作只能在同一个page。

     * 对于24xx02,page size = 8

     * 简单的处理方法为:按字节写操作模式,没写1个字节,都发送地址

     * 为了提高连续写的效率: 本函数采用page wirte操作。

     */

 
 

    usAddr = Page * 0x0040;

    for (i = 0; i < Size; i++)

    {

        /* 当发送第1个字节或是页面首地址时,需要重新发起启动信号和地址 */

        if ((i == 0) || (usAddr & (EEPROM_PAGE_SIZE – 1)) == 0)

        {

//          /* 第0步:发停止信号,启动内部写操作 */

//          IIC_Stop();

            
 

            /* 通过检查器件应答的方式,判断内部写操作是否完成, 一般小于 10ms            

                CLK频率为200KHz时,查询次数为30次左右

            */

            for (m = 0; m < 1000; m++)

            {              

                /* 第1步:发起I2C总线启动信号 */

                IIC_Start();

                
 

                /* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */

                IIC_Send_Byte(EEPROM_DEV_ADDR | I2C_WR);    /* 此处是写指令 */

                
 

                /* 第3步:发送一个时钟,判断器件是否正确应答 */

                if (IIC_Wait_Ack() == 0)

                {

                    break;

                }

            }

            if (m  == 1000)

            {

                goto cmd_fail;  /* EEPROM器件写超时 */

            }

        
 

            /* 第4步:发送字节地址,发送地址直接高八位*/

            IIC_Send_Byte((uint8_t)(usAddr>> 8));

            /*第五步:等待ACK信号*/

            if (IIC_Wait_Ack() != 0)

            {

                goto cmd_fail;  /* EEPROM器件无应答 */

            }

            /* 第6步:发送字节地址,发送地址直接低八位*/

            IIC_Send_Byte((uint8_t)(usAddr&0x00ff));

            /* 第5步:等待ACK */

            if (IIC_Wait_Ack() != 0)

            {

                goto cmd_fail;  /* EEPROM器件无应答 */

            }

        }

    
 

        /* 第6步:开始写入数据 */

        IIC_Send_Byte(WriteBuf[i]);

    
 

        /* 第7步:发送ACK */

        if (IIC_Wait_Ack() != 0)

        {

            goto cmd_fail;  /* EEPROM器件无应答 */

        }

 
 

        usAddr++;   /* 地址增1 */      

    }

    
 

    /* 命令执行成功,发送I2C总线停止信号 */

    IIC_Stop();

    return 1;

 
 

cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */

    /* 发送I2C总线停止信号 */

    IIC_Stop();

    return 0;

}

注:M24256有256kbit空间,每一页的大小Page Size =64,所以计算可得页的取值范围为:256*1024/8/64 = 512 页。

5 M24256读操作

WC引脚的电平状态对读操作无效,所以其对应的时序图入图5-1所示。

图5-1 Read mode sequences

由图5-1可知,M24256共有三种模式的读操作,包括随机地址读取(Random Address Read)、当前地址(Current Address Read)、顺序读取(Sequential Read)

下面主要针对随机地址读取和顺序读取两种模式进行分析。其余分析类似。

5.1 Random Address Read

图5-2 Random Address Read 时序图

由图可知,该模式下,仅从设备的指定地址中读取一个字节的数据。其包括的时序如下:

Start

设备地址和控制字

1010 E2E1E0 0

ACK

待写入的设备地址高8位

Byte addr

ACK

待写入的设备地址低8位

Byte addr

ACK

Start

重启IIC总线

设备地址和控制字

1010 E2E1E0 1

ACK

读出的数据

Data out

NACK

Stop

对应的代码如下:

uint8_t W24256_Byte_Read( uint16_t Address)

{

    uint16_t uAddress;

    uint8_t ReadData;

    uAddress = Address;

    /* 第1步:发起I2C总线启动信号 */

    IIC_Start();    

  
 

    /* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */

    IIC_Send_Byte(EEPROM_DEV_ADDR | I2C_WR);    /* 此处是写指令 */  

  
 

    /* 第3步:等待ACK */

    if (IIC_Wait_Ack() != 0)

    {

        IIC_Stop(); /* EEPROM器件无应答 */

    }

  
 

    /* 第4步:发送字节地址高8位 */

    IIC_Send_Byte((uint8_t)(uAddress>>8));  

  
 

    /* 第5步:等待ACK */

    if (IIC_Wait_Ack() != 0)

    {

        IIC_Stop(); /* EEPROM器件无应答 */

    }  

    /* 第6步:发送字节地址低八位 */

    IIC_Send_Byte((uint8_t)uAddress&0xff);  

  
 

    /* 第7步:等待ACK */

    if (IIC_Wait_Ack() != 0)

    {

        IIC_Stop(); /* EEPROM器件无应答 */

    }

    /* 第8步:重新启动I2C总线。前面的代码的目的向EEPROM传送地址,下面开始读取数据 */

    IIC_Start();    

  
 

    /* 第9步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */

    IIC_Send_Byte(EEPROM_DEV_ADDR | I2C_RD);    /* 此处是读指令 */

    
 

    /* 第10步:发送ACK */

    if (IIC_Wait_Ack() != 0)

    {

        IIC_Stop(); /* EEPROM器件无应答 */

    }  

    
 

 
 

    /* 第11步:读取数据并保存*/

    ReadData = IIC_Read_Byte(); /* 读1个字节 */

    /*第12步:发送NACK命令*/    

    IIC_NAck(); /* 最后1个字节读完后,CPU产生NACK信号(驱动SDA = 1) */

 
 

    /*第13步:发送I2C总线停止信号 */

    IIC_Stop();

    return ReadData;    /* 执行成功 */

}

5.2 Sequention Random Read

图5-3 Sequention Random Read 时序图

由图可知,该模式下,可以向指定地址中读取指定数目的数据。其包括的时序如下:

Start

设备地址和控制字

1010 E2E1E0 0

ACK

待写入的设备地址高8位

Byte addr

ACK

待写入的设备地址低8位

Byte addr

ACK

Start

重启IIC总线

设备地址和控制字

1010 E2E1E0 1

ACK

读出的数据

Data out

如果到达要读取数据个数,发送NACK,反之发送ACK

Stop

其对应的代码如下:

/**

  * 函数功能: 从串行EEPROM指定地址处开始读取若干数据

  * 输入参数: ReadBuf : 存放读到的数据的缓冲区指针

  *           Address : 起始地址  

  *           Size : 数据长度,单位为字节

  * 返 回 值:  0 表示失败,1表示成功

  * 说    明:无

  */

uint8_t W24256_Page_Read(uint8_t *ReadBuf, uint16_t Page, uint16_t Size)

{

    uint16_t i;

    uint16_t uAddress;

    /* 采用串行EEPROM随即读取指令序列,连续读取若干字节 */

    uAddress = Page * 0x0040;

    /* 第1步:发起I2C总线启动信号 */

    IIC_Start();    

  
 

    /* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */

    IIC_Send_Byte(EEPROM_DEV_ADDR_Page | I2C_WR);   /* 此处是写指令 */  

  
 

    /* 第3步:等待ACK */

    if (IIC_Wait_Ack() != 0)

    {

        goto cmd_fail;  /* EEPROM器件无应答 */

    }

  
 

    /* 第4步:发送字节地址高8位 */

    IIC_Send_Byte((uint8_t)(uAddress>>8));  

  
 

    /* 第5步:等待ACK */

    if (IIC_Wait_Ack() != 0)

    {

        goto cmd_fail;  /* EEPROM器件无应答 */

    }  

    /* 第6步:发送字节地址低八位 */

    IIC_Send_Byte((uint8_t)uAddress&0xff);  

  
 

    /* 第7步:等待ACK */

    if (IIC_Wait_Ack() != 0)

    {

        goto cmd_fail;  /* EEPROM器件无应答 */

    }

    /* 第8步:重新启动I2C总线。前面的代码的目的向EEPROM传送地址,下面开始读取数据 */

    IIC_Start();    

  
 

    /* 第7步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */

    IIC_Send_Byte(EEPROM_DEV_ADDR_Page | I2C_RD);   /* 此处是读指令 */

    
 

    /* 第8步:发送ACK */

    if (IIC_Wait_Ack() != 0)

    {

        goto cmd_fail;  /* EEPROM器件无应答 */

    }  

    
 

    /* 第9步:循环读取数据 */

    for (i = 0; i < Size; i++)

    {

        ReadBuf[i] = IIC_Read_Byte();   /* 读1个字节 */

        
 

        /* 每读完1个字节后,需要发送Ack, 最后一个字节不需要Ack,发Nack */

        if (i != Size – 1)

        {

            IIC_Ack();  /* 中间字节读完后,CPU产生ACK信号(驱动SDA = 0) */

        }

        else

        {

            IIC_NAck(); /* 最后1个字节读完后,CPU产生NACK信号(驱动SDA = 1) */

        }

    }

    /* 发送I2C总线停止信号 */

    IIC_Stop();

    return 1;   /* 执行成功 */

 
 

cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */

    /* 发送I2C总线停止信号 */

    IIC_Stop();

    return 0;

}

 
 

6 M24256读写测试

使用Proteus 和Stm32CubeMX keil 联合开发,对M24256的读写测试进行仿真分析。

图6-1 仿真搭建

6.1 按字节读写测试结果

代码如下

W24256_Byte_Write(0x01,0x0000);

HAL_Delay(100);

W24256_Byte_Read(0x0000);

HAL_Delay(500);

图6-2 仿真结果

第一行

S

A0

A

00

A

00

A

01

A

P

向1101 000x设备的0x0000地址写入0x01数据

 
 

第二行

S

A0

A

00

A

00

A

Sr

A1

A

01

N

P

从1101 000x设备的0x0000地址读出数据,读出的数据为0x01

 
 

6.2 按页读写测试结果

uint8_t Data[3]={0x01,0x05,0xff};

uint8_t DataRead[3]={0x00,0x00,0x00};

W24256_Page_Write(Data,10,3);

HAL_Delay(100);

W24256_Page_Read(DataRead,10,3);

HAL_Delay(500);

图6-3 仿真结果

第一行

S

A0

A

02

A

80

A

01

A

05

A

FF

A

P

向1101 000x设备的第10页(0X0280)写入0x01、0X05、0XFF三个字节数据

 
 

第二行

S

A0

A

02

A

80

A

Sr

A1

A

01

A

05

A

FF

N

P

从1101 000x 设备的第10页(0x0280)读取3个字节数据,读出的数据为 0x01、0x05、0xff

 
 

6.3 按字节读写多个字节测试

    uint8_t Data[3]={0x01,0x05,0xff};

    uint8_t DataRead[3]={0x00,0x00,0x00};

    W24256_Write(0x0000,Data,3);

    HAL_Delay(100);

    W24256_Read(0x0000,DataRead,3);

    HAL_Delay(500);

 
 

图6-4 仿真结果

第一行

S

A0

A

00

A

00

A

01

A

P

向1010 000x设备的0x0000地址写入0x01数据

第二行

S

A0

A

00

A

01

A

05

A

P

向1010 000x设备的0x0001地址写入0x05数据

第三行

S

A0

A

00

A

02

A

FF

A

P

向1010 000x设备的0x0002地址写入0xFF数据

 
 

第四行

S

A0

A

00

A

00

A

Sr

A1

A

01

N

P

从1010 000x设备的0x0000地址读取数据,结果为0x01

第五行

S

A0

A

00

A

01

A

Sr

A1

A

05

N

P

从1010 000x设备的0x0001地址读取数据,结果为0x05

第六行

S

A0

A

00

A

02

A

Sr

A1

A

FF

N

P

从1010 000x设备的0x0002地址读取数据,结果为0xFF

 

 

制作不易,如有错误或者不好理解的地方请留言

如果需要仿真源文件,请联系EMAIL:whl1457139188@163.com

并添加QQ:975107705

请注明M24256 读写测试

<

发布回复

请输入评论!
请输入你的名字