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 support@ccsinfo.com

bootloader

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



Joined: 22 Aug 2005
Posts: 275

View user's profile Send private message

bootloader
PostPosted: Tue Apr 15, 2014 6:24 am     Reply with quote

HI to all,

I'm in trouble with my bootloader based on old post and used without any problem with PIC18F4520, PIC18F4525,PIC18F46K22. Booloader firmware start after serial command and it is place in the high side of flash. After compiled with routine "firmware_updater.c" I export only memory part of bootloader, from 0xfc00 to 0x1FFFF, so I can import it as hex file in all my project. In this way I can start bootloader using a call to memory location where it start. Now I don't realize why it work with "firmware_updater.c" but no with imported hex file. Anyway memory location of bootloader are the same in both situation and I jump to same memory location with serial command.

I think there's a possible concept error that I don't understad.

I use PIC18F67K22 and CCS 4.135.
Here the code, somebody can help me ?
Code:

/*! \file firmware_updater.c
*
* Downloads firmware over RS232 and writes it to flash
*
* Based on the CCS supplied example loader.c, modified to only work
* for 18 series
*
* After each good line, the loader sends an ACKLOD character.  The
* driver uses XON/XOFF flow control.  Also, any buffer on the PC
* UART must be turned off, or to its lowest setting, otherwise it
* will miss data.
*
* \author Ed Waugh
* \date 09/06/2009
*/

// Some useful debugging lines
//fprintf(LOADER_STRM,"Loader End 0x%lx, Loader Size 0x%lx, Loader Addr 0x%lx\r", LOADER_END, LOADER_SIZE, LOADER_ADDR);
//fprintf(LOADER_STRM,"Flash erase size 0x%lx, Flash write size 0x%lx\r", getenv("FLASH_ERASE_SIZE"), getenv("FLASH_WRITE_SIZE"));

// Define the size of the loader in ROM and the address to write it to

#ifndef LOADER_END
   #define LOADER_END   getenv("PROGRAM_MEMORY")-1                         ///< Get the end of the program memory and put the loader there
 
#ifdef debug
  #define LOADER_SIZE   0x7ff
#else
  #define LOADER_SIZE   0x3ff                                ///< Size of the loader functions
#endif

#endif
#define LOADER_ADDR     ( LOADER_END - LOADER_SIZE )                       ///< Address of the loader


// Set all the functions following this directive to be included in the
// loader ROM area
//#pragma ORG LOADER_ADDR+10, LOADER_END default

#pragma ORG LOADER_ADDR+10, LOADER_END default

// Serial port stream specific to this area to make the compiler create
// specific specific serial functions stored in the #ORG

// Definitions
#define BUFFER_LEN_LOD  64                                                 ///< Length of a line in an Intel 8-bit hex file
#define ACKLOD 0x06                                                        ///< Acknowledge the last line
#define XON    0x11                                                        ///< Turn transmission on
#define XOFF   0x13                                                        ///< Turn transmission off


//******************************************************************************
/// Convert two hex chars to a byte
/*!
* \param[in] s String 2 chars long
* \return Byte value from hex
*/
#pragma inline                                                          // The SEPARATE directive tells the compiler not to inline this function, this reduces the ROM space required
uint8_t atoi_b16(char_t *s)
{
   uint8_t result = 0;
   uint8_t i;

   for (i=0; i<2; i++,s++)
   {
      if (*s >= 'A')
      {
         result = 16*result + (*s) - 'A' + 10;
      }
      else
      {
         result = 16*result + (*s) - '0';
      }
   }

   return(result);
}

//******************************************************************************
/// Copy of the string compare function
/*!
* This does not get inlined by the compiler so I have made a copy of the CCS supplied
* library function that gets included in the #org section
* \param[in] s1 Pointer to the first string
* \param[in] s2 Pointer to the second string
* \param[in] n Number of characters to compare
* \return 0 for equal, negative or positive for not equal
*/
#pragma inline
int8_t ldr_strncmp(char_t *s1, char_t *s2, uint8_t n)
{
   for (; n > 0; s1++, s2++, n--)
   {
      if (*s1 != *s2) return((*s1 <*s2) ? -1: 1);
      else if (*s1 == '\0') return(0);
   }
   return(0);
}

//******************************************************************************
/// The firmware loader
/*!
* Real load function could be sat anywhere inside the #org area
*/
#pragma inline
void real_load_program (void)
{
   uint1_t  do_ACKLOD, done=FALSE;
   uint8_t  checksum, line_type, dataidx, i, count, buffidx;
   uint16_t l_addr, h_addr=0;
   uint32_t addr;
   
   // Buffers
   uint8_t  data[32];
   uint8_t buffer[BUFFER_LEN_LOD];

   // Only required for parts where the flash erase and write sizes are different
   #if (getenv("FLASH_ERASE_SIZE") > getenv("FLASH_WRITE_SIZE"))
      uint32_t next_addr = 0;
   #endif

   disable_interrupts(global);

   while (!done)  // Loop until the entire program is downloaded
   {
      buffidx = 0;  // Read into the buffer until 0x0D ('\r') is received or the buffer is full
      do
      {
         buffer[buffidx] = getc();

    } while ( (buffer[buffidx++] != 0x0D) && (buffidx <= BUFFER_LEN_LOD) );

     putchar(XOFF);
      do_ACKLOD = TRUE;                                                          // Flag to indicate this is a sentence we should acknowledge

      // Only process data blocks that start with ':'
      if (buffer[0] == ':')
      {
         count = atoi_b16(&buffer[1]);                                           // Get the number of bytes from the buffer
         l_addr = make16(atoi_b16(&buffer[3]),atoi_b16(&buffer[5]));             // Get the lower 16 bits of address
         line_type = atoi_b16(&buffer[7]);                                       // Get the line type code from the string
         addr = make32(h_addr,l_addr);                                           // At the first time through h_addr is zero as we are assuming the high bytes of the addr are zero until we get a type 4 command

         if (line_type == 1)                                                     // If the line type is 1, then data is done being sent
         {
            done = TRUE;
//            do_ACKLOD = FALSE;   //tolto ?
         }
         else if ((addr < LOADER_ADDR || addr > LOADER_END) && addr < 0x300000)  // Don't try to overwrite the loader
         {
            checksum = 0;                                                        // Sum the bytes to find the check sum value
            for (i=1; i<(buffidx-3); i+=2)
            {
               checksum += atoi_b16 (&buffer[i]);
            }
            checksum = 0xFF - checksum + 1;

            if (checksum != atoi_b16 (&buffer[buffidx-3]))
               do_ACKLOD = FALSE;

            else
            {
               if (line_type == 0)
               {
                  // Loops through all of the data and stores it in data
                  // The last 2 bytes are the check sum, hence buffidx-3
                  for (i = 9,dataidx=0; i < buffidx-3; i += 2)
                  {
                     data[dataidx++] = atoi_b16(&buffer[i]);
                  }

                 #if (getenv("FLASH_ERASE_SIZE") > getenv("FLASH_WRITE_SIZE"))
                     if ((addr!=next_addr)&&(addr&(getenv("FLASH_ERASE_SIZE")/2-1)!=0))
                        erase_program_eeprom(addr);
                   
                     next_addr = addr + 1;
                  #endif

                  write_program_memory(addr, data, count);                             // Attempt a write to the program memory
//                 do_ACKLOD = FALSE; // tolto ?

                }
               else if (line_type == 4)         
                  h_addr = make16(atoi_b16(&buffer[9]), atoi_b16(&buffer[11]));
            }
         }
      }

      if (do_ACKLOD)                                                       // Only do this for sentences we have not already responded to
       putchar(ACKLOD);

       putchar(XON);
   }

   putchar(ACKLOD);
   putchar(XON);

   reset_cpu();                                                            // After writing a new program we always want to reset the CPU
}

// This #ORG ends the section holding the loader (default causes all functions within
// the declaration to be put in the ROM section)
// This #ORG ends the section holding the loader (default causes all functions within
// the declaration to be put in the ROM section)
#pragma inline
void load_program(){
   real_load_program();
}

//#pragma ORG default

//******************************************************************************
/// Stub load function
/*!
* Set a stub function at a specific address so we can jump to it by changing the PC
* We must always use this as the new application version that overwrites the code won't
* necessarily have the same layout

//#pragma ORG LOADER_ADDR, LOADER_ADDR+9
void load_program(void)
{
   real_load_program();
}
*/

// Definizione ram usate da seriale
int    puntatore_rx_seriale   ;
int16   calcolo_checksum   ;
int      timeout_ricezione_seriale;
int    tentativi_comunicazione;
int      carattere_ricevuto;
char   buffer_rx_seriale[10]   ;
char   buffer_tx_seriale[7]   ;

char    string1[6];   
char    stringa[5];

long    comunicazioni_eseguite   ;
long   comunicazioni_corrette   ;

// Bit di controllo
int1   buffer_rx_pronto      ;
boolean   checksum_verificato      ;   

#include <stdlib.h>






/*
Routine che scrive i dati in eeprom
Verifica che l'indirizzo

*/

void seriale_isr() {

// Salva carattere ricevuto in ram
carattere_ricevuto=getc(hardware);

// Se carattere ricevuto ESC allora start byte della stringa
   if (carattere_ricevuto==0x1b)
      puntatore_rx_seriale=0;

   buffer_rx_seriale[puntatore_rx_seriale]=carattere_ricevuto;

      if (buffer_rx_seriale[puntatore_rx_seriale]=='&'){
      buffer_rx_pronto=true;
      }

   puntatore_rx_seriale++;

    if (puntatore_rx_seriale>=10)
      puntatore_rx_seriale=0;
}   

/*
***************************************
Funzione che verifica il checksum della stringa
ricevuta e restituisce true o false
***************************************
*/
boolean controlla_checksum_rx(){
int i;
// Azzera flag prima di controllo
checksum_verificato=false;
// Calcola checksum
   calcolo_checksum=0;
   for (i=1;i<=6;i++){
      calcolo_checksum+=buffer_rx_seriale[i];
   }
// Del checksum tengo solo la parte L
      calcolo_checksum=(int)calcolo_checksum;

// Verifico checksum
      strcpy(string1,"0x");
      strcpy(stringa,"00");
      stringa[0]=buffer_rx_seriale[7];
      stringa[1]=buffer_rx_seriale[8];
      strcat(string1, stringa);
      if (calcolo_checksum==atol(string1))
         checksum_verificato=true;      

      return(checksum_verificato);
}


/*
***************************************
Questa routine invia il buffer seriale
dopo aver calcolato il checksum
***************************************
*/
void invia_stringa_seriale(){
int i;
calcolo_checksum=0;

// Statistica comunicazioni
comunicazioni_eseguite++;

   for (i=0;i<=5;i++){
      calcolo_checksum+=buffer_tx_seriale[i];
   }
// Calcolato il checksum invia la richiesta seriale;
// Invia start
printf("%C",0x1b);
// Invia Stringa
printf(buffer_tx_seriale);
// Invia Checksum
printf("%2X",calcolo_checksum);
// Invia Stop
printf("&");

}

void verifica_buffer_rx_seriale(){
   if (buffer_rx_pronto==true){
      if (controlla_checksum_rx()){
         comunicazioni_corrette++;

// Verifica primo carattere
         switch(buffer_rx_seriale[1]){
// Se L leggi locazione EEPROM richiesta ed invia risposta seriale
         case 'L':
         byte_h=buffer_rx_seriale[2];
         byte_l=buffer_rx_seriale[3];
         converti_ascii_hex();
         byte_l=read_eeprom(byte_l);
         converti_hex_ascii();
         buffer_tx_seriale[0]=byte_h;
         buffer_tx_seriale[1]=byte_l;
         break;

// Se S scrivi il dato in locazione EEPROM richiesta ed invia risposta seriale
         case 'S':
         break;

// Se 'R' Richiesta seriale decodifica byte 2 e 3 per tipo richiesta
         case 'R':
         byte_h=buffer_rx_seriale[2];
         byte_l=buffer_rx_seriale[3];
         converti_ascii_hex();   
            switch(byte_l){

// Se 0xFA passa in modalità bootloader;

            case 0xFA:
               #asm
                  CALL 0x1FFCC
               #endasm

            break;
            }
         break;      
         }
      }
      buffer_rx_pronto=false;   
      puntatore_rx_seriale=0;
   }
}

   #include "18F67K22.h"
   #fuses HSM,NODEBUG,NOWDT,NOPROTECT,NOPUT,NOCPD,NOBROWNOUT,NOCPB,STVREN,NOPLLEN,NOFCMEN,SOSC_DIG
   #device  ADC=12

#device *=16


#fill_rom 0x00

#use delay(clock=16000000,RESTART_WDT)
#use rs232(baud=115200, xmit=PIN_C6, rcv=PIN_C7, restart_wdt,stream=hardware)


#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#use fast_io(d)

#include <DEF452.c>
#include "typedef.h"

void seriale_isr();
void verifica_buffer_rx_seriale();


//RAM
byte   byte_l                  ;
byte   byte_h                  ;
      

/*
*************************************************
Routine di conversione HEX-ASCII
Ingresso: Byte_l

Uscite:byte_l e byte_h
*************************************************
*/
void converti_hex_ascii(){
// Salva Parte h
byte_h= (0xf0 & (byte_l));
swap(byte_h);
byte_l= (0x0f & (byte_l));

   if (byte_l < 0x0a){
   byte_l = (byte_l+0x30);
   goto fine_hex_byte_l;
   }
byte_l = (byte_l + 0x37) ;
fine_hex_byte_l:

   if (byte_h < 0x0a){
   byte_h = (byte_h+0x30);
   goto fine_hex_byte_h;
   }
byte_h = (byte_h + 0x37) ;
fine_hex_byte_h:;
}

/*
*************************************************
Routine di conversione ASCII- HEX
Ingresso: Byte_h, Byte_l

Uscite:byte_l
*************************************************
*/
void converti_ascii_hex(){
// Se byte_l > 0x40 allora carattere A-F
// Sottrai 0x41 e somma 0x10
   if (byte_l > 0x40){
      byte_l=((byte_l-0x41)+0x0a);
      goto fine_conversione_byte_l;
   }

// Se byte_l minore di 40 allora numero da 0 a 9
// Sottrai 0x30
   if (byte_l < 0x40){
      byte_l=(byte_l-0x30);
   }

fine_conversione_byte_l:
// Se byte_l > 0x40 allora carattere A-F
// Sottrai 0x41 e somma 0x10
   if (byte_h > 0x40){
      byte_h=((byte_h-0x41)+0x0a);
      goto fine_conversione_byte_h;
   }

// Se byte_l minore di 40 allora numero da 0 a 9
// Sottrai 0x30
   if (byte_h < 0x40){
      byte_h=(byte_h-0x30);
   }
fine_conversione_byte_h:
   swap(byte_h);
   byte_l= (byte_l ??! byte_h);
}


/*
Routine di Interrupt ogni 100us
*/
#int_rtcc                          // This function is called every time
void clock_isr_timer0() {                 // the RTCC (timer0) overflows (255->0).
   set_timer0(80);
}

// Ad ogni interrupt dell'encoder incrementa giri eseguiti motore
// L'interrupt avviene per una transizione L to H

#int_rda
void inter_rda(){
seriale_isr();
}

// Azzera RAM al reset
               
//Programma
#zero_ram   
void main() {

//Definisci I/0 in base allo schema
restart_wdt();

set_tris_a(0b00111111);
set_tris_b(0b00000111);
set_tris_e(0b00000000);
set_tris_d(0b00000000);
set_tris_c(0b10000000);

PORTA = (0x00);
PORTB = (0x00);
PORTC = (0x00);
PORTD = (0x00);
PORTE = (0x00);

port_b_pullups(false);

//Definisci interrupt TIMER0 ogni 100 us per 16Mhz
setup_timer_0 (rtcc_div_2|rtcc_internal|RTCC_8_BIT);
set_timer0(73)      ; //Setto timer 0 a 73 per interrupt ogni 10 ms
//inizializza_ad();

// Configura TIMER1
disable_interrupts(int_timer1);
setup_timer_1 (t1_internal | T1_DIV_BY_4);
ext_int_edge( H_TO_L );   // Sets up EXT
enable_interrupts(int_rda);
enable_interrupts(global);
restart_wdt();

   while(true) {
      restart_wdt();
      verifica_buffer_rx_seriale();
    }
}
#include "seriale.c"
#include "firmware_updater.c"

//#import (HEX, file=boot_18F67K22.hex)

temtronic



Joined: 01 Jul 2010
Posts: 9198
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Tue Apr 15, 2014 8:12 am     Reply with quote

My guess is that since it works fine using 3 other PICs that it may be a 'memory map' problem with your 4th PIC assuming you've already proved your hardware for the 4th PIC does function correctly with the '1Hz LED' and 'Hello World' type programs.

hth
jay
Fabri



Joined: 22 Aug 2005
Posts: 275

View user's profile Send private message

PostPosted: Tue Apr 15, 2014 8:25 am     Reply with quote

Application and hardware work fine. Also basic firmware posted work fine with serial link in the two case.
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Tue Apr 15, 2014 9:36 am     Reply with quote

First comment, your code is difficult to read because you didn't use the 'code buttons. After 232 posts on this forum you should know better. Even when you made a mistake you can go back to your old post and fix it (suggestion: fix it now).

It is difficult to read your code, but do I seriously see that you have added your whole program to the end of the bootloader? Seriously???
You are lost...

Update: I see you fixed the code layout just while I was typing this message.


++++++++++++++++++++
Fixed by Moderator. Changed to Code block.

Fabri, please use Code button, not Quote button.

- Forum Moderator
++++++++++++++++++++
Fabri



Joined: 22 Aug 2005
Posts: 275

View user's profile Send private message

PostPosted: Tue Apr 15, 2014 10:25 am     Reply with quote

Thanks for correction...
Bootloader is at the end of all program and allocate in the top of flash. With serial link, before to send new firmware, I start bootloader and work in reserved area. Usually in my application I import bootloader as "hex" file and call it from application. Don't you agree ?
Fabri



Joined: 22 Aug 2005
Posts: 275

View user's profile Send private message

PostPosted: Tue Apr 15, 2014 2:34 pm     Reply with quote

A strange thing:

After compiled with "firmware_updater.c" compiler tell me Memory usage: ROM=3% otherwise with #import (HEX, file=boot_18F67K22.hex) compiler tell me Memory usage: ROM=52%.

This not happen, for example, with PIC18F46K22.

Thanks for help,
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Wed Apr 16, 2014 3:02 am     Reply with quote

Your method for including the bootloader as a hex file is not how most people are doing it. As far as I know, most people are doing it in two steps: first program the bootloader and never touch this memory again. Then program the real program.
I can see your method has advantages in that you only have to program the device one time.

I looked at your code for 10 minutes but right now I don't see the cause of your problems.
I suggest you make your program a lot smaller. It will not solve your problem but it will make the discussion here on the forum a lot easier. Now I see a lot of code that is not related to your problem but which takes me time to analyse.
As a rule, I stop looking after 5 minutes. So for better answers you have to make sure I spend my time looking at the real problem. Make the bug hunting efficient to us and you will get more and better answers.

One suggestion: get rid of the command for filling the ROM fit zero values. Default value for most FLASH memory devices is 0xFF. Now you are touching the whole flash memory making programming the device slower and running the risk of overwriting the bootloader.
Fabri



Joined: 22 Aug 2005
Posts: 275

View user's profile Send private message

PostPosted: Wed Apr 16, 2014 3:29 am     Reply with quote

I used this way till now for thousand of PIC18F46K22 without any problem. I can include bootloader in every project. I tryed without "#fill_rom 0x00" but nothig changed. Same program recompiled for PIC18F46K22 work well.
The program is smaller then possible but I need serial link to start bootloader. In debug with included hex file I can see program counter jump to correct address but I don't undertsand why it stop to work. I can see it program memory windows of MPLAB. Can you suggest me possible way to check and do some test ?
Ttelmah



Joined: 11 Mar 2010
Posts: 19436

View user's profile Send private message

PostPosted: Wed Apr 16, 2014 3:33 am     Reply with quote

The way people normally combine the bootloader, so that the first time you program the chip with a hardware programmer, both are written, is to load both one after the other in MPLAB, or into the programmer software.

Not quite sure what you mean about 'importing' the bootloader into the application. If this is your 'loader' application, it must _not_ import the bootloader. The loader area should have it's protection bits set (on chips that support this), or the loader be written to not allow anything to write to the loader area. If you try to write the bootloader with the bootloader, it'll cause disasters (especially on later chips, which have much larger page sizes, which could cover the entire loader...).
Fabri



Joined: 22 Aug 2005
Posts: 275

View user's profile Send private message

PostPosted: Wed Apr 16, 2014 1:10 pm     Reply with quote

well, I'll try to explain you better..

I use this small application to compile a working bootloader. In program memory from 0x1fc0a and 0x1ffCe I have "real" loader so I can export program memory of only that part as ".hex"and import it in every my applications. Knowing start location I can invoke loader with call instruction. Routine "load_program()" is located at 0x1FFCC so I use "call 0x1FFCC". I must only take care about application ans possibility to overwrite loader application. I hope you can understand I use this application and help me. I tryed to compile "firmware_updater.c" with my application but compiler relocate it and change "load_program()"



Regards,
Fabri
Fabri



Joined: 22 Aug 2005
Posts: 275

View user's profile Send private message

PostPosted: Wed Apr 16, 2014 3:06 pm     Reply with quote

I give you more informations....
#useRS232 is the same for application and loader.

seems compiling with:
Code:

#import (HEX, file=boot_18F67K22.hex)


compiler relocate in different way #useRS232. So loader don't find RS232 code. This not happened with other PIC.

What are you thinking about ?
Fabri



Joined: 22 Aug 2005
Posts: 275

View user's profile Send private message

SOLVED: Bootloader
PostPosted: Wed Apr 16, 2014 4:53 pm     Reply with quote

Ok... I solved.

Really loader used #use232 of application so I introduced new getc() and putc() routine inside loader. In this way loader has it's routine.
I can't realize wy I haven't this problem before.
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