1 //-----------------------------------------------------------------------------
3 // edits by - Anticat, August 2018
5 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
6 // at your option, any later version. See the LICENSE.txt file for the text of
8 //-----------------------------------------------------------------------------
9 // The main USART code, for serial communications over FPC connector
10 //-----------------------------------------------------------------------------
12 #include "proxmark3_arm.h"
14 volatile AT91PS_USART pUS1
= AT91C_BASE_US1
;
15 volatile AT91PS_PIO pPIO
= AT91C_BASE_PIOA
;
16 volatile AT91PS_PDC pPDC
= AT91C_BASE_PDC_US1
;
18 uint32_t g_usart_baudrate
= 0;
19 uint8_t g_usart_parity
= 0;
21 void usart_close(void) {
22 // Reset the USART mode
25 // Reset the baud rate divisor register
28 // Reset the Timeguard Register
31 // Disable all interrupts
32 pUS1->US_IDR = 0xFFFFFFFF;
34 // Abort the Peripheral Data Transfers
35 pUS1->US_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;
37 // Disable receiver and transmitter and stop any activity immediately
38 pUS1->US_CR = AT91C_US_TXDIS | AT91C_US_RXDIS | AT91C_US_RSTTX | AT91C_US_RSTRX;
42 static uint8_t us_inbuf1
[USART_BUFFLEN
];
43 static uint8_t us_inbuf2
[USART_BUFFLEN
];
44 static uint8_t *usart_cur_inbuf
= NULL
;
45 static uint16_t usart_cur_inbuf_off
= 0;
46 static uint8_t us_rxfifo
[USART_FIFOLEN
];
47 static size_t us_rxfifo_low
= 0;
48 static size_t us_rxfifo_high
= 0;
51 static void usart_fill_rxfifo(void) {
52 uint16_t rxfifo_free
;
53 if (pUS1
->US_RNCR
== 0) { // One buffer got filled, backup buffer being used
55 if (us_rxfifo_low
> us_rxfifo_high
)
56 rxfifo_free
= us_rxfifo_low
- us_rxfifo_high
;
58 rxfifo_free
= sizeof(us_rxfifo
) - us_rxfifo_high
+ us_rxfifo_low
;
60 uint16_t available
= USART_BUFFLEN
- usart_cur_inbuf_off
;
62 if (available
<= rxfifo_free
) {
64 for (uint16_t i
= 0; i
< available
; i
++) {
65 us_rxfifo
[us_rxfifo_high
++] = usart_cur_inbuf
[usart_cur_inbuf_off
+ i
];
66 if (us_rxfifo_high
== sizeof(us_rxfifo
))
71 pUS1
->US_RNPR
= (uint32_t)usart_cur_inbuf
;
72 pUS1
->US_RNCR
= USART_BUFFLEN
;
75 if (usart_cur_inbuf
== us_inbuf1
)
76 usart_cur_inbuf
= us_inbuf2
;
78 usart_cur_inbuf
= us_inbuf1
;
80 usart_cur_inbuf_off
= 0;
82 // Take only what we have room for
83 available
= rxfifo_free
;
84 for (uint16_t i
= 0; i
< available
; i
++) {
85 us_rxfifo
[us_rxfifo_high
++] = usart_cur_inbuf
[usart_cur_inbuf_off
+ i
];
86 if (us_rxfifo_high
== sizeof(us_rxfifo
))
89 usart_cur_inbuf_off
+= available
;
94 if (pUS1
->US_RCR
< USART_BUFFLEN
- usart_cur_inbuf_off
) { // Current buffer partially filled
96 if (us_rxfifo_low
> us_rxfifo_high
)
97 rxfifo_free
= us_rxfifo_low
- us_rxfifo_high
;
99 rxfifo_free
= sizeof(us_rxfifo
) - us_rxfifo_high
+ us_rxfifo_low
;
101 uint16_t available
= USART_BUFFLEN
- pUS1
->US_RCR
- usart_cur_inbuf_off
;
103 if (available
> rxfifo_free
)
104 available
= rxfifo_free
;
105 for (uint16_t i
= 0; i
< available
; i
++) {
106 us_rxfifo
[us_rxfifo_high
++] = usart_cur_inbuf
[usart_cur_inbuf_off
+ i
];
107 if (us_rxfifo_high
== sizeof(us_rxfifo
))
110 usart_cur_inbuf_off
+= available
;
114 uint16_t usart_rxdata_available(void) {
116 if (us_rxfifo_low
<= us_rxfifo_high
)
117 return us_rxfifo_high
- us_rxfifo_low
;
119 return sizeof(us_rxfifo
) - us_rxfifo_low
+ us_rxfifo_high
;
122 uint32_t usart_read_ng(uint8_t *data
, size_t len
) {
123 if (len
== 0) return 0;
124 uint32_t bytes_rcv
= 0;
126 // uint32_t highest_observed_try = 0;
127 // Empirical max try observed: 3000000 / USART_BAUD_RATE
130 uint32_t tryconstant
= 0;
131 #ifdef USART_SLOW_LINK
132 // Experienced up to 13200 tries on BT link even at 460800
136 uint32_t maxtry
= 10 * (3000000 / USART_BAUD_RATE
) + tryconstant
;
139 uint32_t available
= usart_rxdata_available();
141 uint32_t packetSize
= MIN(available
, len
);
143 // Dbprintf_usb("Dbg USART ask %d bytes, available %d bytes, packetsize %d bytes", len, available, packetSize);
144 // highest_observed_try = MAX(highest_observed_try, try);
148 while (packetSize
--) {
149 if (us_rxfifo_low
== sizeof(us_rxfifo
))
151 data
[bytes_rcv
++] = us_rxfifo
[us_rxfifo_low
++];
153 if (try++ == maxtry
) {
154 // Dbprintf_usb("Dbg USART TIMEOUT");
158 // highest_observed_try = MAX(highest_observed_try, try);
159 // Dbprintf_usb("Dbg USART max observed try %i", highest_observed_try);
163 // transfer from device to client
164 int usart_writebuffer_sync(uint8_t *data
, size_t len
) {
166 // Wait for current PDC bank to be free
167 // (and check next bank too, in case there will be a usart_writebuffer_async)
168 while (pUS1
->US_TNCR
|| pUS1
->US_TCR
) {};
169 pUS1
->US_TPR
= (uint32_t)data
;
171 // Wait until finishing all transfers to make sure "data" buffer can be discarded
172 // (if we don't wait here, bulk send as e.g. "hw status" will fail)
173 while (pUS1
->US_TNCR
|| pUS1
->US_TCR
) {};
177 void usart_init(uint32_t baudrate
, uint8_t parity
) {
180 g_usart_baudrate
= baudrate
;
181 if ((parity
== 'N') || (parity
== 'O') || (parity
== 'E'))
182 g_usart_parity
= parity
;
184 // For a nice detailed sample, interrupt driven but still relevant.
185 // See https://www.sparkfun.com/datasheets/DevTools/SAM7/at91sam7%20serial%20communications.pdf
187 // disable & reset receiver / transmitter for configuration
188 pUS1
->US_CR
= (AT91C_US_RSTRX
| AT91C_US_RSTTX
| AT91C_US_RXDIS
| AT91C_US_TXDIS
);
190 //enable the USART1 Peripheral clock
191 AT91C_BASE_PMC
->PMC_PCER
= (1 << AT91C_ID_US1
);
193 // disable PIO control of receive / transmit pins
194 pPIO
->PIO_PDR
|= (AT91C_PA21_RXD1
| AT91C_PA22_TXD1
);
196 // enable peripheral mode A on receive / transmit pins
197 pPIO
->PIO_ASR
|= (AT91C_PA21_RXD1
| AT91C_PA22_TXD1
);
200 // enable pull-up on receive / transmit pins (see 31.5.1 I/O Lines)
201 pPIO
->PIO_PPUER
|= (AT91C_PA21_RXD1
| AT91C_PA22_TXD1
);
204 uint32_t mode
= AT91C_US_USMODE_NORMAL
| // normal mode
205 AT91C_US_CLKS_CLOCK
| // MCK (48MHz)
206 AT91C_US_OVER
| // oversampling
207 AT91C_US_CHRL_8_BITS
| // 8 bits
208 AT91C_US_NBSTOP_1_BIT
| // 1 stop bit
209 AT91C_US_CHMODE_NORMAL
; // channel mode: normal
211 switch (g_usart_parity
) {
213 mode
|= AT91C_US_PAR_NONE
; // parity: none
216 mode
|= AT91C_US_PAR_ODD
; // parity: odd
219 mode
|= AT91C_US_PAR_EVEN
; // parity: even
224 // all interrupts disabled
225 pUS1
->US_IDR
= 0xFFFF;
227 // http://ww1.microchip.com/downloads/en/DeviceDoc/doc6175.pdf
228 // note that for very large baudrates, error is not neglectible:
231 // FP, Fractional Part (Datasheet p402, Supported in AT91SAM512 / 256) (31.6.1.3)
233 // FP = 1-7 Baudrate resolution,
234 // CD, Clock divider,
235 // sync == 0 , (async?)
237 // baudrate == selected clock/16/CD
238 // OVER = 1, -yes we are oversampling
239 // baudrate == selected clock/8/CD --> this is ours
241 uint32_t brgr
= MCK
/ (g_usart_baudrate
<< 3);
242 // doing fp = round((mck / (g_usart_baudrate << 3) - brgr) * 8) with integers:
243 uint32_t fp
= ((16 * MCK
/ (g_usart_baudrate
<< 3) - 16 * brgr
) + 1) / 2;
245 pUS1
->US_BRGR
= (fp
<< 16) | brgr
;
247 // Write the Timeguard Register
253 // Initialize DMA buffers
254 pUS1
->US_TPR
= (uint32_t)0;
256 pUS1
->US_TNPR
= (uint32_t)0;
258 pUS1
->US_RPR
= (uint32_t)us_inbuf1
;
259 pUS1
->US_RCR
= USART_BUFFLEN
;
260 usart_cur_inbuf
= us_inbuf1
;
261 usart_cur_inbuf_off
= 0;
262 pUS1
->US_RNPR
= (uint32_t)us_inbuf2
;
263 pUS1
->US_RNCR
= USART_BUFFLEN
;
265 // Initialize our fifo
269 // re-enable receiver / transmitter
270 pUS1
->US_CR
= (AT91C_US_RXEN
| AT91C_US_TXEN
);
272 // ready to receive and transmit
273 pUS1
->US_PTCR
= AT91C_PDC_RXTEN
| AT91C_PDC_TXTEN
;