CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

RS485 bootloader with sw reset

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
iw2nzm



Joined: 23 Feb 2007
Posts: 55

View user's profile Send private message

RS485 bootloader with sw reset
PostPosted: Thu Mar 08, 2007 7:44 am     Reply with quote

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

View user's profile Send private message Visit poster's website

PostPosted: Thu Mar 08, 2007 9:19 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Mar 08, 2007 10:01 am     Reply with quote

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

View user's profile Send private message Visit poster's website

PostPosted: Thu Mar 08, 2007 2:54 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Mar 12, 2007 3:05 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Mar 17, 2007 10:16 am     Reply with quote

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








PostPosted: Sat Mar 24, 2007 10:17 am     Reply with quote

hi,could you expalin how works the software reset for downloading ?

thanks
nurquhar



Joined: 05 Aug 2006
Posts: 149
Location: Redditch, UK

View user's profile Send private message Visit poster's website

PostPosted: Sun Mar 25, 2007 2:09 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Mar 25, 2007 3:03 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Mar 25, 2007 6:02 am     Reply with quote

philippel13 wrote:
...

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

View user's profile Send private message

PostPosted: Sun Mar 25, 2007 6:11 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Mar 25, 2007 7:26 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Mar 27, 2007 3:33 am     Reply with quote

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

View user's profile Send private message

Questions
PostPosted: Thu Apr 19, 2007 5:56 pm     Reply with quote

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
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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