mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-03-29 16:33:07 +08:00
370 lines
8.4 KiB
C
370 lines
8.4 KiB
C
#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();
|
||
}
|
||
|