2010-02-21 05:57:20 +08:00
//-----------------------------------------------------------------------------
// Jonathan Westhues, Sept 2005
2010-02-21 08:12:52 +08:00
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Utility functions used in many places, not specific to any piece of code.
2010-02-21 05:57:20 +08:00
//-----------------------------------------------------------------------------
2010-02-21 08:12:52 +08:00
2010-02-21 05:57:20 +08:00
# include "proxmark3.h"
2010-02-21 06:51:00 +08:00
# include "util.h"
2010-02-21 08:10:28 +08:00
# include "string.h"
2013-09-15 17:33:17 +08:00
# include "apps.h"
2015-02-06 15:41:02 +08:00
# include "BigBuf.h"
2010-02-21 05:57:20 +08:00
2015-01-08 07:08:33 +08:00
void print_result ( char * name , uint8_t * buf , size_t len ) {
uint8_t * p = buf ;
if ( len % 16 = = 0 ) {
for ( ; p - buf < len ; p + = 16 )
Dbprintf ( " [%s:%d/%d] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x " ,
name ,
p - buf ,
len ,
p [ 0 ] , p [ 1 ] , p [ 2 ] , p [ 3 ] , p [ 4 ] , p [ 5 ] , p [ 6 ] , p [ 7 ] , p [ 8 ] , p [ 9 ] , p [ 10 ] , p [ 11 ] , p [ 12 ] , p [ 13 ] , p [ 14 ] , p [ 15 ]
) ;
}
else {
for ( ; p - buf < len ; p + = 8 )
Dbprintf ( " [%s:%d/%d] %02x %02x %02x %02x %02x %02x %02x %02x " , name , p - buf , len , p [ 0 ] , p [ 1 ] , p [ 2 ] , p [ 3 ] , p [ 4 ] , p [ 5 ] , p [ 6 ] , p [ 7 ] ) ;
}
}
2013-04-03 16:45:04 +08:00
size_t nbytes ( size_t nbits ) {
2015-02-08 04:05:14 +08:00
return ( nbits > > 3 ) + ( ( nbits % 8 ) > 0 ) ;
2013-04-03 16:45:04 +08:00
}
2012-06-29 18:24:05 +08:00
uint32_t SwapBits ( uint32_t value , int nrbits ) {
int i ;
uint32_t newvalue = 0 ;
for ( i = 0 ; i < nrbits ; i + + ) {
newvalue ^ = ( ( value > > i ) & 1 ) < < ( nrbits - 1 - i ) ;
}
return newvalue ;
}
2010-02-21 06:51:00 +08:00
void num_to_bytes ( uint64_t n , size_t len , uint8_t * dest )
2010-02-21 05:57:20 +08:00
{
while ( len - - ) {
2010-02-21 06:51:00 +08:00
dest [ len ] = ( uint8_t ) n ;
2010-02-21 05:57:20 +08:00
n > > = 8 ;
}
}
2010-02-21 06:51:00 +08:00
uint64_t bytes_to_num ( uint8_t * src , size_t len )
2010-02-21 05:57:20 +08:00
{
uint64_t num = 0 ;
while ( len - - )
{
num = ( num < < 8 ) | ( * src ) ;
src + + ;
}
return num ;
}
2015-01-08 07:08:33 +08:00
// RotateLeft - Ultralight, Desfire
void rol ( uint8_t * data , const size_t len ) {
uint8_t first = data [ 0 ] ;
for ( size_t i = 0 ; i < len - 1 ; i + + ) {
data [ i ] = data [ i + 1 ] ;
}
data [ len - 1 ] = first ;
}
void lsl ( uint8_t * data , size_t len ) {
for ( size_t n = 0 ; n < len - 1 ; n + + ) {
data [ n ] = ( data [ n ] < < 1 ) | ( data [ n + 1 ] > > 7 ) ;
}
data [ len - 1 ] < < = 1 ;
}
int32_t le24toh ( uint8_t data [ 3 ] )
{
return ( data [ 2 ] < < 16 ) | ( data [ 1 ] < < 8 ) | data [ 0 ] ;
}
2010-02-21 05:57:20 +08:00
void LEDsoff ( )
{
LED_A_OFF ( ) ;
LED_B_OFF ( ) ;
LED_C_OFF ( ) ;
LED_D_OFF ( ) ;
}
// LEDs: R(C) O(A) G(B) -- R(D) [1, 2, 4 and 8]
void LED ( int led , int ms )
{
if ( led & LED_RED )
LED_C_ON ( ) ;
if ( led & LED_ORANGE )
LED_A_ON ( ) ;
if ( led & LED_GREEN )
LED_B_ON ( ) ;
if ( led & LED_RED2 )
LED_D_ON ( ) ;
if ( ! ms )
return ;
SpinDelay ( ms ) ;
if ( led & LED_RED )
LED_C_OFF ( ) ;
if ( led & LED_ORANGE )
LED_A_OFF ( ) ;
if ( led & LED_GREEN )
LED_B_OFF ( ) ;
if ( led & LED_RED2 )
LED_D_OFF ( ) ;
}
// Determine if a button is double clicked, single clicked,
// not clicked, or held down (for ms || 1sec)
// In general, don't use this function unless you expect a
// double click, otherwise it will waste 500ms -- use BUTTON_HELD instead
int BUTTON_CLICKED ( int ms )
{
// Up to 500ms in between clicks to mean a double click
int ticks = ( 48000 * ( ms ? ms : 1000 ) ) > > 10 ;
// If we're not even pressed, forget about it!
if ( ! BUTTON_PRESS ( ) )
return BUTTON_NO_CLICK ;
// Borrow a PWM unit for my real-time clock
AT91C_BASE_PWMC - > PWMC_ENA = PWM_CHANNEL ( 0 ) ;
// 48 MHz / 1024 gives 46.875 kHz
AT91C_BASE_PWMC_CH0 - > PWMC_CMR = PWM_CH_MODE_PRESCALER ( 10 ) ;
AT91C_BASE_PWMC_CH0 - > PWMC_CDTYR = 0 ;
AT91C_BASE_PWMC_CH0 - > PWMC_CPRDR = 0xffff ;
2010-02-21 06:51:00 +08:00
uint16_t start = AT91C_BASE_PWMC_CH0 - > PWMC_CCNTR ;
2010-02-21 05:57:20 +08:00
int letoff = 0 ;
for ( ; ; )
{
2010-02-21 06:51:00 +08:00
uint16_t now = AT91C_BASE_PWMC_CH0 - > PWMC_CCNTR ;
2010-02-21 05:57:20 +08:00
// We haven't let off the button yet
if ( ! letoff )
{
// We just let it off!
if ( ! BUTTON_PRESS ( ) )
{
letoff = 1 ;
// reset our timer for 500ms
start = AT91C_BASE_PWMC_CH0 - > PWMC_CCNTR ;
ticks = ( 48000 * ( 500 ) ) > > 10 ;
}
// Still haven't let it off
else
// Have we held down a full second?
2010-02-21 06:51:00 +08:00
if ( now = = ( uint16_t ) ( start + ticks ) )
2010-02-21 05:57:20 +08:00
return BUTTON_HOLD ;
}
// We already let off, did we click again?
else
// Sweet, double click!
if ( BUTTON_PRESS ( ) )
return BUTTON_DOUBLE_CLICK ;
// Have we ran out of time to double click?
else
2010-02-21 06:51:00 +08:00
if ( now = = ( uint16_t ) ( start + ticks ) )
2010-02-21 05:57:20 +08:00
// At least we did a single click
return BUTTON_SINGLE_CLICK ;
WDT_HIT ( ) ;
}
// We should never get here
return BUTTON_ERROR ;
}
// Determine if a button is held down
int BUTTON_HELD ( int ms )
{
// If button is held for one second
int ticks = ( 48000 * ( ms ? ms : 1000 ) ) > > 10 ;
// If we're not even pressed, forget about it!
if ( ! BUTTON_PRESS ( ) )
return BUTTON_NO_CLICK ;
// Borrow a PWM unit for my real-time clock
AT91C_BASE_PWMC - > PWMC_ENA = PWM_CHANNEL ( 0 ) ;
// 48 MHz / 1024 gives 46.875 kHz
AT91C_BASE_PWMC_CH0 - > PWMC_CMR = PWM_CH_MODE_PRESCALER ( 10 ) ;
AT91C_BASE_PWMC_CH0 - > PWMC_CDTYR = 0 ;
AT91C_BASE_PWMC_CH0 - > PWMC_CPRDR = 0xffff ;
2010-02-21 06:51:00 +08:00
uint16_t start = AT91C_BASE_PWMC_CH0 - > PWMC_CCNTR ;
2010-02-21 05:57:20 +08:00
for ( ; ; )
{
2010-02-21 06:51:00 +08:00
uint16_t now = AT91C_BASE_PWMC_CH0 - > PWMC_CCNTR ;
2010-02-21 05:57:20 +08:00
// As soon as our button let go, we didn't hold long enough
if ( ! BUTTON_PRESS ( ) )
return BUTTON_SINGLE_CLICK ;
// Have we waited the full second?
else
2010-02-21 06:51:00 +08:00
if ( now = = ( uint16_t ) ( start + ticks ) )
2010-02-21 05:57:20 +08:00
return BUTTON_HOLD ;
WDT_HIT ( ) ;
}
// We should never get here
return BUTTON_ERROR ;
}
// attempt at high resolution microsecond timer
// beware: timer counts in 21.3uS increments (1024/48Mhz)
void SpinDelayUs ( int us )
{
int ticks = ( 48 * us ) > > 10 ;
// Borrow a PWM unit for my real-time clock
AT91C_BASE_PWMC - > PWMC_ENA = PWM_CHANNEL ( 0 ) ;
// 48 MHz / 1024 gives 46.875 kHz
AT91C_BASE_PWMC_CH0 - > PWMC_CMR = PWM_CH_MODE_PRESCALER ( 10 ) ;
AT91C_BASE_PWMC_CH0 - > PWMC_CDTYR = 0 ;
AT91C_BASE_PWMC_CH0 - > PWMC_CPRDR = 0xffff ;
2010-02-21 06:51:00 +08:00
uint16_t start = AT91C_BASE_PWMC_CH0 - > PWMC_CCNTR ;
2010-02-21 05:57:20 +08:00
for ( ; ; ) {
2010-02-21 06:51:00 +08:00
uint16_t now = AT91C_BASE_PWMC_CH0 - > PWMC_CCNTR ;
if ( now = = ( uint16_t ) ( start + ticks ) )
2010-02-21 05:57:20 +08:00
return ;
WDT_HIT ( ) ;
}
}
void SpinDelay ( int ms )
{
// convert to uS and call microsecond delay function
SpinDelayUs ( ms * 1000 ) ;
}
/* Similar to FpgaGatherVersion this formats stored version information
* into a string representation . It takes a pointer to the struct version_information ,
* verifies the magic properties , then stores a formatted string , prefixed by
* prefix in dst .
*/
void FormatVersionInformation ( char * dst , int len , const char * prefix , void * version_information )
{
struct version_information * v = ( struct version_information * ) version_information ;
dst [ 0 ] = 0 ;
2014-10-29 04:44:17 +08:00
strncat ( dst , prefix , len - 1 ) ;
2010-02-21 05:57:20 +08:00
if ( v - > magic ! = VERSION_INFORMATION_MAGIC ) {
2015-05-26 13:37:50 +08:00
strncat ( dst , " Missing/Invalid version information \n " , len - strlen ( dst ) - 1 ) ;
2010-02-21 05:57:20 +08:00
return ;
}
if ( v - > versionversion ! = 1 ) {
2015-05-26 13:37:50 +08:00
strncat ( dst , " Version information not understood \n " , len - strlen ( dst ) - 1 ) ;
2010-02-21 05:57:20 +08:00
return ;
}
if ( ! v - > present ) {
2015-05-26 13:37:50 +08:00
strncat ( dst , " Version information not available \n " , len - strlen ( dst ) - 1 ) ;
2010-02-21 05:57:20 +08:00
return ;
}
2014-04-05 02:14:58 +08:00
strncat ( dst , v - > gitversion , len - strlen ( dst ) - 1 ) ;
2010-02-21 05:57:20 +08:00
if ( v - > clean = = 0 ) {
2014-04-05 02:14:58 +08:00
strncat ( dst , " -unclean " , len - strlen ( dst ) - 1 ) ;
2010-02-21 05:57:20 +08:00
} else if ( v - > clean = = 2 ) {
2014-04-05 02:14:58 +08:00
strncat ( dst , " -suspect " , len - strlen ( dst ) - 1 ) ;
2010-02-21 05:57:20 +08:00
}
2014-04-05 02:14:58 +08:00
strncat ( dst , " " , len - strlen ( dst ) - 1 ) ;
strncat ( dst , v - > buildtime , len - strlen ( dst ) - 1 ) ;
2015-05-26 13:37:50 +08:00
strncat ( dst , " \n " , len - strlen ( dst ) - 1 ) ;
2010-02-21 05:57:20 +08:00
}
2011-06-10 21:35:10 +08:00
2017-11-21 14:31:42 +08:00
2011-06-10 21:35:10 +08:00
// -------------------------------------------------------------------------
// timer lib
// -------------------------------------------------------------------------
// test procedure:
//
// ti = GetTickCount();
// SpinDelay(1000);
// ti = GetTickCount() - ti;
// Dbprintf("timer(1s): %d t=%d", ti, GetTickCount());
void StartTickCount ( )
{
2015-07-30 00:52:43 +08:00
// 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.
uint16_t mainf = AT91C_BASE_PMC - > PMC_MCFR & 0xffff ; // = 16 * main clock frequency (16MHz) / slow clock frequency
// set RealTimeCounter divider to count at 1kHz:
AT91C_BASE_RTTC - > RTTC_RTMR = AT91C_RTTC_RTTRST | ( ( 256000 + ( mainf / 2 ) ) / mainf ) ;
// note: worst case precision is approx 2.5%
2011-06-10 21:35:10 +08:00
}
2017-11-21 14:31:42 +08:00
2011-06-10 21:35:10 +08:00
/*
* Get the current count .
*/
uint32_t RAMFUNC GetTickCount ( ) {
2011-06-16 22:43:49 +08:00
return AT91C_BASE_RTTC - > RTTC_RTVR ; // was * 2;
2011-06-10 21:35:10 +08:00
}
2017-11-21 14:31:42 +08:00
2011-06-16 22:43:49 +08:00
// -------------------------------------------------------------------------
// microseconds timer
// -------------------------------------------------------------------------
void StartCountUS ( )
{
AT91C_BASE_PMC - > PMC_PCER | = ( 0x1 < < 12 ) | ( 0x1 < < 13 ) | ( 0x1 < < 14 ) ;
// AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC1XC1S_TIOA0;
AT91C_BASE_TCB - > TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE ;
// fast clock
AT91C_BASE_TC0 - > TC_CCR = AT91C_TC_CLKDIS ; // timer disable
AT91C_BASE_TC0 - > TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | // MCK(48MHz)/32 -- tick=1.5mks
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
2013-07-09 01:56:05 +08:00
2011-06-16 22:43:49 +08:00
AT91C_BASE_TC0 - > TC_CCR = AT91C_TC_CLKEN ;
AT91C_BASE_TC1 - > TC_CCR = AT91C_TC_CLKEN ;
AT91C_BASE_TCB - > TCB_BCR = 1 ;
2013-07-09 01:56:05 +08:00
}
2011-06-16 22:43:49 +08:00
2017-11-21 14:31:42 +08:00
2011-06-16 22:43:49 +08:00
uint32_t RAMFUNC GetCountUS ( ) {
2017-02-03 13:14:34 +08:00
return ( AT91C_BASE_TC1 - > TC_CV * 0x8000 ) + ( ( AT91C_BASE_TC0 - > TC_CV * 2 ) / 3 ) ; //was /15) * 10);
2011-06-16 22:43:49 +08:00
}
2017-11-21 14:31:42 +08:00
2011-06-16 22:43:49 +08:00
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 ;
}
2013-07-09 01:56:05 +08:00
// -------------------------------------------------------------------------
2014-02-20 04:35:04 +08:00
// Timer for iso14443 commands. Uses ssp_clk from FPGA
2013-07-09 01:56:05 +08:00
// -------------------------------------------------------------------------
2014-02-20 04:35:04 +08:00
void StartCountSspClk ( )
2013-07-09 01:56:05 +08:00
{
AT91C_BASE_PMC - > PMC_PCER = ( 1 < < AT91C_ID_TC0 ) | ( 1 < < AT91C_ID_TC1 ) | ( 1 < < AT91C_ID_TC2 ) ; // Enable Clock to all timers
AT91C_BASE_TCB - > TCB_BMR = AT91C_TCB_TC0XC0S_TIOA1 // XC0 Clock = TIOA1
| AT91C_TCB_TC1XC1S_NONE // XC1 Clock = none
| AT91C_TCB_TC2XC2S_TIOA0 ; // XC2 Clock = TIOA0
// configure TC1 to create a short pulse on TIOA1 when a rising edge on TIOB1 (= ssp_clk from FPGA) occurs:
AT91C_BASE_TC1 - > TC_CCR = AT91C_TC_CLKDIS ; // disable TC1
AT91C_BASE_TC1 - > TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK // TC1 Clock = MCK(48MHz)/2 = 24MHz
| AT91C_TC_CPCSTOP // Stop clock on RC compare
| AT91C_TC_EEVTEDG_RISING // Trigger on rising edge of Event
2014-02-20 04:35:04 +08:00
| AT91C_TC_EEVT_TIOB // Event-Source: TIOB1 (= ssp_clk from FPGA = 13,56MHz/16)
2013-07-09 01:56:05 +08:00
| AT91C_TC_ENETRG // Enable external trigger event
| AT91C_TC_WAVESEL_UP // Upmode without automatic trigger on RC compare
| AT91C_TC_WAVE // Waveform Mode
| AT91C_TC_AEEVT_SET // Set TIOA1 on external event
| AT91C_TC_ACPC_CLEAR ; // Clear TIOA1 on RC Compare
AT91C_BASE_TC1 - > TC_RC = 0x04 ; // RC Compare value = 0x04
// use TC0 to count TIOA1 pulses
2014-02-20 04:35:04 +08:00
AT91C_BASE_TC0 - > TC_CCR = AT91C_TC_CLKDIS ; // disable TC0
2013-07-09 01:56:05 +08:00
AT91C_BASE_TC0 - > TC_CMR = AT91C_TC_CLKS_XC0 // TC0 clock = XC0 clock = TIOA1
| AT91C_TC_WAVE // Waveform Mode
| AT91C_TC_WAVESEL_UP // just count
| AT91C_TC_ACPA_CLEAR // Clear TIOA0 on RA Compare
| AT91C_TC_ACPC_SET ; // Set TIOA0 on RC Compare
AT91C_BASE_TC0 - > TC_RA = 1 ; // RA Compare value = 1; pulse width to TC2
AT91C_BASE_TC0 - > TC_RC = 0 ; // RC Compare value = 0; increment TC2 on overflow
// use TC2 to count TIOA0 pulses (giving us a 32bit counter (TC0/TC2) clocked by ssp_clk)
AT91C_BASE_TC2 - > TC_CCR = AT91C_TC_CLKDIS ; // disable TC2
AT91C_BASE_TC2 - > TC_CMR = AT91C_TC_CLKS_XC2 // TC2 clock = XC2 clock = TIOA0
| AT91C_TC_WAVE // Waveform Mode
| AT91C_TC_WAVESEL_UP ; // just count
AT91C_BASE_TC0 - > TC_CCR = AT91C_TC_CLKEN ; // enable TC0
AT91C_BASE_TC1 - > TC_CCR = AT91C_TC_CLKEN ; // enable TC1
AT91C_BASE_TC2 - > TC_CCR = AT91C_TC_CLKEN ; // enable TC2
2013-09-15 17:33:17 +08:00
2014-02-20 04:35:04 +08:00
//
2017-11-21 14:31:42 +08:00
// synchronize the counter with the ssp_frame signal. Note: FPGA must be in any iso14443 mode, otherwise SSC_FRAME and SSC_CLK signals would not be present
2014-02-20 04:35:04 +08:00
//
while ( ! ( AT91C_BASE_PIOA - > PIO_PDSR & GPIO_SSC_FRAME ) ) ; // wait for ssp_frame to go high (start of frame)
2013-09-15 17:33:17 +08:00
while ( AT91C_BASE_PIOA - > PIO_PDSR & GPIO_SSC_FRAME ) ; // wait for ssp_frame to be low
2014-02-20 04:35:04 +08:00
while ( ! ( AT91C_BASE_PIOA - > PIO_PDSR & GPIO_SSC_CLK ) ) ; // wait for ssp_clk to go high
// note: up to now two ssp_clk rising edges have passed since the rising edge of ssp_frame
// it is now safe to assert a sync signal. This sets all timers to 0 on next active clock edge
2013-07-09 01:56:05 +08:00
AT91C_BASE_TCB - > TCB_BCR = 1 ; // assert Sync (set all timers to 0 on next active clock edge)
2014-02-20 04:35:04 +08:00
// at the next (3rd) ssp_clk rising edge, TC1 will be reset (and not generate a clock signal to TC0)
// at the next (4th) ssp_clk rising edge, TC0 (the low word of our counter) will be reset. From now on,
// whenever the last three bits of our counter go 0, we can be sure to be in the middle of a frame transfer.
// (just started with the transfer of the 4th Bit).
// 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.
2017-11-21 14:31:42 +08:00
while ( AT91C_BASE_TC0 - > TC_CV < 0xFFFF ) ;
// Note: needs one more SSP_CLK cycle (1.18 us) until TC2 resets. Don't call GetCountSspClk() that soon.
2013-07-09 01:56:05 +08:00
}
2017-11-21 14:31:42 +08:00
2017-02-03 13:14:34 +08:00
void ResetSspClk ( void ) {
//enable clock of timer and software trigger
AT91C_BASE_TC0 - > TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG ;
AT91C_BASE_TC1 - > TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG ;
AT91C_BASE_TC2 - > TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG ;
while ( AT91C_BASE_TC2 - > TC_CV > 0 ) ;
}
2017-11-21 14:31:42 +08:00
2014-02-20 04:35:04 +08:00
uint32_t RAMFUNC GetCountSspClk ( ) {
2013-07-09 01:56:05 +08:00
uint32_t tmp_count ;
tmp_count = ( AT91C_BASE_TC2 - > TC_CV < < 16 ) | AT91C_BASE_TC0 - > TC_CV ;
2014-02-20 04:35:04 +08:00
if ( ( tmp_count & 0x0000ffff ) = = 0 ) { //small chance that we may have missed an increment in TC2
2013-07-09 01:56:05 +08:00
return ( AT91C_BASE_TC2 - > TC_CV < < 16 ) ;
}
else {
return tmp_count ;
}
}
2014-02-20 04:35:04 +08:00
2017-11-21 14:31:42 +08:00
2017-02-03 13:14:34 +08:00
// -------------------------------------------------------------------------
2018-08-14 15:24:02 +08:00
// Timer for bitbanging, or LF stuff when you need a very precis timer
2017-02-03 13:14:34 +08:00
// 1us = 1.5ticks
// -------------------------------------------------------------------------
void StartTicks ( void ) {
2018-08-14 15:24:02 +08:00
// initialization of the timer
2017-02-03 13:14:34 +08:00
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 ;
2018-08-14 15:24:02 +08:00
// disable TC0 and TC1 for re-configuration
2017-02-03 13:14:34 +08:00
AT91C_BASE_TC0 - > TC_CCR = AT91C_TC_CLKDIS ;
2018-08-14 15:24:02 +08:00
AT91C_BASE_TC1 - > TC_CCR = AT91C_TC_CLKDIS ;
// first configure TC1 (higher, 0xFFFF0000) 16 bit counter
AT91C_BASE_TC1 - > TC_CMR = AT91C_TC_CLKS_XC1 ; // just connect to TIOA0 from TC0
AT91C_BASE_TC1 - > TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG ; // re-enable timer and wait for TC0
// second configure TC0 (lower, 0x0000FFFF) 16 bit counter
2017-02-03 13:14:34 +08:00
AT91C_BASE_TC0 - > TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | // MCK(48MHz) / 32
2018-08-14 15:24:02 +08:00
AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO |
AT91C_TC_ACPA_CLEAR | // RA comperator clears TIOA (carry bit)
AT91C_TC_ACPC_SET | // RC comperator sets TIOA (carry bit)
AT91C_TC_ASWTRG_SET ; // SWTriger sets TIOA (carry bit)
AT91C_BASE_TC0 - > TC_RC = 0 ; // set TIOA (carry bit) on overflow, return to zero
AT91C_BASE_TC0 - > TC_RA = 1 ; // clear carry bit on next clock cycle
AT91C_BASE_TC0 - > TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG ; // reset and re-enable timer
// synchronized startup procedure
while ( AT91C_BASE_TC0 - > TC_CV > 0 ) ; // wait until TC0 returned to zero
while ( AT91C_BASE_TC0 - > TC_CV < 2 ) ; // and has started (TC_CV > TC_RA, now TC1 is cleared)
// return to zero
AT91C_BASE_TC1 - > TC_CCR = AT91C_TC_SWTRG ;
AT91C_BASE_TC0 - > TC_CCR = AT91C_TC_SWTRG ;
while ( AT91C_BASE_TC0 - > TC_CV > 0 ) ;
}
2017-02-03 13:14:34 +08:00
2018-08-14 15:24:02 +08:00
uint32_t GetTicks ( void ) {
uint32_t hi , lo ;
do {
hi = AT91C_BASE_TC1 - > TC_CV ;
lo = AT91C_BASE_TC0 - > TC_CV ;
} while ( hi ! = AT91C_BASE_TC1 - > TC_CV ) ;
return ( hi < < 16 ) | lo ;
2017-02-03 13:14:34 +08:00
}
2017-11-21 14:31:42 +08:00
2017-02-03 13:14:34 +08:00
// Wait - Spindelay in ticks.
// if called with a high number, this will trigger the WDT...
void WaitTicks ( uint32_t ticks ) {
if ( ticks = = 0 ) return ;
2018-08-14 15:24:02 +08:00
ticks + = GetTicks ( ) ;
while ( GetTicks ( ) < ticks ) ;
2017-02-03 13:14:34 +08:00
}
2017-11-21 14:31:42 +08:00
2017-02-03 13:14:34 +08:00
// Wait / Spindelay in us (microseconds)
// 1us = 1.5ticks.
void WaitUS ( uint16_t us ) {
2018-07-26 23:18:10 +08:00
WaitTicks ( ( uint32_t ) us * 3 / 2 ) ;
2017-02-03 13:14:34 +08:00
}
2017-11-21 14:31:42 +08:00
2017-02-03 13:14:34 +08:00
void WaitMS ( uint16_t ms ) {
2018-07-26 23:18:10 +08:00
WaitTicks ( ( uint32_t ) ms * 1500 ) ;
2017-02-03 13:14:34 +08:00
}
2017-11-21 14:31:42 +08:00
2017-02-03 13:14:34 +08:00
// Starts Clock and waits until its reset
void ResetTicks ( void ) {
AT91C_BASE_TC1 - > TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG ;
2018-08-14 15:24:02 +08:00
AT91C_BASE_TC0 - > TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG ;
while ( AT91C_BASE_TC0 - > TC_CV > 0 ) ;
2017-02-03 13:14:34 +08:00
}
2017-11-21 14:31:42 +08:00
2017-02-03 13:14:34 +08:00
void ResetTimer ( AT91PS_TC timer ) {
timer - > TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG ;
while ( timer - > TC_CV > 0 ) ;
}
2017-11-21 14:31:42 +08:00
2017-02-03 13:14:34 +08:00
// stop clock
void StopTicks ( void ) {
AT91C_BASE_TC0 - > TC_CCR = AT91C_TC_CLKDIS ;
AT91C_BASE_TC1 - > TC_CCR = AT91C_TC_CLKDIS ;
}
2017-11-21 14:31:42 +08:00
2017-01-26 15:16:10 +08:00
static uint64_t next_random = 1 ;
/* Generates a (non-cryptographically secure) 32-bit random number.
*
* We don ' t have an implementation of the " rand " function or a clock to seed it
* with , so we just call GetTickCount the first time to seed ourselves .
*/
uint32_t prand ( ) {
if ( next_random = = 1 ) {
next_random = GetTickCount ( ) ;
}
next_random = next_random * 6364136223846793005 + 1 ;
return ( uint32_t ) ( next_random > > 32 ) % 0xffffffff ;
}