Strict Standards: Declaration of action_plugin_importoldchangelog::register() should be compatible with DokuWiki_Action_Plugin::register($controller) in /home/aqq20189/public_html/embedders.org/kurt/wiki/lib/plugins/importoldchangelog/action.php on line 8
Deprecated: Assigning the return value of new by reference is deprecated in /home/aqq20189/public_html/embedders.org/kurt/wiki/inc/parserutils.php on line 202
Deprecated: Assigning the return value of new by reference is deprecated in /home/aqq20189/public_html/embedders.org/kurt/wiki/inc/parserutils.php on line 205
Deprecated: Assigning the return value of new by reference is deprecated in /home/aqq20189/public_html/embedders.org/kurt/wiki/inc/parserutils.php on line 314
Deprecated: Assigning the return value of new by reference is deprecated in /home/aqq20189/public_html/embedders.org/kurt/wiki/inc/parserutils.php on line 454
Strict Standards: Declaration of cache_instructions::retrieveCache() should be compatible with cache::retrieveCache($clean = true) in /home/aqq20189/public_html/embedders.org/kurt/wiki/inc/cache.php on line 291
Deprecated: Function split() is deprecated in /home/aqq20189/public_html/embedders.org/kurt/wiki/inc/auth.php on line 146
Warning: Cannot modify header information - headers already sent by (output started at /home/aqq20189/public_html/embedders.org/kurt/wiki/lib/plugins/importoldchangelog/action.php:8) in /home/aqq20189/public_html/embedders.org/kurt/wiki/inc/auth.php on line 236
Deprecated: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in /home/aqq20189/public_html/embedders.org/kurt/wiki/inc/auth.php on line 390
Deprecated: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in /home/aqq20189/public_html/embedders.org/kurt/wiki/inc/auth.php on line 390
Deprecated: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in /home/aqq20189/public_html/embedders.org/kurt/wiki/inc/auth.php on line 387
Strict Standards: Only variables should be passed by reference in /home/aqq20189/public_html/embedders.org/kurt/wiki/doku.php on line 69
Warning: Cannot modify header information - headers already sent by (output started at /home/aqq20189/public_html/embedders.org/kurt/wiki/lib/plugins/importoldchangelog/action.php:8) in /home/aqq20189/public_html/embedders.org/kurt/wiki/inc/actions.php on line 350
/**
* @file at45db.c
* @brief AT45DB Module
*
* Support Atmel AT45DB Flash Memory
*
* @author Rustem Kalimullin
* @par E-mail:
* hellos@mail.ru
* @par Copyright:
* (c) Kurt, 2005
*/
#include "common.h"
#include "at45db.h"
#include "spi.h"
// Define DF_AUTODETECT_FEATURES to enable autodetect features
//#define DF_AUTODETECT_FEATURES
//! defines for all opcodes
enum {
BLOCK_ERASE = 0x50, /**< erase 512 pages */
MAIN_MEMORY_PAGE_READ = 0x52, /**< main memory page read */
MM_PAGE_TO_B1_XFER = 0x53, /**< main memory page to buffer 1 transfer */
BUFFER_1_READ = 0x54, /**< Buffer 1 read */
MM_PAGE_TO_B2_XFER = 0x55, /**< main memory page to buffer 2 transfer */
BUFFER_2_READ = 0x56, /**< buffer 2 read */
STATUS_REGISTER_READ = 0x57, /**< status register */
AUTO_PAGE_REWRITE_THROUGH_B1 = 0x58, /**< auto page rewrite through buffer 1 */
AUTO_PAGE_REWRITE_THROUGH_B2 = 0x59, /**< auto page rewrite through buffer 2 */
MM_PAGE_TO_B1_COMP = 0x60, /**< main memory page compare to buffer 1 */
MM_PAGE_TO_B2_COMP = 0x61, /**< main memory page compare to buffer 2 */
ARRAY_READ = 0x68, /**< start continuous array read */
PAGE_ERASE = 0x81, /**< erase a 264 byte page */
MM_PAGE_PROG_THROUGH_B1 = 0x82, /**< main memory page program through buffer 1 */
B1_TO_MM_PAGE_PROG_WITH_ERASE = 0x83, /**< buffer 1 to main memory page program with built-in erase */
BUFFER_1_WRITE = 0x84, /**< Buffer 1 write */
MM_PAGE_PROG_THROUGH_B2 = 0x85, /**< main memory page program through buffer 2 */
B2_TO_MM_PAGE_PROG_WITH_ERASE = 0x86, /**< buffer 2 to main memory page program with built-in erase */
BUFFER_2_WRITE = 0x87, /**< buffer 2 write */
B1_TO_MM_PAGE_PROG_WITHOUT_ERASE = 0x88, /**< buffer 1 to main memory page program without built-in erase */
B2_TO_MM_PAGE_PROG_WITHOUT_ERASE = 0x89 /**< buffer 2 to main memory page program without built-in erase */
};
//! Error codes
enum { DF_NO_ERROR=0, DF_WAIT_FAIL, DF_NOT_MATCH, DF_UNKNOWN_DEVICE };
//! Last error
int df_last_error = DF_UNKNOWN_DEVICE;
//! Current position
__no_init unsigned long df_cur_pos;
////////////////////////////////////////////////////////////////////////////////
#if defined(DF_AUTODETECT_FEATURES)
//! Chip info structure
//! Supported chips
const struct stru_df_info {
const char *pszName; //!< Name of chip
unsigned int pages; //!< Number of pages
unsigned int page_size; //!< Page size in bytes
unsigned char page_bit; //!< Page address len in bits
unsigned char id_density; //!< Density ID mask
} df_table [] = {
{ "AT45DB011B", 512, 264, 9, (0x3<<2) }, // 1M
{ "AT45DB021B", 1024, 264, 9, (0x5<<2) }, // 2M
{ "AT45DB041B", 2048, 264, 9, (0x7<<2) }, // 4M
{ "AT45DB081B", 4096, 264, 9, (0x9<<2) }, // 8M
{ "AT45DB161B", 4096, 528, 10, (0xB<<2) }, // 16M
{ "AT45DB321B", 8192, 528, 10, (0xD<<2) }, // 32M
{ "AT45DB642B", 8192, 1056, 11, (0xF<<2) }, // 64M
};
const char *df_name = "UNKNOWN";
unsigned char df_page_bits = 9;
unsigned int df_num_pages = 4096;
unsigned int df_page_size = 264;
unsigned int df_id_density = (0x9<<2);
unsigned long df_density = 4096L*264L;
#else //////////////////////////////////////////////////////////////////////////
#define df_name ("AT45DB081B")
#define df_num_pages (4096)
#define df_page_size (264)
#define df_page_bits (9)
#define df_id_density (0x9<<2)
#define df_density (4096L*264L)
#endif /////////////////////////////////////////////////////////////////////////
//---------------------------------------------------------
int at45db_getLastError( void )
{
int err = df_last_error;
df_last_error = DF_NO_ERROR;
return err;
}
//---------------------------------------------------------
const char* at45db_getErrorString( int iErr )
{
switch(iErr)
{
case DF_NO_ERROR: return "No error";
case DF_WAIT_FAIL: return "Wait failed";
case DF_NOT_MATCH: return "Cfg failed";
case DF_UNKNOWN_DEVICE: return "Unknown device";
default: return "Unknown error";
}
}
//---------------------------------------------------------
void at45db_init_op( void )
{
DATAFLASH_ENABLE();
__no_operation();
}
//---------------------------------------------------------
void at45db_end_op( void )
{
DATAFLASH_DISABLE();
__no_operation();
}
//---------------------------------------------------------
void at45db_delay( void )
{
unsigned char i=0x00;
do { __no_operation(); } while (--i);
}
//---------------------------------------------------------
void at45db_reset(void)
{
at45db_init_op();
at45db_delay();
DF_RESET_HI();
at45db_delay();
DF_RESET_LO();
at45db_delay();
at45db_end_op();
}
//---------------------------------------------------------
//! wait until DataFlash busy
void at45db_wait(void)
{
unsigned int i;
at45db_init_op();
i =0x1FFF;
do {
spi_write(STATUS_REGISTER_READ);
if( (spi_read() & (1<<7) ) != 0 ) break;
} while( --i );
df_last_error = (i != 0) ? DF_NO_ERROR : DF_WAIT_FAIL;
at45db_end_op();
}
//---------------------------------------------------------
unsigned int _read_density_id(void)
{
unsigned int id;
at45db_init_op();
spi_write(STATUS_REGISTER_READ);
id = ( spi_read() & (0xF<<2) );
at45db_end_op();
return id;
}
//---------------------------------------------------------
int at45db_init(void)
{
at45db_detect_error();
#if defined(DF_AUTODETECT_FEATURES)
if ( df_last_error == DF_WAIT_FAIL ) return df_last_error;
const struct stru_df_info *found = 0;
df_id_density = _read_density_id();
for( int i=0; i<(sizeof(df_table)/sizeof(df_table[0])); i++ ) {
if( df_id_density == df_table[i].id_density ) {
found = &df_table[i];
break;
}
}
if( !found ) {
found = &df_table[0];
df_last_error = DF_UNKNOWN_DEVICE;
}
df_num_pages = found->pages;
df_page_size = found->page_size;
df_page_bits = found->page_bit;
df_name = found->pszName;
df_density = (long)df_num_pages * df_page_size;
#endif
return df_last_error;
}
//---------------------------------------------------------
int at45db_detect_error(void)
{
at45db_reset();
at45db_wait();
if( df_last_error == DF_NO_ERROR ) {
if( _read_density_id() != df_id_density ) df_last_error = DF_NOT_MATCH;
}
return df_last_error;
}
//---------------------------------------------------------
void at45db_setpos(unsigned long pos) { df_cur_pos = pos; }
unsigned long at45db_getpos(void) { return df_cur_pos; }
//---------------------------------------------------------
const char* at45db_getName(void) { return df_name; }
unsigned long at45db_getDensity ( void ) { return df_density; }
unsigned int at45db_getPageSize( void ) { return df_page_size; }
unsigned int at45db_getNumPages( void ) { return df_num_pages; }
//---------------------------------------------------------
void at45db_start_read( void )
{
ldiv_t pos = ldiv(df_cur_pos, df_page_size);
unsigned int cur_page = pos.quot, cur_ofs = pos.rem;
at45db_init_op();
spi_write(ARRAY_READ); // Continuous Array Read op-code
spi_write((unsigned char)(cur_page >> (16 - df_page_bits))); // upper part of page address
spi_write((unsigned char)((cur_page << (df_page_bits - 8))+ (cur_ofs>>8))); // lower part of page address and MSB of int.page adr.
spi_write((unsigned char)(cur_ofs)); // LSB byte of internal page address
spi_write(0x00); // perform 4 dummy writes
spi_write(0x00); // in order to initiate DataFlash
spi_write(0x00); // address pointers
spi_write(0x00);
}
//---------------------------------------------------------
void at45db_cont_read(unsigned char *dst, unsigned int size)
{
while( size-- ) {
df_cur_pos++;
*dst++ = spi_read();
}
}
//---------------------------------------------------------
unsigned char at45db_cont_readbyte(void)
{
df_cur_pos++;
return spi_read();
}
//---------------------------------------------------------
void at45db_end_read( void )
{
at45db_end_op();
}
//---------------------------------------------------------
unsigned int at45db_cont_verify(unsigned int size)
{
unsigned int crc = 0xFFFF;
do {
df_cur_pos++;
crc ^= spi_read();
unsigned char k = 8;
do {
if (crc & 1) { crc >>=1; crc ^=0xA001; }
else { crc >>=1; }
} while( --k );
} while( --size );
return crc;
}
//---------------------------------------------------------
void at45db_read( unsigned char *dst, unsigned int size )
{
at45db_start_read();
at45db_cont_read(dst, size);
at45db_end_op();
}
//---------------------------------------------------------
void df_page_func( unsigned char cmd, unsigned int page )
{
at45db_init_op();
spi_write(cmd);
spi_write((unsigned char)(page >> (16 - df_page_bits))); // upper part of page address
spi_write((unsigned char)(page << (df_page_bits - 8))); // lower part of page address
spi_write(0x00); // don't cares
at45db_end_op();
at45db_wait();
}
//---------------------------------------------------------
void at45db_write( const unsigned char *src, unsigned int size )
{
while(size) {
ldiv_t pos = ldiv( df_cur_pos, df_page_size );
unsigned int cur_page = pos.quot, cur_ofs = pos.rem;
df_page_func(MM_PAGE_TO_B1_XFER, cur_page);
at45db_init_op();
spi_write(BUFFER_1_WRITE); // buffer 1 write op-code
spi_write(0x00); // don't cares
spi_write((unsigned char)(cur_ofs>>8)); // upper part of internal buffer address
spi_write((unsigned char)(cur_ofs)); // lower part of internal buffer address
do {
spi_write(*src++);
df_cur_pos++;
} while( (--size) && (++cur_ofs < df_page_size) );
at45db_end_op();
df_page_func( B1_TO_MM_PAGE_PROG_WITH_ERASE, cur_page );
df_page_func( AUTO_PAGE_REWRITE_THROUGH_B1, cur_page );
}
}
//---------------------------------------------------------
void at45db_start_write( void )
{
ldiv_t pos = ldiv( df_cur_pos, df_page_size );
unsigned int cur_page = pos.quot, cur_ofs = pos.rem;
at45db_end_op();
df_page_func(MM_PAGE_TO_B1_XFER, cur_page );
at45db_init_op();
spi_write(BUFFER_1_WRITE); // buffer 1 write op-code
spi_write(0x00); // don't cares
spi_write((unsigned char)(cur_ofs>>8)); // upper part of internal buffer address
spi_write((unsigned char)(cur_ofs)); // lower part of internal buffer address
}
//--------------------------------------------------------
void at45db_cont_write( unsigned char data )
{
ldiv_t pos = ldiv( df_cur_pos, df_page_size );
unsigned int cur_page = pos.quot, cur_ofs = pos.rem;
spi_write( data );
df_cur_pos++;
if( cur_ofs == (df_page_size-1) ) {
// internal buffer full. flush to nvram
at45db_end_op();
df_page_func( B1_TO_MM_PAGE_PROG_WITH_ERASE, cur_page );
at45db_start_write();
}
}
//--------------------------------------------------------
void at45db_end_write( void )
{
at45db_end_op();
ldiv_t pos = ldiv( df_cur_pos, df_page_size );
unsigned int cur_page = pos.quot, cur_ofs = pos.rem;
if( cur_ofs ) {
df_page_func( B1_TO_MM_PAGE_PROG_WITH_ERASE, cur_page );
}
}
//---------------------------------------------------------
int at45db_erase(void)
{
unsigned int i, err = 0;
at45db_init();
for( i=0; i