Use the PDI REPEAT instruction in the PDI programmer code to reduce protocol overhead...
[pub/USBasp.git] / Projects / AVRISP / Lib / PDITarget.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2009.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.fourwalledcubicle.com
7 */
8
9 /*
10 Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, and distribute this software
13 and its documentation for any purpose and without fee is hereby
14 granted, provided that the above copyright notice appear in all
15 copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaim all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29 */
30
31 /** \file
32 *
33 * Target-related functions for the PDI Protocol decoder.
34 */
35
36 #define INCLUDE_FROM_PDITARGET_C
37 #include "PDITarget.h"
38
39 #if defined(ENABLE_PDI_PROTOCOL) || defined(__DOXYGEN__)
40
41 volatile bool IsSending;
42
43 #if !defined(PDI_VIA_HARDWARE_USART)
44 volatile uint16_t SoftUSART_Data;
45 volatile uint8_t SoftUSART_BitCount;
46
47 ISR(TIMER1_COMPA_vect, ISR_BLOCK)
48 {
49 /* Toggle CLOCK pin in a single cycle (see AVR datasheet) */
50 BITBANG_PDICLOCK_PIN |= BITBANG_PDICLOCK_MASK;
51
52 /* If not sending or receiving, just exit */
53 if (!(SoftUSART_BitCount))
54 return;
55
56 /* Check to see if the current clock state is on the rising or falling edge */
57 bool IsRisingEdge = (BITBANG_PDICLOCK_PORT & BITBANG_PDICLOCK_MASK);
58
59 if (IsSending && !IsRisingEdge)
60 {
61 if (SoftUSART_Data & 0x01)
62 BITBANG_PDIDATA_PORT |= BITBANG_PDIDATA_MASK;
63 else
64 BITBANG_PDIDATA_PORT &= ~BITBANG_PDIDATA_MASK;
65
66 SoftUSART_Data >>= 1;
67 SoftUSART_BitCount--;
68 }
69 else if (!IsSending && IsRisingEdge)
70 {
71 /* Wait for the start bit when receiving */
72 if ((SoftUSART_BitCount == BITS_IN_FRAME) && (BITBANG_PDIDATA_PIN & BITBANG_PDIDATA_MASK))
73 return;
74
75 if (BITBANG_PDIDATA_PIN & BITBANG_PDIDATA_MASK)
76 SoftUSART_Data |= (1 << BITS_IN_FRAME);
77
78 SoftUSART_Data >>= 1;
79 SoftUSART_BitCount--;
80 }
81 }
82 #endif
83
84 void PDITarget_EnableTargetPDI(void)
85 {
86 #if defined(PDI_VIA_HARDWARE_USART)
87 /* Set Tx and XCK as outputs, Rx as input */
88 DDRD |= (1 << 5) | (1 << 3);
89 DDRD &= ~(1 << 2);
90
91 /* Set DATA line high for at least 90ns to disable /RESET functionality */
92 PORTD |= (1 << 3);
93 asm volatile ("NOP"::);
94 asm volatile ("NOP"::);
95
96 /* Set up the synchronous USART for XMEGA communications -
97 8 data bits, even parity, 2 stop bits */
98 UBRR1 = 10;
99 UCSR1B = (1 << TXEN1);
100 UCSR1C = (1 << UMSEL10) | (1 << UPM11) | (1 << USBS1) | (1 << UCSZ11) | (1 << UCSZ10) | (1 << UCPOL1);
101
102 /* Send two BREAKs of 12 bits each to enable PDI interface (need at least 16 idle bits) */
103 PDITarget_SendBreak();
104 PDITarget_SendBreak();
105 #else
106 /* Set DATA and CLOCK lines to outputs */
107 BITBANG_PDIDATA_DDR |= BITBANG_PDIDATA_MASK;
108 BITBANG_PDICLOCK_DDR |= BITBANG_PDICLOCK_MASK;
109
110 /* Set DATA line high for at least 90ns to disable /RESET functionality */
111 BITBANG_PDIDATA_PORT |= BITBANG_PDIDATA_MASK;
112 asm volatile ("NOP"::);
113 asm volatile ("NOP"::);
114
115 /* Fire timer compare ISR every 100 cycles to manage the software USART */
116 OCR1A = 100;
117 TCCR1B = (1 << WGM12) | (1 << CS10);
118 TIMSK1 = (1 << OCIE1A);
119
120 PDITarget_SendBreak();
121 PDITarget_SendBreak();
122 #endif
123 }
124
125 void PDITarget_DisableTargetPDI(void)
126 {
127 #if defined(PDI_VIA_HARDWARE_USART)
128 /* Turn off receiver and transmitter of the USART, clear settings */
129 UCSR1A |= (1 << TXC1) | (1 << RXC1);
130 UCSR1B = 0;
131 UCSR1C = 0;
132
133 /* Set all USART lines as input, tristate */
134 DDRD &= ~((1 << 5) | (1 << 3));
135 PORTD &= ~((1 << 5) | (1 << 3) | (1 << 2));
136 #else
137 /* Set DATA and CLOCK lines to inputs */
138 BITBANG_PDIDATA_DDR &= ~BITBANG_PDIDATA_MASK;
139 BITBANG_PDICLOCK_DDR &= ~BITBANG_PDICLOCK_MASK;
140
141 /* Tristate DATA and CLOCK lines */
142 BITBANG_PDIDATA_PORT &= ~BITBANG_PDIDATA_MASK;
143 BITBANG_PDICLOCK_PORT &= ~BITBANG_PDICLOCK_MASK;
144
145 TCCR0B = 0;
146 #endif
147 }
148
149 void PDITarget_SendByte(uint8_t Byte)
150 {
151 #if defined(PDI_VIA_HARDWARE_USART)
152 /* Switch to Tx mode if currently in Rx mode */
153 if (!(IsSending))
154 {
155 PORTD |= (1 << 3);
156 DDRD |= (1 << 3);
157
158 UCSR1B &= ~(1 << RXEN1);
159 UCSR1B |= (1 << TXEN1);
160
161 IsSending = true;
162 }
163
164 /* Wait until there is space in the hardware Tx buffer before writing */
165 while (!(UCSR1A & (1 << UDRE1)));
166 UDR1 = Byte;
167 #else
168 /* Switch to Tx mode if currently in Rx mode */
169 if (!(IsSending))
170 {
171 BITBANG_PDIDATA_PORT |= BITBANG_PDIDATA_MASK;
172 BITBANG_PDIDATA_DDR |= BITBANG_PDIDATA_MASK;
173
174 IsSending = true;
175 }
176
177 bool EvenParityBit = false;
178 uint8_t ParityData = Byte;
179
180 /* Compute Even parity bit */
181 for (uint8_t i = 0; i < 8; i++)
182 {
183 EvenParityBit ^= ParityData & 0x01;
184 ParityData >>= 1;
185 }
186
187 while (SoftUSART_BitCount);
188
189 /* Data shifted out LSB first, START DATA PARITY STOP STOP */
190 SoftUSART_Data = ((uint16_t)EvenParityBit << 9) | ((uint16_t)Byte << 1) | (1 << 10) | (1 << 11);
191 SoftUSART_BitCount = BITS_IN_FRAME;
192 #endif
193 }
194
195 uint8_t PDITarget_ReceiveByte(void)
196 {
197 #if defined(PDI_VIA_HARDWARE_USART)
198 /* Switch to Rx mode if currently in Tx mode */
199 if (IsSending)
200 {
201 while (!(UCSR1A & (1 << TXC1)));
202 UCSR1A |= (1 << TXC1);
203
204 UCSR1B &= ~(1 << TXEN1);
205 UCSR1B |= (1 << RXEN1);
206
207 DDRD &= ~(1 << 3);
208 PORTD &= ~(1 << 3);
209
210 IsSending = false;
211 }
212
213 /* Wait until a byte has been received before reading */
214 while (!(UCSR1A & (1 << RXC1)));
215 return UDR1;
216 #else
217 /* Switch to Rx mode if currently in Tx mode */
218 if (IsSending)
219 {
220 while (SoftUSART_BitCount);
221
222 BITBANG_PDIDATA_DDR &= ~BITBANG_PDIDATA_MASK;
223 BITBANG_PDIDATA_PORT &= ~BITBANG_PDIDATA_MASK;
224
225 IsSending = false;
226 }
227
228 /* Wait until a byte has been received before reading */
229 SoftUSART_BitCount = BITS_IN_FRAME;
230 while (SoftUSART_BitCount);
231
232 /* Throw away the start, parity and stop bits to leave only the data */
233 return (uint8_t)(SoftUSART_Data >> 1);
234 #endif
235 }
236
237 void PDITarget_SendBreak(void)
238 {
239 #if defined(PDI_VIA_HARDWARE_USART)
240 /* Switch to Tx mode if currently in Rx mode */
241 if (!(IsSending))
242 {
243 PORTD |= (1 << 3);
244 DDRD |= (1 << 3);
245
246 UCSR1B &= ~(1 << RXEN1);
247 UCSR1B |= (1 << TXEN1);
248
249 IsSending = true;
250 }
251
252 /* Need to do nothing for a full frame to send a BREAK */
253 for (uint8_t i = 0; i <= BITS_IN_FRAME; i++)
254 {
255 /* Wait for a full cycle of the clock */
256 while (PIND & (1 << 5));
257 while (!(PIND & (1 << 5)));
258 }
259 #else
260 /* Switch to Tx mode if currently in Rx mode */
261 if (!(IsSending))
262 {
263 BITBANG_PDIDATA_PORT |= BITBANG_PDIDATA_MASK;
264 BITBANG_PDIDATA_DDR |= BITBANG_PDIDATA_MASK;
265
266 IsSending = true;
267 }
268
269 while (SoftUSART_BitCount);
270
271 /* Need to do nothing for a full frame to send a BREAK */
272 SoftUSART_Data = 0x0FFF;
273 SoftUSART_BitCount = BITS_IN_FRAME;
274 #endif
275 }
276
277 bool PDITarget_WaitWhileNVMBusBusy(void)
278 {
279 TCNT0 = 0;
280
281 /* Poll the STATUS register to check to see if NVM access has been enabled */
282 while (TCNT0 < PDI_NVM_TIMEOUT_MS)
283 {
284 /* Send the LDCS command to read the PDI STATUS register to see the NVM bus is active */
285 PDITarget_SendByte(PDI_CMD_LDCS | PDI_STATUS_REG);
286 if (PDITarget_ReceiveByte() & PDI_STATUS_NVM)
287 return true;
288 }
289
290 return false;
291 }
292
293 #endif