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