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