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