From cb0b39561a9839427409a96cf430b2c51b63d63d Mon Sep 17 00:00:00 2001 From: "R. Steve McKown" Date: Tue, 23 Oct 2012 17:45:35 -0600 Subject: [PATCH] tmimsp: support 4 KB sectors on AT25DF041A The tmimsp platform family by default uses an Atmel AT25DF041A serial FLASH part which supports 4 KB erase blocks. Since the part's communications protocol is a super-set of that supported by the STM25P family, a private Stm25PSpiP that issues 0x20 4 KB erase block instead of the default 0xd8 64 KB erase block command, and a companion Stm25p.h that properly defines the sector size (aka erase block size) allows the part to be treated as an array of 4 KB sectors. This is a huge win for most application uses of FLASH. --- .../tmimsp/common/chips/at25df/Stm25p.h | 12 +- .../tmimsp/common/chips/at25df/Stm25pSpiP.nc | 281 ++++++++++++++++++ 2 files changed, 289 insertions(+), 4 deletions(-) create mode 100644 tos/platforms/tmimsp/common/chips/at25df/Stm25pSpiP.nc diff --git a/tos/platforms/tmimsp/common/chips/at25df/Stm25p.h b/tos/platforms/tmimsp/common/chips/at25df/Stm25p.h index a8bfd745..e8ad229f 100644 --- a/tos/platforms/tmimsp/common/chips/at25df/Stm25p.h +++ b/tos/platforms/tmimsp/common/chips/at25df/Stm25p.h @@ -30,10 +30,14 @@ /** * This header must override the one found in TOS/chips/stm25p to account * for the differences in the Atmel AT25DF041A, which is generally compatible - * with the Numonyx (formerly ST) M25P family. + * with the Numonyx (formerly ST) M25P family. The part uses a modified + * Stm25pSpiP.nc file, in this directory, to support 4 KB erase blocks (aka 4 KB + * sector size). * * Derived from original Stm25p.h by Arch Rock Corporation in * TOSDIR/chips/stm25p. + * + * @author R. Steve McKown */ #ifndef __STM25P_H__ /* do not change this header definition */ @@ -45,10 +49,10 @@ typedef storage_addr_t stm25p_addr_t; typedef storage_len_t stm25p_len_t; enum { - STM25P_NUM_SECTORS = 8, - STM25P_SECTOR_SIZE_LOG2 = 16, + STM25P_NUM_SECTORS = 128, + STM25P_SECTOR_SIZE_LOG2 = 12, STM25P_SECTOR_SIZE = 1L << STM25P_SECTOR_SIZE_LOG2, - STM25P_SECTOR_MASK = 0xffff, + STM25P_SECTOR_MASK = 0x0fff, STM25P_PAGE_SIZE_LOG2 = 8, STM25P_PAGE_SIZE = 1 << STM25P_PAGE_SIZE_LOG2, STM25P_PAGE_MASK = STM25P_PAGE_SIZE - 1, diff --git a/tos/platforms/tmimsp/common/chips/at25df/Stm25pSpiP.nc b/tos/platforms/tmimsp/common/chips/at25df/Stm25pSpiP.nc new file mode 100644 index 00000000..df8552d4 --- /dev/null +++ b/tos/platforms/tmimsp/common/chips/at25df/Stm25pSpiP.nc @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2012 Titanium Mirror, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * - Neither the name of the Arch Rock Corporation nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * ARCHED ROCK OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE + */ + +/** + * A derivation of the default TinyOS Stm25pSpiP.nc using 4 KB erase blocks + * supported by the Atmel AT25DF041A which is not supported on most of the other + * STM25P communications compatible devices. + * + * The Stm25p.h file present in this directory accommodates the change in FLASH + * organization by indicating the part is a collection of 4 KB (2^12 B) sectors. + * + * Derived from original Stm25p.h by Arch Rock Corporation in + * TOSDIR/chips/stm25p. + * + * @author R. Steve McKown + */ + +#include "crc.h" + +module Stm25pSpiP { + + provides interface Init; + provides interface Resource as ClientResource; + provides interface Stm25pSpi as Spi; + + uses interface Resource as SpiResource; + uses interface GeneralIO as CSN; + uses interface GeneralIO as Hold; + uses interface SpiByte; + uses interface SpiPacket; + uses interface Leds; + +} + +implementation { + + enum { + CRC_BUF_SIZE = 16, + }; + + typedef enum { + S_READ = 0x3, + S_PAGE_PROGRAM = 0x2, + S_SECTOR_ERASE = 0x20, /* Note: 4KB block erase */ + S_BULK_ERASE = 0xc7, + S_WRITE_ENABLE = 0x6, + S_POWER_ON = 0xab, + S_DEEP_SLEEP = 0xb9, + } stm25p_cmd_t; + + norace uint8_t m_cmd[ 4 ]; + + norace bool m_is_writing = FALSE; + norace bool m_computing_crc = FALSE; + + norace stm25p_addr_t m_addr; + norace uint8_t* m_buf; + norace stm25p_len_t m_len; + norace stm25p_addr_t m_cur_addr; + norace stm25p_len_t m_cur_len; + norace uint8_t m_crc_buf[ CRC_BUF_SIZE ]; + norace uint16_t m_crc; + + error_t newRequest( bool write, stm25p_len_t cmd_len ); + void signalDone( error_t error ); + + uint8_t sendCmd( uint8_t cmd, uint8_t len ) { + + uint8_t tmp = 0; + int i; + + call CSN.clr(); + for ( i = 0; i < len; i++ ) + tmp = call SpiByte.write( cmd ); + call CSN.set(); + + return tmp; + + } + + command error_t Init.init() { + call CSN.makeOutput(); + call Hold.makeOutput(); + call CSN.set(); + call Hold.set(); + return SUCCESS; + } + + async command error_t ClientResource.request() { + return call SpiResource.request(); + } + + async command error_t ClientResource.immediateRequest() { + return call SpiResource.immediateRequest(); + } + + async command error_t ClientResource.release() { + return call SpiResource.release(); + } + + async command uint8_t ClientResource.isOwner() { + return call SpiResource.isOwner(); + } + + stm25p_len_t calcReadLen() { + return ( m_cur_len < CRC_BUF_SIZE ) ? m_cur_len : CRC_BUF_SIZE; + } + + async command error_t Spi.powerDown() { + sendCmd( S_DEEP_SLEEP, 1 ); + return SUCCESS; + } + + async command error_t Spi.powerUp() { + sendCmd( S_POWER_ON, 5 ); + return SUCCESS; + } + + async command error_t Spi.read( stm25p_addr_t addr, uint8_t* buf, + stm25p_len_t len ) { + m_cmd[ 0 ] = S_READ; + m_addr = addr; + m_buf = buf; + m_len = len; + return newRequest( FALSE, 4 ); + } + + async command error_t Spi.computeCrc( uint16_t crc, stm25p_addr_t addr, + stm25p_len_t len ) { + m_computing_crc = TRUE; + m_crc = crc; + m_addr = m_cur_addr = addr; + m_len = m_cur_len = len; + return call Spi.read( addr, m_crc_buf, calcReadLen() ); + } + + async command error_t Spi.pageProgram( stm25p_addr_t addr, uint8_t* buf, + stm25p_len_t len ) { + m_cmd[ 0 ] = S_PAGE_PROGRAM; + m_addr = addr; + m_buf = buf; + m_len = len; + return newRequest( TRUE, 4 ); + } + + async command error_t Spi.sectorErase( uint8_t sector ) { + m_cmd[ 0 ] = S_SECTOR_ERASE; + m_addr = (stm25p_addr_t)sector << STM25P_SECTOR_SIZE_LOG2; + return newRequest( TRUE, 4 ); + } + + async command error_t Spi.bulkErase() { + m_cmd[ 0 ] = S_BULK_ERASE; + return newRequest( TRUE, 1 ); + } + + error_t newRequest( bool write, stm25p_len_t cmd_len ) { + m_cmd[ 1 ] = m_addr >> 16; + m_cmd[ 2 ] = m_addr >> 8; + m_cmd[ 3 ] = m_addr; + if ( write ) + sendCmd( S_WRITE_ENABLE, 1 ); + call CSN.clr(); + call SpiPacket.send( m_cmd, NULL, cmd_len ); + return SUCCESS; + } + + void releaseAndRequest() { + call SpiResource.release(); + call SpiResource.request(); + } + + async event void SpiPacket.sendDone( uint8_t* tx_buf, uint8_t* rx_buf, + uint16_t len, error_t error ) { + + int i; + + switch( m_cmd[ 0 ] ) { + + case S_READ: + if ( tx_buf == m_cmd ) { + call SpiPacket.send( NULL, m_buf, m_len ); + break; + } + else if ( m_computing_crc ) { + for ( i = 0; i < len; i++ ) + m_crc = crcByte( m_crc, m_crc_buf[ i ] ); + m_cur_addr += len; + m_cur_len -= len; + if ( m_cur_len ) { + call SpiPacket.send( NULL, m_crc_buf, calcReadLen() ); + break; + } + } + call CSN.set(); + signalDone( SUCCESS ); + break; + + case S_PAGE_PROGRAM: + if ( tx_buf == m_cmd ) { + call SpiPacket.send( m_buf, NULL, m_len ); + break; + } + // fall through + + case S_SECTOR_ERASE: case S_BULK_ERASE: + call CSN.set(); + m_is_writing = TRUE; + releaseAndRequest(); + break; + + default: + break; + + } + + } + + event void SpiResource.granted() { + + if ( !m_is_writing ) + signal ClientResource.granted(); + else if ( sendCmd( 0x5, 2 ) & 0x1 ) + releaseAndRequest(); + else + signalDone( SUCCESS ); + + } + + void signalDone( error_t error ) { + m_is_writing = FALSE; + switch( m_cmd[ 0 ] ) { + case S_READ: + if ( m_computing_crc ) { + m_computing_crc = FALSE; + signal Spi.computeCrcDone( m_crc, m_addr, m_len, error ); + } + else { + signal Spi.readDone( m_addr, m_buf, m_len, error ); + } + break; + case S_PAGE_PROGRAM: + signal Spi.pageProgramDone( m_addr, m_buf, m_len, error ); + break; + case S_SECTOR_ERASE: + signal Spi.sectorEraseDone( m_addr >> STM25P_SECTOR_SIZE_LOG2, error ); + break; + case S_BULK_ERASE: + signal Spi.bulkEraseDone( error ); + break; + } + } +} -- 2.39.2