|
nedoPC.orgElectronics hobbyists community established in 2002 |
|
|
Page 1 of 1
|
[ 10 posts ] |
|
PDBLv1 = Public Domain Boot Loader v1 для PIC16F870
Author |
Message |
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22564 Location: Silicon Valley
|
Вот собственно этот бутлоадер на 1.4К (в исполнении PICC v9.82 lite), который удалось ужать c 75% до 67% памяти PIC16F870 (т.е. с 3/4 до 2/3 от 2K-слов): http://nedopc.org/nedopc/16/PDBLv1.zip (54K)
| | | | Code: // PDBLv1 - Public Domain Boot Loader version 1 (16 Nov 2011) // Created by Alexander A. Shabarshin <ashabarshin@gmail.com> // For PIC16F870 on frequency 20 MHz and speed 9600 // You are free to use this code in any possible way // Tested in PICC 9.82.9453 lite under MPLABX IDE beta 7.12
// Usage: Press Enter multiple times immediately after reset (~1sec) // then use commands below to run (all numbers are hexadecimal): // !AAAA=BBBB - write word BBBB to program memory in address AAAA // !AAA=BB - write byte BB to data memory in address AAA // !AA=BB - write byte BB to EEPROM in address AA // ?AAAA - read one word from program memory with address AAAA // ?AAA - read one byte from data memory with address AAA // ?AA - read one byte from EEPROM in address AA // . - exit from bootloader and jump to address 0x0001
// ToDo (not yet implemented): // !AAAA=BBBB... - write words to program memory starting with AAAA // !AAA=BB... - write bytes to data memory starting with AAA // ?AAAA=BB - read BB words from program memory starting with AAAA // ?AAA=BB - read BB bytes from data memory starting with AAA // $A - call subprogram from address A // ^A - jump to address A
// Errors: // ERR01 - illegal hexadecimal digit was entered // ERR02 - character '=' is expected // ERR03 - enter is expected // ERR04 - attempt to write in protected region (bootloader code)
#include <pic.h>
__CONFIG(CP_OFF & DEBUG_OFF & WRT_ALL & CPD_OFF & LVP_OFF & PWRTE_OFF & WDTE_OFF & FOSC_HS);
const char sign[] @0x7FA = "PDBLv1";
#define PROTECTION // flag to protect bootloader code
#define ENTER 13 // code of enter key
// all delays for 20 MHz
#define DELAY1US NOP();NOP();NOP();NOP();NOP() #define DELAY10US delay(1,2) #define DELAY15US delay(1,4) #define DELAY20US delay(1,5) #define DELAY25US delay(1,6) #define DELAY30US delay(1,8) #define DELAY40US delay(1,10) #define DELAY50US delay(1,13) #define DELAY60US delay(1,15) #define DELAY75US delay(1,19) #define DELAY100US delay(1,25) #define DELAY150US delay(1,38) #define DELAY200US delay(1,50) #define DELAY300US delay(1,75) #define DELAY400US delay(1,100) #define DELAY500US delay(1,125) #define DELAY600US delay(1,150) #define DELAY750US delay(1,188) #define DELAY900US delay(1,225) #define DELAY1MS delay(1,250) #define DELAY(x) delay(x,250)
void delay(unsigned short ms, unsigned char us4) { unsigned short m; unsigned char s; for(m=0;m<ms;m++) { for(s=0;s<us4;s++) { NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); } } }
void serial_init() { #if 1 SPBRG = 129; // 9600 #else SPBRG = 64; // 19200 #endif BRGH = 1; SYNC = 0; CREN = 0; CREN = 1; SPEN = 1; TXIE = 0; RCIE = 0; TX9 = 0; RX9 = 0; TXEN = 0; TXEN = 1; }
void serial_err() { if(OERR){CREN=0;CREN=1;} if(FERR){RCREG;} }
void serial_send(unsigned char s) { while(!TXIF) serial_err(); TXREG = s; DELAY50US; }
unsigned char serial_recv() { while(!RCIF) serial_err(); return RCREG; }
unsigned char serial_read() { unsigned char b = serial_recv(); if(b>=0x20 && b<0x7F) serial_send(b); return b; }
unsigned char serial_check(unsigned short ms) { unsigned short i; unsigned char r = 0; for(i=0;i<ms;i++) { if(RCIF){r=RCREG;break;} serial_err(); DELAY1MS; } return r; }
void serial_print_nl() { serial_send('\r'); serial_send('\n'); }
void serial_print_hex(char h) { if(h>=0 && h<10) serial_send('0'+h); else if(h>=10 && h<16) serial_send('A'+h-10); }
void serial_print_byte(unsigned char b) { serial_print_hex(b>>4); serial_print_hex(b&15); }
void serial_print_word(unsigned short s) { serial_print_byte(s>>8); serial_print_byte(s&255); }
void serial_print_err(unsigned char n) { serial_print_nl(); serial_send('E'); serial_send('R'); serial_send('R'); serial_print_byte(n); }
void serial_print_ok() { serial_print_nl(); serial_send('O'); serial_send('K'); }
signed char hex1(char h) { char i = -1; if(h >= '0' && h <= '9') i = h-'0'; else if(h >= 'a' && h <= 'f') i = 10+h-'a'; else if(h >= 'A' && h <= 'F') i = 10+h-'A'; return i; }
void data_write(unsigned short a, unsigned char b) { unsigned char* p = a; *p = b; }
unsigned char data_read(unsigned short a) { unsigned char* p = a; return *p; }
void prog_write(unsigned short a, unsigned short b) { FLASH_WRITE(a,b); }
unsigned short prog_read(unsigned short a) { return FLASH_READ(a); }
unsigned short compact_nibbles(unsigned char a, unsigned char b, unsigned char c, unsigned char d) { return (a<<12)|(b<<8)|(c<<4)|d; }
void do_write() { signed char a,b,c,d,e; unsigned short adr = 0; unsigned short val = 0; a = hex1(serial_read()); if(a < 0) serial_print_err(1); else { b = hex1(serial_read()); if(b < 0) serial_print_err(1); else { c = serial_read(); if(c=='=') { // EEPROM adr = compact_nibbles(0,0,a,b); a = hex1(serial_read()); if(a < 0) serial_print_err(1); else { b = hex1(serial_read()); if(b < 0) serial_print_err(1); else { val = compact_nibbles(0,0,a,b); if(serial_recv()!=ENTER) serial_print_err(3); else { eeprom_write(adr,val); serial_print_ok(); } } } } else { c = hex1(c); if(c < 0) serial_print_err(1); else { d = serial_read(); if(d=='=') { // DATA adr = compact_nibbles(0,a,b,c); a = hex1(serial_read()); if(a < 0) serial_print_err(1); else { b = hex1(serial_read()); if(b < 0) serial_print_err(1); else { val = compact_nibbles(0,0,a,b); if(serial_recv()!=ENTER) serial_print_err(3); else { data_write(adr,val); serial_print_ok(); } } } } else { d = hex1(d); if(d < 0) serial_print_err(1); else { e = serial_read(); if(e!='=') serial_print_err(2); else { // FLASH adr = compact_nibbles(a,b,c,d); a = hex1(serial_read()); if(a < 0) serial_print_err(1); else { b = hex1(serial_read()); if(b < 0) serial_print_err(1); else { c = hex1(serial_read()); if(c < 0) serial_print_err(1); else { d = hex1(serial_read()); if(d < 0) serial_print_err(1); else { val = compact_nibbles(a,b,c,d); if(serial_recv()!=ENTER) serial_print_err(3); else { #ifdef PROTECTION static unsigned short bootadr = 0; if(bootadr==0) { bootadr = prog_read(0); bootadr &= 0x07FF; } if(adr >= bootadr) { serial_print_err(4); return; } if(adr==0) adr=1; #endif prog_write(adr,val); serial_print_ok(); } } } } } } } } } } } } }
void do_read() { signed char a,b,c,d,e; unsigned short adr = 0; unsigned short val = 0; unsigned char byte = 0; a = hex1(serial_read()); if(a < 0) serial_print_err(0); else { b = hex1(serial_read()); if(b < 0) serial_print_err(0); else { c = serial_read(); if(c==ENTER) { // EEPROM adr = compact_nibbles(0,0,a,b); byte = eeprom_read(adr); serial_print_nl(); serial_print_byte(byte); } else { c = hex1(c); if(c < 0) serial_print_err(0); else { d = serial_read(); if(d==ENTER) { // DATA adr = compact_nibbles(0,a,b,c); byte = data_read(adr); serial_print_nl(); serial_print_byte(byte); } else { d = hex1(d); if(d < 0) serial_print_err(0); else { if(serial_recv()!=ENTER) serial_print_err(3); else { // FLASH adr = compact_nibbles(a,b,c,d); val = prog_read(adr); serial_print_nl(); serial_print_word(val); } } } } } } } }
main() { ADCON1 = 0x06; INTCON = 0x00; TRISC = 0xFF; // RC6 and RC7 must be inputs serial_init(); unsigned char b = serial_check(1000); if(b==ENTER) { serial_print_nl(); serial_send('P'); serial_send('D'); serial_send('B'); serial_send('L'); serial_send('v'); serial_send('1'); serial_print_nl(); serial_send('>'); b = 0; do { if(b!=ENTER) { b = serial_read(); } if(b==ENTER) { serial_print_nl(); serial_send('>'); b = 0; } if(b=='?'){do_read();b=ENTER;} if(b=='!'){do_write();b=ENTER;} } while(b!='.'); } /* // TEST: print next character from the range [0x20..0x7E] every second char a = 0x20; while(1) { serial_send(a); if(++a==127) a=0x20; DELAY(1000); } */ asm("goto 1"); // jump to the loaded code }
| | | | |
На подгружаемые программы остаётся 671 байт...
P.S. Эту версию (точнее конкретную бинарную сборку этой версии) можно обозвать PDBL v1.2A2 т.к. GOTO 0x2A2 (слово 0x2AA2) стоит по нулевому адресу (это переход на бутлоадер)
Last edited by Shaos on 07 Dec 2014 06:10, edited 8 times in total.
|
15 Nov 2011 22:29 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22564 Location: Silicon Valley
|
вот так выглядел процесс отладки:
тут PICKit3 сам питает плату и адаптер RS-232
|
16 Nov 2011 01:08 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22564 Location: Silicon Valley
|
Написал сишную программку под линух (должно работать на любой POSIX системе), которая зашивает HEX в бутлоадер PDBLv1:
http://nedopc.cvs.sourceforge.net/viewv ... c?view=log
Если ребутнуть девайс и запустить эту программку с аргументом, то она напишет:
|
20 Nov 2011 18:01 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22564 Location: Silicon Valley
|
Процесс создания программулек и их отладки пошёл значительно веселее
Теперь не нужно ни программатора El Cheapo, ни программатора-отладчика PICKit3
Разве что для первоначальной прошивки бутлоадером...
|
20 Nov 2011 23:36 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22564 Location: Silicon Valley
|
Инклудник для работы с подпрограммами бутлоадера PDBLv1:
| | | | Code: ; Constants for PDBLv1.2A2 (16 Nov 2011 - 26 Nov 2011) ; Created by Alexander A. Shabarshin <ashabarshin@gmail.com>
; COMMON #70..#7D(14) free #7E,#7F ; BANK0 #20..#3B(27) free #3C..#6F ; BANK1 (0) free #A0..#BF
bootloader equ 0x02A2
pdbl_entry equ 0x04DC
_PDBL MACRO goto pdbl_entry ENDM
; compact_nibbles - compact 4 nibbles to 1 word ; ARG:W,#70,#71,#72 RET:#70,#71 USE:#20..#2B,#70..#73 compact_nibbles equ 0x0450 compact_nibbles_1 equ 0x70 compact_nibbles_2 equ 0x71 compact_nibbles_3 equ 0x72
_compact_nibbles MACRO A,B,C,D,W0,W1 movf B,w movwf compact_nibbles_1 movf C,w movwf compact_nibbles_2 movf D,w movwf compact_nibbles_3 movf A,w call compact_nibbles movf compact_nibbles_1,w movwf W0 movf compact_nibbles_2,w movwf W1 ENDM
data_read equ 0x02CE ; ARG:a0,a1 RET:W USE:#70..#73 data_read_a0 equ 0x70 data_read_a1 equ 0x71
data_write equ 0x2FA ; ARG:a0,a1,b RET:no USE:#70..#75 data_write_a0 equ 0x70 data_write_a1 equ 0x71 data_write_b equ 0x72
; delay - universal delay in ms or us (for 20MHz) delay equ 0x03C4 ; ARG:#70,#71,#72 RET:no USE:#70..#76 delay_ms0 equ 0x70 delay_ms1 equ 0x71 delay_us4 equ 0x72
_delay_ MACRO H,L,U movlw L movwf delay_ms0 movlw H movwf delay_ms1 movlw U movwf delay_us4 call delay ENDM
_delay_ms MACRO H,L _delay_ H,L,250 ENDM
_delay_us MACRO U _delay_ 0,1,U/4 ENDM
do_read equ 0x052F ; ARG:no RET:no USE:#2C..#37
do_write equ 0x0614 ; ARG:no RET:no USE:#2C..#37,#3A,#3B do_write_bootadr0 equ 0x3A do_write_bootadr1 equ 0x3B
eeprom_read equ 0x0385 ; ARG:W RET:W USE:#70,#71
_eeprom_read MACRO A,B movf A,w call eeprom_read bcf STATUS,RP0 bcf STATUS,RP1 movwf B ENDM
_eeprom_read_ MACRO A,B movlw A call eeprom_read bcf STATUS,RP0 bcf STATUS,RP1 movwf B ENDM
eeprom_write equ 0x041F ; ARG:W,value RET:W USE:#70-#72 eeprom_write_value equ 0x70
_eeprom_write MACRO A,B movf B,w movwf eeprom_write_value movf A,w call eeprom_write ENDM
_eeprom_write_ MACRO A,B movf B,w movwf eeprom_write_value movlw A call eeprom_write ENDM
_eeprom_write_a MACRO A,B movlw B movwf eeprom_write_value movf A,w call eeprom_write ENDM
_eeprom_write__ MACRO A,B movlw B movwf eeprom_write_value movlw A call eeprom_write ENDM
hex1 equ 0x0484 ; ARG:W RET:W USE:#70..#72
prog_read equ 0x03A4 ; ARG:a0,a1 RET:a0,a1 USE:#70..#74 prog_read_a0 equ 0x70 prog_read_a1 equ 0x71
_prog_read MACRO A0,A1,W0,W1 movf A0,w movwf prog_read_a0 movf A1,w movwf prog_read_a1 call prog_read movf prog_read_a0,w movwf W0 movf prog_read_a1,w movwf W1 ENDM
prog_write equ 0x034F ; ARG:a0,a1,b0,b1 RET:no USE:#70..#73 prog_write_a0 equ 0x70 prog_write_a1 equ 0x71 prog_write_b0 equ 0x72 prog_write_b1 equ 0x73
_prog_write MACRO A0,A1,W0,W1 movf A0,w movwf prog_write_a0 movf A1,w movwf prog_write_a1 movf W0,w movwf prog_write_b0 movf W1,w movwf prog_write_b1 call prog_write ENDM
serial_check equ 0x03F1 ; ARG:ms0,ms1 RET:no USE:#77..#7C serial_check_ms0 equ 0x77 serial_check_ms1 equ 0x78
serial_err equ 0x02DC ; ARG:no RET:no USE:?
serial_init equ 0x0337 ; ARG:no RET:no USE:?
serial_print_byte equ 0x02EB ; ARG:W RET:no USE:#7A,#7B
_serial_print_byte MACRO B movf B,w call serial_print_byte ENDM
_serial_print_byte_ MACRO B movlw B call serial_print_byte ENDM
serial_print_err equ 0x02B6 ; ARG:W RET:no USE:#7C
_serial_print_err MACRO B movf B,w call serial_print_err ENDM
_serial_print_err_ MACRO B movlw B call serial_print_err ENDM
serial_print_hex equ 0x0368 ; ARG:W RET:no USE:#79
serial_print_nl equ 0x02A6 ; ARG:no RET:no USE:?
_serial_print_nl MACRO call serial_print_nl ENDM
serial_print_ok equ 0x02B0 ; ARG:no RET:no USE:?
_serial_print_ok MACRO call serial_print_ok ENDM
serial_print_word equ 0x02AB ; ARG:0,1 RET:no USE:#7C,#7D serial_print_word_0 equ 0x7C serial_print_word_1 equ 0x7D
_serial_print_word MACRO B0,B1 movf B0,w movwf serial_print_word_0 movf B1,w movwf serial_print_word_1 call serial_print_word ENDM
serial_read equ 0x030A ; ARG:no RET:W USE:#79,#7A
_serial_read MACRO B call serial_read movwf B ENDM
serial_recv equ 0x02C1 ; ARG:no RET:W USE:?
_serial_recv MACRO B call serial_recv movwf B ENDM serial_send equ 0x0320 ; ARG:W RET:no USE:#77,#78
_serial_send MACRO B movf B,w call serial_send ENDM
_serial_send_ MACRO B movlw B call serial_send ENDM
| | | | |
|
26 Nov 2011 20:57 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22564 Location: Silicon Valley
|
Вот как выглядит процесс заливки программы, занимающей всю свободную память под завязку:
Вся процедура занимает порядка 1 минуты 25 секунд
|
26 Nov 2011 21:03 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22564 Location: Silicon Valley
|
Надо незабыть переписать бутлоадер на ассемблер - а то уже 3 года прошло с момента его создания, а он всё ещё на сях...
P.S. и портировать его на бо'льшие пики типа PIC16F873-PIC16F877 тоже не помешает...
|
07 Dec 2014 00:23 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22564 Location: Silicon Valley
|
Подумалось тут - раз уж мой бутлоадэр умеет писать и читать данные пика, а не только код, то ведь можно пустой пик с этим бутлоадером на борту использовать как пачку двоичных сигналов ввода-вывода (а то и троичных ; - )
|
05 Nov 2015 16:46 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22564 Location: Silicon Valley
|
Например вот так выглядит запуск АЦП на нулевом канале: Сначала мы померяли +2.5В (0x80), а потом +5В (0xFF) А теперь подключим ногу B0 к ноге A0 и туда же два резистора по 1К от земли и питания, чтобы сымитировать троичный сигнал Первый раз подали ноль, второй - единицу, а третий - перевели в Z состояние Таким образом мы выдали наружу и затем прочитали троичный сигнал с помощью двоичного микроконтроллера управляемого по COM-порту P.S. Единственное неудобство - АЦП медленный - по моим подсчётам скорость оцифровки не может превышать 40 кГц, а если управлять им по COM-порту на скорости 9600 бод, то и подавно...
|
05 Nov 2015 21:35 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22564 Location: Silicon Valley
|
Не прошло и 5 лет, как я добавил в эту программку поддержку Windows - теперь указав этой программке макрос WINDA можно собрать её под винды, с использованием виндового Serial API - т.е. теперь эта программка работает не только в Linux и Mac OS X, но и Windows P.S. Попутно оказалось, что после прошивки верификации как-таковой и не происходило - поправил... P.P.S. Вот так выглядит процесс прошивки под виндами (выбран порт COM10, которым система WinXP обозвала мой шнур RS-232-to-USB "Keyspan"): P.P.P.S. Интересно, что тот же самый код, собранный в CYGWIN (эмулятор Linux окружения под виндой), также работает
|
13 Mar 2016 21:10 |
|
|
|
Page 1 of 1
|
[ 10 posts ] |
|
Who is online |
Users browsing this forum: No registered users and 4 guests |
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot post attachments in this forum
|
|