FIX: This commit fixes the broken LF since I change the spindelay calls. The original problem is that spindelayus calls is incremented with21.3us each step, making it very hard to find exact timings found in the datasheets for T55x7, HID etcetc. When @marshmellow and I looked into this 2014, I had this on my back of my mind but forgot it since I didn't know how the source code / pm3 worked. This behavior in spindelayus has given the bit-period for ON/OFF measured in (us) very hard to find. Its kind of magic that it worked so far so good. Well until I started to look into the "hf legic" bitbanging ASK ON/OFF keying and that one needs a much more precis timer. Same goes for the PCF7931 code.

I've added a precise timer in the new files ticks.c and moved some older stuff from util.c to have a solid base for this.
UNTESTED,  and the timings measured for t55x7 in lfops.c and other parts has not been adjusted to this "correct" timer.
This commit is contained in:
iceman1001 2016-09-23 16:35:26 +02:00
parent 8e4021fddc
commit 24c49d36ba
4 changed files with 67 additions and 89 deletions

View file

@ -60,19 +60,19 @@ void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint32_t periods, uint3
while(*command != '\0' && *command != ' ') { while(*command != '\0' && *command != ' ') {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_D_OFF(); LED_D_OFF();
SpinDelayUs(delay_off); WaitUS(delay_off);
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc.divisor); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc.divisor);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
LED_D_ON(); LED_D_ON();
if(*(command++) == '0') if(*(command++) == '0')
SpinDelayUs(period_0); // ICEMAN: problem with (us) clock is 21.3us increments WaitUS(period_0);
else else
SpinDelayUs(period_1); // ICEMAN: problem with (us) clock is 21.3us increments WaitUS(period_1);
} }
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_D_OFF(); LED_D_OFF();
SpinDelayUs(delay_off); // ICEMAN: problem with (us) clock is 21.3us increments WaitUS(delay_off);
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc.divisor); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc.divisor);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
@ -225,20 +225,20 @@ void WriteTIbyte(uint8_t b)
// modulate 8 bits out to the antenna // modulate 8 bits out to the antenna
for (i=0; i<8; i++) for (i=0; i<8; i++)
{ {
if (b&(1<<i)) { if ( b & ( 1 << i ) ) {
// stop modulating antenna // stop modulating antenna 1ms
LOW(GPIO_SSC_DOUT); LOW(GPIO_SSC_DOUT);
SpinDelayUs(1000); // ICEMAN: problem with (us) clock is 21.3us increments WaitUS(1000);
// modulate antenna // modulate antenna 1ms
HIGH(GPIO_SSC_DOUT); HIGH(GPIO_SSC_DOUT);
SpinDelayUs(1000); // ICEMAN: problem with (us) clock is 21.3us increments WaitUS(1000);
} else { } else {
// stop modulating antenna // stop modulating antenna 1ms
LOW(GPIO_SSC_DOUT); LOW(GPIO_SSC_DOUT);
SpinDelayUs(300); // ICEMAN: problem with (us) clock is 21.3us increments WaitUS(300);
// modulate antenna // modulate antenna 1m
HIGH(GPIO_SSC_DOUT); HIGH(GPIO_SSC_DOUT);
SpinDelayUs(1700); // ICEMAN: problem with (us) clock is 21.3us increments WaitUS(1700);
} }
} }
} }
@ -437,7 +437,7 @@ void SimulateTagLowFrequency(int period, int gap, int ledcontrol)
if (gap) { if (gap) {
WDT_HIT(); WDT_HIT();
SHORT_COIL(); SHORT_COIL();
SpinDelayUs(gap); // ICEMAN: problem with (us) clock is 21.3us increments WaitUS(gap);
} }
} }
} }
@ -1138,13 +1138,12 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol)
void TurnReadLFOn(int delay) { void TurnReadLFOn(int delay) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
// Give it a bit of time for the resonant antenna to settle.
// measure antenna strength. // measure antenna strength.
//int adcval = ((MAX_ADC_LF_VOLTAGE * AvgAdc(ADC_CHAN_LF)) >> 10); //int adcval = ((MAX_ADC_LF_VOLTAGE * AvgAdc(ADC_CHAN_LF)) >> 10);
// where to save it
// Give it a bit of time for the resonant antenna to settle.
SpinDelayCountUs(delay); // ICEMAN: problem with (us) clock is 21.3us increments WaitUS(delay);
} }
// Write one bit to card // Write one bit to card
@ -1154,7 +1153,7 @@ void T55xxWriteBit(int bit) {
else else
TurnReadLFOn(WRITE_1); TurnReadLFOn(WRITE_1);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelayCountUs(WRITE_GAP); // ICEMAN: problem with (us) clock is 21.3us increments WaitUS(WRITE_GAP);
} }
// Send T5577 reset command then read stream (see if we can identify the start of the stream) // Send T5577 reset command then read stream (see if we can identify the start of the stream)
@ -1168,7 +1167,7 @@ void T55xxResetRead(void) {
// Trigger T55x7 in mode. // Trigger T55x7 in mode.
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelayCountUs(START_GAP); // ICEMAN: problem with (us) clock is 21.3us increments WaitUS(START_GAP);
// reset tag - op code 00 // reset tag - op code 00
T55xxWriteBit(0); T55xxWriteBit(0);
@ -1198,7 +1197,7 @@ void T55xxWriteBlockExt(uint32_t Data, uint8_t Block, uint32_t Pwd, uint8_t arg)
// Trigger T55x7 in mode. // Trigger T55x7 in mode.
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelayCountUs(START_GAP); // ICEMAN: problem with (us) clock is 21.3us increments WaitUS(START_GAP);
// Opcode 10 // Opcode 10
T55xxWriteBit(1); T55xxWriteBit(1);
@ -1258,7 +1257,7 @@ void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd) {
// Trigger T55x7 Direct Access Mode with start gap // Trigger T55x7 Direct Access Mode with start gap
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelayCountUs(START_GAP); // ICEMAN: problem with (us) clock is 21.3us increments WaitUS(START_GAP);
// Opcode 1[page] // Opcode 1[page]
T55xxWriteBit(1); T55xxWriteBit(1);
@ -1298,7 +1297,7 @@ void T55xxWakeUp(uint32_t Pwd){
// Trigger T55x7 Direct Access Mode // Trigger T55x7 Direct Access Mode
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelayCountUs(START_GAP); // ICEMAN: problem with (us) clock is 21.3us increments WaitUS(START_GAP);
// Opcode 10 // Opcode 10
T55xxWriteBit(1); T55xxWriteBit(1);
@ -1629,20 +1628,20 @@ void SendForward(uint8_t fwd_bit_count) {
fwd_bit_sz--; //prepare next bit modulation fwd_bit_sz--; //prepare next bit modulation
fwd_write_ptr++; fwd_write_ptr++;
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
SpinDelayUs(55*8); //55 cycles off (8us each)for 4305 // ICEMAN: problem with (us) clock is 21.3us increments WaitUS(55*8); //55 cycles off (8us each)for 4305 // ICEMAN: problem with (us) clock is 21.3us increments
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);//field on FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);//field on
SpinDelayUs(16*8); //16 cycles on (8us each) // ICEMAN: problem with (us) clock is 21.3us increments WaitUS(16*8); //16 cycles on (8us each) // ICEMAN: problem with (us) clock is 21.3us increments
// now start writting // now start writting
while(fwd_bit_sz-- > 0) { //prepare next bit modulation while(fwd_bit_sz-- > 0) { //prepare next bit modulation
if(((*fwd_write_ptr++) & 1) == 1) if(((*fwd_write_ptr++) & 1) == 1)
SpinDelayUs(32*8); //32 cycles at 125Khz (8us each) // ICEMAN: problem with (us) clock is 21.3us increments WaitUS(32*8); //32 cycles at 125Khz (8us each) // ICEMAN: problem with (us) clock is 21.3us increments
else { else {
//These timings work for 4469/4269/4305 (with the 55*8 above) //These timings work for 4469/4269/4305 (with the 55*8 above)
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
SpinDelayUs(23*8); //16-4 cycles off (8us each) // ICEMAN: problem with (us) clock is 21.3us increments WaitUS(23*8); //16-4 cycles off (8us each) // ICEMAN: problem with (us) clock is 21.3us increments
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);//field on FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);//field on
SpinDelayUs(9*8); //16 cycles on (8us each) // ICEMAN: problem with (us) clock is 21.3us increments WaitUS(9*8); //16 cycles on (8us each) // ICEMAN: problem with (us) clock is 21.3us increments
} }
} }
} }

View file

@ -6,17 +6,11 @@
// Miscellaneous routines for low frequency sampling. // Miscellaneous routines for low frequency sampling.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "proxmark3.h"
#include "apps.h"
#include "util.h"
#include "string.h"
#include "usb_cdc.h" // for usb_poll_validate_length
#include "lfsampling.h" #include "lfsampling.h"
sample_config config = { 1, 8, 1, 95, 0 } ; sample_config config = { 1, 8, 1, 95, 0 } ;
void printConfig() void printConfig() {
{
Dbprintf("LF Sampling config: "); Dbprintf("LF Sampling config: ");
Dbprintf(" [q] divisor: %d ", config.divisor); Dbprintf(" [q] divisor: %d ", config.divisor);
Dbprintf(" [b] bps: %d ", config.bits_per_sample); Dbprintf(" [b] bps: %d ", config.bits_per_sample);
@ -37,8 +31,7 @@ void printConfig()
* @brief setSamplingConfig * @brief setSamplingConfig
* @param sc * @param sc
*/ */
void setSamplingConfig(sample_config *sc) void setSamplingConfig(sample_config *sc) {
{
if(sc->divisor != 0) config.divisor = sc->divisor; if(sc->divisor != 0) config.divisor = sc->divisor;
if(sc->bits_per_sample != 0) config.bits_per_sample = sc->bits_per_sample; if(sc->bits_per_sample != 0) config.bits_per_sample = sc->bits_per_sample;
if(sc->decimation != 0) config.decimation = sc->decimation; if(sc->decimation != 0) config.decimation = sc->decimation;
@ -51,8 +44,7 @@ void setSamplingConfig(sample_config *sc)
printConfig(); printConfig();
} }
sample_config* getSamplingConfig() sample_config* getSamplingConfig() {
{
return &config; return &config;
} }
@ -67,8 +59,7 @@ typedef struct {
* @param stream * @param stream
* @param bit * @param bit
*/ */
void pushBit( BitstreamOut* stream, uint8_t bit) void pushBit( BitstreamOut* stream, uint8_t bit) {
{
int bytepos = stream->position >> 3; // divide by 8 int bytepos = stream->position >> 3; // divide by 8
int bitpos = stream->position & 7; int bitpos = stream->position & 7;
*(stream->buffer+bytepos) |= (bit > 0) << (7 - bitpos); *(stream->buffer+bytepos) |= (bit > 0) << (7 - bitpos);
@ -83,8 +74,7 @@ void pushBit( BitstreamOut* stream, uint8_t bit)
* 0 or 95 ==> 125 KHz * 0 or 95 ==> 125 KHz
* *
**/ **/
void LFSetupFPGAForADC(int divisor, bool lf_field) void LFSetupFPGAForADC(int divisor, bool lf_field) {
{
FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
if ( (divisor == 1) || (divisor < 0) || (divisor > 255) ) if ( (divisor == 1) || (divisor < 0) || (divisor > 255) )
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz
@ -101,6 +91,9 @@ void LFSetupFPGAForADC(int divisor, bool lf_field)
SpinDelay(50); SpinDelay(50);
// Now set up the SSC to get the ADC samples that are now streaming at us. // Now set up the SSC to get the ADC samples that are now streaming at us.
FpgaSetupSsc(); FpgaSetupSsc();
// start a 1.5ticks is 1us
StartTicks();
} }
/** /**
@ -118,8 +111,7 @@ void LFSetupFPGAForADC(int divisor, bool lf_field)
* @param silent - is true, now outputs are made. If false, dbprints the status * @param silent - is true, now outputs are made. If false, dbprints the status
* @return the number of bits occupied by the samples. * @return the number of bits occupied by the samples.
*/ */
uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averaging, int trigger_threshold,bool silent) uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averaging, int trigger_threshold,bool silent) {
{
//bigbuf, to hold the aquired raw data signal //bigbuf, to hold the aquired raw data signal
uint8_t *dest = BigBuf_get_addr(); uint8_t *dest = BigBuf_get_addr();
uint16_t bufsize = BigBuf_max_traceLen(); uint16_t bufsize = BigBuf_max_traceLen();
@ -210,12 +202,10 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag
* @param silent * @param silent
* @return number of bits sampled * @return number of bits sampled
*/ */
uint32_t DoAcquisition_default(int trigger_threshold, bool silent) uint32_t DoAcquisition_default(int trigger_threshold, bool silent) {
{
return DoAcquisition(1,8,0,trigger_threshold,silent); return DoAcquisition(1,8,0,trigger_threshold,silent);
} }
uint32_t DoAcquisition_config( bool silent) uint32_t DoAcquisition_config( bool silent) {
{
return DoAcquisition(config.decimation return DoAcquisition(config.decimation
,config.bits_per_sample ,config.bits_per_sample
,config.averaging ,config.averaging
@ -223,11 +213,10 @@ uint32_t DoAcquisition_config( bool silent)
,silent); ,silent);
} }
uint32_t ReadLF(bool activeField, bool silent) uint32_t ReadLF(bool activeField, bool silent) {
{ if (!silent)
if (!silent) printConfig(); printConfig();
LFSetupFPGAForADC(config.divisor, activeField); LFSetupFPGAForADC(config.divisor, activeField);
// Now call the acquisition routine
return DoAcquisition_config(silent); return DoAcquisition_config(silent);
} }
@ -235,8 +224,7 @@ uint32_t ReadLF(bool activeField, bool silent)
* Initializes the FPGA for reader-mode (field on), and acquires the samples. * Initializes the FPGA for reader-mode (field on), and acquires the samples.
* @return number of bits sampled * @return number of bits sampled
**/ **/
uint32_t SampleLF(bool printCfg) uint32_t SampleLF(bool printCfg) {
{
return ReadLF(true, printCfg); return ReadLF(true, printCfg);
} }
/** /**
@ -253,23 +241,22 @@ uint32_t SnoopLF() {
**/ **/
void doT55x7Acquisition(size_t sample_size) { void doT55x7Acquisition(size_t sample_size) {
#define T55xx_READ_UPPER_THRESHOLD 128+60 // 60 grph #define T55xx_READ_UPPER_THRESHOLD 128+40 // 60 grph
#define T55xx_READ_LOWER_THRESHOLD 128-60 // -60 grph #define T55xx_READ_LOWER_THRESHOLD 128-40 // -60 grph
#define T55xx_READ_TOL 5 #define T55xx_READ_TOL 2
uint8_t *dest = BigBuf_get_addr(); uint8_t *dest = BigBuf_get_addr();
uint16_t bufsize = BigBuf_max_traceLen(); uint16_t bufsize = BigBuf_max_traceLen();
if ( bufsize > sample_size ) if ( bufsize > sample_size )
bufsize = sample_size; bufsize = sample_size;
uint16_t i = 0; uint8_t curSample = 0, lastSample = 0;
uint16_t i = 0, skipCnt = 0;
bool startFound = false; bool startFound = false;
bool highFound = false; bool highFound = false;
bool lowFound = false; bool lowFound = false;
uint8_t curSample = 0;
uint8_t lastSample = 0;
uint16_t skipCnt = 0;
while(!BUTTON_PRESS() && !usb_poll_validate_length() && skipCnt < 1000 && (i < bufsize) ) { while(!BUTTON_PRESS() && !usb_poll_validate_length() && skipCnt < 1000 && (i < bufsize) ) {
WDT_HIT(); WDT_HIT();
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
@ -301,7 +288,7 @@ void doT55x7Acquisition(size_t sample_size) {
// skip until first high samples begin to change // skip until first high samples begin to change
if (startFound || curSample > T55xx_READ_LOWER_THRESHOLD+T55xx_READ_TOL){ if (startFound || curSample > T55xx_READ_LOWER_THRESHOLD + T55xx_READ_TOL){
// if just found start - recover last sample // if just found start - recover last sample
if (!startFound) { if (!startFound) {
dest[i++] = lastSample; dest[i++] = lastSample;

View file

@ -1,6 +1,13 @@
#ifndef LFSAMPLING_H #ifndef LFSAMPLING_H
#define LFSAMPLING_H #define LFSAMPLING_H
#include "proxmark3.h"
#include "apps.h"
#include "util.h"
#include "string.h"
#include "usb_cdc.h" // for usb_poll_validate_length
#include "ticks.h" // for StartTicks
/** /**
* acquisition of T55x7 LF signal. Similart to other LF, but adjusted with @marshmellows thresholds * acquisition of T55x7 LF signal. Similart to other LF, but adjusted with @marshmellows thresholds
* the data is collected in BigBuf. * the data is collected in BigBuf.

View file

@ -48,7 +48,6 @@ void SpinDelay(int ms) {
// SpinDelay(1000); // SpinDelay(1000);
// ti = GetTickCount() - ti; // ti = GetTickCount() - ti;
// Dbprintf("timer(1s): %d t=%d", ti, GetTickCount()); // Dbprintf("timer(1s): %d t=%d", ti, GetTickCount());
void StartTickCount() { void StartTickCount() {
// This timer is based on the slow clock. The slow clock frequency is between 22kHz and 40kHz. // This timer is based on the slow clock. The slow clock frequency is between 22kHz and 40kHz.
// We can determine the actual slow clock frequency by looking at the Main Clock Frequency Register. // We can determine the actual slow clock frequency by looking at the Main Clock Frequency Register.
@ -88,7 +87,7 @@ void StartCountUS() {
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
AT91C_BASE_TCB->TCB_BCR = 1; AT91C_BASE_TCB->TCB_BCR = 1;
while (AT91C_BASE_TC1->TC_CV >= 1); while (AT91C_BASE_TC1->TC_CV > 1);
} }
uint32_t RAMFUNC GetCountUS(){ uint32_t RAMFUNC GetCountUS(){
@ -100,22 +99,9 @@ void ResetUSClock(void) {
//enable clock of timer and software trigger //enable clock of timer and software trigger
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
while (AT91C_BASE_TC1->TC_CV >= 1); while (AT91C_BASE_TC1->TC_CV > 1);
} }
// attempt at high resolution microsecond timer
// beware: timer counts in 21.3uS increments (1024/48Mhz)
void SpinDelayCountUs(uint32_t us) {
if (us < 8) return;
us += GetCountUS();
while ( GetCountUS() < us ){}
}
// static uint32_t GlobalUsCounter = 0;
// uint32_t RAMFUNC GetDeltaCountUS(){
// uint32_t g_cnt = GetCountUS();
// uint32_t g_res = g_cnt - GlobalUsCounter;
// GlobalUsCounter = g_cnt;
// return g_res;
// }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// Timer for iso14443 commands. Uses ssp_clk from FPGA // Timer for iso14443 commands. Uses ssp_clk from FPGA
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
@ -174,7 +160,7 @@ void StartCountSspClk() {
// The high word of the counter (TC2) will not reset until the low word (TC0) overflows. // The high word of the counter (TC2) will not reset until the low word (TC0) overflows.
// Therefore need to wait quite some time before we can use the counter. // Therefore need to wait quite some time before we can use the counter.
while (AT91C_BASE_TC2->TC_CV >= 1); while (AT91C_BASE_TC2->TC_CV > 1);
} }
void ResetSspClk(void) { void ResetSspClk(void) {
//enable clock of timer and software trigger //enable clock of timer and software trigger
@ -192,17 +178,16 @@ uint32_t RAMFUNC GetCountSspClk(){
} }
// -------------------------------------------------------------------------
// Timer for bitbanging, or LF stuff when you need a very precis timer
// 1us = 1.5ticks
// -------------------------------------------------------------------------
void StartTicks(void){ void StartTicks(void){
//initialization of the timer //initialization of the timer
AT91C_BASE_PMC->PMC_PCER |= (1 << 12) | (1 << 13) | (1 << 14); AT91C_BASE_PMC->PMC_PCER |= (1 << 12) | (1 << 13) | (1 << 14);
AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE; AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE;
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
// fast clock TC0
// tick=1.5mks
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK; //clock at 48/32 MHz AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK; //clock at 48/32 MHz
// Enable and reset timer
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
AT91C_BASE_TCB->TCB_BCR = 1; AT91C_BASE_TCB->TCB_BCR = 1;
// wait until timer becomes zero. // wait until timer becomes zero.