Werner's Miscellanea
Sign in or create your account | Project List | Help
Werner's Miscellanea Commit Details
Date: | 2012-05-25 18:55:02 (11 years 10 months ago) |
---|---|
Author: | Werner Almesberger |
Commit: | 6bdfea64359b0229aa1389c3706d324692ea674a |
Message: | bacon/prog/: simple PIC 18F{2,4}xJxx programmer (for the Ben
Nanonote) |
Files: |
bacon/prog/Makefile (1 diff) bacon/prog/gpio-xburst.c (1 diff) bacon/prog/gpio-xburst.h (1 diff) bacon/prog/picpen.c (1 diff) |
Change Details
bacon/prog/Makefile | ||
---|---|---|
1 | # | |
2 | # picpen/Makefile - PIC Programmer/Emulator for Nanonote | |
3 | # | |
4 | # Written 2008, 2010-2011 by Werner Almesberger | |
5 | # Copyright 2008, 2010-2011 Werner Almesberger | |
6 | # | |
7 | # This program is free software; you can redistribute it and/or modify | |
8 | # it under the terms of the GNU General Public License as published by | |
9 | # the Free Software Foundation; either version 2 of the License, or | |
10 | # (at your option) any later version. | |
11 | # | |
12 | ||
13 | ||
14 | PREFIX=/usr | |
15 | ||
16 | ifeq ($(TARGET),) | |
17 | TARGET = ben_openwrt | |
18 | endif | |
19 | ||
20 | CC_ben_jlime = mipsel-linux-gcc | |
21 | CC_ben_openwrt = mipsel-openwrt-linux-gcc | |
22 | ||
23 | UPLOAD_ben_jlime = scp f32x jlime: | |
24 | UPLOAD_ben_openwrt = scp f32x ben: | |
25 | ||
26 | NAME = picpen | |
27 | CC = $(CC_$(TARGET)) | |
28 | CFLAGS = -Wall -Wshadow -O9 -g -static | |
29 | OBJS = picpen.o gpio-xburst.o | |
30 | LDFLAGS = -static | |
31 | ||
32 | ||
33 | .PHONY: all install uninstall clean depend spotless | |
34 | ||
35 | all: $(NAME) | |
36 | ||
37 | $(NAME): $(OBJS) | |
38 | ||
39 | upload: | |
40 | $(UPLOAD_$(TARGET)) | |
41 | ||
42 | install: $(NAME) | |
43 | install -D $(NAME) $(PREFIX)/bin/$(NAME) | |
44 | ||
45 | uninstall: | |
46 | rm -f $(PREFIX)/bin/$(NAME) | |
47 | ||
48 | depend: | |
49 | $(CPP) $(CFLAGS) -MM -MG *.c >.depend || \ | |
50 | { rm -f .depend; exit 1; } | |
51 | ||
52 | ifeq (.depend,$(wildcard .depend)) | |
53 | include .depend | |
54 | endif | |
55 | ||
56 | c2-om.o: c2-bitbang.c | |
57 | c2-ben.o: c2-bitbang.c | |
58 | ||
59 | clean: | |
60 | rm -f $(OBJS) $(OBJS_ben) .depend | |
61 | ||
62 | spotless: clean | |
63 | rm -f $(NAME) |
bacon/prog/gpio-xburst.c | ||
---|---|---|
1 | /* | |
2 | * gpio-xburst.c - Really primitive XBurst GPIO access | |
3 | * | |
4 | * Written 2010-2011 by Werner Almesberger | |
5 | * Copyright 2010-2011 Werner Almesberger | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation; either version 2 of the License, or | |
10 | * (at your option) any later version. | |
11 | */ | |
12 | ||
13 | ||
14 | #include <stdlib.h> | |
15 | #include <stdio.h> | |
16 | #include <fcntl.h> | |
17 | #include <sys/mman.h> | |
18 | ||
19 | #include "gpio-xburst.h" | |
20 | ||
21 | ||
22 | #define BASE 0x10010000 | |
23 | ||
24 | ||
25 | volatile void *mem; | |
26 | ||
27 | ||
28 | void gpio_init(void) | |
29 | { | |
30 | int fd; | |
31 | ||
32 | fd = open("/dev/mem", O_RDWR | O_SYNC); | |
33 | if (fd < 0) { | |
34 | perror("/dev/mem"); | |
35 | exit(1); | |
36 | } | |
37 | mem = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, BASE); | |
38 | if (mem == MAP_FAILED) { | |
39 | perror("mmap"); | |
40 | exit(1); | |
41 | } | |
42 | } |
bacon/prog/gpio-xburst.h | ||
---|---|---|
1 | /* | |
2 | * gpio-xburst.h - Really primitive XBurst GPIO access | |
3 | * | |
4 | * Written 2010 by Werner Almesberger | |
5 | * Copyright 2010 Werner Almesberger | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation; either version 2 of the License, or | |
10 | * (at your option) any later version. | |
11 | */ | |
12 | ||
13 | /* | |
14 | * Ports are numbered 0 = A, 1 = B, ... | |
15 | */ | |
16 | ||
17 | ||
18 | #ifndef GPIO_XBURST_H | |
19 | #define GPIO_XBURST_H | |
20 | ||
21 | ||
22 | #include <stdint.h> | |
23 | ||
24 | ||
25 | volatile void *mem; | |
26 | ||
27 | ||
28 | #define REG(off) (*(volatile uint32_t *) (mem+(off))) | |
29 | ||
30 | #define port_pin(port) REG(port*0x100) | |
31 | #define port_dats(port) REG(port*0x100+0x14) | |
32 | #define port_datc(port) REG(port*0x100+0x18) | |
33 | #define port_func(port) REG(port*0x100+0x48) | |
34 | #define port_dirs(port) REG(port*0x100+0x64) | |
35 | #define port_dirc(port) REG(port*0x100+0x68) | |
36 | ||
37 | ||
38 | static inline void gpio_high(unsigned port, unsigned bit) | |
39 | { | |
40 | port_dats(port) = 1 << bit; | |
41 | } | |
42 | ||
43 | ||
44 | static inline void gpio_low(unsigned port, unsigned bit) | |
45 | { | |
46 | port_datc(port) = 1 << bit; | |
47 | } | |
48 | ||
49 | ||
50 | static inline void gpio_set(unsigned port, unsigned bit, int value) | |
51 | { | |
52 | if (value) | |
53 | gpio_high(port, bit); | |
54 | else | |
55 | gpio_low(port, bit); | |
56 | } | |
57 | ||
58 | ||
59 | static inline int gpio_get(unsigned port, unsigned bit) | |
60 | { | |
61 | return (port_pin(port) >> bit) & 1; | |
62 | } | |
63 | ||
64 | ||
65 | static inline void gpio_output(unsigned port, unsigned bit) | |
66 | { | |
67 | port_dirs(port) = 1 << bit; | |
68 | } | |
69 | ||
70 | ||
71 | static inline void gpio_input(unsigned port, unsigned bit) | |
72 | { | |
73 | port_dirc(port) = 1 << bit; | |
74 | } | |
75 | ||
76 | ||
77 | void gpio_init(void); | |
78 | ||
79 | ||
80 | #endif /* !GPIO_XBURST_H */ |
bacon/prog/picpen.c | ||
---|---|---|
1 | /* | |
2 | * picpen.c - PIC (18F{2,4}xJxx) Programmer/Emulator for Nanonote | |
3 | * | |
4 | * Written 2012 by Werner Almesberger | |
5 | * Copyright 2012 Werner Almesberger | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation; either version 2 of the License, or | |
10 | * (at your option) any later version. | |
11 | */ | |
12 | ||
13 | ||
14 | #include <stdint.h> | |
15 | #include <stdlib.h> | |
16 | #include <stdio.h> | |
17 | #include <unistd.h> | |
18 | #include <string.h> | |
19 | #include <assert.h> | |
20 | ||
21 | #include "gpio-xburst.h" | |
22 | ||
23 | ||
24 | #define POWER_OFF 3, 2 /* PD02 */ | |
25 | #define nMCLR 3, 13 /* PD13 DAT3 */ | |
26 | #define PGD 3, 8 /* PD09 CMD */ | |
27 | #define PGC 3, 9 /* PD08 CLK */ | |
28 | ||
29 | #define ICSP_KEY 0x4d434850 | |
30 | ||
31 | #define P5_US 1 /* Delay Between 4-Bit Command and Command Operand */ | |
32 | #define P5A_US 1 /* Delay Between 4-Bit Command Operand and Next 4-Bit | |
33 | Command */ | |
34 | #define P6_US 1 /* Delay Between Last PGC down of Command Byte | |
35 | to First PGC up of Read of Data Word */ | |
36 | #define P9_US 1200 /* Delay to allow Block Programming to Occur */ | |
37 | #define P10_US 54000 /* Delay to allow Row Erase to Occur */ | |
38 | #define P11_US 524000 /* Delay to allow Bulk Erase to Occur */ | |
39 | #define P12_US 400 /* Input Data Hold Time from nMCLR up */ | |
40 | #define P13_US 1 /* VDD up Setup Time to nMCLR up */ | |
41 | #define P16_US 1 /* Delay Between Last PGC down and nMCLR down */ | |
42 | #define P17_US 3 /* nMCLR down to VDD down */ | |
43 | #define P19_US 4000 /* Delay from First nMCLR down to First PGC up for | |
44 | Key Sequence on PGD */ | |
45 | #define P20_US 1 /* Delay from Last PGC down for Key Sequence on | |
46 | PGD to Second nMCLR up */ | |
47 | ||
48 | #define CMD_INSN 0 | |
49 | #define CMD_TABLAT 0x2 | |
50 | #define CMD_READ_INC 0x9 /* post-increment by 1 */ | |
51 | #define CMD_WRITE 0xc | |
52 | #define CMD_WRITE_INC 0xd /* post-increment by 2 */ | |
53 | #define CMD_WRITE_START 0xf | |
54 | ||
55 | #define INSN_MOVLW 0x0e | |
56 | #define INSN_MOVWF 0x6e | |
57 | #define INSN_MOVF_W_0 0x50 | |
58 | #define INSN_MOVFF1 0xcf | |
59 | #define INSN_MOVFF2 0xff | |
60 | ||
61 | #define REG_TABLAT 0xf5 | |
62 | #define REG_TBLPTRL 0xf6 | |
63 | #define REG_TBLPTRH 0xf7 | |
64 | #define REG_TBLPTRU 0xf8 | |
65 | ||
66 | #define REG_ANCON0 0x48 /* banked ! */ | |
67 | #define REG_ANCON1 0x49 /* banked ! */ | |
68 | #define REG_PORTA 0x80 | |
69 | #define REG_PORTC 0x82 | |
70 | #define REG_LATA 0x89 | |
71 | #define REG_TRISA 0x92 /* 1 = in */ | |
72 | #define REG_EECON1 0xa6 | |
73 | #define REG_CTMUICON 0xb1 | |
74 | #define REG_CTMUCONL 0xb2 | |
75 | #define REG_CTMUCONH 0xb3 | |
76 | #define REG_ADCON1 0xc1 | |
77 | #define REG_ADCON0 0xc2 | |
78 | #define REG_ADRESL 0xc3 | |
79 | #define REG_ADRESH 0xc4 | |
80 | ||
81 | #define BLOCK 64 | |
82 | ||
83 | ||
84 | struct rec { | |
85 | uint32_t addr; | |
86 | uint8_t *data; | |
87 | int len; | |
88 | struct rec *next; | |
89 | }; | |
90 | ||
91 | static int kb; | |
92 | ||
93 | ||
94 | /* The multiplier (100) is a wild guess. Tested down to 0. */ | |
95 | ||
96 | static inline void delay(int us) | |
97 | { | |
98 | uint32_t i; | |
99 | ||
100 | if (us < 10) | |
101 | for (i = 0; i != us*100; i++) | |
102 | asm(""); | |
103 | else | |
104 | usleep(us); | |
105 | } | |
106 | ||
107 | ||
108 | static void icsp_begin(int power) | |
109 | { | |
110 | int i; | |
111 | ||
112 | gpio_init(); | |
113 | ||
114 | gpio_high(nMCLR); | |
115 | gpio_high(PGD); | |
116 | gpio_high(PGC); | |
117 | ||
118 | if (power) { | |
119 | gpio_output(POWER_OFF); | |
120 | gpio_output(PGD); | |
121 | gpio_output(PGC); | |
122 | gpio_output(nMCLR); | |
123 | ||
124 | delay(100*1000); /* precharge */ | |
125 | } | |
126 | ||
127 | gpio_low(PGD); | |
128 | gpio_low(PGC); | |
129 | gpio_low(nMCLR); | |
130 | ||
131 | if (power) | |
132 | gpio_low(POWER_OFF); | |
133 | delay(P13_US); | |
134 | ||
135 | gpio_high(nMCLR); | |
136 | delay(1); | |
137 | gpio_low(nMCLR); | |
138 | delay(P19_US); | |
139 | ||
140 | for (i = 31; i >= 0; i--) { | |
141 | if ((ICSP_KEY >> i) & 1) | |
142 | gpio_high(PGD); | |
143 | else | |
144 | gpio_low(PGD); | |
145 | gpio_high(PGC); | |
146 | gpio_low(PGC); | |
147 | } | |
148 | ||
149 | delay(P20_US); | |
150 | gpio_high(nMCLR); | |
151 | delay(P12_US); | |
152 | } | |
153 | ||
154 | ||
155 | static void icsp_end(void) | |
156 | { | |
157 | gpio_low(PGD); | |
158 | gpio_low(PGC); | |
159 | ||
160 | delay(P16_US); | |
161 | gpio_low(nMCLR); | |
162 | delay(P17_US); | |
163 | ||
164 | gpio_high(nMCLR); | |
165 | // gpio_high(POWER_OFF); | |
166 | ||
167 | gpio_input(PGD); | |
168 | gpio_input(PGC); | |
169 | } | |
170 | ||
171 | ||
172 | static void icsp_send(uint8_t v, int n) | |
173 | { | |
174 | int i; | |
175 | ||
176 | for (i = 0; i != n; i++) { | |
177 | if ((v >> i) & 1) | |
178 | gpio_high(PGD); | |
179 | else | |
180 | gpio_low(PGD); | |
181 | gpio_high(PGC); | |
182 | gpio_low(PGC); | |
183 | } | |
184 | } | |
185 | ||
186 | ||
187 | static uint8_t icsp_recv(int n) | |
188 | { | |
189 | uint8_t v = 0; | |
190 | int i; | |
191 | ||
192 | for (i = 0; i != n; i++) { | |
193 | gpio_high(PGC); | |
194 | gpio_low(PGC); | |
195 | if (gpio_get(PGD)) | |
196 | v |= 1 << i; | |
197 | } | |
198 | return v; | |
199 | } | |
200 | ||
201 | ||
202 | static void icsp_write(uint8_t cmd, uint8_t a, uint8_t b) | |
203 | { | |
204 | icsp_send(cmd, 4); | |
205 | delay(P5_US); | |
206 | icsp_send(b, 8); | |
207 | icsp_send(a, 8); | |
208 | delay(P5A_US); | |
209 | } | |
210 | ||
211 | ||
212 | static void write_reg(uint8_t addr, uint8_t v) | |
213 | { | |
214 | icsp_write(CMD_INSN, INSN_MOVLW, v); | |
215 | icsp_write(CMD_INSN, INSN_MOVWF, addr); | |
216 | } | |
217 | ||
218 | ||
219 | static uint8_t read_reg(uint8_t addr) | |
220 | { | |
221 | uint8_t v; | |
222 | ||
223 | icsp_write(CMD_INSN, 0x50, addr); | |
224 | /* for some strange reason we need two writes */ | |
225 | icsp_write(CMD_INSN, INSN_MOVWF, REG_TABLAT); | |
226 | icsp_write(CMD_INSN, INSN_MOVWF, REG_TABLAT); | |
227 | ||
228 | icsp_send(CMD_TABLAT, 4); | |
229 | delay(P5_US); | |
230 | ||
231 | icsp_send(0, 8); | |
232 | delay(P6_US); | |
233 | gpio_input(PGD); | |
234 | ||
235 | v = icsp_recv(8); | |
236 | delay(P5A_US); | |
237 | gpio_output(PGD); | |
238 | ||
239 | return v; | |
240 | } | |
241 | ||
242 | ||
243 | static void set_tblptr(uint32_t addr) | |
244 | { | |
245 | write_reg(REG_TBLPTRU, addr >> 16); | |
246 | write_reg(REG_TBLPTRH, addr >> 8); | |
247 | write_reg(REG_TBLPTRL, addr); | |
248 | } | |
249 | ||
250 | ||
251 | static void read_mem(uint32_t addr, uint8_t *buf, int len) | |
252 | { | |
253 | set_tblptr(addr); | |
254 | ||
255 | while (len--) { | |
256 | icsp_send(CMD_READ_INC, 4); | |
257 | delay(P5_US); | |
258 | icsp_send(0, 8); | |
259 | delay(P6_US); | |
260 | gpio_input(PGD); | |
261 | ||
262 | *buf++ = icsp_recv(8); | |
263 | delay(P5A_US); | |
264 | gpio_output(PGD); | |
265 | } | |
266 | } | |
267 | ||
268 | ||
269 | static void bulk_erase(void) | |
270 | { | |
271 | set_tblptr(0x3c0005); | |
272 | icsp_write(CMD_WRITE, 0x01, 0x01); | |
273 | set_tblptr(0x3c0004); | |
274 | icsp_write(CMD_WRITE, 0x80, 0x80); | |
275 | icsp_write(CMD_INSN, 0, 0); | |
276 | ||
277 | icsp_send(0, 4); | |
278 | delay(P11_US+P10_US); | |
279 | ||
280 | icsp_send(0, 16); | |
281 | delay(P5A_US); /* guess*/ | |
282 | } | |
283 | ||
284 | ||
285 | static void write_mem(uint32_t addr, const uint8_t *buf, int len) | |
286 | { | |
287 | int i; | |
288 | uint8_t first; | |
289 | ||
290 | assert(!(addr & (BLOCK-1))); | |
291 | assert(!(len & (BLOCK-1))); | |
292 | ||
293 | /* BSF EECON1, WREN */ | |
294 | icsp_write(CMD_INSN, 0x84, REG_EECON1); | |
295 | ||
296 | while (len) { | |
297 | set_tblptr(addr); | |
298 | for (i = 0; i != BLOCK/2-1; i++) { | |
299 | first = *buf++; | |
300 | icsp_write(CMD_WRITE_INC, *buf++, first); | |
301 | } | |
302 | first = *buf++; | |
303 | icsp_write(CMD_WRITE_START, *buf++, first); | |
304 | ||
305 | icsp_send(0, 3); | |
306 | gpio_low(PGD); | |
307 | gpio_high(PGC); | |
308 | delay(P9_US); | |
309 | gpio_low(PGC); | |
310 | delay(P5_US); | |
311 | ||
312 | icsp_send(0, 16); | |
313 | delay(P5A_US); /* guess*/ | |
314 | ||
315 | addr += BLOCK; | |
316 | len -= BLOCK; | |
317 | } | |
318 | } | |
319 | ||
320 | ||
321 | /* ----- Flash-level operations -------------------------------------------- */ | |
322 | ||
323 | ||
324 | static void flash_record(const struct rec *rec) | |
325 | { | |
326 | uint8_t *tmp; | |
327 | int off, padded; | |
328 | ||
329 | off = rec->addr & (BLOCK-1); | |
330 | padded = (rec->len+off+BLOCK-1) & ~(BLOCK-1); | |
331 | if (!off && padded == rec->len) { | |
332 | write_mem(rec->addr, rec->data, rec->len); | |
333 | return; | |
334 | } | |
335 | tmp = malloc(padded); | |
336 | if (!tmp) { | |
337 | perror("malloc"); | |
338 | exit(1); | |
339 | } | |
340 | memset(tmp, 0xff, off); | |
341 | memcpy(tmp+off, rec->data, rec->len); | |
342 | memset(tmp+off+rec->len, 0xff, padded-rec->len-off); | |
343 | write_mem(rec->addr-off, tmp, padded); | |
344 | } | |
345 | ||
346 | ||
347 | static void verify_record(const struct rec *rec) | |
348 | { | |
349 | uint8_t *tmp; | |
350 | int i; | |
351 | ||
352 | tmp = malloc(rec->len); | |
353 | if (!tmp) { | |
354 | perror("malloc"); | |
355 | exit(1); | |
356 | } | |
357 | read_mem(rec->addr, tmp, rec->len); | |
358 | for (i = 0; i != rec->len; i++) | |
359 | if (rec->data[i] != tmp[i]) { | |
360 | fprintf(stderr, | |
361 | "%04x: wrote %02x != read %02x\n", | |
362 | rec->addr+i, rec->data[i], tmp[i]); | |
363 | } | |
364 | } | |
365 | ||
366 | ||
367 | static void flash_file(const struct rec *recs) | |
368 | { | |
369 | const struct rec *rec; | |
370 | ||
371 | for (rec = recs; rec; rec = rec->next) | |
372 | if (rec->addr+rec->len > kb*1024) { | |
373 | fprintf(stderr, | |
374 | "record 0x%x+0x%x ends outside Flash of %d bytes\n", | |
375 | rec->addr, rec->len, kb*1024-8); | |
376 | exit(1); | |
377 | } | |
378 | ||
379 | bulk_erase(); | |
380 | for (rec = recs; rec; rec = rec->next) | |
381 | flash_record(rec); | |
382 | ||
383 | for (rec = recs; rec; rec = rec->next) | |
384 | verify_record(rec); | |
385 | } | |
386 | ||
387 | ||
388 | static void dump_flash(void) | |
389 | { | |
390 | uint8_t *tmp, c; | |
391 | int i, j; | |
392 | ||
393 | tmp = malloc(kb*1024); | |
394 | if (!tmp) { | |
395 | perror("malloc"); | |
396 | exit(1); | |
397 | } | |
398 | ||
399 | read_mem(0, tmp, kb*1024); | |
400 | ||
401 | for (i = 0; i != kb*1024; i += 16) { | |
402 | printf("%04X: ", i); | |
403 | for (j = 0; j != 16; j++) | |
404 | printf("%02X ", tmp[i+j]); | |
405 | for (j = 0; j != 16; j++) { | |
406 | c = tmp[i+j]; | |
407 | printf("%c", c >= ' ' && c <= '~' ? c : '.'); | |
408 | } | |
409 | printf("\n"); | |
410 | } | |
411 | } | |
412 | ||
413 | ||
414 | /* ----- Experiments ------------------------------------------------------- */ | |
415 | ||
416 | ||
417 | #if 0 | |
418 | ||
419 | static void blink(void) | |
420 | { | |
421 | write_reg(REG_TRISA, 0xfc); | |
422 | while (1) { | |
423 | write_reg(REG_LATA, 1); | |
424 | gpio_high(PGD); | |
425 | delay(200*1000); | |
426 | write_reg(REG_LATA, 2); | |
427 | gpio_high(PGD); | |
428 | delay(200*1000); | |
429 | } | |
430 | } | |
431 | ||
432 | ||
433 | static void adc(void) | |
434 | { | |
435 | int i; | |
436 | ||
437 | #if 0 | |
438 | for (i = 0; i != 256; i++) { | |
439 | // write_reg(REG_ANCON0, 0xff); | |
440 | // write_reg(REG_TABLAT, i); | |
441 | // write_reg(REG_TABLAT, i); | |
442 | printf("%02x ", read_reg(REG_PORTC)); | |
443 | fflush(stdout); | |
444 | } | |
445 | #endif | |
446 | write_reg(REG_TRISA, 0xfc); | |
447 | // write_reg(REG_ANCON0, 0x10); /* AN4 is analog */ | |
448 | write_reg(REG_ADCON0, 0x20); /* AN4, Vss to AVdd */ | |
449 | write_reg(REG_ADCON1, 0x80); /* Tad = 0, Fosc/2, right just. */ | |
450 | write_reg(REG_ADCON0, 0x21); /* Enable ADC module */ | |
451 | while (1) { | |
452 | uint8_t hi, lo; | |
453 | ||
454 | write_reg(REG_ADCON0, 0x23); /* GO */ | |
455 | while (read_reg(REG_ADCON0) & 2) | |
456 | write(2, ".", 1); | |
457 | hi = read_reg(REG_ADRESH); | |
458 | lo = read_reg(REG_ADRESL); | |
459 | printf("\r%02x %02x (%u)\n", hi, lo, hi << 8 | lo); | |
460 | } | |
461 | ||
462 | #if 0 | |
463 | while (1) { | |
464 | write_reg( | |
465 | } | |
466 | #endif | |
467 | ||
468 | } | |
469 | ||
470 | ||
471 | static void cap(void) | |
472 | { | |
473 | write_reg(REG_CTMUCONH, 0x00); /* page 405 */ | |
474 | write_reg(REG_CTMUCONL, 0x90); | |
475 | write_reg(REG_CTMUICON, 0x01); | |
476 | ||
477 | write_reg(REG_TRISA, 0xfc); | |
478 | write_reg(REG_ADCON0, 0x20); /* AN4, Vss to AVdd */ | |
479 | // write_reg(REG_ADCON1, 0x8e); /* Tad = 2, Fosc/32, right just. */ | |
480 | write_reg(REG_ADCON1, 0x88); /* Tad = 2, Fosc/2, right just. */ | |
481 | write_reg(REG_ADCON0, 0x21); /* Enable ADC module */ | |
482 | ||
483 | /* bandgap ?!? */ | |
484 | ||
485 | while (1) { | |
486 | uint8_t hi, lo; | |
487 | ||
488 | write_reg(REG_CTMUCONH, 0x80); /* enable CTMU */ | |
489 | write_reg(REG_CTMUCONL, 0x90); /* clear EDGxSTAT */ | |
490 | write_reg(REG_CTMUCONH, 0x82); /* ground output */ | |
491 | delay(1); | |
492 | write_reg(REG_CTMUCONH, 0x80); /* end drain */ | |
493 | write_reg(REG_CTMUCONL, 0x91); /* current on */ | |
494 | write_reg(REG_CTMUCONL, 0x90); /* current off */ | |
495 | ||
496 | write_reg(REG_ADCON0, 0x23); /* GO */ | |
497 | while (read_reg(REG_ADCON0) & 2) | |
498 | write(2, ".", 1); | |
499 | hi = read_reg(REG_ADRESH); | |
500 | lo = read_reg(REG_ADRESL); | |
501 | printf("\r%02x %02x (%u)\n", hi, lo, hi << 8 | lo); | |
502 | } | |
503 | } | |
504 | ||
505 | ||
506 | static void dump(uint32_t addr) | |
507 | { | |
508 | uint8_t buf[BLOCK]; | |
509 | int i; | |
510 | ||
511 | read_mem(addr, buf, BLOCK); | |
512 | for (i = 0; i != BLOCK; i++) { | |
513 | if (!(i & 15)) | |
514 | printf("%04X:", i); | |
515 | printf(" %02X", buf[i]); | |
516 | if ((i & 15) == 15) | |
517 | printf("\n"); | |
518 | } | |
519 | } | |
520 | ||
521 | ||
522 | static void rerwr(void) | |
523 | { | |
524 | uint8_t buf[BLOCK]; | |
525 | int i; | |
526 | ||
527 | dump(0x3fffc0); | |
528 | dump(0); | |
529 | bulk_erase(); | |
530 | dump(0); | |
531 | for (i = 0; i != BLOCK; i++) | |
532 | buf[i] = i; | |
533 | write_mem(0, buf, BLOCK); | |
534 | dump(0x3fffc0); | |
535 | dump(0); | |
536 | } | |
537 | ||
538 | #endif | |
539 | ||
540 | /* ----- Chip identification ----------------------------------------------0 */ | |
541 | ||
542 | ||
543 | struct chip { | |
544 | const char *name; | |
545 | uint8_t id2, id1; | |
546 | int kb; | |
547 | } chips[] = { | |
548 | { "PIC18F24J50", 0x4c, 0x00, 16 }, | |
549 | { NULL } | |
550 | }; | |
551 | ||
552 | ||
553 | #define DEVID1 0x3ffffe | |
554 | ||
555 | ||
556 | static void identify(void) | |
557 | { | |
558 | uint8_t id[2]; | |
559 | const struct chip *chip; | |
560 | ||
561 | read_mem(DEVID1, id, 2); | |
562 | for (chip = chips; chip->name; chip++) { | |
563 | if ((chip->id1 ^ id[0]) & 0xe0) | |
564 | continue; | |
565 | if (chip->id2 == id[1]) | |
566 | break; | |
567 | } | |
568 | fprintf(stderr, "ID = 0x%02x%02x (%s)\n", id[1], id[0], | |
569 | chip->name ? chip->name : "?"); | |
570 | if (!chip->name) | |
571 | exit(1); | |
572 | fprintf(stderr, "%d kB Flash\n", chip->kb); | |
573 | kb = chip->kb; | |
574 | } | |
575 | ||
576 | ||
577 | /* ----- Intel HEX file reader --------------------------------------------- */ | |
578 | ||
579 | ||
580 | static int hex(char c, int lineno) | |
581 | { | |
582 | if (c >= '0' && c <= '9') | |
583 | return c-'0'; | |
584 | if (c >= 'A' && c <= 'F') | |
585 | return c-'A'+10; | |
586 | fprintf(stderr, "non-hex character \"%c\" in line %d\n", c, lineno); | |
587 | exit(1); | |
588 | } | |
589 | ||
590 | ||
591 | /* http://en.wikipedia.org/wiki/Intel_HEX */ | |
592 | ||
593 | ||
594 | static struct rec *load_file(const char *name) | |
595 | { | |
596 | struct rec *recs = NULL, *last = NULL, *rec; | |
597 | const struct rec *other; | |
598 | FILE *file; | |
599 | int lineno = 1; | |
600 | char line[1000]; | |
601 | const char *s; | |
602 | uint8_t buf[sizeof(line)/2]; | |
603 | uint8_t *p, *t, sum; | |
604 | uint32_t xaddr = 0, addr; | |
605 | ||
606 | file = fopen(name, "r"); | |
607 | if (!file) { | |
608 | perror(name); | |
609 | exit(1); | |
610 | } | |
611 | while (fgets(line, sizeof(line), file)) { | |
612 | if (*line != ':') { | |
613 | fprintf(stderr, "line %d doesn't start with colon\n", | |
614 | lineno); | |
615 | exit(1); | |
616 | } | |
617 | p = buf; | |
618 | for (s = line+1; *s > ' '; s += 2) | |
619 | *p++ = hex(s[0], lineno) << 4 | hex(s[1], lineno); | |
620 | if (p-buf < 5) { | |
621 | fprintf(stderr, "short record in line %d\n", lineno); | |
622 | exit(1); | |
623 | } | |
624 | lineno++; | |
625 | sum = 0; | |
626 | for (t = buf; t != p-1; t++) | |
627 | sum += *t; | |
628 | if (0x100-sum != p[-1]) { | |
629 | fprintf(stderr, | |
630 | "checksum error (0x%02x vs. 0x%02x) in line %d\n", | |
631 | p[-1], 0x100-sum, lineno); | |
632 | exit(1); | |
633 | } | |
634 | switch (buf[3]) { | |
635 | case 0: /* Data record */ | |
636 | if (p-buf != buf[0]+5) { | |
637 | fprintf(stderr, | |
638 | "data record of %d bytes has length %d\n", | |
639 | p-buf, buf[0]); | |
640 | exit(1); | |
641 | } | |
642 | addr = xaddr << 16 | buf[1] << 8 | buf[2]; | |
643 | if (last && last->addr+last->len == addr) { | |
644 | last->data = realloc(last->data, | |
645 | last->len+buf[0]); | |
646 | if (!last->data) { | |
647 | perror("realloc"); | |
648 | exit(1); | |
649 | } | |
650 | memcpy(last->data+last->len, buf+4, buf[0]); | |
651 | last->len += buf[0]; | |
652 | break; | |
653 | } | |
654 | rec = malloc(sizeof(struct rec)); | |
655 | rec->addr = xaddr << 16 | buf[1] << 8 | buf[2]; | |
656 | rec->len = buf[0]; | |
657 | rec->data = malloc(rec->len); | |
658 | if (!rec->data) { | |
659 | perror("realloc"); | |
660 | exit(1); | |
661 | } | |
662 | rec->next = NULL; | |
663 | memcpy(rec->data, buf+4, rec->len); | |
664 | if (last) | |
665 | last->next = rec; | |
666 | else | |
667 | recs = rec; | |
668 | last = rec; | |
669 | break; | |
670 | case 1: /* End Of File record */ | |
671 | goto end; | |
672 | case 4: /* Extended Linear Address record */ | |
673 | xaddr = buf[4] << 8 | buf[5]; | |
674 | break; | |
675 | default: | |
676 | fprintf(stderr, | |
677 | "unrecognized record type 0x%02x in line %d\n", | |
678 | buf[3], lineno); | |
679 | exit(1); | |
680 | } | |
681 | } | |
682 | end: | |
683 | for (rec = recs; rec; rec = rec->next) | |
684 | for (other = rec->next; other; other = other->next) | |
685 | if (rec->addr < other->addr+other->len && | |
686 | rec->addr+rec->len > other->addr) { | |
687 | fprintf(stderr, | |
688 | "overlapping address ranges 0x%x+0x%x " | |
689 | "and 0x%x+0x%x\n", | |
690 | rec->addr, rec->len, other->addr, | |
691 | other->len); | |
692 | } | |
693 | fclose(file); | |
694 | return recs; | |
695 | } | |
696 | ||
697 | ||
698 | /* ----- Command-line parsing ---------------------------------------------- */ | |
699 | ||
700 | ||
701 | static void usage(const char *name) | |
702 | { | |
703 | fprintf(stderr, | |
704 | "usage: %s [-n] [file.bin]\n", name); | |
705 | exit(1); | |
706 | } | |
707 | ||
708 | ||
709 | int main(int argc, char **argv) | |
710 | { | |
711 | const struct rec *recs = NULL; | |
712 | int power = 1; | |
713 | int c; | |
714 | ||
715 | while ((c = getopt(argc, argv, "n")) != EOF) | |
716 | switch (c) { | |
717 | case 'n': | |
718 | power = 0; | |
719 | break; | |
720 | default: | |
721 | usage(*argv); | |
722 | } | |
723 | ||
724 | switch (argc-optind) { | |
725 | case 0: | |
726 | break; | |
727 | case 1: | |
728 | recs = load_file(argv[optind]); | |
729 | break; | |
730 | default: | |
731 | usage(*argv); | |
732 | } | |
733 | ||
734 | icsp_begin(power); | |
735 | identify(); | |
736 | ||
737 | if (recs) | |
738 | flash_file(recs); | |
739 | else | |
740 | dump_flash(); | |
741 | icsp_end(); | |
742 | ||
743 | return 0; | |
744 | } |
Branches:
master