#!/usr/bin/python
__author__ = "D.Qendri"
__copyright__ = "Copyright 2015 Sensorian"
__license__ = "GPL V3"
__version__ = "1.0"
import RPi.GPIO as GPIO
import time
import spidev as spi
spi = spi.SpiDev()
##################******** Commands ************************************/
CMD_RDSR1 = 0x05
CMD_RDSR2 = 0x35
CMD_RDSR3 = 0x33
CMD_WREN = 0x06
CMD_EWSR = 0x50 #write enable volatile
CMD_WRDI = 0x04
CMD_SETBURST = 0x77
PAGE_PROGRAM = 0x02
CMD_READ_DATA = 0x03
CMD_READ_HS = 0x0B
ERASE_SECTOR = 0x20
ERASE_BLOCK32 = 0x52
ERASE_BLOCK64 = 0xD8
ERASE_CHIP = 0x60
CMD_DEEPSLP = 0xB9
CMD_RESDPD = 0xAB #release from sleep
CMD_RDID = 0x90
JEDEC = 0x9F
CMD_RDSFDP = 0x5A
CMD_RDSECREG = 0x48
CMD_ERSECREG = 0x44 #erase security reg
CMD_EHLD = 0xAA
S64MANID = 0x01
S64DEVID = 0x16
CMD_RSID = 0x88
CMD_PSID = 0xA5
CMD_LSID = 0x85
#resume from deep sleep
CMD_WRSR = 0x01 #write status register
STAT_REG1 = 0x05 #status register number one
STAT_REG2 = 0x35 #status register number two
STAT_REG3 = 0x33 #status register mumber three
##################Memory map#####################################
#sector 4 kbyte
#block 64 kbyte
SECTOR_SIZE = 4096 #0x000-0xfff
SECTOR_COUNT = 128
PAGE_NUM = 2048 #16 pages per sector
PAGE_INCR = 0x100 #256 bytes
[docs]class S25FL204K(object):
"""Class object for 4Mbit NOR flash memory chip"""
def __init__(self):
"""Configures the SPI bus and the chip select pin."""
spi.open(0,1) #will open bus 0, CE1.
spi.max_speed_hz = 8000000
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
self.CE_OUTPUT()
self.CE_DESELECT()
[docs] def CE_OUTPUT(self):
"""
Configure Chip Enable pin as output.
:param none:
:returns: none
"""
GPIO.setup(26, GPIO.OUT) #Set GPIO26 as output
[docs] def CE_SELECT(self):
"""
Select flash memory chip.
:param none:
:returns: none
"""
GPIO.output(26, 0)
[docs] def CE_DESELECT(self):
"""
Deselect flash memory.
:param none:
:returns: none
"""
GPIO.output(26, 1)
[docs] def writeByte(self,data,address):
"""
Write one byte at a specific address in the memory chip.
:param data:
:param address:
:returns: none
"""
self.CE_SELECT()
spi.writebytes([CMD_WREN]) #Send WREN command
self.CE_DESELECT()
self.CE_SELECT()
spi.writebytes([PAGE_PROGRAM])
spi.writebytes([(address&0xFF0000)>>16,(address&0xFF00)>>8,address&0xFF,0])
spi.writebytes([data]) #Program page, and send 3 address bytes and data
self.CE_DESELECT()
# while ((self.readStatusRegister(CMD_RDSR1) and 0x01) == 0x01):#Waste time until not busy
# pass
[docs] def readByte(self,address):
"""
Read one byte from the given memory address.
:param address: Address of data in memory.
:returns: none
"""
self.CE_SELECT()
spi.writebytes([CMD_READ_DATA])
spi.writebytes([(address&0xFF0000)>>16,(address&0xFF00)>>8,address&0xFF,0]) #Read command,Send 3 address bytes
mybyte = spi.readbytes(1)
self.CE_DESELECT()
return mybyte #Return one byte read
[docs] def writeArray(self,address, pData, arrayLength):
"""
Write an array to the memory chip.
:param address: Address of data in memory.
:param pData:
:param arrayLength:
:returns: none
"""
self.CE_SELECT()
spi.writebytes([CMD_WREN]) #Send WREN command
self.CE_DESELECT()
self.CE_SELECT()
spi.writebytes([PAGE_PROGRAM,(address&0xFF0000)>>16,(address&0xFF00)>>8,address&0xFF,0]) #Send Byte
for item in range(len(pData)):
data = ord(pData[item]) #this is a hack ,convert char data to hex and write bytes individually, slow
spi.writebytes([data])
self.CE_DESELECT()
[docs] def readArray(self,address, arrayLength):
"""
Flash memory chip class.
:param address: Starting address of array
:param arrayLength: Array length in bytes
:returns: none
"""
pData = []
self.CE_SELECT()
spi.writebytes([CMD_READ_DATA,(address&0xFF0000)>>16,(address&0xFF00)>>8,address&0xFF,0]) #Read command
pData = spi.readbytes(arrayLength)
self.CE_DESELECT()
return pData
[docs] def jedec_ID_Read(self):
"""
Flash memory chip class.
:param none:
:returns: none
"""
self.CE_SELECT()
spi.writebytes([JEDEC]) #Send JEDEC ID command (9Fh)
jedec = spi.readbytes(3)
self.CE_DESELECT()
jedid = int((jedec[0] << 16) | (jedec[1] << 8) | jedec[2])
return jedid
[docs] def readID(self):
"""
Flash memory chip class.
:param none:
:returns: none
"""
self.CE_SELECT()
spi.writebytes([CMD_RDID]) #Send read ID command (90h or ABh)
spi.writebytes([0x00]) #Send dummy byte
spi.writebytes([0x00]) #Send dummy byte
spi.writebytes([0x00]) #Send 0x00
id = spi.readbytes(2) #Send either manufacturer ID or device ID
self.CE_DESELECT()
return ((id[1] << 8) | id[0])
[docs] def chipErase(self):
"""
Flash memory chip class.
:param none:
:returns: none
"""
self.CE_SELECT()
spi.writebytes([CMD_WREN]) #Send WREN command
self.CE_DESELECT()
self.CE_SELECT()
spi.writebytes([ERASE_CHIP]) #Send Sector Erase command
self.CE_DESELECT()
[docs] def sectorErase(self,address):
"""
Erase a sector from the flash memory chip.
:param address: Sector address
:returns: none
"""
self.CE_SELECT()
spi.writebytes([CMD_WREN]) #Send WREN command
self.CE_DESELECT()
self.CE_SELECT()
spi.writebytes([ERASE_SECTOR,(address&0xFF0000)>>16,(address&0xFF00)>>8,address&0xFF,0]) #Send Sector Erase command
self.CE_DESELECT()
[docs] def blockErase(self,address):
"""
Erase a block from the flash memory chip.
:param address: Block initial address
:returns: none
"""
self.CE_SELECT()
spi.writebytes([CMD_WREN]) #Send WREN command
self.CE_DESELECT()
data = [hex(address >> i & 0xff) for i in (16,8,0)]
self.CE_SELECT()
spi.writebytes([ERASE_BLOCK64,data]) #Send Sector Erase command
self.CE_DESELECT()
[docs] def isWriteBusy(self):
"""
Check if a write is in process.
:param none:
:returns: none
"""
self.CE_SELECT()
spi.writebytes([CMD_RDSR1]) #Send RDSR command
temp = spi.read(1)
self.CE_DESELECT()
if (temp and 0x01):
return 1
else:
return 0
[docs] def readStatusRegister(self,statReg):
"""
Read the contents of the status register.
:param statReg: Address of one of the status registers
:returns: stat - Status register contents
"""
self.CE_SELECT()
spi.writebytes([statReg]) # send RDSR command
byte = spi.readbytes(1) # receive byte
self.CE_DESELECT()
return byte
[docs] def writeStatusRegister(self,statReg):
"""
Write a new value to the contents of the status register
:param statReg: Address of one of the status registers
:returns: none
"""
self.CE_SELECT()
spi.writebytes([CMD_WREN]) #Send WREN command
self.CE_DESELECT()
self.CE_SELECT()
spi.writebytes([CMD_WRSR]) # select write to status register
spi.writebytes([statReg]) # data that will change the status of BPx or BPL (only bits 2,3,4,5,7 can be written)
self.CE_DESELECT()
[docs] def deepSleep(self):
"""
Put the memory in deep sleep mode.
:param none:
:returns: none
"""
self.CE_SELECT() #enable device
spi.writebytes([CMD_DEEPSLP]) # select write to status register
self.CE_DESELECT() # disable the device
return 0
[docs] def wakeUp(self):
"""
Wake up from deep sleep mode.
:param none:
:returns: none
"""
self.CE_SELECT() # enable device
spi.writebytes([CMD_RESDPD]) # select write to status register
self.CE_DESELECT() # disable the device
return 0
[docs] def setBlockProtection(self,prot):
"""
Set the contents of a specific block as protected.
:param prot: Specific block
:returns: none
"""
self.CE_SELECT()
spi.writebytes([CMD_EWSR]) #enable write to volatile register
self.CE_DESELECT()
self.CE_SELECT()
spi.writebytes([CMD_WRSR,(prot & 0x0f)<<2]) #write status register
self.CE_DESELECT()
[docs] def close(self):
"""
Close the SPI interface for the flash memory chip.
:param none:
:returns: none
"""
spi.close()