Собрался купить для очереного проекта память AT45DB161 в корпусе SO8-300, но не смог по причине отсутсвия у поставщиков :( хотя у одного поставщика нашел по цене в 600 рублей.
Решил глянуть что есть у ST Microelectronics, и как оказалось не зря :)
Есть у них серия микросхем в небольших корпусах, до двух мегабайт в SO-8, выше в SO16-300.
На пробу купил на два мегабайта M25P16, всего за 45 рублей.
Вся область разбита на сектора, сектора в свою очередь на страницы по 256 байт.
Не понравилось то что стереть можно либо всю флешку, либо сектор :( хотелось бы иметь возможность стирать страницу.
Для теста подключил к свободным ножкам МК и простым “ножко-дрыганьем” записал и считал пару страниц.
Команды:
enum M25P16_Command
{
M25P16_WRITE_ENABLE = 0x06 ,
M25P16_WRITE_DISABLE = 0x04 ,
M25P16_READ_IDENTEFICATION = 0x9F ,
M25P16_READ_STATUS_REGISTER = 0x05 ,
M25P16_WRITE_STATUS_REGISTER = 0x01 ,
M25P16_READ = 0x03 ,
M25P16_READ_FAST = 0x0B ,
M25P16_PAGE_PROGAM = 0x02 ,
M25P16_SECTOR_ERASE = 0xD8 ,
M25P16_BULK_ERASE = 0xC7 ,
M25P16_DEEP_POWER_DOWN = 0xB9 ,
M25P16_RELEASE_FROM_POWER_DOWN = 0xAB ,
};
Тестовый кусочек кода:
void m25p16_test ( void )
{
for ( i = 0 ; i & amp ; lt ; 256 ; i ++ )
buffer [ i ] = i ;
// разрешаем запись
m25p16_write_enable ();
// стираем
m25p16_bulk_erase ();
// ожидаем
while ( m25p16_read_status () & amp ; amp ; 0x01 )
{
}
// разрешаем запись
m25p16_write_enable ();
// пишем
m25p16_page_write ( 0 , & amp ; amp ; buffer [ 0 ]);
// ожидаем
while ( m25p16_read_status () & amp ; amp ; 0x01 )
{
}
// разрешаем запись
m25p16_write_enable ();
// пишем
m25p16_page_write ( 1 , & amp ; amp ; buffer [ 0 ]);
// ожидаем
while ( m25p16_read_status () & amp ; amp ; 0x01 )
{
}
// читаем
m25p16_page_read ( 0 , & amp ; amp ; buffer [ 0 ]);
for ( i = 0 ; i & amp ; lt ; 256 ; i ++ )
_DBH ( buffer [ i ]);
// читаем
m25p16_page_read ( 1 , & amp ; amp ; buffer [ 0 ]);
for ( i = 0 ; i & amp ; lt ; 256 ; i ++ )
_DBH ( buffer [ i ]);
}
Чтение регистра статуса:
uint8_t m25p16_read_status ( void )
{
uint8_t status ;
PIN_M25P16_CS_ON ();
m25p16_io_write ( M25P16_READ_STATUS_REGISTER );
status = m25p16_io_read ();
PIN_M25P16_CS_OFF ();
return status ;
}
Перед стиранием или программированием необходимо разрешить запись:
void m25p16_write_enable ( void )
{
PIN_M25P16_CS_ON ();
m25p16_io_write ( M25P16_WRITE_ENABLE );
PIN_M25P16_CS_OFF ();
}
и если передумали отменить:
void m25p16_write_disable ( void )
{
PIN_M25P16_CS_ON ();
m25p16_io_write ( M25P16_WRITE_DISABLE );
PIN_M25P16_CS_OFF ();
}
Запись одной страницы:
void m25p16_page_write ( uint16_t page_address , uint8_t * buffer )
{
uint8_t byte_number ;
PIN_M25P16_CS_ON ();
m25p16_io_write ( M25P16_PAGE_PROGAM );
m25p16_io_write ( page_address & amp ; gt ; & amp ; gt ; 8 );
m25p16_io_write ( page_address & amp ; gt ; & amp ; gt ; 0 );
m25p16_io_write ( 0x00 );
for ( byte_number = 0 ; byte_number ++ & amp ; lt ; 255 ;)
{
m25p16_io_write ( * buffer ++ );
}
m25p16_io_write ( * buffer );
PIN_M25P16_CS_OFF ();
}
Чтение одной страницы:
void m25p16_page_read ( uint16_t page_address , uint8_t * buffer )
{
uint8_t byte_number ;
PIN_M25P16_CS_ON ();
m25p16_io_write ( M25P16_READ );
m25p16_io_write ( page_address & amp ; gt ; & amp ; gt ; 8 );
m25p16_io_write ( page_address & amp ; gt ; & amp ; gt ; 0 );
m25p16_io_write ( 0 );
for ( byte_number = 0 ; byte_number ++ & amp ; lt ; 255 ;)
{
* buffer ++ = m25p16_io_read ();
}
* buffer = m25p16_io_read ();
PIN_M25P16_CS_OFF ();
}
Стереть всю флешку:
void m25p16_bulk_erase ( void )
{
PIN_M25P16_CS_ON ();
m25p16_io_write ( M25P16_BULK_ERASE );
PIN_M25P16_CS_OFF ();
}
Стереть один сектор:
void m25p16_sector_erase ( uint8_t sector_address )
{
PIN_M25P16_CS_ON ();
m25p16_io_write ( M25P16_SECTOR_ERASE );
m25p16_io_write ( sector_address );
m25p16_io_write ( 0x00 );
m25p16_io_write ( 0x00 );
PIN_M25P16_CS_OFF ();
}
Обмен данными:
void m25p16_io_write ( uint8_t data )
{
uint8_t bit_number ;
for ( bit_number = 8 ; bit_number -- & amp ; gt ; 0 ;)
{
PIN_M25P16_CLK_OFF ();
if (( data & amp ; amp ; 0x80 ) == 0 )
{
PIN_M25P16_DI_OFF ();
}
else
{
PIN_M25P16_DI_ON ();
}
PIN_M25P16_CLK_ON ();
data = data & amp ; lt ; & amp ; lt ; 1 ;
}
PIN_M25P16_CLK_OFF ();
}
uint8_t m25p16_io_read ( void )
{
uint8_t bit_number ;
uint8_t data = 0 ;
for ( bit_number = 8 ; bit_number -- & amp ; gt ; 0 ;)
{
PIN_M25P16_CLK_OFF ();
data = data & amp ; lt ; & amp ; lt ; 1 ;
PIN_M25P16_CLK_ON ();
if ( PIN_M25P16_DO_SIGNAL ())
data |= 1 ;
}
PIN_M25P16_CLK_OFF ();
return data ;
}