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

Bootloader, program will not run when #ORG is changed
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
russk2txb



Joined: 30 Mar 2008
Posts: 109
Location: New Jersey

View user's profile Send private message

Bootloader, program will not run when #ORG is changed
PostPosted: Tue Jan 31, 2017 10:08 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Jan 31, 2017 10:40 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Jan 31, 2017 11:29 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Jan 31, 2017 4:40 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Jan 31, 2017 5:33 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Jan 31, 2017 6:38 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Jan 31, 2017 7:13 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Jan 31, 2017 8:27 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Jan 31, 2017 10:51 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Feb 01, 2017 3:33 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Feb 01, 2017 7:57 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Feb 01, 2017 8:02 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Feb 01, 2017 8:43 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Feb 01, 2017 8:53 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Feb 01, 2017 8:57 am     Reply with quote

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

 
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