Merge pull request #1331 from Guilhem7/master
[RRG-proxmark3.git] / armsrc / lfadc.c
blob6a351bfca2133fb5eb7bb04ab745a78f59a600d0
1 //-----------------------------------------------------------------------------
2 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
3 // at your option, any later version. See the LICENSE.txt file for the text of
4 // the license.
5 //-----------------------------------------------------------------------------
6 // LF ADC read/write implementation
7 //-----------------------------------------------------------------------------
9 #include "lfadc.h"
10 #include "lfsampling.h"
11 #include "fpgaloader.h"
12 #include "ticks.h"
13 #include "dbprint.h"
14 #include "appmain.h"
16 // Sam7s has several timers, we will use the source TIMER_CLOCK1 (aka AT91C_TC_CLKS_TIMER_DIV1_CLOCK)
17 // TIMER_CLOCK1 = MCK/2, MCK is running at 48 MHz, Timer is running at 48/2 = 24 MHz
18 // Carrier periods (T0) have duration of 8 microseconds (us), which is 1/125000 per second
19 // T0 = TIMER_CLOCK1 / 125000 = 192
20 //#define T0 192
22 // Sam7s has three counters, we will use the first TIMER_COUNTER_0 (aka TC0)
23 // using TIMER_CLOCK3 (aka AT91C_TC_CLKS_TIMER_DIV3_CLOCK)
24 // as a counting signal. TIMER_CLOCK3 = MCK/32, MCK is running at 48 MHz, so the timer is running at 48/32 = 1500 kHz
25 // Carrier period (T0) have duration of 8 microseconds (us), which is 1/125000 per second (125 kHz frequency)
26 // T0 = timer/carrier = 1500kHz/125kHz = 1500000/125000 = 6
27 //#define HITAG_T0 3
29 //////////////////////////////////////////////////////////////////////////////
30 // Exported global variables
31 //////////////////////////////////////////////////////////////////////////////
33 bool g_logging = true;
35 //////////////////////////////////////////////////////////////////////////////
36 // Global variables
37 //////////////////////////////////////////////////////////////////////////////
39 static bool rising_edge = false;
40 static bool reader_mode = false;
42 //////////////////////////////////////////////////////////////////////////////
43 // Auxiliary functions
44 //////////////////////////////////////////////////////////////////////////////
46 bool lf_test_periods(size_t expected, size_t count) {
47 // Compute 10% deviation (integer operation, so rounded down)
48 size_t diviation = expected / 10;
49 return ((count > (expected - diviation)) && (count < (expected + diviation)));
52 //////////////////////////////////////////////////////////////////////////////
53 // Low frequency (LF) adc passthrough functionality
54 //////////////////////////////////////////////////////////////////////////////
55 static uint8_t previous_adc_val = 0; //0xFF;
56 static uint8_t adc_avg = 0;
58 uint8_t get_adc_avg(void) {
59 return adc_avg;
61 void lf_sample_mean(void) {
62 uint8_t periods = 0;
63 uint32_t adc_sum = 0;
64 while (periods < 32) {
65 if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
66 adc_sum += AT91C_BASE_SSC->SSC_RHR;
67 periods++;
70 // division by 32
71 adc_avg = adc_sum >> 5;
72 previous_adc_val = adc_avg;
74 if (DBGLEVEL >= DBG_EXTENDED)
75 Dbprintf("LF ADC average %u", adc_avg);
78 static size_t lf_count_edge_periods_ex(size_t max, bool wait, bool detect_gap) {
80 #define LIMIT_DEV 20
82 // timeout limit to 100 000 w/o
83 uint32_t timeout = 100000;
84 size_t periods = 0;
85 uint8_t avg_peak = adc_avg + LIMIT_DEV;
86 uint8_t avg_through = adc_avg - LIMIT_DEV;
88 while (BUTTON_PRESS() == false) {
89 WDT_HIT();
91 timeout--;
92 if (timeout == 0) {
93 return 0;
96 if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
97 AT91C_BASE_SSC->SSC_THR = 0x00;
98 continue;
101 if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
103 periods++;
105 // reset timeout
106 timeout = 100000;
108 volatile uint8_t adc_val = AT91C_BASE_SSC->SSC_RHR;
110 if (g_logging) logSampleSimple(adc_val);
112 // Only test field changes if state of adc values matter
113 if (wait == false) {
114 // Test if we are locating a field modulation (100% ASK = complete field drop)
115 if (detect_gap) {
116 // Only return when the field completely dissapeared
117 if (adc_val == 0) {
118 return periods;
121 } else {
122 // Trigger on a modulation swap by observing an edge change
123 if (rising_edge) {
125 if ((previous_adc_val > avg_peak) && (adc_val <= previous_adc_val)) {
126 rising_edge = false;
127 return periods;
130 } else {
132 if ((previous_adc_val < avg_through) && (adc_val >= previous_adc_val)) {
133 rising_edge = true;
134 return periods;
141 previous_adc_val = adc_val;
143 if (periods >= max) {
144 return 0;
149 if (g_logging) logSampleSimple(0xFF);
150 return 0;
153 size_t lf_count_edge_periods(size_t max) {
154 return lf_count_edge_periods_ex(max, false, false);
157 size_t lf_detect_gap(size_t max) {
158 return lf_count_edge_periods_ex(max, false, true);
161 void lf_reset_counter(void) {
163 // TODO: find out the correct reset settings for tag and reader mode
164 // if (reader_mode) {
165 // Reset values for reader mode
166 rising_edge = false;
167 previous_adc_val = 0xFF;
169 // } else {
170 // Reset values for tag/transponder mode
171 // rising_edge = false;
172 // previous_adc_val = 0xFF;
173 // }
176 bool lf_get_tag_modulation(void) {
177 return (rising_edge == false);
180 bool lf_get_reader_modulation(void) {
181 return rising_edge;
184 void lf_wait_periods(size_t periods) {
185 // wait detect gap
186 lf_count_edge_periods_ex(periods, true, false);
189 void lf_init(bool reader, bool simulate) {
191 StopTicks();
193 reader_mode = reader;
195 FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
197 sample_config *sc = getSamplingConfig();
198 sc->decimation = 1;
199 sc->averaging = 0;
201 FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor);
202 if (reader) {
203 FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
204 } else {
205 if (simulate)
206 FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC);
207 else
208 // Sniff
209 //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC);
210 FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE);
214 // Connect the A/D to the peak-detected low-frequency path.
215 SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
217 // Now set up the SSC to get the ADC samples that are now streaming at us.
218 FpgaSetupSsc(FPGA_MAJOR_MODE_LF_READER);
220 // When in reader mode, give the field a bit of time to settle.
221 // 313T0 = 313 * 8us = 2504us = 2.5ms Hitag2 tags needs to be fully powered.
222 // if (reader) {
223 // 10 ms
224 SpinDelay(10);
225 // }
227 // Steal this pin from the SSP (SPI communication channel with fpga) and use it to control the modulation
228 AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;
229 AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
230 LOW(GPIO_SSC_DOUT);
232 // Enable peripheral Clock for TIMER_CLOCK 0
233 AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0);
234 AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
235 AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV4_CLOCK;
237 // Enable peripheral Clock for TIMER_CLOCK 1
238 AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1);
239 AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
240 AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV4_CLOCK;
242 // Clear all leds
243 LEDsoff();
245 // Reset and enable timers
246 AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
247 AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
249 // Prepare data trace
250 uint32_t bufsize = 10000;
252 // use malloc
253 if (g_logging) initSampleBufferEx(&bufsize, true);
255 lf_sample_mean();
258 void lf_finalize(void) {
259 // Disable timers
260 AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
261 AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
263 // return stolen pin to SSP
264 AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DOUT;
265 AT91C_BASE_PIOA->PIO_ASR = GPIO_SSC_DIN | GPIO_SSC_DOUT;
267 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
269 LEDsoff();
271 StartTicks();
274 size_t lf_detect_field_drop(size_t max) {
276 size_t periods = 0;
277 // int16_t checked = 0;
279 while (BUTTON_PRESS() == false) {
281 // // only every 1000th times, in order to save time when collecting samples.
282 // if (checked == 4000) {
283 // if (data_available()) {
284 // checked = -1;
285 // break;
286 // } else {
287 // checked = 0;
288 // }
289 // }
290 // ++checked;
292 WDT_HIT();
294 if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
295 periods++;
296 volatile uint8_t adc_val = AT91C_BASE_SSC->SSC_RHR;
298 if (g_logging) logSampleSimple(adc_val);
300 if (adc_val == 0) {
301 rising_edge = false;
302 return periods;
305 if (periods == max) return 0;
309 return 0;
312 void lf_modulation(bool modulation) {
313 if (modulation) {
314 HIGH(GPIO_SSC_DOUT);
315 } else {
316 LOW(GPIO_SSC_DOUT);
320 // simulation
321 static void lf_manchester_send_bit(uint8_t bit) {
322 lf_modulation(bit != 0);
323 lf_wait_periods(16);
324 lf_modulation(bit == 0);
325 lf_wait_periods(32);
328 // simulation
329 bool lf_manchester_send_bytes(const uint8_t *frame, size_t frame_len) {
331 LED_B_ON();
333 lf_manchester_send_bit(1);
334 lf_manchester_send_bit(1);
335 lf_manchester_send_bit(1);
336 lf_manchester_send_bit(1);
337 lf_manchester_send_bit(1);
339 // Send the content of the frame
340 for (size_t i = 0; i < frame_len; i++) {
341 lf_manchester_send_bit((frame[i / 8] >> (7 - (i % 8))) & 1);
344 LED_B_OFF();
345 return true;