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
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 讀寫測試