mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 13:00:42 -07:00
Bootrom: Enable serial number from flash
* Add `.ramfunc` section to bootrom loader script * exclude spiffs functionality from flashmem.h/flashmem.c (allows bootrom to use flashmem) * hide unused tick.h / flashmem.h functions from bootrom (not technically necessary; see comments) * bootrom: add source files, include path, and defines when `PLATFORM_DEFS` defines `WITH_FLASH` * Define `AS_BOOTROM` to indicate code is building for bootrom
This commit is contained in:
parent
5784c8de77
commit
44676bde72
9 changed files with 373 additions and 272 deletions
|
@ -2684,7 +2684,7 @@ void __attribute__((noreturn)) AppMain(void) {
|
||||||
if (FlashInit()) {
|
if (FlashInit()) {
|
||||||
uint64_t flash_uniqueID = 0;
|
uint64_t flash_uniqueID = 0;
|
||||||
if (!Flash_CheckBusy(BUSY_TIMEOUT)) { // OK because firmware was built for devices with flash
|
if (!Flash_CheckBusy(BUSY_TIMEOUT)) { // OK because firmware was built for devices with flash
|
||||||
Flash_UniqueID((uint8_t*)&(flash_uniqueID));
|
Flash_UniqueID((uint8_t*)(&flash_uniqueID));
|
||||||
}
|
}
|
||||||
FlashStop();
|
FlashStop();
|
||||||
usb_update_serial(flash_uniqueID);
|
usb_update_serial(flash_uniqueID);
|
||||||
|
|
|
@ -34,11 +34,17 @@ VERSIONSRC = version_pm3.c
|
||||||
# THUMBSRC :=
|
# THUMBSRC :=
|
||||||
|
|
||||||
# stdint.h provided locally until GCC 4.5 becomes C99 compliant
|
# stdint.h provided locally until GCC 4.5 becomes C99 compliant
|
||||||
APP_CFLAGS = -I. -ffunction-sections -fdata-sections
|
APP_CFLAGS = -I. -ffunction-sections -fdata-sections -DAS_BOOTROM
|
||||||
|
|
||||||
# stack-protect , no-pie reduces size on Gentoo Hardened 8.2 gcc, no-common makes sure uninitialized vars don't end up in COMMON area
|
# stack-protect , no-pie reduces size on Gentoo Hardened 8.2 gcc, no-common makes sure uninitialized vars don't end up in COMMON area
|
||||||
APP_CFLAGS += -fno-stack-protector -fno-pie -fno-common
|
APP_CFLAGS += -fno-stack-protector -fno-pie -fno-common
|
||||||
|
|
||||||
|
ifneq (,$(findstring WITH_FLASH,$(PLATFORM_DEFS)))
|
||||||
|
APP_CFLAGS += -DWITH_FLASH
|
||||||
|
APP_CFLAGS += -I../common_arm
|
||||||
|
THUMBSRC += flashmem.c ticks.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
# Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC
|
# Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC
|
||||||
include ../common_arm/Makefile.common
|
include ../common_arm/Makefile.common
|
||||||
|
|
|
@ -20,6 +20,10 @@
|
||||||
#include "clocks.h"
|
#include "clocks.h"
|
||||||
#include "usb_cdc.h"
|
#include "usb_cdc.h"
|
||||||
|
|
||||||
|
#ifdef WITH_FLASH
|
||||||
|
#include "flashmem.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "proxmark3_arm.h"
|
#include "proxmark3_arm.h"
|
||||||
#define DEBUG 0
|
#define DEBUG 0
|
||||||
|
|
||||||
|
@ -214,8 +218,18 @@ static void flash_mode(void) {
|
||||||
bootrom_unlocked = false;
|
bootrom_unlocked = false;
|
||||||
uint8_t rx[sizeof(PacketCommandOLD)];
|
uint8_t rx[sizeof(PacketCommandOLD)];
|
||||||
g_common_area.command = COMMON_AREA_COMMAND_NONE;
|
g_common_area.command = COMMON_AREA_COMMAND_NONE;
|
||||||
if (!g_common_area.flags.button_pressed && BUTTON_PRESS())
|
if (!g_common_area.flags.button_pressed && BUTTON_PRESS()) {
|
||||||
g_common_area.flags.button_pressed = 1;
|
g_common_area.flags.button_pressed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WITH_FLASH
|
||||||
|
if (FlashInit()) { // checks for existence of flash also ... OK because bootrom was built for devices with flash
|
||||||
|
uint64_t flash_uniqueID = 0;
|
||||||
|
Flash_UniqueID((uint8_t*)&flash_uniqueID);
|
||||||
|
FlashStop();
|
||||||
|
usb_update_serial(flash_uniqueID);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
usb_enable();
|
usb_enable();
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@ SECTIONS
|
||||||
*(.rodata.*)
|
*(.rodata.*)
|
||||||
*(.data)
|
*(.data)
|
||||||
*(.data.*)
|
*(.data.*)
|
||||||
|
*(.ramfunc)
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
} >ram AT>bootphase2 :phase2
|
} >ram AT>bootphase2 :phase2
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,11 @@
|
||||||
|
|
||||||
#include "proxmark3_arm.h"
|
#include "proxmark3_arm.h"
|
||||||
#include "ticks.h"
|
#include "ticks.h"
|
||||||
|
|
||||||
|
#ifndef AS_BOOTROM
|
||||||
#include "dbprint.h"
|
#include "dbprint.h"
|
||||||
|
#endif // AS_BOOTROM
|
||||||
|
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "usb_cdc.h"
|
#include "usb_cdc.h"
|
||||||
|
|
||||||
|
@ -37,197 +41,13 @@
|
||||||
static uint32_t FLASHMEM_SPIBAUDRATE = FLASH_BAUD;
|
static uint32_t FLASHMEM_SPIBAUDRATE = FLASH_BAUD;
|
||||||
#define FASTFLASH (FLASHMEM_SPIBAUDRATE > FLASH_MINFAST)
|
#define FASTFLASH (FLASHMEM_SPIBAUDRATE > FLASH_MINFAST)
|
||||||
|
|
||||||
|
#ifndef AS_BOOTROM
|
||||||
|
|
||||||
void FlashmemSetSpiBaudrate(uint32_t baudrate) {
|
void FlashmemSetSpiBaudrate(uint32_t baudrate) {
|
||||||
FLASHMEM_SPIBAUDRATE = baudrate;
|
FLASHMEM_SPIBAUDRATE = baudrate;
|
||||||
Dbprintf("Spi Baudrate : %dMHz", FLASHMEM_SPIBAUDRATE / 1000000);
|
Dbprintf("Spi Baudrate : %dMHz", FLASHMEM_SPIBAUDRATE / 1000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize
|
|
||||||
bool FlashInit(void) {
|
|
||||||
FlashSetup(FLASHMEM_SPIBAUDRATE);
|
|
||||||
|
|
||||||
StartTicks();
|
|
||||||
|
|
||||||
if (Flash_CheckBusy(BUSY_TIMEOUT)) {
|
|
||||||
StopTicks();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FlashSetup(uint32_t baudrate) {
|
|
||||||
//WDT_DISABLE
|
|
||||||
AT91C_BASE_WDTC->WDTC_WDMR = AT91C_WDTC_WDDIS;
|
|
||||||
|
|
||||||
// PA10 -> SPI_NCS2 chip select (FLASHMEM)
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
|
|
||||||
//reset spi needs double SWRST, see atmel's errata on this case
|
|
||||||
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST;
|
|
||||||
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST;
|
|
||||||
|
|
||||||
// Enable SPI
|
|
||||||
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIEN;
|
|
||||||
|
|
||||||
// NPCS2 Mode 0
|
|
||||||
AT91C_BASE_SPI->SPI_MR =
|
|
||||||
(0 << 24) | // Delay between chip selects = DYLBCS/MCK BUT:
|
|
||||||
// If DLYBCS is less than or equal to six, six MCK periods
|
|
||||||
// will be inserted by default.
|
|
||||||
SPI_PCS(SPI_CSR_NUM) | // Peripheral Chip Select (selects SPI_NCS2 or PA10)
|
|
||||||
(0 << 7) | // Disable LLB (1=MOSI2MISO test mode)
|
|
||||||
(1 << 4) | // Disable ModeFault Protection
|
|
||||||
(0 << 3) | // makes spi operate at MCK (1 is MCK/2)
|
|
||||||
(0 << 2) | // Chip selects connected directly to peripheral
|
|
||||||
AT91C_SPI_PS_FIXED | // Fixed Peripheral Select
|
|
||||||
AT91C_SPI_MSTR; // Master Mode
|
|
||||||
|
|
||||||
uint8_t csaat = 1;
|
|
||||||
uint32_t dlybct = 0;
|
|
||||||
uint8_t ncpha = 1;
|
|
||||||
uint8_t cpol = 0;
|
|
||||||
if (baudrate > FLASH_MINFAST) {
|
|
||||||
baudrate = FLASH_FASTBAUD;
|
|
||||||
//csaat = 0;
|
|
||||||
dlybct = 1500;
|
|
||||||
ncpha = 0;
|
|
||||||
cpol = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
AT91C_BASE_SPI->SPI_CSR[2] =
|
|
||||||
SPI_DLYBCT(dlybct, MCK) | // Delay between Consecutive Transfers (32 MCK periods)
|
|
||||||
SPI_DLYBS(0, MCK) | // Delay Beforce SPCK CLock
|
|
||||||
SPI_SCBR(baudrate, MCK) | // SPI Baudrate Selection
|
|
||||||
AT91C_SPI_BITS_8 | // Bits per Transfer (8 bits)
|
|
||||||
//AT91C_SPI_CSAAT | // Chip Select inactive after transfer
|
|
||||||
// 40.4.6.2 SPI: Bad tx_ready Behavior when CSAAT = 1 and SCBR = 1
|
|
||||||
// If the SPI is programmed with CSAAT = 1, SCBR(baudrate) = 1 and two transfers are performed consecutively on
|
|
||||||
// the same slave with an IDLE state between them, the tx_ready signal does not rise after the second data has been
|
|
||||||
// transferred in the shifter. This can imply for example, that the second data is sent twice.
|
|
||||||
// COLIN :: For now we STILL use CSAAT=1 to avoid having to (de)assert NPCS manually via PIO lines and we deal with delay
|
|
||||||
(csaat << 3) |
|
|
||||||
/* Spi modes:
|
|
||||||
Mode CPOL CPHA NCPHA
|
|
||||||
0 0 0 1 clock normally low read on rising edge
|
|
||||||
1 0 1 0 clock normally low read on falling edge
|
|
||||||
2 1 0 1 clock normally high read on falling edge
|
|
||||||
3 1 1 0 clock normally high read on rising edge
|
|
||||||
However, page 512 of the AT91SAM7Sx datasheet say "Note that in SPI
|
|
||||||
master mode the ATSAM7S512/256/128/64/321/32 does not sample the data
|
|
||||||
(MISO) on the opposite edge where data clocks out (MOSI) but the same
|
|
||||||
edge is used as shown in Figure 36-3 and Figure 36-4." Figure 36-3
|
|
||||||
shows that CPOL=NCPHA=0 or CPOL=NCPHA=1 samples on the rising edge and
|
|
||||||
that the data changes sometime after the rising edge (about 2 ns). To
|
|
||||||
be consistent with normal SPI operation, it is probably safe to say
|
|
||||||
that the data changes on the falling edge and should be sampled on the
|
|
||||||
rising edge. Therefore, it appears that NCPHA should be treated the
|
|
||||||
same as CPHA. Thus:
|
|
||||||
Mode CPOL CPHA NCPHA
|
|
||||||
0 0 0 0 clock normally low read on rising edge
|
|
||||||
1 0 1 1 clock normally low read on falling edge
|
|
||||||
2 1 0 0 clock normally high read on falling edge
|
|
||||||
3 1 1 1 clock normally high read on rising edge
|
|
||||||
Update: for 24MHz, writing is more stable with ncpha=1, else bitflips occur.
|
|
||||||
*/
|
|
||||||
(ncpha << 1) | // Clock Phase data captured on leading edge, changes on following edge
|
|
||||||
(cpol << 0); // Clock Polarity inactive state is logic 0
|
|
||||||
|
|
||||||
// read first, empty buffer
|
|
||||||
if (AT91C_BASE_SPI->SPI_RDR == 0) {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void FlashStop(void) {
|
|
||||||
//Bof
|
|
||||||
//* 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;
|
|
||||||
|
|
||||||
if (g_dbglevel > 3) Dbprintf("FlashStop");
|
|
||||||
|
|
||||||
StopTicks();
|
|
||||||
}
|
|
||||||
|
|
||||||
// send one byte over SPI
|
|
||||||
uint16_t FlashSendByte(uint32_t data) {
|
|
||||||
|
|
||||||
// wait until SPI is ready for transfer
|
|
||||||
//if you are checking for incoming data returned then the TXEMPTY flag is redundant
|
|
||||||
//while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0) {};
|
|
||||||
|
|
||||||
// send the data
|
|
||||||
AT91C_BASE_SPI->SPI_TDR = data;
|
|
||||||
|
|
||||||
//while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TDRE) == 0){};
|
|
||||||
|
|
||||||
// wait receive transfer is complete
|
|
||||||
while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_RDRF) == 0) {};
|
|
||||||
|
|
||||||
// reading incoming data
|
|
||||||
return ((AT91C_BASE_SPI->SPI_RDR) & 0xFFFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
// send last byte over SPI
|
|
||||||
uint16_t FlashSendLastByte(uint32_t data) {
|
|
||||||
return FlashSendByte(data | AT91C_SPI_LASTXFER);
|
|
||||||
}
|
|
||||||
|
|
||||||
// read state register 1
|
|
||||||
uint8_t Flash_ReadStat1(void) {
|
|
||||||
FlashSendByte(READSTAT1);
|
|
||||||
return FlashSendLastByte(0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Flash_CheckBusy(uint32_t timeout) {
|
|
||||||
WaitUS(WINBOND_WRITE_DELAY);
|
|
||||||
StartCountUS();
|
|
||||||
uint32_t _time = GetCountUS();
|
|
||||||
|
|
||||||
if (g_dbglevel > 3) Dbprintf("Checkbusy in...");
|
|
||||||
|
|
||||||
do {
|
|
||||||
if (!(Flash_ReadStat1() & BUSY)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} while ((GetCountUS() - _time) < timeout);
|
|
||||||
|
|
||||||
if (timeout <= (GetCountUS() - _time)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// read ID out
|
// read ID out
|
||||||
uint8_t Flash_ReadID(void) {
|
uint8_t Flash_ReadID(void) {
|
||||||
|
|
||||||
|
@ -250,28 +70,6 @@ uint8_t Flash_ReadID(void) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// read unique id for chip.
|
|
||||||
void Flash_UniqueID(uint8_t *uid) {
|
|
||||||
|
|
||||||
if (Flash_CheckBusy(BUSY_TIMEOUT)) return;
|
|
||||||
|
|
||||||
// reading unique serial number
|
|
||||||
FlashSendByte(UNIQUE_ID);
|
|
||||||
FlashSendByte(0xFF);
|
|
||||||
FlashSendByte(0xFF);
|
|
||||||
FlashSendByte(0xFF);
|
|
||||||
FlashSendByte(0xFF);
|
|
||||||
|
|
||||||
uid[7] = FlashSendByte(0xFF);
|
|
||||||
uid[6] = FlashSendByte(0xFF);
|
|
||||||
uid[5] = FlashSendByte(0xFF);
|
|
||||||
uid[4] = FlashSendByte(0xFF);
|
|
||||||
uid[3] = FlashSendByte(0xFF);
|
|
||||||
uid[2] = FlashSendByte(0xFF);
|
|
||||||
uid[1] = FlashSendByte(0xFF);
|
|
||||||
uid[0] = FlashSendLastByte(0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t Flash_ReadData(uint32_t address, uint8_t *out, uint16_t len) {
|
uint16_t Flash_ReadData(uint32_t address, uint8_t *out, uint16_t len) {
|
||||||
|
|
||||||
if (!FlashInit()) return 0;
|
if (!FlashInit()) return 0;
|
||||||
|
@ -326,7 +124,6 @@ uint16_t Flash_ReadDataCont(uint32_t address, uint8_t *out, uint16_t len) {
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
// Write data can only program one page. A page has 256 bytes.
|
// Write data can only program one page. A page has 256 bytes.
|
||||||
// if len > 256, it might wrap around and overwrite pos 0.
|
// if len > 256, it might wrap around and overwrite pos 0.
|
||||||
|
@ -372,7 +169,6 @@ uint16_t Flash_WriteData(uint32_t address, uint8_t *in, uint16_t len) {
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// length should never be zero
|
// length should never be zero
|
||||||
// Max 256 bytes write
|
// Max 256 bytes write
|
||||||
// out-of-range
|
// out-of-range
|
||||||
|
@ -571,7 +367,7 @@ void Flashmem_print_status(void) {
|
||||||
|
|
||||||
uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
Flash_UniqueID(uid);
|
Flash_UniqueID(uid);
|
||||||
Dbprintf(" Unique ID............... 0x%02X%02X%02X%02X%02X%02X%02X%02X",
|
Dbprintf( " Unique ID............... " _YELLOW_("0x%02X%02X%02X%02X%02X%02X%02X%02X"),
|
||||||
uid[7], uid[6], uid[5], uid[4],
|
uid[7], uid[6], uid[5], uid[4],
|
||||||
uid[3], uid[2], uid[1], uid[0]
|
uid[3], uid[2], uid[1], uid[0]
|
||||||
);
|
);
|
||||||
|
@ -616,4 +412,217 @@ void Flashmem_print_info(void) {
|
||||||
FlashStop();
|
FlashStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // #ifndef AS_BOOTROM
|
||||||
|
|
||||||
|
|
||||||
|
// initialize
|
||||||
|
bool FlashInit(void) {
|
||||||
|
FlashSetup(FLASHMEM_SPIBAUDRATE);
|
||||||
|
|
||||||
|
StartTicks();
|
||||||
|
|
||||||
|
if (Flash_CheckBusy(BUSY_TIMEOUT)) {
|
||||||
|
StopTicks();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read unique id for chip.
|
||||||
|
void Flash_UniqueID(uint8_t *uid) {
|
||||||
|
|
||||||
|
if (Flash_CheckBusy(BUSY_TIMEOUT)) return;
|
||||||
|
|
||||||
|
// reading unique serial number
|
||||||
|
FlashSendByte(UNIQUE_ID);
|
||||||
|
FlashSendByte(0xFF);
|
||||||
|
FlashSendByte(0xFF);
|
||||||
|
FlashSendByte(0xFF);
|
||||||
|
FlashSendByte(0xFF);
|
||||||
|
|
||||||
|
uid[7] = FlashSendByte(0xFF);
|
||||||
|
uid[6] = FlashSendByte(0xFF);
|
||||||
|
uid[5] = FlashSendByte(0xFF);
|
||||||
|
uid[4] = FlashSendByte(0xFF);
|
||||||
|
uid[3] = FlashSendByte(0xFF);
|
||||||
|
uid[2] = FlashSendByte(0xFF);
|
||||||
|
uid[1] = FlashSendByte(0xFF);
|
||||||
|
uid[0] = FlashSendLastByte(0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlashStop(void) {
|
||||||
|
//Bof
|
||||||
|
//* 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;
|
||||||
|
|
||||||
|
#ifndef AS_BOOTROM
|
||||||
|
if (g_dbglevel > 3) Dbprintf("FlashStop");
|
||||||
|
#endif // AS_BOOTROM
|
||||||
|
|
||||||
|
StopTicks();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlashSetup(uint32_t baudrate) {
|
||||||
|
//WDT_DISABLE
|
||||||
|
AT91C_BASE_WDTC->WDTC_WDMR = AT91C_WDTC_WDDIS;
|
||||||
|
|
||||||
|
// PA10 -> SPI_NCS2 chip select (FLASHMEM)
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
|
||||||
|
//reset spi needs double SWRST, see atmel's errata on this case
|
||||||
|
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST;
|
||||||
|
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST;
|
||||||
|
|
||||||
|
// Enable SPI
|
||||||
|
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIEN;
|
||||||
|
|
||||||
|
// NPCS2 Mode 0
|
||||||
|
AT91C_BASE_SPI->SPI_MR =
|
||||||
|
(0 << 24) | // Delay between chip selects = DYLBCS/MCK BUT:
|
||||||
|
// If DLYBCS is less than or equal to six, six MCK periods
|
||||||
|
// will be inserted by default.
|
||||||
|
SPI_PCS(SPI_CSR_NUM) | // Peripheral Chip Select (selects SPI_NCS2 or PA10)
|
||||||
|
(0 << 7) | // Disable LLB (1=MOSI2MISO test mode)
|
||||||
|
(1 << 4) | // Disable ModeFault Protection
|
||||||
|
(0 << 3) | // makes spi operate at MCK (1 is MCK/2)
|
||||||
|
(0 << 2) | // Chip selects connected directly to peripheral
|
||||||
|
AT91C_SPI_PS_FIXED | // Fixed Peripheral Select
|
||||||
|
AT91C_SPI_MSTR; // Master Mode
|
||||||
|
|
||||||
|
uint8_t csaat = 1;
|
||||||
|
uint32_t dlybct = 0;
|
||||||
|
uint8_t ncpha = 1;
|
||||||
|
uint8_t cpol = 0;
|
||||||
|
if (baudrate > FLASH_MINFAST) {
|
||||||
|
baudrate = FLASH_FASTBAUD;
|
||||||
|
//csaat = 0;
|
||||||
|
dlybct = 1500;
|
||||||
|
ncpha = 0;
|
||||||
|
cpol = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
AT91C_BASE_SPI->SPI_CSR[2] =
|
||||||
|
SPI_DLYBCT(dlybct, MCK) | // Delay between Consecutive Transfers (32 MCK periods)
|
||||||
|
SPI_DLYBS(0, MCK) | // Delay Beforce SPCK CLock
|
||||||
|
SPI_SCBR(baudrate, MCK) | // SPI Baudrate Selection
|
||||||
|
AT91C_SPI_BITS_8 | // Bits per Transfer (8 bits)
|
||||||
|
//AT91C_SPI_CSAAT | // Chip Select inactive after transfer
|
||||||
|
// 40.4.6.2 SPI: Bad tx_ready Behavior when CSAAT = 1 and SCBR = 1
|
||||||
|
// If the SPI is programmed with CSAAT = 1, SCBR(baudrate) = 1 and two transfers are performed consecutively on
|
||||||
|
// the same slave with an IDLE state between them, the tx_ready signal does not rise after the second data has been
|
||||||
|
// transferred in the shifter. This can imply for example, that the second data is sent twice.
|
||||||
|
// COLIN :: For now we STILL use CSAAT=1 to avoid having to (de)assert NPCS manually via PIO lines and we deal with delay
|
||||||
|
(csaat << 3) |
|
||||||
|
/* Spi modes:
|
||||||
|
Mode CPOL CPHA NCPHA
|
||||||
|
0 0 0 1 clock normally low read on rising edge
|
||||||
|
1 0 1 0 clock normally low read on falling edge
|
||||||
|
2 1 0 1 clock normally high read on falling edge
|
||||||
|
3 1 1 0 clock normally high read on rising edge
|
||||||
|
However, page 512 of the AT91SAM7Sx datasheet say "Note that in SPI
|
||||||
|
master mode the ATSAM7S512/256/128/64/321/32 does not sample the data
|
||||||
|
(MISO) on the opposite edge where data clocks out (MOSI) but the same
|
||||||
|
edge is used as shown in Figure 36-3 and Figure 36-4." Figure 36-3
|
||||||
|
shows that CPOL=NCPHA=0 or CPOL=NCPHA=1 samples on the rising edge and
|
||||||
|
that the data changes sometime after the rising edge (about 2 ns). To
|
||||||
|
be consistent with normal SPI operation, it is probably safe to say
|
||||||
|
that the data changes on the falling edge and should be sampled on the
|
||||||
|
rising edge. Therefore, it appears that NCPHA should be treated the
|
||||||
|
same as CPHA. Thus:
|
||||||
|
Mode CPOL CPHA NCPHA
|
||||||
|
0 0 0 0 clock normally low read on rising edge
|
||||||
|
1 0 1 1 clock normally low read on falling edge
|
||||||
|
2 1 0 0 clock normally high read on falling edge
|
||||||
|
3 1 1 1 clock normally high read on rising edge
|
||||||
|
Update: for 24MHz, writing is more stable with ncpha=1, else bitflips occur.
|
||||||
|
*/
|
||||||
|
(ncpha << 1) | // Clock Phase data captured on leading edge, changes on following edge
|
||||||
|
(cpol << 0); // Clock Polarity inactive state is logic 0
|
||||||
|
|
||||||
|
// read first, empty buffer
|
||||||
|
if (AT91C_BASE_SPI->SPI_RDR == 0) {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Flash_CheckBusy(uint32_t timeout) {
|
||||||
|
WaitUS(WINBOND_WRITE_DELAY);
|
||||||
|
StartCountUS();
|
||||||
|
uint32_t _time = GetCountUS();
|
||||||
|
|
||||||
|
#ifndef AS_BOOTROM
|
||||||
|
if (g_dbglevel > 3) Dbprintf("Checkbusy in...");
|
||||||
|
#endif // AS_BOOTROM
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (!(Flash_ReadStat1() & BUSY)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} while ((GetCountUS() - _time) < timeout);
|
||||||
|
|
||||||
|
if (timeout <= (GetCountUS() - _time)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read state register 1
|
||||||
|
uint8_t Flash_ReadStat1(void) {
|
||||||
|
FlashSendByte(READSTAT1);
|
||||||
|
return FlashSendLastByte(0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// send one byte over SPI
|
||||||
|
uint16_t FlashSendByte(uint32_t data) {
|
||||||
|
|
||||||
|
// wait until SPI is ready for transfer
|
||||||
|
//if you are checking for incoming data returned then the TXEMPTY flag is redundant
|
||||||
|
//while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0) {};
|
||||||
|
|
||||||
|
// send the data
|
||||||
|
AT91C_BASE_SPI->SPI_TDR = data;
|
||||||
|
|
||||||
|
//while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TDRE) == 0){};
|
||||||
|
|
||||||
|
// wait receive transfer is complete
|
||||||
|
while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_RDRF) == 0) {};
|
||||||
|
|
||||||
|
// reading incoming data
|
||||||
|
return ((AT91C_BASE_SPI->SPI_RDR) & 0xFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// send last byte over SPI
|
||||||
|
uint16_t FlashSendLastByte(uint32_t data) {
|
||||||
|
return FlashSendByte(data | AT91C_SPI_LASTXFER);
|
||||||
|
}
|
|
@ -100,17 +100,67 @@
|
||||||
|
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
void FlashmemSetSpiBaudrate(uint32_t baudrate);
|
|
||||||
bool FlashInit(void);
|
bool FlashInit(void);
|
||||||
void FlashSetup(uint32_t baudrate);
|
void Flash_UniqueID(uint8_t *uid);
|
||||||
void FlashStop(void);
|
void FlashStop(void);
|
||||||
bool Flash_WaitIdle(void);
|
|
||||||
|
void FlashSetup(uint32_t baudrate);
|
||||||
|
bool Flash_CheckBusy(uint32_t timeout);
|
||||||
uint8_t Flash_ReadStat1(void);
|
uint8_t Flash_ReadStat1(void);
|
||||||
uint8_t Flash_ReadStat2(void);
|
|
||||||
uint16_t FlashSendByte(uint32_t data);
|
uint16_t FlashSendByte(uint32_t data);
|
||||||
|
uint16_t FlashSendLastByte(uint32_t data);
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef AS_BOOTROM
|
||||||
|
// Bootrom does not require these functions.
|
||||||
|
// Wrap in #ifndef to avoid accidental bloat of bootrom
|
||||||
|
// Bootrom needs only enough to get uniqueID from flash.
|
||||||
|
// It calls three functions. Full call trees listed:
|
||||||
|
//
|
||||||
|
// FlashInit()
|
||||||
|
// |
|
||||||
|
// \____ FlashSetup()
|
||||||
|
// | \____ leaf
|
||||||
|
// |
|
||||||
|
// \____ StartTicks()
|
||||||
|
// | \____ leaf
|
||||||
|
// |
|
||||||
|
// \____ Flash_CheckBusy() [*]
|
||||||
|
// | \____ WaitUS()
|
||||||
|
// | | \____ WaitTicks()
|
||||||
|
// | | \____ leaf
|
||||||
|
// | |
|
||||||
|
// | \____ StartCountUS()
|
||||||
|
// | | \____ leaf
|
||||||
|
// | |
|
||||||
|
// | \____ GetCountUS()
|
||||||
|
// | | \____ leaf
|
||||||
|
// | |
|
||||||
|
// | \____ Flash_ReadStat1()
|
||||||
|
// | \____ FlashSendByte()
|
||||||
|
// | | \____ leaf
|
||||||
|
// | |
|
||||||
|
// | \____ FlashSendLastByte()
|
||||||
|
// | \____ FlashSendByte()
|
||||||
|
// | \____ leaf
|
||||||
|
// |
|
||||||
|
// \____ StopTicks()
|
||||||
|
// \____ leaf
|
||||||
|
//
|
||||||
|
// Flash_UniqueID()
|
||||||
|
// \____ FlashCheckBusy() (see FlashInit)
|
||||||
|
// \____ FlashSendByteByte() (see FlashInit)
|
||||||
|
// \____ FlashSendByteLastByte() (see FlashInit)
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// FlashStop() [*]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void FlashmemSetSpiBaudrate(uint32_t baudrate);
|
||||||
|
bool Flash_WaitIdle(void);
|
||||||
void Flash_TransferAdresse(uint32_t address);
|
void Flash_TransferAdresse(uint32_t address);
|
||||||
|
|
||||||
bool Flash_CheckBusy(uint32_t timeout);
|
|
||||||
|
|
||||||
void Flash_WriteEnable(void);
|
void Flash_WriteEnable(void);
|
||||||
bool Flash_WipeMemoryPage(uint8_t page);
|
bool Flash_WipeMemoryPage(uint8_t page);
|
||||||
|
@ -119,7 +169,6 @@ bool Flash_Erase4k(uint8_t block, uint8_t sector);
|
||||||
//bool Flash_Erase32k(uint32_t address);
|
//bool Flash_Erase32k(uint32_t address);
|
||||||
bool Flash_Erase64k(uint8_t block);
|
bool Flash_Erase64k(uint8_t block);
|
||||||
|
|
||||||
void Flash_UniqueID(uint8_t *uid);
|
|
||||||
uint8_t Flash_ReadID(void);
|
uint8_t Flash_ReadID(void);
|
||||||
uint16_t Flash_ReadData(uint32_t address, uint8_t *out, uint16_t len);
|
uint16_t Flash_ReadData(uint32_t address, uint8_t *out, uint16_t len);
|
||||||
uint16_t Flash_ReadDataCont(uint32_t address, uint8_t *out, uint16_t len);
|
uint16_t Flash_ReadDataCont(uint32_t address, uint8_t *out, uint16_t len);
|
||||||
|
@ -128,6 +177,8 @@ uint16_t Flash_WriteData(uint32_t address, uint8_t *in, uint16_t len);
|
||||||
uint16_t Flash_WriteDataCont(uint32_t address, uint8_t *in, uint16_t len);
|
uint16_t Flash_WriteDataCont(uint32_t address, uint8_t *in, uint16_t len);
|
||||||
void Flashmem_print_status(void);
|
void Flashmem_print_status(void);
|
||||||
void Flashmem_print_info(void);
|
void Flashmem_print_info(void);
|
||||||
uint16_t FlashSendLastByte(uint32_t data);
|
|
||||||
|
#endif // #ifndef AS_BOOTROM
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -19,9 +19,13 @@
|
||||||
#include "ticks.h"
|
#include "ticks.h"
|
||||||
|
|
||||||
#include "proxmark3_arm.h"
|
#include "proxmark3_arm.h"
|
||||||
#include "dbprint.h"
|
#ifndef AS_BOOTROM
|
||||||
|
#include "dbprint.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef AS_BOOTROM
|
||||||
|
|
||||||
// timer counts in 666ns increments (32/48MHz), rounding applies
|
// timer counts in 666ns increments (32/48MHz), rounding applies
|
||||||
// WARNING: timer can't measure more than 43ms (666ns * 0xFFFF)
|
// WARNING: timer can't measure more than 43ms (666ns * 0xFFFF)
|
||||||
void SpinDelayUsPrecision(int us) {
|
void SpinDelayUsPrecision(int us) {
|
||||||
|
@ -117,40 +121,6 @@ uint32_t RAMFUNC GetTickCountDelta(uint32_t start_ticks) {
|
||||||
return (UINT32_MAX - start_ticks) + stop_ticks;
|
return (UINT32_MAX - start_ticks) + stop_ticks;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
|
||||||
// microseconds timer
|
|
||||||
// -------------------------------------------------------------------------
|
|
||||||
void StartCountUS(void) {
|
|
||||||
AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1);
|
|
||||||
AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE;
|
|
||||||
|
|
||||||
// fast clock
|
|
||||||
// tick=1.5mks
|
|
||||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable
|
|
||||||
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | // MCK(48MHz) / 32
|
|
||||||
AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_ACPA_CLEAR |
|
|
||||||
AT91C_TC_ACPC_SET | AT91C_TC_ASWTRG_SET;
|
|
||||||
AT91C_BASE_TC0->TC_RA = 1;
|
|
||||||
AT91C_BASE_TC0->TC_RC = 0xBFFF + 1; // 0xC000
|
|
||||||
|
|
||||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // timer disable
|
|
||||||
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_XC1; // from timer 0
|
|
||||||
|
|
||||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
|
||||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
|
||||||
|
|
||||||
// Assert a sync signal. This sets all timers to 0 on next active clock edge
|
|
||||||
AT91C_BASE_TCB->TCB_BCR = 1;
|
|
||||||
|
|
||||||
while (AT91C_BASE_TC1->TC_CV > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t RAMFUNC GetCountUS(void) {
|
|
||||||
//return (AT91C_BASE_TC1->TC_CV * 0x8000) + ((AT91C_BASE_TC0->TC_CV / 15) * 10);
|
|
||||||
// By suggestion from PwPiwi, http://www.proxmark.org/forum/viewtopic.php?pid=17548#p17548
|
|
||||||
return ((uint32_t)AT91C_BASE_TC1->TC_CV) * 0x8000 + (((uint32_t)AT91C_BASE_TC0->TC_CV) * 2) / 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// Timer for iso14443 commands. Uses ssp_clk from FPGA
|
// Timer for iso14443 commands. Uses ssp_clk from FPGA
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
@ -246,6 +216,47 @@ uint32_t RAMFUNC GetCountSspClkDelta(uint32_t start) {
|
||||||
return (UINT32_MAX - start) + stop;
|
return (UINT32_MAX - start) + stop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WaitMS(uint32_t ms) {
|
||||||
|
WaitTicks((ms & 0x1FFFFF) * 1500);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // #ifndef AS_BOOTROM
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// microseconds timer
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
void StartCountUS(void) {
|
||||||
|
AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1);
|
||||||
|
AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE;
|
||||||
|
|
||||||
|
// fast clock
|
||||||
|
// tick=1.5mks
|
||||||
|
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable
|
||||||
|
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | // MCK(48MHz) / 32
|
||||||
|
AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_ACPA_CLEAR |
|
||||||
|
AT91C_TC_ACPC_SET | AT91C_TC_ASWTRG_SET;
|
||||||
|
AT91C_BASE_TC0->TC_RA = 1;
|
||||||
|
AT91C_BASE_TC0->TC_RC = 0xBFFF + 1; // 0xC000
|
||||||
|
|
||||||
|
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // timer disable
|
||||||
|
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_XC1; // from timer 0
|
||||||
|
|
||||||
|
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
||||||
|
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
||||||
|
|
||||||
|
// Assert a sync signal. This sets all timers to 0 on next active clock edge
|
||||||
|
AT91C_BASE_TCB->TCB_BCR = 1;
|
||||||
|
|
||||||
|
while (AT91C_BASE_TC1->TC_CV > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t RAMFUNC GetCountUS(void) {
|
||||||
|
//return (AT91C_BASE_TC1->TC_CV * 0x8000) + ((AT91C_BASE_TC0->TC_CV / 15) * 10);
|
||||||
|
// By suggestion from PwPiwi, http://www.proxmark.org/forum/viewtopic.php?pid=17548#p17548
|
||||||
|
return ((uint32_t)AT91C_BASE_TC1->TC_CV) * 0x8000 + (((uint32_t)AT91C_BASE_TC0->TC_CV) * 2) / 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// Timer for bitbanging, or LF stuff when you need a very precis timer
|
// Timer for bitbanging, or LF stuff when you need a very precis timer
|
||||||
// 1us = 1.5ticks
|
// 1us = 1.5ticks
|
||||||
|
@ -282,7 +293,6 @@ void StartTicks(void) {
|
||||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||||
while (AT91C_BASE_TC0->TC_CV > 0);
|
while (AT91C_BASE_TC0->TC_CV > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t GetTicks(void) {
|
uint32_t GetTicks(void) {
|
||||||
uint32_t hi, lo;
|
uint32_t hi, lo;
|
||||||
|
|
||||||
|
@ -307,9 +317,6 @@ void WaitTicks(uint32_t ticks) {
|
||||||
void WaitUS(uint32_t us) {
|
void WaitUS(uint32_t us) {
|
||||||
WaitTicks((us & 0x3FFFFFFF) * 3 / 2);
|
WaitTicks((us & 0x3FFFFFFF) * 3 / 2);
|
||||||
}
|
}
|
||||||
void WaitMS(uint32_t ms) {
|
|
||||||
WaitTicks((ms & 0x1FFFFF) * 1500);
|
|
||||||
}
|
|
||||||
|
|
||||||
// stop clock
|
// stop clock
|
||||||
void StopTicks(void) {
|
void StopTicks(void) {
|
|
@ -26,6 +26,19 @@
|
||||||
#define GET_TICKS GetTicks()
|
#define GET_TICKS GetTicks()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void StartTicks(void);
|
||||||
|
uint32_t GetTicks(void);
|
||||||
|
void WaitUS(uint32_t us);
|
||||||
|
void WaitTicks(uint32_t ticks);
|
||||||
|
void StartCountUS(void);
|
||||||
|
uint32_t RAMFUNC GetCountUS(void);
|
||||||
|
void StopTicks(void);
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef AS_BOOTROM //////////////////////////////////////////////////////////////
|
||||||
|
// Bootrom does not require these functions.
|
||||||
|
// Wrap in #ifndef to avoid accidental bloat of bootrom
|
||||||
|
|
||||||
void SpinDelay(int ms);
|
void SpinDelay(int ms);
|
||||||
void SpinDelayUs(int us);
|
void SpinDelayUs(int us);
|
||||||
void SpinDelayUsPrecision(int us); // precision 0.6us , running for 43ms before
|
void SpinDelayUsPrecision(int us); // precision 0.6us , running for 43ms before
|
||||||
|
@ -34,8 +47,6 @@ void StartTickCount(void);
|
||||||
uint32_t RAMFUNC GetTickCount(void);
|
uint32_t RAMFUNC GetTickCount(void);
|
||||||
uint32_t RAMFUNC GetTickCountDelta(uint32_t start_ticks);
|
uint32_t RAMFUNC GetTickCountDelta(uint32_t start_ticks);
|
||||||
|
|
||||||
void StartCountUS(void);
|
|
||||||
uint32_t RAMFUNC GetCountUS(void);
|
|
||||||
void ResetUSClock(void);
|
void ResetUSClock(void);
|
||||||
void SpinDelayCountUs(uint32_t us);
|
void SpinDelayCountUs(uint32_t us);
|
||||||
|
|
||||||
|
@ -44,12 +55,10 @@ void ResetSspClk(void);
|
||||||
uint32_t RAMFUNC GetCountSspClk(void);
|
uint32_t RAMFUNC GetCountSspClk(void);
|
||||||
uint32_t RAMFUNC GetCountSspClkDelta(uint32_t start);
|
uint32_t RAMFUNC GetCountSspClkDelta(uint32_t start);
|
||||||
|
|
||||||
void StartTicks(void);
|
|
||||||
uint32_t GetTicks(void);
|
|
||||||
void WaitTicks(uint32_t ticks);
|
|
||||||
void WaitUS(uint32_t us);
|
|
||||||
void WaitMS(uint32_t ms);
|
void WaitMS(uint32_t ms);
|
||||||
|
|
||||||
void StopTicks(void);
|
#endif // #ifndef AS_BOOTROM
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -382,7 +382,6 @@ static const char StrSerialNumber[] = {
|
||||||
// offset 18, length 32: 16x unicode chars (8-byte serial as hex characters)
|
// offset 18, length 32: 16x unicode chars (8-byte serial as hex characters)
|
||||||
// ============================
|
// ============================
|
||||||
// total: 50 bytes
|
// total: 50 bytes
|
||||||
|
|
||||||
#define USB_STRING_DESCRIPTOR_SERIAL_NUMBER_LENGTH 50
|
#define USB_STRING_DESCRIPTOR_SERIAL_NUMBER_LENGTH 50
|
||||||
char StrSerialNumber[] = {
|
char StrSerialNumber[] = {
|
||||||
14, // Length is initially identical to non-unique version ... The length updated at boot, if unique serial is available
|
14, // Length is initially identical to non-unique version ... The length updated at boot, if unique serial is available
|
||||||
|
@ -399,6 +398,7 @@ void usb_update_serial(uint64_t newSerialNumber) {
|
||||||
}
|
}
|
||||||
// run this only once per boot... even if it fails to find serial number
|
// run this only once per boot... even if it fails to find serial number
|
||||||
configured = true;
|
configured = true;
|
||||||
|
// reject serial number if all-zero or all-ones
|
||||||
if ((newSerialNumber == 0x0000000000000000) || (newSerialNumber == 0xFFFFFFFFFFFFFFFF)) {
|
if ((newSerialNumber == 0x0000000000000000) || (newSerialNumber == 0xFFFFFFFFFFFFFFFF)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -407,10 +407,14 @@ void usb_update_serial(uint64_t newSerialNumber) {
|
||||||
// Convert uniqueID's eight bytes to 16 unicode characters in the
|
// Convert uniqueID's eight bytes to 16 unicode characters in the
|
||||||
// descriptor and, finally, update the descriptor's length, which
|
// descriptor and, finally, update the descriptor's length, which
|
||||||
// causes the serial number to become visible.
|
// causes the serial number to become visible.
|
||||||
for (uint8_t i = 0; i < 16; i++) {
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
uint8_t nibble = (uint8_t)((newSerialNumber >> (60 - (4*i))) & 0xFu);
|
// order of nibbles chosen to match display order from `hw status`
|
||||||
char c = nibble < 10 ? '0' + nibble : 'A' + (nibble-10);
|
uint8_t nibble1 = (newSerialNumber >> ((8*i) + 4)) & 0xFu; // bitmasks [0xF0, 0xF000, 0xF00000, ... 0xF000000000000000]
|
||||||
StrSerialNumber[18+(2*i)] = c; // [ 18, 20, 22, .., 46, 48 ]
|
uint8_t nibble2 = (newSerialNumber >> ((8*i) + 0)) & 0xFu; // bitmasks [0x0F, 0x0F00, 0x0F0000, ... 0x0F00000000000000]
|
||||||
|
char c1 = nibble1 < 10 ? '0' + nibble1 : 'A' + (nibble1-10);
|
||||||
|
char c2 = nibble2 < 10 ? '0' + nibble2 : 'A' + (nibble2-10);
|
||||||
|
StrSerialNumber[46-(4*i)] = c1; // [ 46, 42, .., 22, 18 ]
|
||||||
|
StrSerialNumber[48-(4*i)] = c2; // [ 48, 44, .., 24, 20 ]
|
||||||
}
|
}
|
||||||
StrSerialNumber[0] = USB_STRING_DESCRIPTOR_SERIAL_NUMBER_LENGTH;
|
StrSerialNumber[0] = USB_STRING_DESCRIPTOR_SERIAL_NUMBER_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue