|
|
View previous topic :: View next topic |
Author |
Message |
nhol
Joined: 22 Jun 2009 Posts: 5
|
Bootloader problem |
Posted: Tue May 09, 2017 4:55 am |
|
|
Hello,
I use the pic 18f46k22 and the Compiler Revision 5.070.
I'm working on a bootloader application. The bootloader should have the loader routines and also routines for testing the pcb after assembling the board.
I have the following code:
- Bootloader:
Code: |
#case
#include <18F46K22.h>
#FUSES NOWDT
#FUSES PUT // Power Up Timer
#FUSES BORV29 // Brownout reset at 2.85V
#FUSES BROWNOUT // BrownOut-Reset aktiv
#FUSES NOPBADEN // PORTB pins Digital I/O nach RESET
#FUSES NOLVP // no low voltage programing, B5 as I/O
#FUSES NOXINST // Extended set extension und Indexed Addressing mode ausgeschaltet
//#FUSES PROTECT // Code protected
//#FUSES CPB // Boot Block read protected
//#FUSES WRTC // Configuration registers write protected
//#FUSES WRTB // Boot block write protected
//#FUSES EBTR // memory read protected
//#FUSES EBTRB // Boot block read protected
#define _bootloader
#include "bootloader.h"
#include "bootloader_defs.h"
#include <string.h>
#include <math.h>
#include "my_eeprom.c"
#use delay(clock=32MHz, crystal=8MHz) // 8 MHz-Crystal, PLL on -> 32 MHz
#use FAST_IO (ALL)
#use rs232(baud=57600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=PCPORT,errors,brgh1ok) // serial port -> 57600 Bd, 8 bit, No Parity
// -> RxD = PC6, TxD = PC7
// ----- Global vars ------------------------------------------------------------------------------------------------------------------------
char HWRevision[6] = "1.01b";
int BLbuffidx;
char BLbuffer[BUFFER_LEN_LOD] = {0};
unsigned int16 BLTimeOut = 0;
unsigned int8 BLStartBootLoader = 0;
char BLRXBuffer[20] = {0};
char BLTXBuffer[20] = {0};
unsigned int8 BLError = 1;
unsigned int8 BLStartTest = 0;
unsigned int32 BLRXTimeOut = 0;
unsigned int8 BLReceivedBytes = 0;
unsigned int8 BLReceived = 0;
unsigned int8 BLNumberOfReceivedBytes = 0;
unsigned int8 BLReceiveState = 0;
char BLReceivedByte = 0;
unsigned int8 BLRcvState = 0;
// --------------------------------------------------------------------------------------------------------------------------------------------------
// Functions
// --------------------------------------------------------------------------------------------------------------------------------------------------
unsigned int16 ReadADC (unsigned int8 channel) // need for check the pcb
{
unsigned int8 i = 0;
unsigned int16 retval = 0;
ADCON0 &= 0x03;
ADCON0 |= (channel << 2);
delay_us (200);
for (i = 0; i < 10; i++)
{
ADCON0 |= 0x02;
while (ADCON0 & 0x02);
retval += (AD_RES_H * 0x100) + AD_RES_L;
delay_ms (2);
}
return (retval / 10);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------
unsigned int8 CharToBIN (unsigned int8 *value) // ASCII to Bin
{
unsigned int8 i;
unsigned int8 retval;
unsigned int8 chr;
for (i=0; i<2; i++)
{
chr = toupper(*value);
if (chr >= 'A')
{
chr -= 'A';
chr += 10;
}
else
chr -= '0';
retval <<= 4;
retval |= chr;
value++;
}
return retval;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------
void CheckBoard(void) // Leiterplatten-Prüfroutine !
{
// do some stuff to check the pcb.
// only needed to test the board after assembling
// should be overwritten with the device firmware
}
// --------------------------------------------------------------------------------------------------------------------------------------------------
unsigned int8 atoi_bl (unsigned int8 *value) // ascii to bin for the bootloader
{
unsigned int8 i;
unsigned int8 retVal = 0;
unsigned int8 chr;
for (i = 0; i < 2; i++)
{
chr = toupper(*value);
if (chr >= 'A')
{
chr -= 'A';
chr += 10;
}
else
chr -= '0';
retVal <<= 4;
retVal |= chr;
value++;
}
return retVal;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------
// loader routine according the driver delivered with the compiler with some small modifications
void real_load_program (void)
{
int1 do_ACKLOD, done=FALSE;
unsigned int8 checksum, line_type;
unsigned int16 l_addr;
unsigned int16 h_addr = 0;
signed int32 addr;
#if getenv("FLASH_ERASE_SIZE") != getenv("FLASH_WRITE_SIZE")
int32 next_addr;
#endif
unsigned int8 dataidx;
unsigned int8 i;
unsigned int8 count;
unsigned int8 data[BUFFER_LEN_LOD / 2];
unsigned int8 BLReceived = 0;
BLRcvState = 0;
while (!done)
{
BLbuffidx = 0;
BLReceived = 0;
do // polling serial port
{
if (kbhit(PCPORT))
{
BLReceivedByte = getc(PCPORT);
switch (BLRcvState)
{
case 0: if (BLReceivedByte == ':')
{
BLbuffer[0] = BLReceivedByte;
BLbuffidx = 1;
BLRcvState = 1;
}
break;
case 1: BLbuffer[BLbuffidx++] = BLReceivedByte;
if (BLReceivedByte == 0x0a)
{
BLReceived = 1;
BLRcvState = 0;
}
break;
}
}
}
while ((!BLReceived) && (BLbuffidx <= BUFFER_LEN_LOD));
putchar (XOFF,PCPORT);
do_ACKLOD = TRUE;
if (BLbuffer[0] == ':')
{
count = atoi_bl (&BLbuffer[1]);
l_addr = ((unsigned int16)(atoi_bl (&BLbuffer[3])) << 8) + atoi_bl (&BLbuffer[5]);
line_type = atoi_bl (&BLbuffer[7]);
addr = ((unsigned int32)(h_addr) << 16) + l_addr;
checksum = 0;
for (i = 1; i < (BLbuffidx - 3); i+=2)
checksum += atoi_bl (&BLbuffer[i]);
checksum = 0xFF - checksum + 1;
if (checksum != atoi_bl (&BLbuffer[BLbuffidx-3]))
do_ACKLOD = FALSE;
else
{
if (line_type == 1)
done = TRUE;
else
{
if (((addr < LOADER_ADDR) || (addr > LOADER_END)) && (addr < getenv("PROGRAM_MEMORY")))
{
for (i = 9; i <( BLbuffidx - 3); i += 2)
data[dataidx++] = atoi_bl (&BLbuffer[i]);
#if getenv("FLASH_ERASE_SIZE") > getenv("FLASH_WRITE_SIZE")
if ((addr!=next_addr) && (addr > (next_addr + (getenv("FLASH_ERASE_SIZE") - (next_addr % getenv("FLASH_ERASE_SIZE"))))) && ((addr & (getenv("FLASH_ERASE_SIZE")-1)) != 0))
{
#if ((getenv("PROGRAM_MEMORY") % getenv("FLASH_ERASE_SIZE")) != 0)
if (addr > (getenv("PROGRAM_MEMORY") - (getenv("PROGRAM_MEMORY") % getenv("FLASH_ERASE_SIZE"))))
{
read_program_memory(getenv("PROGRAM_MEMORY"), rBuffer[0].buffer, getenv("FLASH_ERASE_SIZE") - (getenv("PROGRAM_MEMORY") % getenv("FLASH_ERASE_SIZE")));
erase_program_eeprom(addr);
write_program_memory(getenv("PROGRAM_MEMORY"), rBuffer[0].buffer, getenv("FLASH_ERASE_SIZE") - (getenv("PROGRAM_MEMORY") % getenv("FLASH_ERASE_SIZE")));
}
else
#endif
erase_program_eeprom(addr);
}
next_addr = addr + count;
#endif
#if ((getenv("PROGRAM_MEMORY") % getenv("FLASH_ERASE_SIZE")) != 0)
if (addr == (getenv("PROGRAM_MEMORY") - (getenv("PROGRAM_MEMORY") % getenv("FLASH_ERASE_SIZE"))))
{
read_program_memory(getenv("PROGRAM_MEMORY"), rBuffer[0].buffer, getenv("FLASH_ERASE_SIZE") - (getenv("PROGRAM_MEMORY") % getenv("FLASH_ERASE_SIZE")));
write_program_memory(addr, data, count);
write_program_memory(getenv("PROGRAM_MEMORY"), rBuffer[0].buffer, getenv("FLASH_ERASE_SIZE") - (getenv("PROGRAM_MEMORY") % getenv("FLASH_ERASE_SIZE")));
}
else
#endif
write_program_memory(addr, data, count);
}
}
}
}
if (do_ACKLOD)
putc (ACKLOD, PCPORT);
putc(XON, PCPORT);
}
putc (ACKLOD, PCPORT);
putc(XON, PCPORT);
reset_cpu();
}
// --------------------------------------------------------------------------------------------------------------------------------------------------
void load_program(void)
{
real_load_program();
}
// --------------------------------------------------------------------------------------------------------------------------------------------------
#org LOADER_END+2, LOADER_END+4
void application (void)
{
reset_cpu(); // periodical start of the mcu if no application uploaded
}
// --------------------------------------------------------------------------------------------------------------------------------------------------
// Hauptprogramm
// --------------------------------------------------------------------------------------------------------------------------------------------------
void main(void)
{
unsigned int8 i = 0;
unsigned int8 chksum = 0;
char outval[3] = "";
unsigned int8 bytestosend = 0;
setup_adc_ports (sAN0 | sAN1 | sAN2 | sAN3 | sAN4); // setup the adc for using durring check pcb
setup_adc (ADC_CLOCK_INTERNAL | ADC_TAD_MUL_20);
PORTA = 0x00; // Init all portpins
LATA = 0x00;
TRISA = 0xff;
PORTB = 0x20;
LATB = 0x20;
TRISB = 0x00;
PORTC = 0x00;
LATC = 0x00;
TRISC = 0x9f;
PORTD = 0x00;
LATD = 0x00;
TRISD = 0x80;
PORTE = 0x00;
LATE = 0x00;
TRISE = 0x01;
ANSELA = 0x2f;
ANSELB = 0x00;
ANSELC = 0x00;
ANSELD = 0x00;
ANSELE = 0x00;
VREFCON0 = 0xb0;
ADCON1 = 0x08;
ADCON2 |= 0x80;
port_b_pullups (0x00);
disable_interrupts (GLOBAL);
BUZZER = 1; // short beep to indicate the start of the mcu
delay_ms (50);
BUZZER = 0;
BLTimeOut = 0; // Init vars
BLReceived = 0;
BLReceivedByte = 0;
BLRXTimeOut = 0;
BLReceiveState = 0;
BLStartBootLoader = 0;
while ((++BLTimeOut < 25) && (!BLStartBootLoader )) // loop till timeout or start bootloader
{
for (i = 0; i < 20; i++) // clear buffer
{
BLRXBuffer[i] = 0;
BLTXBuffer[i] = 0;
}
BLRXTimeOut = 0;
bytestosend = 0;
while ((!BLReceived) && (++BLRXTimeOut < 10000)) // poll serial port till data received or timeout
{
if (kbhit(PCPORT))
{
BLReceivedByte = getc(PCPORT);
switch (BLReceiveState)
{
case 0: if (BLReceivedByte == 0x02)
{
BLRXBuffer[0] = BLReceivedByte;
BLReceivedBytes = 1;
BLRXTimeOut = 0;
BLReceiveState = 1;
}
break;
case 1: BLRXBuffer[BLReceivedBytes++] = BLReceivedByte;
BLRXTimeOut = 0;
if (BLReceivedByte == 0x03)
{
BLReceived = 1;
BLNumberOfReceivedBytes = BLReceivedBytes - 1;
BLReceivedBytes = 0;
BLReceiveState = 0;
}
break;
}
}
delay_us (10);
}
if (BLReceived) // data received?
{
BLReceived = 0;
switch (BLRXBuffer[1]) // evaluate data
{
case 'G': switch (BLRXBuffer[2]) // (G)et
{
case 'I': BLTXBuffer[0] = 0x02; // (I)d
BLTXBuffer[1] = 'G';
BLTXBuffer[2] = 'B';
BLTXBuffer[3] = 'o';
BLTXBuffer[4] = 'o';
BLTXBuffer[5] = 't';
BLTXBuffer[6] = ' ';
BLTXBuffer[7] = 'M';
BLTXBuffer[8] = 'C';
BLTXBuffer[9] = HWRevision[0];
BLTXBuffer[10] = HWRevision[1];
BLTXBuffer[11] = HWRevision[2];
BLTXBuffer[12] = HWRevision[3];
BLTXBuffer[13] = HWRevision[4];
bytestosend = 14;
break;
}
break;
case 'S': switch (BLRXBuffer[2]) // Start ->
{
case 'F': BLStartBootLoader = 1; // -> firmware update
BLTXBuffer[1] = 'O';
BLTXBuffer[2] = 'K';
bytestosend = 3;
break;
case 'T': if (read_eeprom_int16 (0x00) == 0xffff) // no data stored -> new pcb with routine for board check
{
BLStartTest = 1;
BLTXBuffer[1] = 'T'; // prepare answer to pc
BLTXBuffer[2] = 'e';
BLTXBuffer[3] = 's';
BLTXBuffer[4] = 't';
bytestosend = 5;
}
else // pcb with firmware -> no test routine
{ //
BLTXBuffer[1] = 'N';
BLTXBuffer[2] = 'o';
BLTXBuffer[3] = 'T';
BLTXBuffer[4] = 'e';
BLTXBuffer[5] = 's';
BLTXBuffer[6] = 't';
bytestosend = 7;
}
break;
}
break;
}
if (bytestosend) // data to pc?
{
BLTXBuffer[0] = 0x02; // STX
chksum = 0; // checksum
for (i = 1; i < bytestosend; i++)
chksum ^= BLTXBuffer[i];
sprintf(outval,"%2u", chksum);
BLTXBuffer[bytestosend++] = outval[0]; // checksum into txbuffer
BLTXBuffer[bytestosend++] = outval[1];
BLTXBuffer[bytestosend++] = 0x03; // ETX
BLTXBuffer[bytestosend++] = 0x0a; // LF
BLTXBuffer[bytestosend++] = 0x0d; // CR
delay_ms (10);
for(i = 0; i < bytestosend; i++) // send answer
putc(BLTXBuffer[i], PCPORT);
bytestosend = 0;
}
}
}
if (BLStartBootLoader)
{
BUZZER = 1; // -> only for development -> short beep
delay_ms (100);
BUZZER = 0;
load_program (); // prog flash
}
if (BLStartTest)
CheckBoard (); // check pcb
BLStartBootLoader = 0; // clear flags
BLStartTest = 0;
}
application (); // run application
}
// --------------------------------------------------------------------------------------------------------------------------------------------------
#int_global
void isr(void) // map interrupt vectors
{
jump_to_isr(LOADER_END + 5 * (getenv("BITS_PER_INSTRUCTION") / 8));
}
// --------------------------------------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------------------------------------
|
- Bootloader defines:
Code: |
// ----- serial commands ------------------------------------------------------------------------------------------------------------------------
#define ACKLOD 0x06 // Zeichen "ACK"
#define XON 0x11 // Zeichen "XON"
#define XOFF 0x13 // Zeichen "XOFF"
// ----- port defines ---------------------------------------------------------------------------------------------------------------
#byte PORTA = 0xf80
#byte PORTB = 0xf81
#byte PORTC = 0xf82
#byte PORTD = 0xf83
#byte PORTE = 0xf84
#byte TRISA = 0xf92
#byte TRISB = 0xf93
#byte TRISC = 0xf94
#byte TRISD = 0xf95
#byte TRISE = 0xf96
#byte LATA = 0xf89
#byte LATB = 0xf8a
#byte LATC = 0xf8b
#byte LATD = 0xf8c
#byte LATE = 0xf8d
// ----- ad converter defines ---------------------------------------------------------------------------------------------------------
#byte ADCON0 = 0xfc2
#byte ADCON1 = 0xfc1
#byte ADCON2 = 0xfc0
#byte AD_RES_H = 0xfc4
#byte AD_RES_L = 0xfc3
#byte ANSELA = 0xf38
#byte ANSELB = 0xf39
#byte ANSELC = 0xf3a
#byte ANSELD = 0xf3b
#byte ANSELE = 0xf3c
#byte VREFCON0 = 0xf42
#byte VREFCON1 = 0xf41
#byte VREFCON2 = 0xf40
// ----- interrupt control register ---------------------------------------------------------------------------------------------------
#byte INTCON = 0x0ff2
#byte INTCON2 = 0x0ff1
#byte INTCON3 = 0x0ff0
#byte PIR1 = 0x0f9e
#byte PIR2 = 0x0fa1
#byte PIR3 = 0x0fa4
#byte PIR4 = 0x0f7b
#byte PIR5 = 0x0f7e
#byte PIE1 = 0x0f9d
#byte PIE2 = 0x0fa0
#byte PIE3 = 0x0fa3
#byte PIE4 = 0x0f7a
#byte PIE5 = 0x0f7d
#byte IPR1 = 0x0f9f
#byte IPR2 = 0x0fa2
#byte IPR3 = 0x0fa5
#byte IPR4 = 0x0f7c
#byte IPR5 = 0x0f7f
#byte RCON = 0x0fd0
// ----- timer register ---------------------------------------------------------------------------------------------------------------------------
#byte T0CON = 0x0fd5
#byte TMR0H = 0x0fd7
#byte TMR0L = 0x0fd6
#byte T1CON = 0x0fcd
#byte TMR1H = 0x0fcf
#byte TMR1L = 0x0fce
#byte T1GCON = 0x0fcc
#byte T2CON = 0x0fba
#byte TMR2_PR = 0x0fbb
#byte TMR2 = 0x0fbc
#byte T3CON = 0x0fb1
#byte TMR3H = 0x0fb3
#byte TMR3L = 0x0fb2
#byte T3GCON = 0x0fb4
#byte T4CON = 0x0f51
#byte TMR4_PR = 0x0f52
#byte TMR4 = 0x0f53
#byte T5CON = 0x0f4e
#byte TMR5H = 0x0f50
#byte TMR5L = 0x0f4f
#byte T5GCON = 0x0f4d
#byte T6CON = 0x0f4a
#byte TMR6_PR = 0x0f4b
#byte TMR6 = 0x0f4c
// ----- uart register ----------------------------------------------------------------------------------------------------------------------------
#byte RCREG1 = 0x0fae // UART 1
#byte TXSTA1 = 0x0fac
#byte RCSTA1 = 0x0fab
#byte BAUDCON1 = 0x0fb8
#byte SPBRGH1 = 0x0fb0
#byte SPBRG1 = 0x0faf
#byte RCREG2 = 0x0f74 // UART 2
#byte TXSTA2 = 0x0f72
#byte RCSTA2 = 0x0f71
#byte BAUDCON2 = 0x0f70
#byte SPBRGH2 = 0x0f76
#byte SPBRG2 = 0x0f75
// ----- portpin assign -----------------------------------------------------------------------------------------------
#bit REMOTE_IN = LATB.0
#bit REMOTE_OUT = LATD.6
#bit LED_GREEN_RIGHT = LATB.1
#bit LED_GREEN_LEFT = LATB.2
#bit MOTOR_RIGHT_C = LATB.3
#bit MOTOR_RIGHT_D = LATB.4
#bit SWITCH_ACCU = LATB.5
#bit LED_RED_LEFT = LATB.6
#bit LED_RED_RIGHT = LATB.7
#bit POS_1 = PORTC.2
#bit POS_2 = PORTC.1
#bit POS_3 = PORTC.0
#bit POS_4 = PORTD.7
#bit BUTTON_RIGHT = PORTC.3
#bit BUTTON_LEFT = PORTC.4
#bit BUZZER = LATC.5
#bit MOTOR_LEFT_A = LATD.0
#bit MOTOR_LEFT_B = LATD.1
#bit MOTOR_LEFT_C = LATD.2
#bit MOTOR_LEFT_D = LATD.3
#bit MOTOR_RIGHT_A = LATD.4
#bit MOTOR_RIGHT_B = LATD.5
#bit KEYSWITCH_CLOSE = PORTE.0
#bit KEYSWITCH_OPEN = PORTA.4
#bit SEL_POS_LEFT = LATE.1
#bit SEL_POS_RIGHT = LATE.2
#bit DEBUG = LATD.6
#define MOTORCURRENT_LEFT 0 // ad channels
#define MOTORCURRENT_RIGHT 1
#define PS_VOLTAGE 2
#define TEMPERATURE 3
#define ALARM 4
// --------------------------------------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------------------------------------
|
- Bootloader settings
Code: |
#define FLASH_SIZE getenv("FLASH_ERASE_SIZE")
#define LOADER_END 0x4FF
#define LOADER_SIZE 0x3ff
#define LOADER_ADDR (LOADER_END-LOADER_SIZE)
#ifndef _bootloader
#build(reset=LOADER_END+1, interrupt=LOADER_END+9)
#org 0, LOADER_END {}
#endif
#define BUFFER_LEN_LOD 64
|
- Routines for EEPROM read and write:
Code: |
#if (getenv ("DATA_EEPROM") > 256) // Größe EEPROM holen und Adresstyp automatisch setzen
typedef unsigned int16 addr_size;
#else
typedef unsigned int8 addr_size;
#endif
// --------------------------------------------------------------------------------------------------------------------------------------------------
// Prototypes
// --------------------------------------------------------------------------------------------------------------------------------------------------
unsigned int16 read_eeprom_int16 (addr_size address);
void write_eeprom_int16 (addr_size address, unsigned int16 data);
// --------------------------------------------------------------------------------------------------------------------------------------------------
void write_eeprom_int16 (addr_size address, unsigned int16 data) // write 16bit value to eeprom
{
signed int8 i = 0;
for(i = 1; i >= 0; i--)
{
write_eeprom ((address + i), (data & 0xff));
data >>= 8;
}
}
// --------------------------------------------------------------------------------------------------------------------------------------------------
unsigned int16 read_eeprom_int16 (addr_size address) // read 16bit value from eeprom
{
unsigned int8 i = 0;
unsigned int16 data = 0;
for (i=0; i<2; i++)
{
data <<= 8;
data += read_eeprom (address++);
}
return data;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------------------------------------
|
The bootloader should read a command from the serial port.
If the command "Test" is received, the board check routine should start if there is no value at the first two positions in the eeprom. Otherwise the loader should send an answer, that no test routine is present.
If the command "Flash" is received, the loader should write the application to the flash. This should overwrite the routines for the board check. The routines for the board check are too big for storing in the bootloader area.
If the pcb is programed with the bootloader only, everything works fine. I can run the test routine and also start the upload of an firmware. But after I upload a firmware, the application did not start and also the bootloader did not start anymore. In the application software i included also the bootloader settings (_bootloader is not defined).
I'm sure i missed a setting for the bootloader in my application. Can you please help me ?
nhol |
|
|
nhol
Joined: 22 Jun 2009 Posts: 5
|
|
Posted: Wed May 10, 2017 9:24 am |
|
|
Hello,
i found the problem. The Problem was the sprintf to convert the checksum to a string.
Snip from main of the bootloader:
Code: |
if (bytestosend) // data to pc?
{
BLTXBuffer[0] = 0x02; // STX
chksum = 0; // checksum
for (i = 1; i < bytestosend; i++)
chksum ^= BLTXBuffer[i];
sprintf(outval,"%2u", chksum); // ----------> did not work if application program is loaded
BLTXBuffer[bytestosend++] = outval[0]; // checksum into txbuffer
BLTXBuffer[bytestosend++] = outval[1];
BLTXBuffer[bytestosend++] = 0x03; // ETX
BLTXBuffer[bytestosend++] = 0x0a; // LF
BLTXBuffer[bytestosend++] = 0x0d; // CR
delay_ms (10);
for(i = 0; i < bytestosend; i++) // send answer
putc(BLTXBuffer[i], PCPORT);
bytestosend = 0;
}
}
|
nhol |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1355
|
|
Posted: Wed May 10, 2017 10:53 am |
|
|
You should check to see if the sprintf code is located inside the application address space. I didn't see any #orgs to prevent the bootloader from overwriting the application space. There was one for the application not to override the bootloader and one to place the dummy application main, but nothing to prevent an overly large bootloader from spilling out into the application space. |
|
|
nhol
Joined: 22 Jun 2009 Posts: 5
|
|
Posted: Thu Jun 08, 2017 8:21 am |
|
|
Hello,
i've reworked may bootloader and put some #org into the code.
Code: |
#case
#include <18F46K22.h>
#FUSES NOWDT
#FUSES PUT
#FUSES BORV29
#FUSES BROWNOUT
#FUSES NOPBADEN
#FUSES NOLVP
#FUSES NOXINST
#FUSES PROTECT
//#FUSES CPB
//#FUSES WRTC
#FUSES WRTB
//#FUSES EBTR
//#FUSES EBTRB
#define _bootloader
#include "Motorcontroller_bootloader.h"
#include "Motorcontroller_bootloader_defs.h"
#include <string.h>
#include <math.h>
#include "my_eeprom.c"
#use delay(clock=32MHz, crystal=8MHz)
#use FAST_IO (ALL)
#use rs232(baud=57600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=PORT1,errors,brgh1ok)
#ZERO_RAM
// ----- global vars ------------------------------------------------------------------------------------------------------------------------
char HWRevision[6] = "1.01b";
int BLbuffidx;
char BLbuffer[BUFFER_LEN_LOD] = {0};
unsigned int8 BLStartBootLoader = 0;
char BLRXBuffer[30] = {0};
char BLTXBuffer[30] = {0};
unsigned int8 BLStartTest = 0;
// --------------------------------------------------------------------------------------------------------------------------------------------------
// functions
// --------------------------------------------------------------------------------------------------------------------------------------------------
#org APPLICATION_START, APPLICATION_START+0x100
void application (void)
{
reset_cpu();
}
// --------------------------------------------------------------------------------------------------------------------------------------------------
unsigned int16 ReadADC (unsigned int8 channel)
{
unsigned int8 i = 0;
unsigned int16 retval = 0;
ADCON0 &= 0x03;
ADCON0 |= (channel << 2);
delay_us (200);
for (i = 0; i < 10; i++)
{
ADCON0 |= 0x02;
while (ADCON0 & 0x02);
retval += (AD_RES_H * 0x100) + AD_RES_L;
delay_ms (2);
}
return (retval / 10);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------
unsigned int8 CharToBIN (unsigned int8 *value)
{
unsigned int8 i;
unsigned int8 retval;
unsigned int8 chr;
for (i=0; i<2; i++)
{
chr = toupper(*value);
if (chr >= 'A')
{
chr -= 'A';
chr += 10;
}
else
chr -= '0';
retval <<= 4;
retval |= chr;
value++;
}
return retval;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------
void CheckBoard(void)
{
// do some stuff to check the board after assembling
}
// --------------------------------------------------------------------------------------------------------------------------------------------------
#ORG LOADER_ADDR+10, LOADER_END auto=0 default
unsigned int8 atoi_bl (unsigned int8 *value)
{
unsigned int8 i;
unsigned int8 retVal = 0;
unsigned int8 chr;
for (i = 0; i < 2; i++)
{
chr = toupper(*value);
if (chr >= 'A')
{
chr -= 'A';
chr += 10;
}
else
chr -= '0';
retVal <<= 4;
retVal |= chr;
value++;
}
return retVal;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------
void real_load_program (void)
{
int1 do_ACKLOD, done=FALSE;
unsigned int8 checksum, line_type;
unsigned int16 l_addr;
unsigned int16 h_addr = 0;
unsigned int32 addr;
#if getenv("FLASH_ERASE_SIZE") != getenv("FLASH_WRITE_SIZE")
unsigned int32 next_addr;
#endif
unsigned int8 dataidx;
unsigned int8 i;
unsigned int8 count;
unsigned int8 data[32];
unsigned int8 BLReceived = 0;
unsigned int8 rcvstate = 0;
char rcvchar = 0;;
rcvstate = 0;
while (!done)
{
BLbuffidx = 0;
BLReceived = 0;
do
{
if (kbhit(PORT1))
{
rcvchar = getc(PORT1);
switch (rcvstate)
{
case 0: if (rcvchar == ':')
{
BLbuffer[0] = rcvchar;
BLbuffidx = 1;
rcvstate = 1;
}
break;
case 1: BLbuffer[BLbuffidx++] = rcvchar;
if (rcvchar == 0x0a)
{
BLReceived = 1;
rcvstate = 0;
}
break;
}
}
}
while ((!BLReceived) && (BLbuffidx <= BUFFER_LEN_LOD));
putchar (XOFF,PORT1);
do_ACKLOD = TRUE;
if (BLbuffer[0] == ':')
{
count = atoi_bl (&BLbuffer[1]);
l_addr = ((unsigned int16)(atoi_bl (&BLbuffer[3])) << 8) + atoi_bl (&BLbuffer[5]);
line_type = atoi_bl (&BLbuffer[7]);
addr = ((unsigned int32)(h_addr) << 16) + l_addr;
checksum = 0;
for (i=1; i<(BLbuffidx-3); i+=2)
checksum += atoi_bl (&BLbuffer[i]);
checksum = 0xFF - checksum + 1;
if (checksum != atoi_bl (&BLbuffer[BLbuffidx-3]))
do_ACKLOD = FALSE;
else
{
switch (line_type)
{
case 0: if (((addr < LOADER_ADDR) || (addr > LOADER_END)) && (addr < getenv("PROGRAM_MEMORY")))
{
dataidx = 0;
for (i=9; i<(BLbuffidx-3); i+=2)
data[dataidx++] = atoi_bl (&BLbuffer[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);
}
break;
case 1: done = TRUE;
break;
case 4: h_addr = ((unsigned int16)(atoi_bl (&BLbuffer[9]) << 8)) + atoi_bl (&BLbuffer[11]);
break;
}
}
}
if (do_ACKLOD)
putc (ACKLOD, PORT1);
putc(XON, PORT1);
}
putc (ACKLOD, PORT1);
putc(XON, PORT1);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------
#org default
#org LOADER_ADDR, LOADER_ADDR+9
void load_program(void)
{
real_load_program();
}
// --------------------------------------------------------------------------------------------------------------------------------------------------
#int_global
void isr(void)
{
jump_to_isr(LOADER_END + 5 * (getenv("BITS_PER_INSTRUCTION") / 8));
}
// --------------------------------------------------------------------------------------------------------------------------------------------------
// main
// --------------------------------------------------------------------------------------------------------------------------------------------------
#org 0x0040, 0x044f
void main(void)
{
unsigned int8 i = 0;
unsigned int8 chksum = 0;
unsigned int8 bytestosend = 0;
unsigned int8 rxstate = 0;
unsigned int16 rxtimeout = 0;
unsigned int8 rcvchar = 0;
int1 received = FALSE;
unsigned int8 bytecounter = 0;
unsigned int8 bootloaderruntime = 0;
unsigned int8 nibble = 0;
setup_adc_ports (sAN0 | sAN1 | sAN2 | sAN3 | sAN4);
setup_adc (ADC_CLOCK_INTERNAL | ADC_TAD_MUL_20);
PORTA = 0x00;
LATA = 0x00;
TRISA = 0xff;
PORTB = 0x20;
LATB = 0x20;
TRISB = 0x00;
PORTC = 0x00;
LATC = 0x00;
TRISC = 0x9f;
PORTD = 0x00;
LATD = 0x00;
TRISD = 0x80;
PORTE = 0x00;
LATE = 0x00;
TRISE = 0x01;
ANSELA = 0x2f;
ANSELB = 0x00;
ANSELC = 0x00;
ANSELD = 0x00;
ANSELE = 0x00;
VREFCON0 = 0xb0;
ADCON1 = 0x08;
ADCON2 |= 0x80;
port_b_pullups (0x00);
disable_interrupts (GLOBAL);
disable_interrupts (INT_TIMER0);
disable_interrupts (INT_RDA);
clear_interrupt (INT_TIMER0);
clear_interrupt (INT_RDA);
// while (TRUE) // delete comment for DEBUG
{
BUZZER = 1;
delay_ms (30);
BUZZER = 0;
received = FALSE;
rcvchar = 0;
rxtimeout = 0;
rxstate = 0;
BLStartBootLoader = 0;
bytecounter = 0;
bootloaderruntime = 0;
while ((++bootloaderruntime < 40) && (!BLStartBootLoader))
{
for (i = 0; i < 30; i++)
{
BLRXBuffer[i] = 0;
BLTXBuffer[i] = 0;
}
rxtimeout = 0;
bytestosend = 0;
rxtimeout = 0;
received = 0;
while ((!received) && (++rxtimeout < 10000))
{
if (kbhit(PORT1))
{
rcvchar = getc(PORT1);
switch (rxstate)
{
case 0: if (rcvchar == 0x02)
{
BLRXBuffer[0] = rcvchar;
bytecounter = 1;
rxtimeout = 0;
rxstate = 1;
}
break;
case 1: BLRXBuffer[bytecounter++] = rcvchar;
rxtimeout = 0;
if (rcvchar == 0x03)
{
rcvchar = 0;
received = TRUE;
bytecounter = 0;
rxstate = 0;
}
if (bytecounter > 10)
{
rcvchar = 0;
bytecounter = 0;
rxstate = 0;
rxtimeout = 10000;
}
break;
}
}
delay_us (10);
if (received)
{
received = FALSE;
switch (BLRXBuffer[1])
{
case 'G': switch (BLRXBuffer[2])
{
case 'I': BLTXBuffer[0] = 0x02;
BLTXBuffer[1] = 'G';
BLTXBuffer[2] = 'B';
BLTXBuffer[3] = 'o';
BLTXBuffer[4] = 'o';
BLTXBuffer[5] = 't';
BLTXBuffer[6] = ' ';
BLTXBuffer[7] = 'M';
BLTXBuffer[8] = 'C';
BLTXBuffer[9] = HWRevision[0];
BLTXBuffer[10] = HWRevision[1];
BLTXBuffer[11] = HWRevision[2];
BLTXBuffer[12] = HWRevision[3];
BLTXBuffer[13] = HWRevision[4];
bytestosend = 14;
break;
}
break;
case 'S': switch (BLRXBuffer[2])
{
case 'F': BLStartBootLoader = 1;
BLTXBuffer[1] = 'O';
BLTXBuffer[2] = 'K';
bytestosend = 3;
break;
case 'T': if (read_eeprom_int16 (0x00) == 0xffff)
{
BLStartTest = 1;
BLTXBuffer[1] = 'T';
BLTXBuffer[2] = 'e';
BLTXBuffer[3] = 's';
BLTXBuffer[4] = 't';
bytestosend = 5;
}
else
{
BLTXBuffer[1] = 'N';
BLTXBuffer[2] = 'o';
BLTXBuffer[3] = 'T';
BLTXBuffer[4] = 'e';
BLTXBuffer[5] = 's';
BLTXBuffer[6] = 't';
bytestosend = 7;
}
break;
}
break;
}
if (bytestosend)
{
BLTXBuffer[0] = 0x02;
chksum = 0;
for (i = 1; i < bytestosend; i++)
chksum ^= BLTXBuffer[i];
nibble = chksum / 0x10;
if (nibble > 9)
BLTXBuffer[bytestosend++] = 'a' + (nibble - 10);
else
BLTXBuffer[bytestosend++] = '0' + nibble;
nibble = chksum % 0x10;
if (nibble > 9)
BLTXBuffer[bytestosend++] = 'a' + (nibble - 10);
else
BLTXBuffer[bytestosend++] = '0' + nibble;
BLTXBuffer[bytestosend++] = 0x03;
BLTXBuffer[bytestosend++] = 0x0a;
BLTXBuffer[bytestosend++] = 0x0d;
delay_ms (10);
for(i = 0; i < bytestosend; i++)
putc(BLTXBuffer[i], PORT1);
bytestosend = 0;
}
}
}
if (BLStartBootLoader)
load_program ();
if (BLStartTest)
CheckBoard ();
BLStartBootLoader = 0;
BLStartTest = 0;
}
application ();
}
// --------------------------------------------------------------------------------------------------------------------------------------------------
// END
// --------------------------------------------------------------------------------------------------------------------------------------------------
|
Everything works fine. I can check my board and i can upload a firmware. If i programmed a firmware with about 50 % of ROM and about 77 % of RAM, my application works as expected. But if i programmed a firmware with about 69% of ROM and about 81 % of RAM, my application sporadical restart (checked by an counter that increments an eeprom cell after each start of the application).
If i programmed the bigger application without the bootloader (and also removed the #build before compiling), my application works fine.
Can you please give me some suggestions, what i should check to get my big application to work with the bootloader?
nhol |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19545
|
|
Posted: Thu Jun 08, 2017 9:03 am |
|
|
I'd start the other way.
Get rid of your #org's.
Then build your bootloader.
Look at the resulting assembler.
Where is the end of the bootloader?. Remember LOADER_END needs to be one byte under the next page erase boundary above this.
Then where is the booloader const data being stored?.
Then try something else. Expand your code size without adding anything. Just create a large const array to use up some space. Don't do anything else. Does it still work?. Try the same with the RAM. Does it still work. I'd be slightly suspicious that something else is going wrong. Possibly a stack overflow in the extra code, or an array overflow etc.. So you need to make some demo code that is simple, and uses the space, to see if this really is the problem. |
|
|
nhol
Joined: 22 Jun 2009 Posts: 5
|
|
Posted: Fri Jun 09, 2017 12:29 am |
|
|
Thanks Ttelmah
LOADER_END is defines with 0x07ff. This is the last address of the bootblock. The loader size is 0x0408. So this shouldn't be the problem.
The routines for the pcb test are located at the application space. They will be overwritten by the final application.
Now i store some countervalues and flags at the end of my eeprom. The flags are the restart causes. I hope, that with the flags i can find out the reason for the sporadic restarts.
nhol |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19545
|
|
Posted: Fri Jun 09, 2017 1:37 am |
|
|
There are conflicts in what you are posting/saying.
If we look at your posted original bootloader 'main', the posted code has one more closing '}' than opening '{', so cannot compile.
There is a similar problem in your newer code, with a remarked out 'while', but the opening bracket still there, so it can't compile as posted....
Then you have as a posted code section:
Code: |
#define FLASH_SIZE getenv("FLASH_ERASE_SIZE")
#define LOADER_END 0x4FF
#define LOADER_SIZE 0x3ff
#define LOADER_ADDR (LOADER_END-LOADER_SIZE)
#ifndef _bootloader
#build(reset=LOADER_END+1, interrupt=LOADER_END+9)
#org 0, LOADER_END {}
#endif
#define BUFFER_LEN_LOD 64
|
This differs from what you are saying about the declared loader size.
There is also a problem with this declaration. If you look at how the values are calculated in the bootloader.h, LOADER_SIZE is declared after other calculation, to be equal to LOADER_END. This way for a loader at the start of memory, LOADER_ADDR will always be zero. With your figures above, you have 100 locations at the start of memory, not protected from writes.....
You then say 'The loader size is 0x0408'. It isn't.
Fixing the bracket, the loader sizing errors, and compiling the code as posted, gives a size of 0x782.
You need to clean up and stop doing random fiddling.
It's important to understand how loader.h is used. All you need to do, to compile for a bootloader that is this size, is:
Code: |
#define LOADER_END 0x7FF
#define _bootloader
#include "bootloader.h"
|
The bootloader file then automatically handles the #ORG's etc., for you.
As a general comment, sort out your include order. Generally the clock declaration must be in front of anything that may use the clock. I don't think there is any problem in this case, but it is bad practice to be putting it after other code includes. |
|
|
nhol
Joined: 22 Jun 2009 Posts: 5
|
|
Posted: Fri Jun 09, 2017 5:00 am |
|
|
Thanks Ttelmah,
You are right. In my newest code, there is missing a closing bracket after the 10 us delay and before if (received). Sorry, for this (copy/paste error).
About the loader size, i forgot to show my new settings for the bootloader. I've changed the loader_end to 0x07ff.
All other points will be checked and will reorder my code. Thanks for your help.
nhol |
|
|
|
|
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
|