9d79354bd08e697c7834af3a67bc3c2511031637
[pub/USBasp.git] / firmware / main.c
1 /*
2 USBasp - USB in-circuit programmer for Atmel AVR controllers
3
4 Thomas Fischl <tfischl@gmx.de>
5
6 License:
7 The project is built with AVR USB driver by Objective Development, which is
8 published under an own licence based on the GNU General Public License (GPL).
9 USBasp is also distributed under this enhanced licence. See Documentation.
10
11 Target.........: ATMega8 at 12 MHz
12 Creation Date..: 2005-02-20
13 Last change....: 2005-04-20
14
15 PC2 SCK speed option. GND -> slow (8khz SCK),
16 open -> fast (375kHz SCK)
17 */
18
19 #include <avr/io.h>
20 #include <avr/signal.h>
21 #include <avr/interrupt.h>
22 #include <avr/pgmspace.h>
23 #include <avr/wdt.h>
24
25 #include "usbdrv.h"
26 #include "isp.h"
27 #include "clock.h"
28
29 #define USBASP_FUNC_CONNECT 1
30 #define USBASP_FUNC_DISCONNECT 2
31 #define USBASP_FUNC_TRANSMIT 3
32 #define USBASP_FUNC_READFLASH 4
33 #define USBASP_FUNC_ENABLEPROG 5
34 #define USBASP_FUNC_WRITEFLASH 6
35 #define USBASP_FUNC_READEEPROM 7
36 #define USBASP_FUNC_WRITEEEPROM 8
37
38 #define PROG_STATE_IDLE 0
39 #define PROG_STATE_WRITEFLASH 1
40 #define PROG_STATE_READFLASH 2
41 #define PROG_STATE_READEEPROM 3
42 #define PROG_STATE_WRITEEEPROM 4
43
44 #define PROG_BLOCKFLAG_FIRST 1
45 #define PROG_BLOCKFLAG_LAST 2
46
47 #define ledRedOn() PORTC &= ~(1 << PC1)
48 #define ledRedOff() PORTC |= (1 << PC1)
49 #define ledGreenOn() PORTC &= ~(1 << PC0)
50 #define ledGreenOff() PORTC |= (1 << PC0)
51
52 static uchar replyBuffer[8];
53
54 static uchar prog_state = PROG_STATE_IDLE;
55
56 static unsigned int prog_address;
57 static unsigned int prog_nbytes = 0;
58 static uchar prog_pagesize;
59 static uchar prog_blockflags;
60 static uchar prog_pagecounter;
61
62
63 uchar usbFunctionSetup(uchar data[8]) {
64
65 uchar len = 0;
66
67 if(data[1] == USBASP_FUNC_CONNECT){
68
69 /* set SCK speed */
70 if ((PINC & (1 << PC2)) == 0) {
71 ispSetSCKOption(ISP_SCK_SLOW);
72 } else {
73 ispSetSCKOption(ISP_SCK_FAST);
74 }
75
76 ispConnect();
77 ledRedOn();
78
79 } else if (data[1] == USBASP_FUNC_DISCONNECT) {
80 ispDisconnect();
81 ledRedOff();
82
83 } else if (data[1] == USBASP_FUNC_TRANSMIT) {
84 replyBuffer[0] = ispTransmit(data[2]);
85 replyBuffer[1] = ispTransmit(data[3]);
86 replyBuffer[2] = ispTransmit(data[4]);
87 replyBuffer[3] = ispTransmit(data[5]);
88 len = 4;
89
90 } else if (data[1] == USBASP_FUNC_READFLASH) {
91 prog_address = (data[3] << 8) | data[2];
92 prog_nbytes = (data[7] << 8) | data[6];
93 prog_state = PROG_STATE_READFLASH;
94 len = 0xff; /* multiple in */
95
96 } else if (data[1] == USBASP_FUNC_READEEPROM) {
97 prog_address = (data[3] << 8) | data[2];
98 prog_nbytes = (data[7] << 8) | data[6];
99 prog_state = PROG_STATE_READEEPROM;
100 len = 0xff; /* multiple in */
101
102 } else if (data[1] == USBASP_FUNC_ENABLEPROG) {
103 replyBuffer[0] = ispEnterProgrammingMode();;
104 len = 1;
105
106 } else if (data[1] == USBASP_FUNC_WRITEFLASH) {
107 prog_address = (data[3] << 8) | data[2];
108 prog_pagesize = data[4];
109 prog_blockflags = data[5];
110 if (prog_blockflags & PROG_BLOCKFLAG_FIRST) {
111 prog_pagecounter = prog_pagesize;
112 }
113 prog_nbytes = (data[7] << 8) | data[6];
114 prog_state = PROG_STATE_WRITEFLASH;
115 len = 0xff; /* multiple out */
116
117 } else if (data[1] == USBASP_FUNC_WRITEEEPROM) {
118 prog_address = (data[3] << 8) | data[2];
119 prog_pagesize = 0;
120 prog_blockflags = 0;
121 prog_nbytes = (data[7] << 8) | data[6];
122 prog_state = PROG_STATE_WRITEEEPROM;
123 len = 0xff; /* multiple out */
124 }
125
126 usbMsgPtr = replyBuffer;
127
128 return len;
129 }
130
131
132 uchar usbFunctionRead(uchar *data, uchar len) {
133
134 uchar i;
135
136 /* check if programmer is in correct read state */
137 if ((prog_state != PROG_STATE_READFLASH) &&
138 (prog_state != PROG_STATE_READEEPROM)) {
139 return 0xff;
140 }
141
142 /* fill packet */
143 for (i = 0; i < len; i++) {
144 if (prog_state == PROG_STATE_READFLASH) {
145 data[i] = ispReadFlash(prog_address);
146 } else {
147 data[i] = ispReadEEPROM(prog_address);
148 }
149 prog_address++;
150 }
151
152 /* last packet? */
153 if (len < 8) {
154 prog_state = PROG_STATE_IDLE;
155 }
156
157 return len;
158 }
159
160
161 uchar usbFunctionWrite(uchar *data, uchar len) {
162
163 uchar i;
164
165 /* check if programmer is in correct write state */
166 if ((prog_state != PROG_STATE_WRITEFLASH) &&
167 (prog_state != PROG_STATE_WRITEEEPROM)) {
168 return 0xff;
169 }
170
171
172 for (i = 0; i < len; i++) {
173
174 if (prog_state == PROG_STATE_WRITEFLASH) {
175 /* Flash */
176
177 if (prog_pagesize == 0) {
178 /* not paged */
179 ispWriteFlash(prog_address, data[i], 1);
180 } else {
181 /* paged */
182 ispWriteFlash(prog_address, data[i], 0);
183 prog_pagecounter --;
184 if (prog_pagecounter == 0) {
185 ispFlushPage(prog_address, data[i]);
186 prog_pagecounter = prog_pagesize;
187 }
188 }
189
190 } else {
191 /* EEPROM */
192 ispWriteEEPROM(prog_address, data[i]);
193 }
194
195 prog_nbytes --;
196
197 if (prog_nbytes == 0) {
198 prog_state = PROG_STATE_IDLE;
199 if ((prog_blockflags & PROG_BLOCKFLAG_LAST) &&
200 (prog_pagecounter != prog_pagesize)) {
201
202 /* last block and page flush pending, so flush it now */
203 ispFlushPage(prog_address, data[i]);
204 }
205 }
206
207 prog_address ++;
208 }
209
210 return 0;
211 }
212
213
214 int main(void)
215 {
216 PORTD = 0;
217 PORTB = 0; /* no pullups on USB and ISP pins */
218 DDRD = ~(1 << 2); /* all outputs except PD2 = INT0 */
219 DDRB = 0; /* all USB and ISP pins inputs */
220
221 DDRC = 0x03; /* all inputs except PC0, PC1 */
222 PORTC = 0xfe;
223
224 clockInit(); /* init timer */
225
226 ispSetSCKOption(ISP_SCK_FAST);
227
228 usbInit();
229 sei();
230 for(;;){ /* main event loop */
231 usbPoll();
232 }
233 return 0;
234 }