proxmark3/armsrc/flashmem.c

370 lines
8.4 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "flashmem.h"
#define address_length 3
/* here: use NCPS2 @ PA10: */
#define SPI_CSR_NUM 2 // Chip Select register[] 0,1,2,3 (at91samv512 has 4)
/* PCS_0 for NPCS0, PCS_1 for NPCS1 ... */
#define PCS_0 ((0<<0)|(1<<1)|(1<<2)|(1<<3)) // 0xE - 1110
#define PCS_1 ((1<<0)|(0<<1)|(1<<2)|(1<<3)) // 0xD - 1101
#define PCS_2 ((1<<0)|(1<<1)|(0<<2)|(1<<3)) // 0xB - 1011
#define PCS_3 ((1<<0)|(1<<1)|(1<<2)|(0<<3)) // 0x7 - 0111
/* TODO: ## */
#if (SPI_CSR_NUM == 0)
#define SPI_MR_PCS PCS_0
#elif (SPI_CSR_NUM == 1)
#define SPI_MR_PCS PCS_1
#elif (SPI_CSR_NUM == 2)
#define SPI_MR_PCS PCS_2
#elif (SPI_CSR_NUM == 3)
#define SPI_MR_PCS PCS_3
#else
#error "SPI_CSR_NUM invalid"
// not realy - when using an external address decoder...
// but this code takes over the complete SPI-interace anyway
#endif
/*
读取指令,可以从一个位置开始持续的读,最多能将整块芯片读取完
页写指令每次写入为1-256字节但是不能跨越256字节边界
擦除指令擦除指令后必须将CS拉高否则不会执行
*/
// 初始化Flash
void FlashSetup()
{
// PA1 -> SPI_NCS3 chip select (MEM)
// PA10 -> SPI_NCS2 chip select (LCD)
// PA11 -> SPI_NCS0 chip select (FPGA)
// PA12 -> SPI_MISO Master-In Slave-Out
// PA13 -> SPI_MOSI Master-Out Slave-In
// PA14 -> SPI_SPCK Serial Clock
// Disable PIO control of the following pins, allows use by the SPI peripheral
AT91C_BASE_PIOA->PIO_PDR = GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK | GPIO_NCS2;
// Pull-up Enable
AT91C_BASE_PIOA->PIO_PPUER = GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK | GPIO_NCS2;
// Peripheral A
AT91C_BASE_PIOA->PIO_ASR = GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK;
// Peripheral B
AT91C_BASE_PIOA->PIO_BSR |= GPIO_NCS2;
//enable the SPI Peripheral clock
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SPI);
// Enable SPI
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIEN;
// NPCS2 Mode 0
AT91C_BASE_SPI->SPI_MR =
( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods)
(0xB << 16) | // Peripheral Chip Select (selects SPI_NCS2 or PA10)
( 0 << 7) | // Local Loopback Disabled
( 1 << 4) | // Mode Fault Detection disabled
( 0 << 2) | // Chip selects connected directly to peripheral
( 0 << 1) | // Fixed Peripheral Select
( 1 << 0); // Master Mode
// 8 bit
AT91C_BASE_SPI->SPI_CSR[2] =
( 0 << 24) | // Delay between Consecutive Transfers (32 MCK periods)
( 0 << 16) | // Delay Before SPCK (1 MCK period)
( 6 << 8) | // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud
( 0 << 4) | // Bits per Transfer (8 bits)
( 1 << 3) | // Chip Select inactive after transfer
( 1 << 1) | // Clock Phase data captured on leading edge, changes on following edge
( 0 << 0); // Clock Polarity inactive state is logic 0
// read first, empty buffer
if (AT91C_BASE_SPI->SPI_RDR == 0)
;
}
// end up SPI
void FlashStop(void)
{
//* Reset all the Chip Select register
AT91C_BASE_SPI->SPI_CSR[0] = 0;
AT91C_BASE_SPI->SPI_CSR[1] = 0;
AT91C_BASE_SPI->SPI_CSR[2] = 0;
AT91C_BASE_SPI->SPI_CSR[3] = 0;
// Reset the SPI mode
AT91C_BASE_SPI->SPI_MR = 0;
// Disable all interrupts
AT91C_BASE_SPI->SPI_IDR = 0xFFFFFFFF;
// SPI disable
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIDIS;
Dbprintf("FlashStop");
}
// 发送一个字节 send one byte
uint16_t FlashSendByte(uint32_t data)
{
uint16_t incoming = 0;
WDT_HIT();
// wait until SPI is ready for transfer
while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0) {};
// send the data
AT91C_BASE_SPI->SPI_TDR = data;
// wait recive transfer is complete
while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_RDRF) == 0)
WDT_HIT();
// reading incoming data
incoming = ((AT91C_BASE_SPI->SPI_RDR) & 0xFFFF);
return incoming;
}
// send last one byte
uint16_t FlashSendLastByte(uint32_t data) {
return FlashSendByte(data | AT91C_SPI_LASTXFER);
}
// Read state register 1
uint8_t Flash_ReadStat1(void) {
FlashSendByte(READSTAT1);
uint8_t stat1 = FlashSendLastByte(0xFF);
Dbprintf("stat1 [%02x]", stat1);
return stat1;
}
// Read state register 2
uint8_t Flash_ReadStat2(void) {
FlashSendByte(READSTAT2);
uint8_t stat2 = FlashSendLastByte(0xFF);
Dbprintf("stat2 [%02x]", stat2);
return stat2;
}
// Determine whether FLASHMEM is busy
bool Flash_CheckBusy(uint16_t times){
bool bRet = (Flash_ReadStat1() & BUSY);
if (!bRet || !times || !(times--))
return bRet;
while (times)
{
WDT_HIT();
SpinDelayUs(1000); // wait 1ms
bRet = (Flash_ReadStat1() & BUSY);
if (!bRet)
break;
times--;
}
return bRet;
}
// read ID out
uint8_t Flash_ReadID(void) {
if (Flash_CheckBusy(1000))
return 0;
// Manufacture ID / device ID
uint8_t t0 = FlashSendByte(ID);
uint8_t t1 = FlashSendByte(0x00);
uint8_t t2 = FlashSendByte(0x00);
uint8_t t3 = FlashSendByte(0x00);
uint8_t man_id = FlashSendByte(0xFF);
uint8_t dev_id = FlashSendLastByte(0xFF);
Dbprintf(" [%02x] %02x %02x %02x | %02x %02x", t0,t1,t2,t3, man_id, dev_id);
//WINBOND_MANID
if ( man_id == WINBOND_MANID ) {
Dbprintf("Correct read of Manucaturer ID [%02x] == %02x", man_id, WINBOND_MANID);
}
if (man_id != WINBOND_MANID)
dev_id = 0;
return dev_id;
}
// 读取数据 address buffer length
uint8_t Flash_ReadDate(uint32_t Address, uint8_t *Buffer, uint16_t len)
{
// length should never be zero
if (!len || Flash_CheckBusy(1000))
return 0;
FlashSendByte(READDATA);
FlashSendByte((Address >> 16) & 0xFF);
FlashSendByte((Address >> 8) & 0xFF);
FlashSendByte((Address >> 0) & 0xFF);
uint16_t i = 0;
for (; i < (len - 1); i++)
Buffer[i] = FlashSendByte(0xFF);
Buffer[i] = FlashSendLastByte(0xFF);
return len;
}
// 写入数据 地址 address 缓冲区 buffer 长度length
uint8_t Flash_WriteDate(uint32_t Address, uint8_t *Buffer, uint16_t len)
{
// length should never be zero
if (!len || Flash_CheckBusy(1000))
return 0;
// 不能跨越 256 字节边界
if (((Address & 255) + len) > 256)
return 0;
FlashSendByte(PAGEPROG);
FlashSendByte((Address >> 16) & 0xFF);
FlashSendByte((Address >> 8) & 0xFF);
FlashSendByte((Address >> 0) & 0xFF);
uint16_t i = 0;
for (; i < (len - 1); i++)
FlashSendByte(Buffer[i]);
FlashSendLastByte(Buffer[i]);
return len;
}
// enable the flash write
void Flash_WriteEnable()
{
FlashSendLastByte(WRITEENABLE);
Dbprintf("Flash WriteEnabled");
}
// erase 4K at one time
bool Flash_Erase4k(uint32_t Address)
{
if (Address & (4096 - 1))
{
Dbprintf("Flash_Erase4k : Address is not align at 4096");
return false;
}
FlashSendByte(SECTORERASE);
FlashSendByte((Address >> 16) & 0xFF);
FlashSendByte((Address >> 8) & 0xFF);
FlashSendLastByte((Address >> 0) & 0xFF);
return true;
}
// erase 32K at one time
bool Flash_Erase32k(uint32_t Address)
{
if (Address & (32*1024 - 1))
{
Dbprintf("Flash_Erase4k : Address is not align at 4096");
return false;
}
FlashSendByte(BLOCK32ERASE);
FlashSendByte((Address >> 16) & 0xFF);
FlashSendByte((Address >> 8) & 0xFF);
FlashSendLastByte((Address >> 0) & 0xFF);
return true;
}
// erase 64k at one time
bool Flash_Erase64k(uint32_t Address)
{
if (Address & (64*1024 - 1))
{
Dbprintf("Flash_Erase4k : Address is not align at 4096");
return false;
}
FlashSendByte(BLOCK64ERASE);
FlashSendByte((Address >> 16) & 0xFF);
FlashSendByte((Address >> 8) & 0xFF);
FlashSendLastByte((Address >> 0) & 0xFF);
return true;
}
// erase all
void Flash_EraseChip(void)
{
FlashSendLastByte(CHIPERASE);
}
// initialize
bool FlashInit(void)
{
FlashSetup();
if (Flash_CheckBusy(1000))
return false;
Dbprintf("FlashInit");
return true;
}
void EXFLASH_TEST(void)
{
uint8_t Data[256] = { 0x00, 0x01, 0x02 };
uint8_t Data2[256] = { 0x00};
uint32_t FlashSize = 0;
if (!FlashInit()) return;
Flash_ReadStat1();
switch (Flash_ReadID())
{
case 0x11: // W25X20CL
FlashSize = 2048*1024;
break;
case 0x10: // W25X10CL
FlashSize = 1024*1024;
break;
case 0x05: // W25X05CL
FlashSize = 512*1024;
break;
}
Dbprintf("Flash Size = %dk", FlashSize / 1024);
if (FlashSize != 2048*1024)
return;
Dbprintf("Flash test write: 012 to 0x00 0x01 0x02");
Flash_WriteEnable();
Flash_Erase4k(0x00);
if (Flash_CheckBusy(1000))
{
Dbprintf("Flash_Erase4k CheckBusy Error.");
return;
}
Flash_ReadDate(0, Data2, 256);
Flash_WriteEnable();
Flash_WriteDate(0x12, Data, sizeof(Data)); // this will never run, cuz out of 256byte boundary
Flash_WriteDate(0x12, Data, 3);
if (Flash_CheckBusy(1000))
{
Dbprintf("Flash_WriteDate CheckBusy Error.");
return;
}
Flash_ReadDate(0, Data2, 256);
FlashStop();
}