|
|
View previous topic :: View next topic |
Author |
Message |
russk2txb
Joined: 30 Mar 2008 Posts: 109 Location: New Jersey
|
Bootloader, program will not run when #ORG is changed |
Posted: Tue Jan 31, 2017 10:08 am |
|
|
Ok, so I finally have my bootloader working. At least it successfully loads and runs a simple test program that flashes a LED. But it does not work with my real program. In fact the real program will not run even when loaded with the ICD programmer (in other words it fails when bootloader.h is included in the project). I have boiled down bootloader.h for just the PCH programmer and just the device I am using:
Code: | #define LOADER_END 0x4ff
#ifndef _bootloader
#build(reset=LOADER_END+1, interrupt=LOADER_END+9)
#org 0, LOADER_END {}
#else
#if getenv("PROGRAM_MEMORY") <= 0x10000
#org LOADER_END+5, (getenv("PROGRAM_MEMORY") - 1) {}
#else
#org LOADER_END+5, 0xFFFE {}
#org 0x10000, (getenv("PROGRAM_MEMORY") - 1) {}
#endif
#endif
|
As I mentioned, this works fine with the test program, but my desired program will not run. It starts off ok and runs for a dozen lines or so and then gets lost about the first time it attempts to use the serial port. I removed all the calls that write to the serial port and it did not help. But exactly where it stops is somewhat random, sometimes it stops sooner than other times. I am wondered if maybe it is the rs232 interrupt routine that is causing the problem, but there is no serial data being sent to the controller during the test.
Does anyone have any ideas why this might happen. (I have plenty of program memory - only uses 50%).
Thanks, Russ |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Tue Jan 31, 2017 10:40 am |
|
|
If you've got the serial ISR enabled without a handler (the ISR routine) that WILL cause the PIC to 'go funny'....
Since the bootloader and a small test program are OK... look inside your 'real' program.
Perhaps the fuses are different (should be same as bootloader), maybe the WDT is enabled, maybe a timer not set right, ???
Real hard to debug without seeing the code of course...
Jay |
|
|
russk2txb
Joined: 30 Mar 2008 Posts: 109 Location: New Jersey
|
|
Posted: Tue Jan 31, 2017 11:29 am |
|
|
Hello Jay and thanks for responding. No the serial interrupts are enabled but there is a handler that works. I did try disabling the interrupts for everything but the timer. I guess I will try the timer too, but I have to disable some other code to do that. The fuses are the same and the RS-232 is set up exactly the same. Besides that should not really matter when I am trying to make it run when loaded with the ICD. I do notice that there is no code between zero and 0x500, as expected. Of course there would be if I load it with the boot loader.
I do know it is hard without seeing the code but it is long and complicated. I don't want anyone to have to dig through it to try to find my problem, but I thought maybe the symptoms were familiar to someone. The program works flawlessly when compiled without bootloader.h.
I guess I am going to have to start stripping it down until I find out what makes it start running...
Thanks again, Russ |
|
|
russk2txb
Joined: 30 Mar 2008 Posts: 109 Location: New Jersey
|
|
Posted: Tue Jan 31, 2017 4:40 pm |
|
|
Ok, I have more information. It is the interrupts. As soon as I enable global interrupts (with any interrupt enabled) the processor reboots. The program counter just starts over at address zero. It seems like the Code: | interrupt=LOADER_END+9 | is not working, instead it is going to address zero.
However I am not even sure that interrupt vector at 0x508 is for the software interrupts. I can't find any information in CCS help file about that. The timer and rs232 interrupts are what I would call software interrupts, and they might have a different path than a hardware interrupt. In any case something is wrong with the interrupt vectoring when the program has been re-org'd from zero to 0x500.
I tried setting a breakpoint at 0x508 but it never hits.
Any ideas?
Thanks much, Russ |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Jan 31, 2017 5:33 pm |
|
|
You know the drill on this forum. If you want replies, you should post all
this stuff:
1. Post your compiler version.
2. Post your PIC.
3. Tell us the type of bootloader you are doing. Is it RS-232 only, or
is it a USB bootloader ?
4. Post your small compilable test program.
Don't post the driver files. If we know your compiler version, we can
install it and we'll have the files. Or, we can see the changes that you
already posted. |
|
|
russk2txb
Joined: 30 Mar 2008 Posts: 109 Location: New Jersey
|
|
Posted: Tue Jan 31, 2017 6:38 pm |
|
|
Ok Jay. Most of that stuff was in the previous thread and I forgot that it would need repeating here.
I'm using the CCS compiler V 5.064
The processor is PIC18F4680
The bootloader is not really relevant since the program won't run even without the boot loader. The only difference from the working program is the #build and #org statements in bootload.h, which I did post in the first message in this thread. This is the entire header file:
Code: | #define FLASH_SIZE 64
#define LOADER_END 0x4ff // loader always starts at zero so end is also size
#ifndef _bootloader
#build(RESET=LOADER_END+1, INTERRUPT=LOADER_END+9)
#org 0, LOADER_END {}
#else
#if getenv("PROGRAM_MEMORY") <= 0x10000
#org LOADER_END+5, (getenv("PROGRAM_MEMORY") - 1) {}
#else
#org LOADER_END+5, 0xFFFE {}
#org 0x10000, (getenv("PROGRAM_MEMORY") - 1) {}
#endif
#endif
| Here is the startup code for the program that will not run when bootload.h is included: Code: | #define PROC_4680 // enable this define for the PIC4680 processor
#define CLOCK_20 // enable this define for 20 Mhz clock
#ifdef PROC_4680
#include <18F4680.h>
#else
#include <18F4580.h>
#endif
//#define __DEBUG
#ifdef __DEBUG
#device ICD = TRUE
#endif
#device ADC=16
#device HIGH_INTS = TRUE
#device WRITE_EEPROM = NOINT
#fuses NOWDT,NOPROTECT,BORV21,NOLVP,PUT
#ifdef CLOCK_20
#fuses HS // no pll
#use delay(clock=20M)
#else
#fuses H4 // 4X pll
#use delay(clock=40M)
#endif
#include "DrzBootloader.h"
#include <float.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <lcd.c>
#include "DrzControl.h"
#include "config.c"
#include "encoders.c"
void main ()
{
setup_ccp1 (CCP_OFF);
setup_ccp2 (CCP_OFF);
#ifdef CLOCK_20
setup_timer_0 (RTCC_INTERNAL | RTCC_DIV_8); // setup timer 0 interrupts
Time.Preset = 3036;
#else
setup_timer_0 (RTCC_INTERNAL | RTCC_DIV_16); // setup timer 0 interrupts
Time.Preset = 3036; // overflows in 100 msec. This is the same as 20 MHz because we use div by 16 instead of by 8.
#endif
setup_adc_ports (AN0_TO_AN3); // for 18F4580
setup_adc (ADC_CLOCK_DIV_32);
input (LCD_PRESENT); // set LCD flag pin as a input
set_tris_a (0x1B); // A0,A1,A3,A4 are inputs. A2, A5-A7 outputs
set_tris_b (0x3F); // B0-B5 are inputs. B6,B7 are outputs
set_tris_c (0x8F); // C0-C3 and C7 are inputs, C4-C6 outputs
set_tris_e (0x00); // all outputs
output_low (MOTOR_UP); // UP
output_low (MOTOR_DOWN); // DOWN
output_low (TX_LED); // Turn off the tx led
output_low (MOTOR_CCW); // CCW Turn off the relays.
output_low (MOTOR_CW); // CW
output_low (ABS_ENABLE); // Set LOAD for AB chip to a low RECIEVE state
output_low (CTS_PIN); // USED TO TOGGLE "HIGH" DSR LINE by the spare RS232 T2 in
enable_interrupts (INT_RTCC);
enable_interrupts (int_rda);
enable_interrupts (int_ad);
enable_interrupts (global); // start all interrupts
|
As soon as global interrupts are enabled the program immediately starts rebooting every time an interrupt takes place. If no interrupts are enabled but global is enabled then the program runs.
I have compared the enable interrupt code between the working program and the failing one and the code is the same.
If I place a breakpoint at address 0x508, or at the first line of any of the interrupt handlers, the break never happens.
I hope that is enough information so you could see what is going on. If not, I will supply whatever more you want.
Thanks, Russ |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Tue Jan 31, 2017 7:13 pm |
|
|
any chance this is happening because it's attached to the ICD and in debug mode?
or
does this also happen to a separate, stand alone PCB ?
Jay |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Jan 31, 2017 8:27 pm |
|
|
That isn't really a test program. Just to make it compile, I had to
comment out 14 lines.
One reason for crashing would be if there are no interrupt handlers.
Do you have interrupt handlers for these ? You probably do, but
I don't know that.
Code: |
enable_interrupts (INT_RTCC);
enable_interrupts (int_rda);
enable_interrupts (int_ad);
|
To truly make a test program, you should:
1. Strip out all the ifdefs. Just make it run for one version.
2. Remove all unneeded #include files, which is going to be most of them.
3. Strip out all the motor code, and disconnect all motor circuits.
4. Get rid of HIGH INTS, eeprom NOINT, etc.
And keep on stripping it down to almost nothing. If it still fails at that
point, then you've got something we can work with. Right now, your
program has got tons of fluff in it. For example, it's well know on the
forum to get a post such as "Help, my PIC keeps resetting". And it turns
out to be the motors put such a load on the power supply when they kick
in, that it loads the Vdd down, or the motors or relays put noise into the
system, or they are missing the back EMF diode, etc.
Your assumption is that the problem is pure code. It could be. But we
won't know for sure until you take the time to strip it down. |
|
|
russk2txb
Joined: 30 Mar 2008 Posts: 109 Location: New Jersey
|
|
Posted: Tue Jan 31, 2017 10:51 pm |
|
|
Ok. I can do that. There are no motors connected. There are driver transistors that can drive relays but there are no relays connected either. The board is powered by a lab quality DC power supply providing +15 volts to the 5 volt regulator. The two processors I use are both identical except that the 4680 has twice the program memory space.
Yes there are interrupt handlers for every interrupt. As I said, this program works very well when it has it's origin at zero. The fact that it fails as soon as the interrupts are enabled tells me that it is not in any of the code that follows (except for possibly the interrupt handlers themselves).
But it does not matter which interrupt is left running - I can turn them all off except for one and the same thing happens as soon as the interrupt fires. These are all software interrupts, no hardware ones, so as soon as the timer fires, or the RS232 receives a byte, or the A/D completes and fires it's interrupt, the computer reboots. But program control never reaches the interrupt handlers. I just don't think it can be any of the code that is called from the main loop, since it never gets to that code.
Immediately after the interrupts are enabled I do send several lines of text to the LCD. When interrupts are enabled usually only the first line, sometimes two lines, get displayed before the program crashes. If interrupts are all turned off then LCD displays everything.
But I will try to strip it down to a test program and post it - Tomorrow. I am going to bed now, it is just about midnight here...
Thanks, Russ |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19499
|
|
Posted: Wed Feb 01, 2017 3:33 am |
|
|
Er:
Quote: |
The bootloader is not really relevant since the program won't run even without the boot loader.
|
You are disagreeing with yourself. Saying the code works at address 0, then than it "won't run even without the bootloader".
You do understand that the code can _only_ load at address 0, if you don't have the bootloader. So how are you testing it at any other address?.
Part of the bootloader's 'job' is to re-vector the boot and the interrupt addresses. Without these re-vector operations, code at any other address can't work.
Understand you cannot easily (it is possible, but only at a massive cost in performance), use interrupts both in the bootloader and the main code. This code in the bootloader:
Code: |
#int_global
void isr(void) {
jump_to_isr(LOADER_END+5*(getenv("BITS_PER_INSTRUCTION")/8));
}
|
Creates the two jumps to automatically re-vector the interrupts up to the 'main' code. If you try to use interrupts in the bootloader, or you don't have this code, it'll stop interrupts in the main code from working. This is why the USB bootloader example _polls_ the USB handling rather than using interrupts. |
|
|
russk2txb
Joined: 30 Mar 2008 Posts: 109 Location: New Jersey
|
|
Posted: Wed Feb 01, 2017 7:57 am |
|
|
Hello again Jay. I think you have put your finger on it. I expected that the bootloader.h statement Code: | #build(RESET=LOADER_END+1, INTERRUPT=LOADER_END+9) |
would cause interrupts to be vectored to address ox508. If not, what is the purpose of that statement?
For test, I am loading the program (that includes bootload.h) via the ICD. I thought I had said that but it was in a previous thread, sorry. So all ROM between zero and 0x500 contains zeros. The program counter starts at zero and increments up through all the NOPs until it gets to x500 and then runs. This works fine with my test program that has no interrupts. Apparently an interrupt still vectors to address 8 - hence the reboot. But what is the purpose of the #build statement if not to change the starting points used by the processor?
Thanks, Russ |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19499
|
|
Posted: Wed Feb 01, 2017 8:02 am |
|
|
It changes the starting point used by the _code_. The processor point is fixed by the hardware.
In the bootloader, this:
Code: |
#int_global
void isr(void) {
jump_to_isr(LOADER_END+5*(getenv("BITS_PER_INSTRUCTION")/8));
}
|
Re-vectors the interrupts to the address used in the main code. The 'jump_to_isr' instruction automatically creates the assembler to re-vector the interrupt. In the case of PIC18's, it automatically handles both interrupt locations. Effectively this is a dummy interrupt 'handler' containing the re-vectoring instruction(s). |
|
|
russk2txb
Joined: 30 Mar 2008 Posts: 109 Location: New Jersey
|
|
Posted: Wed Feb 01, 2017 8:43 am |
|
|
Looking at the bootloader code: Code: | #int_global
void isr ()
{
jump_to_isr (LOADER_END + 5 * (getenv ("BITS_PER_INSTRUCTION") / 8));
}
*
0008: GOTO 0508
000C: NOP
000E: NOP
0010: NOP
0012: NOP
0014: NOP
0016: NOP
0018: GOTO 0518
|
This is right at the end. I don't understand what I am seeing. BITS_PER_INSTRUCTION is 16, so I would expect to see a jump to 0x4FF + (5 * 2) = 0x509. But the compiler properly generates a jump to 0x508. And then it seems to use the value 5 * 2 to generate an additional jump 10 addresses higher to a vector that is also 10 bytes higher than the first one. That is not at all what the compiler manual says about what the jump_to_isr command does. Can you shed any light on that?
Thanks, Russ |
|
|
russk2txb
Joined: 30 Mar 2008 Posts: 109 Location: New Jersey
|
|
Posted: Wed Feb 01, 2017 8:53 am |
|
|
Ok our messages crossed. You said that the #build statement is used to place code to revector the interrupts, but that #build statement is not seen by the bootload program (because of _bootloader being defined). And I don't see any effect on the code generated for the actual program. It seems that only the jump_to_isr handles the revectoring, but again, the math does not make sense to me???
In the meantime, I loaded my program using the bootloader, and it seems to work except that the EEPROM is not loaded. This causes the program to put an error message on the LCD and then stop before the interrupts are enabled.
I read somewhere that the bootloader will not load EEPROM, but the addresses and values are in the hex file so I am thinking that maybe the bootloader can be modified to write to EEPROM when it encounters those addresses.
Thanks, Russ |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1345
|
|
Posted: Wed Feb 01, 2017 8:57 am |
|
|
russk2txb wrote: |
I thought I had said that but it was in a previous thread, sorry. |
Just wanted to comment since you mentioned this a couple of times. Each thread needs to have the current information. While you are generally only concerned with the threads that concern your projects so it is easier for you to swap between threads, the rest of us might see 10 or 20 threads active at a time, all by different people. It isn't easy for us to have to manage information in multiple threads by multiple people that may or may not be related. Then on top of that there are many instances where the same poster has multiple configurations they are working with and different threads might indicate different configurations.
So please make sure the compiler rev, chip part number, etc. are always posted in the current thread, even if you have posted them in a previous question in another thread. Don't rely on it being in a previous thread. It makes it easier for us, which hopefully makes it better for you. |
|
|
|
|
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
|