Created
July 27, 2017 02:55
-
-
Save amaork/4b62224ba32555f85b37b4f4cb58d824 to your computer and use it in GitHub Desktop.
Raspberry pi read/write winbond W25Q80 SPI Flash
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
from spidev import SpiDev | |
class SPIFlash(object): | |
READ_ID = 0x9f | |
READ_RS = 0x05 | |
CHIP_ERASE = 0x60 | |
PAGE_READ = 0x3 | |
PAGE_WRITE = 0x2 | |
WRITE_ENABLE = 0x6 | |
WRITE_DISABLE = 0x4 | |
# Flash attribute | |
W25Q80_MID = 0xEF | |
W25Q80_DID = 0x4014 | |
FLASH_PAGE_SIZE = 256 | |
FLASH_TOTAL_SIZE = 1024 * 1024 | |
def __init__(self, bus, dev, speed): | |
"""Init a spi flash | |
:param bus: spi bus number | |
:param dev: spi device number | |
:param speed: spi speed unit khz | |
""" | |
try: | |
self.__spi = SpiDev() | |
self.__spi.open(bus, dev) | |
self.__spi.max_speed_hz = speed * 1000 | |
print("Device:/dev/spidev{}.{}, speed:{}".format(bus, dev, speed)) | |
except IOError: | |
raise("Do not found spi device:/dev/spidev{}.{}".format(bus, dev)) | |
def __del__(self): | |
self.__spi.close() | |
def probe(self): | |
try: | |
data = self.__spi.xfer([self.READ_ID, 0, 0, 0]) | |
return data[1], data[2] << 8 | data[3] | |
except IndexError: | |
return 0, 0 | |
def erase(self): | |
# First enable write | |
self.__spi.xfer([self.WRITE_ENABLE]) | |
# Second erase chip | |
self.__spi.xfer([self.CHIP_ERASE]) | |
# Final wait chip erase done | |
while self.get_rs() & 0x1: | |
pass | |
def get_rs(self): | |
return self.__spi.xfer([self.READ_RS, 0])[1] | |
def read_page(self, page): | |
address = page * self.FLASH_PAGE_SIZE | |
# Msb first | |
cmd = [self.PAGE_READ, (address >> 16) & 0xff, (address >> 8) & 0xff, address & 0xff] | |
return bytearray(self.__spi.xfer(cmd + [0] * self.FLASH_PAGE_SIZE)[4:]) | |
def read_chip(self): | |
data = bytearray() | |
for page in range(self.FLASH_TOTAL_SIZE / self.FLASH_PAGE_SIZE): | |
data += self.read_page(page) | |
return data | |
def write_page(self, page, data): | |
address = page * self.FLASH_PAGE_SIZE | |
cmd = [self.PAGE_WRITE, (address >> 16) & 0xff, (address >> 8) & 0xff, address & 0xff] | |
# First enable write | |
self.__spi.xfer([self.WRITE_ENABLE]) | |
# Second write page data | |
self.__spi.xfer(cmd + data) | |
# Wait done | |
while self.get_rs() & 0x1: | |
pass | |
def write_chip(self, data, verify=False): | |
"""Write chip | |
:param data: data will write to chip | |
:param verify: verify data | |
:return:success return true else false | |
""" | |
# Check data len | |
if len(data) != self.FLASH_TOTAL_SIZE: | |
print("Data size error!") | |
return False | |
# First erase chip | |
self.erase() | |
# Convert data to list | |
data = list(data) | |
# Write data to page | |
for page in range(self.FLASH_TOTAL_SIZE / self.FLASH_PAGE_SIZE): | |
start = page * self.FLASH_PAGE_SIZE | |
write_buffer = map(ord, data[start: start + self.FLASH_PAGE_SIZE]) | |
self.write_page(page, write_buffer) | |
if verify and bytearray(write_buffer) != self.read_page(page): | |
print("Verify error, page:{}".format(page)) | |
return False | |
return True | |
if __name__ == "__main__": | |
flash = SPIFlash(0, 0, 8000) | |
# Get device manufacturer id and device id | |
mid, device_id = flash.probe() | |
print("Manufacturer ID:0x{0:X}, Device ID:0x{1:X}".format(mid, device_id)) | |
if mid != SPIFlash.W25Q80_MID or device_id != SPIFlash.W25Q80_DID: | |
print("SPI Flash is not Winbond W25Q80") | |
sys.exit() | |
# Write RL6193_Project.bin to flash | |
with open("RL6193_Project.bin", "rb") as fp: | |
flash.write_chip(fp.read()) | |
# Read data to flash.bin | |
with open("flash.bin", "wb") as fp: | |
fp.write(flash.read_chip()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment