From 199b130492d8a51e46c5cfa382ac8724670a8355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Thu, 19 Mar 2015 20:56:02 +0100 Subject: [PATCH] Updated SPIflash to work with Arduino 1.6.x --- libraries/SPIFlash/SPIFlash.cpp | 60 ++++++++++++++++++++++++--------- libraries/SPIFlash/SPIFlash.h | 38 ++++++++++++--------- 2 files changed, 67 insertions(+), 31 deletions(-) diff --git a/libraries/SPIFlash/SPIFlash.cpp b/libraries/SPIFlash/SPIFlash.cpp index 03d6a1a..bad4cdf 100644 --- a/libraries/SPIFlash/SPIFlash.cpp +++ b/libraries/SPIFlash/SPIFlash.cpp @@ -6,6 +6,9 @@ * Minimal modifications should allow chips that have different page size but modifications * DEPENDS ON: Arduino SPI library * + * Updated Jan. 5, 2015, TomWS1, modified writeBytes to allow blocks > 256 bytes and handle page misalignment. + * Updated Feb. 26, 2015 TomWS1, added support for SPI Transactions (Arduino 1.5.8 and above) + * * This file is free software; you can redistribute it and/or modify * it under the terms of either the GNU General Public License version 2 * or the GNU Lesser General Public License version 2.1, both as @@ -32,15 +35,22 @@ SPIFlash::SPIFlash(uint8_t slaveSelectPin, uint16_t jedecID) { /// Select the flash chip void SPIFlash::select() { - noInterrupts(); //save current SPI settings +#ifndef SPI_HAS_TRANSACTION + _SREG = SREG; + noInterrupts(); +#endif _SPCR = SPCR; _SPSR = SPSR; - //set FLASH chip SPI settings + +#ifdef SPI_HAS_TRANSACTION + SPI.beginTransaction(_settings); +#else + // set FLASH SPI settings SPI.setDataMode(SPI_MODE0); SPI.setBitOrder(MSBFIRST); - SPI.setClockDivider(SPI_CLOCK_DIV4); //decided to slow down from DIV2 after SPI stalling in some instances, especially visible on mega1284p when RFM69 and FLASH chip both present - SPI.begin(); + SPI.setClockDivider(SPI_CLOCK_DIV4); // decided to slow down from DIV2 after SPI stalling in some instances, especially visible on mega1284p when RFM69 and FLASH chip both present +#endif digitalWrite(_slaveSelectPin, LOW); } @@ -48,9 +58,13 @@ void SPIFlash::select() { void SPIFlash::unselect() { digitalWrite(_slaveSelectPin, HIGH); //restore SPI settings to what they were before talking to the FLASH chip +#ifdef SPI_HAS_TRANSACTION + SPI.endTransaction(); +#else + SREG = _SREG; // restore interrupts IFF they were enabled +#endif SPCR = _SPCR; SPSR = _SPSR; - interrupts(); } /// setup SPI, read device ID etc... @@ -58,7 +72,10 @@ boolean SPIFlash::initialize() { _SPCR = SPCR; _SPSR = SPSR; + digitalWrite(_slaveSelectPin, HIGH); pinMode(_slaveSelectPin, OUTPUT); + SPI.begin(); + _settings = SPISettings(4000000, MSBFIRST, SPI_MODE0); unselect(); wakeup(); @@ -185,22 +202,33 @@ void SPIFlash::writeByte(long addr, uint8_t byt) { unselect(); } -/// write 1-256 bytes to flash memory +/// write multiple bytes to flash memory (up to 64K) /// WARNING: you can only write to previously erased memory locations (see datasheet) /// use the block erase commands to first clear memory (write 0xFFs) -/// WARNING: if you write beyond a page boundary (or more than 256bytes), -/// the bytes will wrap around and start overwriting at the beginning of that same page -/// see datasheet for more details +/// This version handles both page alignment and data blocks larger than 256 bytes. +/// void SPIFlash::writeBytes(long addr, const void* buf, uint16_t len) { - command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program - SPI.transfer(addr >> 16); - SPI.transfer(addr >> 8); - SPI.transfer(addr); - for (uint16_t i = 0; i < len; i++) - SPI.transfer(((byte*) buf)[i]); - unselect(); + uint16_t n; + uint16_t maxBytes = 256-(addr%256); // force the first set of bytes to stay within the first page + uint16_t offset = 0; + while (len>0) + { + n = (len<=maxBytes) ? len : maxBytes; + command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program + SPI.transfer(addr >> 16); + SPI.transfer(addr >> 8); + SPI.transfer(addr); + for (uint16_t i = 0; i < n; i++) + SPI.transfer(((byte*) buf)[offset + i]); + unselect(); + addr+=n; // adjust the addresses and remaining bytes by what we've just transferred. + offset +=n; + len -= n; + maxBytes = 256; // now we can do up to 256 bytes per loop + } } + /// erase entire flash memory array /// may take several seconds depending on size, but is non blocking /// so you may wait for this to complete using busy() or continue doing diff --git a/libraries/SPIFlash/SPIFlash.h b/libraries/SPIFlash/SPIFlash.h index f0c071a..8f530b7 100644 --- a/libraries/SPIFlash/SPIFlash.h +++ b/libraries/SPIFlash/SPIFlash.h @@ -1,11 +1,13 @@ /* * Copyright (c) 2013 by Felix Rusu * SPI Flash memory library for arduino/moteino. - * This works with 256byte/page SPI flash memory - * For instance a 4MBit (512Kbyte) flash chip will have 2048 pages: 256*2048 = 524288 bytes (512Kbytes) + * This works with 256uint8_t/page SPI flash memory + * For instance a 4MBit (512Kuint8_t) flash chip will have 2048 pages: 256*2048 = 524288 uint8_ts (512Kuint8_ts) * Minimal modifications should allow chips that have different page size but modifications * DEPENDS ON: Arduino SPI library * + * Updated Feb. 26, 2015 TomWS1, added support for SPI Transactions (Arduino 1.5.8 and above) + * * This file is free software; you can redistribute it and/or modify * it under the terms of either the GNU General Public License version 2 * or the GNU Lesser General Public License version 2.1, both as @@ -56,34 +58,34 @@ // but no actual need to wait for completion (instead need to check the status register BUSY bit) #define SPIFLASH_STATUSREAD 0x05 // read status register #define SPIFLASH_STATUSWRITE 0x01 // write status register -#define SPIFLASH_ARRAYREAD 0x0B // read array (fast, need to add 1 dummy byte after 3 address bytes) +#define SPIFLASH_ARRAYREAD 0x0B // read array (fast, need to add 1 dummy uint8_t after 3 address uint8_ts) #define SPIFLASH_ARRAYREADLOWFREQ 0x03 // read array (low frequency) #define SPIFLASH_SLEEP 0xB9 // deep power down #define SPIFLASH_WAKE 0xAB // deep power wake up -#define SPIFLASH_BYTEPAGEPROGRAM 0x02 // write (1 to 256bytes) -#define SPIFLASH_IDREAD 0x9F // read JEDEC manufacturer and device ID (2 bytes, specific bytes for each manufacturer and device) +#define SPIFLASH_BYTEPAGEPROGRAM 0x02 // write (1 to 256uint8_ts) +#define SPIFLASH_IDREAD 0x9F // read JEDEC manufacturer and device ID (2 uint8_ts, specific uint8_ts for each manufacturer and device) // Example for Atmel-Adesto 4Mbit AT25DF041A: 0x1F44 (page 27: http://www.adestotech.com/sites/default/files/datasheets/doc3668.pdf) // Example for Winbond 4Mbit W25X40CL: 0xEF30 (page 14: http://www.winbond.com/NR/rdonlyres/6E25084C-0BFE-4B25-903D-AE10221A0929/0/W25X40CL.pdf) #define SPIFLASH_MACREAD 0x4B // read unique ID number (MAC) class SPIFlash { public: - static byte UNIQUEID[8]; - SPIFlash(byte slaveSelectPin, uint16_t jedecID=0); + static uint8_t UNIQUEID[8]; + SPIFlash(uint8_t slaveSelectPin, uint16_t jedecID=0); boolean initialize(); - void command(byte cmd, boolean isWrite=false); - byte readStatus(); - byte readByte(long addr); + void command(uint8_t cmd, boolean isWrite=false); + uint8_t readStatus(); + uint8_t readByte(long addr); void readBytes(long addr, void* buf, word len); - void writeByte(long addr, byte byt); + void writeByte(long addr, uint8_t byt); void writeBytes(long addr, const void* buf, uint16_t len); boolean busy(); void chipErase(); void blockErase4K(long address); void blockErase32K(long address); word readDeviceId(); - byte* readUniqueId(); + uint8_t* readUniqueId(); void sleep(); void wakeup(); @@ -91,10 +93,16 @@ public: protected: void select(); void unselect(); - byte _slaveSelectPin; + uint8_t _slaveSelectPin; uint16_t _jedecID; - byte _SPCR; - byte _SPSR; + uint8_t _SPCR; + uint8_t _SPSR; + uint8_t _SREG; + +#ifdef SPI_HAS_TRANSACTION + SPISettings _settings; +#endif + }; #endif \ No newline at end of file