|
|
View previous topic :: View next topic |
Author |
Message |
iw2nzm
Joined: 23 Feb 2007 Posts: 55
|
RS485 bootloader with sw reset |
Posted: Thu Mar 08, 2007 7:44 am |
|
|
Hi!
I need a bootloader for a PIC18F4520 with RS485 capability.
I guess I can use the ex_bootloader provided by CCS adding the RS485 enable pin in the #use rs232 directive.
However, I can't use a pin to start loading program, so I'd like to do a software reset (reset_cpu()) when I receive a predefined char over serial link. The bootloader should wait about 1 second after reset and if it receive no data from serial starts my application, otherwise loads the new program.
How I should modify the bootloader to achieve this?
Tiny Bootloader does this, but if I add the rs485 enable pin handling (bsf before transmission and bcf after) it doesn't work.
Thanks,
Marco / iw2nzm |
|
|
treitmey
Joined: 23 Jan 2004 Posts: 1094 Location: Appleton,WI USA
|
|
Posted: Thu Mar 08, 2007 9:19 am |
|
|
remember to look at restart_cause().
If you get a power hickup during normal rs485 data,
your PIC may restart and then think the rs485 data
is the new code. ... perhaps you could send a
rs485 command to say,... from here out the data
is the new code. And not have to have the reset at all. |
|
|
iw2nzm
Joined: 23 Feb 2007 Posts: 55
|
|
Posted: Thu Mar 08, 2007 10:01 am |
|
|
treitmey wrote: | remember to look at restart_cause().
If you get a power hickup during normal rs485 data,
your PIC may restart and then think the rs485 data
is the new code. |
mmm.... if I look at restart_cause() == reset_instruction I can't program the first time because there is no code to reset the PIC.
Quote: | ... perhaps you could send a
rs485 command to say,... from here out the data
is the new code. And not have to have the reset at all. |
This is a very good idea, indeed.
I should call the real_load_program() routine after I received the rs485 command. So I will include that routine directly in the main code.
Thus, may I forget anything about the bootloader place?
Every time it rewrites all the code and every time it replaces the bootloader routine...
What do you think about this?
Marco / iw2nzm |
|
|
treitmey
Joined: 23 Jan 2004 Posts: 1094 Location: Appleton,WI USA
|
|
Posted: Thu Mar 08, 2007 2:54 pm |
|
|
No.
Don't write to the area that is the bootloader.
I think that is a bad idea.
The bootloader area should be written once when the board is mfg. and
then that area is left alone. |
|
|
jds-pic
Joined: 17 Sep 2003 Posts: 205
|
|
Posted: Mon Mar 12, 2007 3:05 pm |
|
|
treitmey wrote: | No.
Don't write to the area that is the bootloader.
I think that is a bad idea.
The bootloader area should be written once when the board is mfg. and
then that area is left alone. |
i agree 100% with what is written above.
i implemented a RS232-based system with a bootloader and SW-driven remote update. the original bootloader remains resident through the life of the product. the PIC software can at any time shoot itself in the head and cause the PIC to reload from the host. this is only complicated by the fact that you need to do your best to get the PIC back into a state which resembles the power on configuration PRIOR to calling reset_cpu(). otherwise, unhandled interrupts and so on will cause extremely hard to diagnose problems.
jds-pic
Code: | void jump_to_bootloader() {
disable_interrupts(GLOBAL);
internal_eeprom(INCREMENT16, EEPROM_FLASH_ATTEMPTS, DONT_CARE);
display_message(MSG_FWUPDATE,MOD_NONE,TIMEOUT_NONE);
delay_ms(250); // >200ms for downloader sync
FSR0H = 0x00; // clean up special purpose registers
PIR1 = 0x00;
PIR2 = 0x00;
TMR2 = 0x00;
T2CON = 0x00;
PIE1 = 0x00;
PR2 = 0xff;
STATUS = 0x00;
TMR0H = 0x00;
TMR0L = 0x00;
T0CON = 0xFF;
INTCON = 0x00;
INTCON2= 0xff;
INTCON3= 0xc0;
T1CON = 0x00;
TMR1L = 0x00;
TMR1H = 0x00;
SPBRG = 0x00;
TXSTA = 0x02;
RCSTA = 0x00;
TXREG = 0x00;
RCREG = 0x00;
reset_cpu(); // then jump to reset vector
}
|
Code: |
case HOST_CMD_UPGRADE_FLASH: {
printf(serial_putc,"200: waiting for download...\r\n");
enable_interrupts(INT_EXT);
pushbutton_flag=FALSE;
while ( (!pushbutton_flag) && (!serial_port_byte_avail()) )
; // blocks until rx a byte or button is pressed.
disable_interrupts(GLOBAL);
jump_to_bootloader();
break;
} |
see also
http://www.ccsinfo.com/forum/viewtopic.php?t=20282 |
|
|
VanHauser
Joined: 03 Oct 2005 Posts: 88 Location: Ploiesti, Romania
|
|
Posted: Sat Mar 17, 2007 10:16 am |
|
|
I have modifed the TinyBootloader to work with RS485 for my personal use, with help from its author. If anyone is interrested, here is the asm I use for 18F452:
Code: | radix DEC
LIST P=18F452 ; change also: Configure->SelectDevice from Mplab
xtal EQU 40000000 ; you may want to change: _XT_OSC_1H _HS_OSC_1H _HSPLL_OSC_1H
baud EQU 19200 ; standard TinyBld baud rates: 115200 or 19200
; The above 3 lines can be changed and buid a bootloader for the desired frequency (and PIC type)
;********************************************************************
; Tiny Bootloader 18F series Size=132words
; claudiu.chiculita@ugal.ro
; http://www.etc.ugal.ro/cchiculita/software/picbootloader.htm
;********************************************************************
#include "icdpictypes.inc" ;takes care of: #include "p18fxxx.inc", max_flash, IdTypePIC
#include "spbrgselect.inc" ; RoundResult and baud_rate
#define first_address max_flash-264 ;132 words, DO NOT FORGET tinybld.ini !!
__CONFIG _CONFIG1H, _OSCS_OFF_1H & _HSPLL_OSC_1H
__CONFIG _CONFIG2L, _BOR_ON_2L & _BORV_45_2L & _PWRT_ON_2L
__CONFIG _CONFIG2H, _WDT_ON_2H & _WDTPS_128_2H ; WDT ON !!
__CONFIG _CONFIG4L, _STVR_OFF_4L & _LVP_OFF_4L & _DEBUG_OFF_4L
;----------------------------- PROGRAM ---------------------------------
cblock 0
crc
i
cnt1
cnt2
cnt3
counter_hi
counter_lo
flag
endc
cblock 10
buffer:64
dummy4crc
sendb ; Byte to send
d1 ; For delay routine
endc
;0000000000000000000000000 RESET 00000000000000000000000000
ORG 0x0000
GOTO IntrareBootloader
;view with TabSize=4
;&&&&&&&&&&&&&&&&&&&&&&& START &&&&&&&&&&&&&&&&&&&&&&
;---------------------- Bootloader ----------------------
;PC_flash: C1h U H L x ... <64> ... crc
;PC_eeprom: C1h 40h EEADR EEDATA 0 crc
;PC_cfg C1h U OR 80h H L 1 byte crc
;PIC_response: type `K`
ORG first_address ;space to deposit first 4 instr. of user prog.
nop
nop
nop
nop
org first_address+8
IntrareBootloader
movlw b'10011111'
movwf TRISC
;init serial port
movlw b'00100100'
movwf TXSTA
movlw spbrg_value
movwf SPBRG
movlw b'10010000'
movwf RCSTA
;wait for computer
rcall Receive
sublw 0xC1 ;Expect C1h
bnz way_to_exit
movlw IdTypePIC
rcall SendW ;send PIC type
MainLoop
movlw 'K'
rcall SendW ; "-Everything OK, ready and waiting."
mainl
clrf crc
rcall Receive ;Upper
movwf TBLPTRU
movwf flag ;(for EEPROM and CFG cases)
rcall Receive ;Hi
movwf TBLPTRH
movwf EEADR ;(for EEPROM case)
rcall Receive ;Lo
movwf TBLPTRL
movwf EEDATA ;(for EEPROM case)
rcall Receive ;count
movwf i
incf i
lfsr FSR0, (buffer-1)
rcvoct ;read 64+1 bytes
movwf TABLAT ;prepare for cfg; => store byte before crc
rcall Receive
movwf PREINC0
decfsz i
bra rcvoct
tstfsz crc ;check crc
bra ziieroare
btfss flag,6 ;is EEPROM data?
bra noeeprom
movlw b'00000100' ;Setup eeprom
rcall Write
bra waitwre
noeeprom
btfss flag,7 ;is CFG data?
bra noconfig
tblwt* ;write TABLAT(byte before crc) to TBLPTR***
movlw b'11000100' ;Setup cfg
rcall Write
bra waitwre
noconfig
;write
eraseloop
movlw b'10010100' ; Setup erase
rcall Write
TBLRD*- ; point to adr-1
writebigloop
movlw 8 ; 8groups
movwf counter_hi
lfsr FSR0,buffer
writesloop
movlw 8 ; 8bytes = 4instr
movwf counter_lo
writebyte
movf POSTINC0,w ; put 1 byte
movwf TABLAT
tblwt+*
decfsz counter_lo
bra writebyte
movlw b'10000100' ; Setup writes
rcall Write
decfsz counter_hi
bra writesloop
waitwre
;btfsc EECON1,WR ;for eeprom writes (wait to finish write)
;bra waitwre ;no need: round trip time with PC bigger than 4ms
bcf EECON1,WREN ;disable writes
bra MainLoop
ziieroare ;CRC failed
movlw 'N'
rcall SendW
bra mainl
;******** procedures ******************
; Delay is needed because the optocouplers need time for transitions.
; Only required for the RE_DE line.
Delay50us
movlw 165*xtal/40000000
movwf d1
Delay_0
decfsz d1, f
goto Delay_0
return
SendW
movwf sendb
bsf PORTC,5 ; RE_DE_485
btfss PIR1,TXIF
goto $-2
rcall Delay50us
movff sendb,TXREG
nop
bsf PORTC,5
btfss TXSTA,TRMT
goto $-2
bcf PORTC,5
rcall Delay50us
return
Write
clrwdt
movwf EECON1
movlw 0x55
movwf EECON2
movlw 0xAA
movwf EECON2
bsf EECON1,WR ;WRITE
nop
;nop
return
Receive
clrwdt
movlw xtal/2000000+1 ; for 20MHz => 11 => 1second delay
movwf cnt1
rpt2
clrf cnt2
rpt3
clrf cnt3
rptc
btfss PIR1,RCIF ;test RX
bra notrcv
movf RCREG,w ;return read data in W
addwf crc,f ;compute crc
return
notrcv
decfsz cnt3
bra rptc
decfsz cnt2
bra rpt3
decfsz cnt1
bra rpt2
;timeout:
way_to_exit
bcf RCSTA, SPEN ; deactivate UART
movlw b'11111111'
movwf TRISC
bra first_address
;*************************************************************
; After reset
; Do not expect the memory to be zero,
; Do not expect registers to be initialised like in catalog.
END
|
It is crucial to have this tweak in the tinybld.ini file:
Code: | [OPTIONS]
SizeOfBLD=264
SizeOfBLD_W=132 |
Otherwise it will not work and will overwrite the start of the boot section!
This code is heavily tested at 19200 bps, with galvanic isolation and the MAX3085 driver. The RE/DE line should be connected to pin C5 of the PIC.
Works perfectly on RS232 too. |
|
|
Guest
|
|
Posted: Sat Mar 24, 2007 10:17 am |
|
|
hi,could you expalin how works the software reset for downloading ?
thanks |
|
|
nurquhar
Joined: 05 Aug 2006 Posts: 149 Location: Redditch, UK
|
|
Posted: Sun Mar 25, 2007 2:09 am |
|
|
I built me own RS485 bootlaoder for the 16F876A. Its been designed to handle multiple rs485 slaves on a half duplex bus. Thus with my PC util at one end I can re-program any or all the devices on the bus. Each PIC has unique serial no generated by #serialise.
The system relies on the PC to read the hex file and send data to the pic in the correct command structure. This gave me a smaller bootloader. The PC util is written with MS VC++ MFC and gives various other options to the user other than just programming. Such as read memory, restart, and search for units in a given ID range, program a list of units one by one.
To get the slave PIC's into bootloader mode I set the PC util to "ping" with a "wake up" command and reset the PSU to all the PIC's. The bootloader will wait for 4s to see a "ping" is being sent to it, other wise it starts the app. Once the bootloader is running it listens for a host command with its unique ID to put it into active mode for handshaked two way communication with the host. Its probably not quickest or the smallest bootloader but it does the job. The communication proctocol may look a bit querky but its very efficent and I can run 20mhz pic with a baud of 250K.
Here is my code for the loader, not sure how to post the MFC code.
Code: |
// CPU Clock Freq
#define FOSC 20000000
#define OSC_DIV 4
//#define BAUDRT 9600
//#define BAUDRT 19200
//#define BAUDRT 57600
//#define BAUDRT 128000
#define BAUDRT 256000
//#define _PIC16F88
#define _PIC16F876A
// Allow EEPROM Programming
#define ALLOW_EEPROM
// Application info structure fixed address
#define APP_INFO_BASE 0xA0
// PIC16F88
#ifdef _PIC16F88
#include <16F88.h>
// Reserve for reporting bootstart location to the application
#fuses HS,NOWDT,PUT,NOPROTECT,NOBROWNOUT,NOMCLR,NOLVP,NOCPD
#use delay(clock=FOSC)
#use rs232(baud=BAUDRT, xmit=PIN_B5, rcv=PIN_B2, PARITY=N, BITS=8, ENABLE=PIN_B0, ERRORS)
#endif
// PIC16F876A
#ifdef _PIC16F876A
#include <16F876A.h>
// Reserve for reporting bootstart location to the application
#fuses HS,NOWDT,PUT,NOPROTECT,NOBROWNOUT,NOLVP,NOCPD,NOWRT
#use delay(clock=FOSC)
#use rs232 (baud=BAUDRT, xmit=PIN_C6, rcv=PIN_C7, PARITY=N, BITS=8, ENABLE=PIN_B0, ERRORS)
#endif
// Use TMR2 to supply a "Hook" for the application to get Bootloader Info
#include "bootstrap.h"
// Check this chip can be used
#if getenv("READ_PROGRAM") != 1
#error getenv("DEVICE") can not modify its memory ! Bootstrap not possible
#endif
// OSC
#if getenv("FUSE_SET:LP")==1
#define FUSE_OSC 0x0000
#elif getenv("FUSE_SET:XT")==1
#define FUSE_OSC 0x0001
#elif getenv("FUSE_SET:HS")==1
#define FUSE_OSC 0x0002
#elif getenv("FUSE_SET:RC")==1
#define FUSE_OSC 0x0003
#else
#define FUSE_OSC 0x0000
#endif
// Use the Watch Dog ?
#if getenv("FUSE_SET:WDT")==1
#define RESET_WDT
#define FUSE_WDT 0x0004
#else
#define FUSE_WDT 0
#endif
// PWRTEN
#if getenv("FUSE_SET:PUT")==1
#define FUSE_PUTDE 0
#else
#define FUSE_PUTDE 0x0008
#endif
// BOREN
#if getenv("FUSE_SET:BROWNOUT")==1
#define FUSE_BOREN 0x0040
#else
#define FUSE_BOREN 0
#endif
// LVP
#if getenv("FUSE_SET:LVP")==1
#define FUSE_LVP 0x0080
#else
#define FUSE_LVP 0
#endif
// Fuses used by the bootstrap
#define FUSEREG FUSE_OSC | FUSE_WDT | FUSE_PUTDE | 0x0030 | FUSE_BOREN | FUSE_LVP
// T1 Timer Stuff
// ********** Pre-Define to override ****************
#ifndef T1_PS
#define T1_PS T1_DIV_BY_8 // Divide By : 1,2,4,8
#endif
#if T1_PS == T1_DIV_BY_1
#define T1_DIV 1
#elif T1_PS == T1_DIV_BY_2
#define T1_DIV 2
#elif T1_PS == T1_DIV_BY_4
#define T1_DIV 4
#elif T1_PS == T1_DIV_BY_8
#define T1_DIV 8
#endif
#define T1_RUN (T1_INTERNAL | T1_PS)
#define T1_STOP (T1_DISABLED)
#define T1_PRESCALE (OSC_DIV * T1_DIV)
#define t1ticks(us) (((FOSC/1000000) * us) / T1_PRESCALE)
#define t1tc(us) (65536 - (((FOSC/1000000) * us) / T1_PRESCALE))
// Calc the time (us) to send one byte (1 start + 8 data + 1 stop) at with the uart at the baud rate selected
#define TX_TIME ((1000000 * (1+8+1)) / (BAUDRT))
// The time for 'n' chars
#define TX_TIMEOUT(n) (t1ticks(TX_TIME * (n)))
// The time to listen for, seconds
#define LISTEN_TIME 5
#define TGETC_COUNT 100
// Listen count
#define LISTEN_COUNT ((LISTEN_TIME * 1000000) / (TX_TIME * TGETC_COUNT))
// Local Type Defs
#ifdef BYTE
#undef BYTE
#endif
#ifdef BOOLEAN
#undef BOOLEAN
#endif
typedef unsigned int8 BYTE ;
typedef unsigned int16 WORD ;
typedef unsigned int32 DWORD ;
typedef unsigned int1 BOOLEAN ;
// The memory sizes
#define MEM_SIZE (getenv("PROGRAM_MEMORY"))
#define EEPROM_SIZE (getenv("DATA_EEPROM"))
// Constant Data Size
#define _ROM_UID_CZ 8
#define _VECT_VALID_CZ 1
#define _RESET_VECT_CZ 4
#define BOOTSTRAP_CONST (_ROM_UID_CZ + _VECT_VALID_CZ + _RESET_VECT_CZ)
// Bootstap program size
#ifdef ALLOW_EEPROM
#define BOOTSTRAP_PROG 0x02F0
// #define BOOTSTRAP_PROG 0x0400
#else
#define BOOTSTRAP_PROG 0x02A0
#endif
// Program Seg
#define PSEG (MEM_SIZE - BOOTSTRAP_PROG - BOOTSTRAP_CONST)
#define PSEG_END (MEM_SIZE - BOOTSTRAP_CONST - 1)
// Constants Seg
#define CSEG (MEM_SIZE - BOOTSTRAP_CONST)
#define CSEG_END (MEM_SIZE - 1)
// Application Seg
#define ASEG 0x0004
#define ASEG_END (PSEG - 1)
// EEPROM Seg
#define ESEG 0x2100
#define ESEG_END (EEPROM_SIZE + ESEG - 1)
// Constants Seg Data
// ==================
// Define the address of CSEG data
#define _ROM_UID_CS CSEG
#define _ROM_UID_CE _ROM_UID_CS + _ROM_UID_CZ - 1
#define _VECT_VALID_CS _ROM_UID_CS + _ROM_UID_CZ
#define _VECT_VALID_CE _VECT_VALID_CS + _VECT_VALID_CZ - 1
#define _RESET_VECT_CS _ROM_UID_CS + _ROM_UID_CZ + _VECT_VALID_CZ
#define _RESET_VECT_CE _RESET_VECT_CS + _RESET_VECT_CZ - 1
// ROM_UID - Get the default from serialno.h
#include "SERIALNO.H"
#org _ROM_UID_CS, _ROM_UID_CE
unsigned int32 const ROM_UID = SERIALNO ;
#serialize(id=ROM_UID,file="snbootstrap.txt",log="snbootstraplog.txt")
// Store the vector valid value
#rom _VECT_VALID_CS = {0x3400 | 0x00}
// Reset Vector - Self modifying code
// Default code is reset_cpu() ;
// 0000 NOP
// 018A CLRF PCLATH
// 1283 BCF STATUS, 0x5
// 2800 GOTO 0
#rom _RESET_VECT_CS = {0x0000, 0x018A,0x1283,0x2800}
// The application reset vector
#define RESET_VECT _RESET_VECT_CS
// The vector valid value call address
#define VECT_VALID _VECT_VALID_CS
// Size the bootstrap for reporting to host
#define BOOTSTRAP_START PSEG
#define BOOTSTRAP_SIZE BOOTSTRAP_PROG + _VECT_VALID_CZ + _ROM_UID_CZ
#define CMD_LISTEN 0x0D // Enter Listening Mode
#define CMD_END_ID 0x23 // '#'
#define CMD_START_ID 0x2A // '*'
#define CMD_ACK_ID 0x2B // '+'
#define CMD_DATA_ID 0x30 // ID data value from host
#define CMD_WRITE_REG 0x40 // Write data register to Program EEPROM
#define CMD_READ_REG 0x41 // Read Program EEPROM to register, use address in the register
#define CMD_RESTART 0x42 // Restart at the application
#define CMD_DATA_UPLOAD 0x43 // Upload data to host
#define CMD_ADDR_DNLOAD 0x44 // Download data from host to the address register
#define CMD_DATA_DNLOAD 0x45 // Download data from host
#define CMD_INFO_DATA 0x46 // Copy info to data register
#define CMD_LOOP 0x50 // Loop Count Data from remote
#define CMD_DATA 0x60 // Data from remote
// Read/Write EEPROM Data
typedef struct {
union {
struct {
WORD adr ;
WORD siz ;
} xx ;
struct {
BYTE buf[4] ;
} x ;
} x ;
} bsadr ;
// Read/Write EEPROM Data
typedef struct {
union {
struct {
WORD dat[16] ;
} xx ;
struct {
BYTE buf[32] ;
} x ;
struct {
DWORD dword[16] ;
} xxxx ;
} x ;
} bsdat ;
// Build the memory structure for app to read the info from
BSInfo appInfo = { 0x00000001, PSEG, FUSEREG } ;
#locate appInfo = APP_INFO_BASE
// Reserve the Application Program Segment
// =======================================
#include "resrvapp.h"
// Timeout getc
#separate char tgetc()
{
set_timer1(0) ;
while(!kbhit()) {
// Wait for upto 4 char time for an answer
if (get_timer1() >= TX_TIMEOUT(TGETC_COUNT))
return 0 ;
#ifdef RESET_WDT
// Reset the watchdog when waiting
restart_wdt();
#endif
}
// Return the data waiting
return getc() ;
}
#ifdef ALLOW_EEPROM
// Read a memory address
#separate WORD read_mem(WORD adr)
{
if (adr >= ESEG) {
return read_eeprom ((adr - ESEG));
} else {
return read_program_eeprom (adr);
}
}
#else
// Read a memory address
#separate WORD read_mem(WORD adr)
{
return read_program_eeprom (adr);
}
#endif
#ifdef ALLOW_EEPROM
// Write to memory
#separate void write_mem(WORD adr, WORD dat)
{
if (adr < ASEG) // Don't allow changes to reset vector
return ;
if (adr <= ASEG_END) { // Program the application
write_program_eeprom (adr, dat);
return ;
}
if (adr < _VECT_VALID_CS) // Don't allow changes to bootstrap prog
return ;
if (adr <= CSEG_END) { // Program the application restart vector
write_program_eeprom (adr, dat);
return ;
}
if (adr < ESEG) // Don't allow changes to undefined mem
return ;
if (adr <= ESEG_END) // Program the eeprom
write_eeprom ((adr - ESEG), dat);
}
#else
// Write to memory
#separate void write_mem(WORD adr, WORD dat)
{
if (adr < ASEG) // Don't allow changes to reset vector
return ;
if (adr <= ASEG_END) { // Program the application
write_program_eeprom (adr, dat);
return ;
}
if (adr < _VECT_VALID_CS) // Don't allow changes to bootstrap prog
return ;
if (adr <CSEG_END>> 4)) ;
putc(CMD_DATA | (val & 0x0F)) ;
}
// Recieve a byte value from the host
#separate BYTE getbyte()
{
BYTE val ;
val = (tgetc() <<4>= CMD_LISTEN && ch <CMD_WRITE_REG>> 1] |= (ch & 0x0F) ;
} else {
dat.x.x.buf[dataCnt >> 1] = ch << 4 ;
}
dataCnt++ ;
}
// Limit the read/write range to 'dat'
dataCnt &= 0x07 ;
} else if (ch) {
// Default is not an address command
addrCmd = FALSE ;
// Process host commands
switch(ch) {
case CMD_WRITE_REG : // Write to Program EEPROM
for (i = 0 ; i < adr.x.xx.siz ; i++) {
write_mem(adr.x.xx.adr++, dat.x.xx.dat[i]);
}
break ;
case CMD_READ_REG : // Read to Program EEPROM
for (i = 0 ; i < adr.x.xx.siz ; i++) {
dat.x.xx.dat[i] = read_mem(adr.x.xx.adr++) ;
}
break ;
case CMD_RESTART : // Restart at the application
// Start the application
rst_flag = TRUE ;
break ;
case CMD_DATA_UPLOAD : // Upload data register
csum = 0 ;
// Bytes to send is twice the number of words
cnt = (BYTE)(adr.x.xx.siz) << 1 ;
for (i = 0 ; i < cnt ; i++) {
csum += val = dat.x.x.buf[i] ;
// Send byte as two nibbles
putbyte(val) ;
}
// End with the CheckSum
// csum = 0xFF - csum + 1;
// putbyte(csum) ;
putbyte(0xFF - csum + 1);
break ;
case CMD_ADDR_DNLOAD : // Download data register to address register
addrCmd = TRUE ;
adr.x.xx.siz = 2 ;
case CMD_DATA_DNLOAD : // Download data register
csum = 0 ;
// Bytes to recieve is twice the number of words
cnt = (BYTE)(adr.x.xx.siz) << 1 ;
for (i = 0 ; i < cnt ; i++) {
val = (tgetc() << 4) ;
val |= (tgetc() & 0x0F) ;
// val = getbyte() ;
csum += dat.x.x.buf[i] = val ;
}
// Get the sent checksum
val = (tgetc() << 4) ;
val |= (tgetc() & 0x0F) ;
// val = getbyte() ;
// Calc the buffers CheckSum
// csum = 0xFF - csum + 1;
// Retrun the answer to the checksum comparison
ch = ((0xFF - csum + 1) == val) ? CMD_DATA | 0x01 : CMD_DATA | 0x00 ;
// Copy to the address register if Address Command
if (addrCmd) {
adr.x.xx.adr = dat.x.xx.dat[0] ;
adr.x.xx.siz = dat.x.xx.dat[1] ;
}
break ;
case CMD_INFO_DATA : // Copy device info to data register
dat.x.xxxx.dword[0] = appInfo.uid ;
dat.x.xxxx.dword[1] = BOOTSTRAP_START ;
dat.x.xx.dat[4] = BOOTSTRAP_SIZE ;
strcpy(&dat.x.x.buf[10], getenv("DEVICE")) ;
break ;
}
// Echo the command or return value
putc(ch) ;
// Limit the read/write range to 'dat'
dataCnt &= 0x3F ;
// adrCnt &= 0x07 ;
// Report to host the command is complete
putc((loop++ & 0x0F) | CMD_LOOP) ;
if(rst_flag) {
// Goto start app
break ;
}
}
}
// Get the vector valid flag (stored before the UID as RETLW)
#ASM
CALL VECT_VALID
MOVWF val ;
#ENDASM
if (val) {
// Copy Applications Info Structure Address To Our Hook
INFOHOOK = &appInfo ;
// Do short jump to where the apps reset vector must be put
goto_address(RESET_VECT);
} else {
reset_cpu() ;
}
}
|
|
|
|
philippel13
Joined: 25 Mar 2007 Posts: 3
|
|
Posted: Sun Mar 25, 2007 3:03 am |
|
|
VanHauser, i've tried to use your rs485 bootloader version with a pic 18f2620 and i've a few problems :
- I can easily read and write with RS485
- I can do a software reset + download with rs232
- but the download with rs485 doesn't works. I've an answer "couldn't write" from tiny.
In fact it works only when i am just near my pc and without using terminator resistor. If i use terminator resistor or if i put the pic at 5 or 10 meters, it doesn't works anymore ...
As difference with you, i don't use WDT, i don't use optocouplers and i use a pic 18f2620.
How do you connect le re/de pin ? Directly from C5 and with a resistor ?
Do you use 120 ohm terminator resistor ?
Perhaps i've done an error with transfering your code for a 18f2620 ... Could you have a little look to my code ?
thanks
radix DEC
LIST P=18F2620 ; change also: Configure->SelectDevice from Mplab
xtal EQU 20000000 ; you may want to change: _XT_OSC_1H _HS_OSC_1H _HSPLL_OSC_1H
baud EQU 19200 ; standard TinyBld baud rates: 115200 or 19200
; The above 3 lines can be changed and buid a bootloader for the desired frequency (and PIC type)
;********************************************************************
; Tiny Bootloader 18F series Size=132words
; claudiu.chiculita@ugal.ro
; http://www.etc.ugal.ro/cchiculita/software/picbootloader.htm
;********************************************************************
#include "icdpictypes.inc" ;takes care of: #include "p18fxxx.inc", max_flash, IdTypePIC
#include "spbrgselect.inc" ; RoundResult and baud_rate
#define first_address max_flash-264 ;132 words, DO NOT FORGET tinybld.ini !!
__CONFIG _CONFIG1H, _OSC_HS_1H & _FCMEN_OFF_1H & _IESO_OFF_1H
__CONFIG _CONFIG2L, _PWRT_OFF_2L & _BOREN_OFF_2L
__CONFIG _CONFIG2H, _WDT_OFF_2H & _WDTPS_1_2H
__CONFIG _CONFIG3H, _MCLRE_ON_3H & _PBADEN_OFF_3H & _CCP2MX_PORTBE_3H
__CONFIG _CONFIG4L, _DEBUG_OFF_4L & _LVP_OFF_4L & _STVREN_OFF_4L & _XINST_OFF_4L
__CONFIG _CONFIG5L, _CP0_OFF_5L & _CP1_OFF_5L & _CP2_OFF_5L
__CONFIG _CONFIG5H, _CPB_OFF_5H
__CONFIG _CONFIG6L, _WRT0_OFF_6L & _WRT1_OFF_6L & _WRT2_OFF_6L
__CONFIG _CONFIG6H, _WRTB_OFF_6H & _WRTC_OFF_6H
__CONFIG _CONFIG7L, _EBTR0_OFF_7L & _EBTR1_OFF_7L & _EBTR2_OFF_7L
__CONFIG _CONFIG7H, _EBTRB_OFF_7H & _DEVID1 & _IDLOC0
;----------------------------- PROGRAM ---------------------------------
cblock 0
crc
i
cnt1
cnt2
cnt3
counter_hi
counter_lo
flag
endc
cblock 10
buffer:64
dummy4crc
sendb ; Byte to send
d1 ; For delay routine
endc
;0000000000000000000000000 RESET 00000000000000000000000000
ORG 0x0000
GOTO IntrareBootloader
;view with TabSize=4
;&&&&&&&&&&&&&&&&&&&&&&& START &&&&&&&&&&&&&&&&&&&&&&
;---------------------- Bootloader ----------------------
;PC_flash: C1h U H L x ... <64> ... crc
;PC_eeprom: C1h 40h EEADR EEDATA 0 crc
;PC_cfg C1h U OR 80h H L 1 byte crc
;PIC_response: type `K`
ORG first_address ;space to deposit first 4 instr. of user prog.
nop
nop
nop
nop
org first_address+8
IntrareBootloader
movlw b'10011111'
movwf TRISC
;init serial port
movlw b'00100100'
movwf TXSTA
movlw spbrg_value
movwf SPBRG
movlw b'10010000'
movwf RCSTA
;wait for computer
rcall Receive
sublw 0xC1 ;Expect C1h
bnz way_to_exit
movlw IdTypePIC
rcall SendW ;send PIC type
MainLoop
movlw 'K'
rcall SendW ; "-Everything OK, ready and waiting."
mainl
clrf crc
rcall Receive ;Upper
movwf TBLPTRU
movwf flag ;(for EEPROM and CFG cases)
rcall Receive ;Hi
movwf TBLPTRH
movwf EEADR ;(for EEPROM case)
rcall Receive ;Lo
movwf TBLPTRL
movwf EEDATA ;(for EEPROM case)
rcall Receive ;count
movwf i
incf i
lfsr FSR0, (buffer-1)
rcvoct ;read 64+1 bytes
movwf TABLAT ;prepare for cfg; => store byte before crc
rcall Receive
movwf PREINC0
decfsz i
bra rcvoct
tstfsz crc ;check crc
bra ziieroare
btfss flag,6 ;is EEPROM data?
bra noeeprom
movlw b'00000100' ;Setup eeprom
rcall Write
bra waitwre
noeeprom
btfss flag,7 ;is CFG data?
bra noconfig
tblwt* ;write TABLAT(byte before crc) to TBLPTR***
movlw b'11000100' ;Setup cfg
rcall Write
bra waitwre
noconfig
;write
eraseloop
movlw b'10010100' ; Setup erase
rcall Write
TBLRD*- ; point to adr-1
writebigloop
movlw 8 ; 8groups
movwf counter_hi
lfsr FSR0,buffer
writesloop
movlw 8 ; 8bytes = 4instr
movwf counter_lo
writebyte
movf POSTINC0,w ; put 1 byte
movwf TABLAT
tblwt+*
decfsz counter_lo
bra writebyte
movlw b'10000100' ; Setup writes
rcall Write
decfsz counter_hi
bra writesloop
waitwre
;btfsc EECON1,WR ;for eeprom writes (wait to finish write)
;bra waitwre ;no need: round trip time with PC bigger than 4ms
bcf EECON1,WREN ;disable writes
bra MainLoop
ziieroare ;CRC failed
movlw 'N'
rcall SendW
bra mainl
;******** procedures ******************
; Delay is needed because the optocouplers need time for transitions.
; Only required for the RE_DE line.
Delay50us
movlw 165*xtal/40000000
movwf d1
Delay_0
decfsz d1, f
goto Delay_0
return
SendW
movwf sendb
bsf PORTC,5 ; RE_DE_485
btfss PIR1,TXIF
goto $-2
rcall Delay50us
movff sendb,TXREG
nop
bsf PORTC,5
btfss TXSTA,TRMT
goto $-2
bcf PORTC,5
rcall Delay50us
return
Write
clrwdt
movwf EECON1
movlw 0x55
movwf EECON2
movlw 0xAA
movwf EECON2
bsf EECON1,WR ;WRITE
nop
;nop
return
Receive
clrwdt
movlw xtal/2000000+1 ; for 20MHz => 11 => 1second delay
movwf cnt1
rpt2
clrf cnt2
rpt3
clrf cnt3
rptc
btfss PIR1,RCIF ;test RX
bra notrcv
movf RCREG,w ;return read data in W
addwf crc,f ;compute crc
return
notrcv
decfsz cnt3
bra rptc
decfsz cnt2
bra rpt3
decfsz cnt1
bra rpt2
;timeout:
way_to_exit
bcf RCSTA, SPEN ; deactivate UART
movlw b'11111111'
movwf TRISC
bra first_address
;*************************************************************
; After reset
; Do not expect the memory to be zero,
; Do not expect registers to be initialised like in catalog.
END |
|
|
VanHauser
Joined: 03 Oct 2005 Posts: 88 Location: Ploiesti, Romania
|
|
Posted: Sun Mar 25, 2007 6:02 am |
|
|
I tested it with and without the 120 ohm terminating resistor. For termination, I also have 470 ohm resistors, one tied from DATA+ to Vcc and one from DATA- to Gnd. These 3 resistors are connected when I activate two switches. Maybe you should try the termination type I'm using.
The RE and DE pins of the 485 driver chip are not linked directly to pin C5, they are connected via one optocoupler.
What driver chip are you using? |
|
|
philippel13
Joined: 25 Mar 2007 Posts: 3
|
|
Posted: Sun Mar 25, 2007 6:11 am |
|
|
i'm using an st485 (max485). I can also tried with a ltc485.
how do you use your 470 ohm ? Only for the bootloader and any time ? |
|
|
philippel13
Joined: 25 Mar 2007 Posts: 3
|
|
Posted: Sun Mar 25, 2007 7:26 am |
|
|
i've found the problem. It works perfectly with a ltc485 but doesn't works with st485 .... |
|
|
VanHauser
Joined: 03 Oct 2005 Posts: 88 Location: Ploiesti, Romania
|
|
Posted: Tue Mar 27, 2007 3:33 am |
|
|
philippel13 wrote: | i'm using an st485 (max485). I can also tried with a ltc485.
how do you use your 470 ohm ? Only for the bootloader and any time ? |
I'm using a termination like the one on this page, see the second schematic. Termination is only required at both ends of long networks, but I tried the bootloader with an without it and works ok. |
|
|
Mark Weir
Joined: 11 Sep 2003 Posts: 51 Location: New Zealand
|
Questions |
Posted: Thu Apr 19, 2007 5:56 pm |
|
|
Hi There,
I have not used bootloaders before and have a few questions
I would like to use this arrangement with an 18F4620. If I understand things correctly I need to modify the bootloader file for my desired frequency(4000000) and baudrate(9600) then modify the tinybld ini file [options] to SizeofBLD=264 and SizeofBLD_W=264?
Hardware wise I should be able to connect straight to the comms pins i.e C5 enable C6 and C7 with correct pull ups and termination resistors?
Thanks for your help.
Cheers
Mark |
|
|
|
|
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 vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|