python 使用 mpsse 读写 EEPROM

安装mpsse

eeprom 读写时序

写时序

  • BYTE WRITE
    只写一个字节

  • MULTIBYTE AND PAGE WRITE
    这个可以写多个字节 但是一次写的字节数不得超过PAGE SIZE 否则会写失败
    PAGE SIZE 一般在芯片手册的 Feature 可以看到 如:


    Page SIZE 为 8 bytes


    Page SIZE 为 16 bytes

读时序

  • CURRENT ADDRESS READ
    该时序从eeprom当前地址开始读 每读一个Byte eeprom 内部地址指针加1
  • RANDOM ADDRESS READ
    该时序可以实现任意地址读一个字节
    假设设备地址为 0x50 则 START -> 0xA0 -> 0x10 -> START -> 0xA1 -> data -> STOP
    可以实现读0x10的数据
    可以看到 通过写命令可以设置eeprom的指针
  • SEQUENTIAL CURRENT ADDRESS READ
    和 CURRENT ADDRESS READ 类似 从当前地址开始读多个字节
  • SEQUENTIAL RANDOM ADDRESS READ
    和RANDOM ADDRESS READ 类似只不过是读完一个字节后不发STOP 接着读

地址

以24c04为例


可以看到 它内部有两个block

  • 当我们发送 0xA0 0x00或 0xA1 0x00时对eeprom的 block0 的0地址操作
  • 当我们发送 0xA2 0x00或 0xA3 0x00时对eeprom的 block1 的0地址操作

注意: 不同型号的EEPROM 对 DEV字节的定义不同

如ATMEL的:

测试代码

以下代码仅适用于24C04 其它型号的需要适当更改对 Device Address的操作

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# -*- coding: utf-8 -*-
#********************************************************************************
#Copyright © 2020 Wcq
#File Name: eeprom_rw.py
#Author: Wcq
#Email: wcq-062821@163.com
#Created: 2020-05-28 19:42:47
#Last Update: 2022-09-27 18:37:32
#         By: Wcq
#Description:
#********************************************************************************
import os, sys
from mpsse import *
from time import sleep
from myprint import *
import sys
import argparse


devINFO = {
    # Name   : [AddrSize, pageSIZE],
    '24C01'  : [7,  16],
    '24C02'  : [8,  16],
    '24C04'  : [9,  16],
    '24C08'  : [10, 16],
    '24C16'  : [11, 16],
    '24C32'  : [12, 32],
    '24C64'  : [13, 32],
    '24C128' : [14, 64],
    '24C256' : [15, 64],
    '24C512' : [16, 128],
    '24C1024': [17, 256],
}

class I2CRW:
    RCMD = None     # Read command
    WCMD = None
    RAddressList = [0xA1]
    testRCMD = None        # Read command
    reTryCnt = 0
    i2c = None
    byteSIZE  = 0
    pageSIZE  = 0
    addrBYTES = 0

    def __init__(self, customAddr=False):
        testAddrList = []
        if customAddr:
            testAddrList.append(customAddr)
        else:
            testAddrList.extend(self.RAddressList)
        try:
            self.i2c = MPSSE(I2C, FOUR_HUNDRED_KHZ)
            print ("%s initialized at %dHz (I2C)" % (self.i2c.GetDescription(), self.i2c.GetClock()))
            self.i2c.PinLow(GPIOL3)   #3V3 ON
        except OSError as e:
            raise TypeError("MPSSE failure")

        for testADDR in testAddrList:
            for i in range(5):
                self.testRCMD = testADDR        # Read command
                data = self.i2cRead(25)
                if len(data):
                    # hexPrint('data: ', data, 1)
                    break
            if self.RCMD is not None:
                break
        else:
            raise Warning('device no responses!')
        sleep(0.3)

    def tryI2cRead(self, lens):
        self.i2c.Start()
        if self.RCMD:
            self.i2c.Write(bytes([self.RCMD]))
        else:
            self.i2c.Write(bytes([self.testRCMD]))
        if self.i2c.GetAck() == ACK:
            self.i2c.SendAcks()
            data = list(self.i2c.Read(lens-1))
            self.i2c.SendNacks()
            data.extend(list(self.i2c.Read(1)))
            self.i2c.Stop()
            self.reTryCnt = 0
            return bytes(data)
        else:
            self.i2c.Stop()
            return False
    def i2cRead(self, lens):
        while True:
            readData = self.tryI2cRead(lens)
            if readData:
                #read success, set WCMD and RCMD if they are None
                if self.RCMD is None:
                    self.RCMD = self.testRCMD
                    print('self.RCMD : 0x%X'%self.RCMD)
                if self.WCMD is None:
                    self.WCMD = self.RCMD - 1
                    print('self.WCMD : 0x%X'%self.WCMD)
                return readData
            else:
                self.reTryCnt += 1
                if self.reTryCnt > 20 and (self.RCMD is None):
                    self.reTryCnt = 0
                    print('test I2C Address 0x%X'%self.testRCMD)
                    return []

    def i2cWrite(self, wbuf):
        self.i2c.Start()
        self.i2c.Write(wbuf)
        if self.i2c.GetAck() == ACK:
            self.i2c.Stop()
            return 0
        else:
            raise Exception("In Write Received write command NACK!")

    def i2cWriteNoStop(self, wbuf):
        self.i2c.Start()
        self.i2c.Write(wbuf)
        if self.i2c.GetAck() == ACK:
            return 0
        else:
            raise Exception("In Write Received write command NACK!")
    def i2cWriteAndRead(self, wbuf, readCnt, label, sleepTime):
        self.i2cWriteNoStop(wbuf)
        # hexPrint('%s Sent : '%label, wbuf, 1)
        sleep(sleepTime)
        recv_buf = self.i2cRead(readCnt)
        # hexPrint('received %s data : 0x%X '%(label, self.RCMD), recv_buf, 1)
        return recv_buf

    def i2cClose(self):
        self.i2c.close()

    def eepromRead(self, addr, num_bytes):
        wbuf = []
        wbuf.append(self.WCMD)
        wbuf.extend(addr.to_bytes(self.addrBYTES, "big"))
        return self.i2cWriteAndRead(bytes(wbuf), num_bytes, 'Read addr : 0x%08X : '%addr, 0)

    def eepromWrite(self, addr, write_buf):
        chunked_list = [write_buf[i:i+self.pageSIZE] for i in range(0, len(write_buf), self.pageSIZE)]
        write_add = addr
        for wb in chunked_list:
            wbuf = []
            wbuf.append(self.WCMD)
            wbuf.extend(write_add.to_bytes(self.addrBYTES, "big"))
            wbuf.extend(wb)
            self.i2cWrite(bytes(wbuf))
            write_add += len(wb)
            sleep(0.01)
            # hexPrint('wbuf: ', wbuf, 1)
            # print('write addr : 0x%08X finished'%addr)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="read write eeprom 24c04")
    parser.add_argument('-r', help='read eeprom and save file', default = None)
    parser.add_argument('-w', help='write file to eeprom', default = None)
    parser.add_argument('-d', help='device type e.g. 24c04', default = '24c04')
    args = parser.parse_args()

    if (len(sys.argv) < 2):
        print('python %s -h      :to get useage'%sys.argv[0])

    read_file = args.r
    write_file = args.w
    device_type = args.d
    try:
        device_size = devINFO[device_type.upper()]
    except:
        print('device_type error please select device from below table')
        print('********************************************************************************')
        for dev in devINFO.keys():
            print('device : %08s  '%(dev))
        print('********************************************************************************')
        exit(-1)
            
    print('********************************************************************************')
    print('device_type : ', device_type.upper())
    print('********************************************************************************')
    
    i2cRW = I2CRW()
    
    i2cRW.byteSIZE  = 2**devINFO[device_type.upper()][0]
    i2cRW.pageSIZE  = devINFO[device_type.upper()][1]
    i2cRW.addrBYTES = (devINFO[device_type.upper()][0] + 7) // 8

    if read_file:
        recvBuf = i2cRW.eepromRead(0, i2cRW.byteSIZE- 128)
        with open(read_file, 'wb') as fpw:
            fpw.write(bytes(recvBuf))
    elif write_file:
        with open(write_file, 'rb') as fpr:
            buf = list(fpr.read())
            i2cRW.eepromWrite(0, buf)
            sleep(0.01)
            recvBuf = i2cRW.eepromRead(0, len(buf))
            sleep(0.01)
            if (bytes(buf) != recvBuf):
                print('write error')
                hexPrint('write_buf : ', buf, 1)
                hexPrint('recvBuf : ', recvBuf, 1)
                exit(0)
            # print('\rwriting addr 0x%08X  %d%%'%(i, i*100//device_size), end='')
            # print('\rwriting addr 0x%08X  %d%%'%(device_size, 100))
    else:
        print('error')
    print('All Done')