Rev Author Line No. Line
3471 miho 1 /*
2 * isp.c - part of USBasp
3 *
4 * Autor..........: Thomas Fischl <tfischl@gmx.de>
5 * Description....: Provides functions for communication/programming
6 * over ISP interface
7 * Licence........: GNU GPL v2 (see Readme.txt)
8 * Creation Date..: 2005-02-23
9 * Last change....: 2010-01-19
10 */
11  
12 #include <avr/io.h>
13 #include "isp.h"
14 #include "clock.h"
15 #include "usbasp.h"
16  
17 #define spiHWdisable() SPCR = 0
18  
19 uchar sck_sw_delay;
20 uchar sck_spcr;
21 uchar sck_spsr;
22 uchar isp_hiaddr;
23  
24 void spiHWenable() {
25 SPCR = sck_spcr;
26 SPSR = sck_spsr;
27 }
28  
29 void ispSetSCKOption(uchar option) {
30  
31 if (option == USBASP_ISP_SCK_AUTO)
32 option = USBASP_ISP_SCK_375;
33  
34 if (option >= USBASP_ISP_SCK_93_75) {
35 ispTransmit = ispTransmit_hw;
36 sck_spsr = 0;
37 sck_sw_delay = 1; /* force RST#/SCK pulse for 320us */
38  
39 switch (option) {
40  
41 case USBASP_ISP_SCK_1500:
42 /* enable SPI, master, 1.5MHz, XTAL/8 */
43 sck_spcr = (1 << SPE) | (1 << MSTR) | (1 << SPR0);
44 sck_spsr = (1 << SPI2X);
45 case USBASP_ISP_SCK_750:
46 /* enable SPI, master, 750kHz, XTAL/16 */
47 sck_spcr = (1 << SPE) | (1 << MSTR) | (1 << SPR0);
48 break;
49 case USBASP_ISP_SCK_375:
50 default:
51 /* enable SPI, master, 375kHz, XTAL/32 (default) */
52 sck_spcr = (1 << SPE) | (1 << MSTR) | (1 << SPR1);
53 sck_spsr = (1 << SPI2X);
54 break;
55 case USBASP_ISP_SCK_187_5:
56 /* enable SPI, master, 187.5kHz XTAL/64 */
57 sck_spcr = (1 << SPE) | (1 << MSTR) | (1 << SPR1);
58 break;
59 case USBASP_ISP_SCK_93_75:
60 /* enable SPI, master, 93.75kHz XTAL/128 */
61 sck_spcr = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);
62 break;
63 }
64  
65 } else {
66 ispTransmit = ispTransmit_sw;
67 switch (option) {
68  
69 case USBASP_ISP_SCK_32:
70 sck_sw_delay = 3;
71  
72 break;
73 case USBASP_ISP_SCK_16:
74 sck_sw_delay = 6;
75  
76 break;
77 case USBASP_ISP_SCK_8:
78 sck_sw_delay = 12;
79  
80 break;
81 case USBASP_ISP_SCK_4:
82 sck_sw_delay = 24;
83  
84 break;
85 case USBASP_ISP_SCK_2:
86 sck_sw_delay = 48;
87  
88 break;
89 case USBASP_ISP_SCK_1:
90 sck_sw_delay = 96;
91  
92 break;
93 case USBASP_ISP_SCK_0_5:
94 sck_sw_delay = 192;
95  
96 break;
97 }
98 }
99 }
100  
101 void ispDelay() {
102  
103 uint8_t starttime = TIMERVALUE;
104 while ((uint8_t) (TIMERVALUE - starttime) < sck_sw_delay) {
105 }
106 }
107  
108 void ispConnect() {
109  
110 /* all ISP pins are inputs before */
111 /* now set output pins */
112 ISP_DDR |= (1 << ISP_RST) | (1 << ISP_SCK) | (1 << ISP_MOSI);
113  
114 /* reset device */
115 ISP_OUT &= ~(1 << ISP_RST); /* RST low */
116 ISP_OUT &= ~(1 << ISP_SCK); /* SCK low */
117  
118 /* positive reset pulse > 2 SCK (target) */
119 ispDelay();
120 ISP_OUT |= (1 << ISP_RST); /* RST high */
121 ispDelay();
122 ISP_OUT &= ~(1 << ISP_RST); /* RST low */
123  
124 if (ispTransmit == ispTransmit_hw) {
125 spiHWenable();
126 }
127  
128 /* Initial extended address value */
129 isp_hiaddr = 0;
130 }
131  
132 void ispDisconnect() {
133  
134 /* set all ISP pins inputs */
135 ISP_DDR &= ~((1 << ISP_RST) | (1 << ISP_SCK) | (1 << ISP_MOSI));
136 /* switch pullups off */
137 ISP_OUT &= ~((1 << ISP_RST) | (1 << ISP_SCK) | (1 << ISP_MOSI));
138  
139 /* disable hardware SPI */
140 spiHWdisable();
141 }
142  
143 uchar ispTransmit_sw(uchar send_byte) {
144  
145 uchar rec_byte = 0;
146 uchar i;
147 for (i = 0; i < 8; i++) {
148  
149 /* set MSB to MOSI-pin */
150 if ((send_byte & 0x80) != 0) {
151 ISP_OUT |= (1 << ISP_MOSI); /* MOSI high */
152 } else {
153 ISP_OUT &= ~(1 << ISP_MOSI); /* MOSI low */
154 }
155 /* shift to next bit */
156 send_byte = send_byte << 1;
157  
158 /* receive data */
159 rec_byte = rec_byte << 1;
160 if ((ISP_IN & (1 << ISP_MISO)) != 0) {
161 rec_byte++;
162 }
163  
164 /* pulse SCK */
165 ISP_OUT |= (1 << ISP_SCK); /* SCK high */
166 ispDelay();
167 ISP_OUT &= ~(1 << ISP_SCK); /* SCK low */
168 ispDelay();
169 }
170  
171 return rec_byte;
172 }
173  
174 uchar ispTransmit_hw(uchar send_byte) {
175 SPDR = send_byte;
176  
177 while (!(SPSR & (1 << SPIF)))
178 ;
179 return SPDR;
180 }
181  
182 uchar ispEnterProgrammingMode() {
183 uchar check;
184 uchar count = 32;
185  
186 while (count--) {
187 ispTransmit(0xAC);
188 ispTransmit(0x53);
189 check = ispTransmit(0);
190 ispTransmit(0);
191  
192 if (check == 0x53) {
193 return 0;
194 }
195  
196 spiHWdisable();
197  
198 /* pulse RST */
199 ispDelay();
200 ISP_OUT |= (1 << ISP_RST); /* RST high */
201 ispDelay();
202 ISP_OUT &= ~(1 << ISP_RST); /* RST low */
203 ispDelay();
204  
205 if (ispTransmit == ispTransmit_hw) {
206 spiHWenable();
207 }
208  
209 }
210  
211 return 1; /* error: device dosn't answer */
212 }
213  
214 static void ispUpdateExtended(unsigned long address)
215 {
216 uchar curr_hiaddr;
217  
218 curr_hiaddr = (address >> 17);
219  
220 /* check if extended address byte is changed */
221 if(isp_hiaddr != curr_hiaddr)
222 {
223 isp_hiaddr = curr_hiaddr;
224 /* Load Extended Address byte */
225 ispTransmit(0x4D);
226 ispTransmit(0x00);
227 ispTransmit(isp_hiaddr);
228 ispTransmit(0x00);
229 }
230 }
231  
232 uchar ispReadFlash(unsigned long address) {
233  
234 ispUpdateExtended(address);
235  
236 ispTransmit(0x20 | ((address & 1) << 3));
237 ispTransmit(address >> 9);
238 ispTransmit(address >> 1);
239 return ispTransmit(0);
240 }
241  
242 uchar ispWriteFlash(unsigned long address, uchar data, uchar pollmode) {
243  
244 /* 0xFF is value after chip erase, so skip programming
245 if (data == 0xFF) {
246 return 0;
247 }
248 */
249  
250 ispUpdateExtended(address);
251  
252 ispTransmit(0x40 | ((address & 1) << 3));
253 ispTransmit(address >> 9);
254 ispTransmit(address >> 1);
255 ispTransmit(data);
256  
257 if (pollmode == 0)
258 return 0;
259  
260 if (data == 0x7F) {
261 clockWait(15); /* wait 4,8 ms */
262 return 0;
263 } else {
264  
265 /* polling flash */
266 uchar retries = 30;
267 uint8_t starttime = TIMERVALUE;
268 while (retries != 0) {
269 if (ispReadFlash(address) != 0x7F) {
270 return 0;
271 };
272  
273 if ((uint8_t) (TIMERVALUE - starttime) > CLOCK_T_320us) {
274 starttime = TIMERVALUE;
275 retries--;
276 }
277  
278 }
279 return 1; /* error */
280 }
281  
282 }
283  
284 uchar ispFlushPage(unsigned long address, uchar pollvalue) {
285  
286 ispUpdateExtended(address);
287  
288 ispTransmit(0x4C);
289 ispTransmit(address >> 9);
290 ispTransmit(address >> 1);
291 ispTransmit(0);
292  
293 if (pollvalue == 0xFF) {
294 clockWait(15);
295 return 0;
296 } else {
297  
298 /* polling flash */
299 uchar retries = 30;
300 uint8_t starttime = TIMERVALUE;
301  
302 while (retries != 0) {
303 if (ispReadFlash(address) != 0xFF) {
304 return 0;
305 };
306  
307 if ((uint8_t) (TIMERVALUE - starttime) > CLOCK_T_320us) {
308 starttime = TIMERVALUE;
309 retries--;
310 }
311  
312 }
313  
314 return 1; /* error */
315 }
316  
317 }
318  
319 uchar ispReadEEPROM(unsigned int address) {
320 ispTransmit(0xA0);
321 ispTransmit(address >> 8);
322 ispTransmit(address);
323 return ispTransmit(0);
324 }
325  
326 uchar ispWriteEEPROM(unsigned int address, uchar data) {
327  
328 ispTransmit(0xC0);
329 ispTransmit(address >> 8);
330 ispTransmit(address);
331 ispTransmit(data);
332  
333 clockWait(30); // wait 9,6 ms
334  
335 return 0;
336 }